PR15350, Fix compressed debug sections for PE targets
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index a67663da1f434090fc07b75706d066bb47ddf840..3656046eea4f43e48836a53abf7719d7a7f07ca2 100644 (file)
@@ -1,6 +1,5 @@
 /* MIPS-specific support for ELF
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1993-2019 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
 #include "libbfd.h"
 #include "libiberty.h"
 #include "elf-bfd.h"
+#include "ecoff-bfd.h"
 #include "elfxx-mips.h"
 #include "elf/mips.h"
 #include "elf-vxworks.h"
+#include "dwarf2.h"
 
 /* Get the ECOFF swapping routines.  */
 #include "coff/sym.h"
 
 #include "hashtab.h"
 
+/* Types of TLS GOT entry.  */
+enum mips_got_tls_type {
+  GOT_TLS_NONE,
+  GOT_TLS_GD,
+  GOT_TLS_LDM,
+  GOT_TLS_IE
+};
+
 /* This structure is used to hold information about one GOT entry.
-   There are three types of entry:
-
-      (1) absolute addresses
-           (abfd == NULL)
-      (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
-           (abfd != NULL, symndx >= 0)
-      (3) global and forced-local symbols
-           (abfd != NULL, symndx == -1)
-
-   Type (3) entries are treated differently for different types of GOT.
-   In the "master" GOT -- i.e.  the one that describes every GOT
-   reference needed in the link -- the mips_got_entry is keyed on both
-   the symbol and the input bfd that references it.  If it turns out
-   that we need multiple GOTs, we can then use this information to
-   create separate GOTs for each input bfd.
-
-   However, we want each of these separate GOTs to have at most one
-   entry for a given symbol, so their type (3) entries are keyed only
-   on the symbol.  The input bfd given by the "abfd" field is somewhat
-   arbitrary in this case.
-
-   This means that when there are multiple GOTs, each GOT has a unique
-   mips_got_entry for every symbol within it.  We can therefore use the
-   mips_got_entry fields (tls_type and gotidx) to track the symbol's
-   GOT index.
-
-   However, if it turns out that we need only a single GOT, we continue
-   to use the master GOT to describe it.  There may therefore be several
-   mips_got_entries for the same symbol, each with a different input bfd.
-   We want to make sure that each symbol gets a unique GOT entry, so when
-   there's a single GOT, we use the symbol's hash entry, not the
-   mips_got_entry fields, to track a symbol's GOT index.  */
+   There are four types of entry:
+
+      (1) an absolute address
+           requires: abfd == NULL
+           fields: d.address
+
+      (2) a SYMBOL + OFFSET address, where SYMBOL is local to an input bfd
+           requires: abfd != NULL, symndx >= 0, tls_type != GOT_TLS_LDM
+           fields: abfd, symndx, d.addend, tls_type
+
+      (3) a SYMBOL address, where SYMBOL is not local to an input bfd
+           requires: abfd != NULL, symndx == -1
+           fields: d.h, tls_type
+
+      (4) a TLS LDM slot
+           requires: abfd != NULL, symndx == 0, tls_type == GOT_TLS_LDM
+           fields: none; there's only one of these per GOT.  */
 struct mips_got_entry
 {
-  /* The input bfd in which the symbol is defined.  */
+  /* One input bfd that needs the GOT entry.  */
   bfd *abfd;
   /* The index of the symbol, as stored in the relocation r_info, if
      we have a local symbol; -1 otherwise.  */
@@ -94,24 +88,47 @@ struct mips_got_entry
        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).  */
+       corresponding to a symbol in the GOT.  The symbol's entry
+       is in the local area if h->global_got_area is GGA_NONE,
+       otherwise it is in the global area.  */
     struct mips_elf_link_hash_entry *h;
   } d;
 
-  /* The TLS types included in this GOT entry (specifically, GD and
-     IE).  The GD and IE flags can be added as we encounter new
-     relocations.  LDM can also be set; it will always be alone, not
-     combined with any GD or IE flags.  An LDM GOT entry will be
-     a local symbol entry with r_symndx == 0.  */
+  /* The TLS type of this GOT entry.  An LDM GOT entry will be a local
+     symbol entry with r_symndx == 0.  */
   unsigned char tls_type;
 
+  /* True if we have filled in the GOT contents for a TLS entry,
+     and created the associated relocations.  */
+  unsigned char tls_initialized;
+
   /* The offset from the beginning of the .got section to the entry
      corresponding to this symbol+addend.  If it's a global symbol
      whose offset is yet to be decided, it's going to be -1.  */
   long gotidx;
 };
 
+/* This structure represents a GOT page reference from an input bfd.
+   Each instance represents a symbol + ADDEND, where the representation
+   of the symbol depends on whether it is local to the input bfd.
+   If it is, then SYMNDX >= 0, and the symbol has index SYMNDX in U.ABFD.
+   Otherwise, SYMNDX < 0 and U.H points to the symbol's hash table entry.
+
+   Page references with SYMNDX >= 0 always become page references
+   in the output.  Page references with SYMNDX < 0 only become page
+   references if the symbol binds locally; in other cases, the page
+   reference decays to a global GOT reference.  */
+struct mips_got_page_ref
+{
+  long symndx;
+  union
+  {
+    struct mips_elf_link_hash_entry *h;
+    bfd *abfd;
+  } u;
+  bfd_vma addend;
+};
+
 /* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND].
    The structures form a non-overlapping list that is sorted by increasing
    MIN_ADDEND.  */
@@ -123,13 +140,11 @@ struct mips_got_page_range
 };
 
 /* This structure describes the range of addends that are applied to page
-   relocations against a given symbol.  */
+   relocations against a given section.  */
 struct mips_got_page_entry
 {
-  /* The input bfd in which the symbol is defined.  */
-  bfd *abfd;
-  /* The index of the symbol, as stored in the relocation r_info.  */
-  long symndx;
+  /* The section that these entries are based on.  */
+  asection *sec;
   /* The ranges for this page entry.  */
   struct mips_got_page_range *ranges;
   /* The maximum number of page entries needed for RANGES.  */
@@ -140,11 +155,10 @@ struct mips_got_page_entry
 
 struct mips_got_info
 {
-  /* The global symbol in the GOT with the lowest index in the dynamic
-     symbol table.  */
-  struct elf_link_hash_entry *global_gotsym;
   /* The number of global .got entries.  */
   unsigned int global_gotno;
+  /* The number of global .got entries that are in the GGA_RELOC_ONLY area.  */
+  unsigned int reloc_only_gotno;
   /* The number of .got slots used for TLS.  */
   unsigned int tls_gotno;
   /* The first unused TLS .got entry.  Used only during
@@ -154,39 +168,27 @@ struct mips_got_info
   unsigned int local_gotno;
   /* The maximum number of page entries needed.  */
   unsigned int page_gotno;
-  /* The number of local .got entries we have used.  */
-  unsigned int assigned_gotno;
+  /* The number of relocations needed for the GOT entries.  */
+  unsigned int relocs;
+  /* The first unused local .got entry.  */
+  unsigned int assigned_low_gotno;
+  /* The last unused local .got entry.  */
+  unsigned int assigned_high_gotno;
   /* A hash table holding members of the got.  */
   struct htab *got_entries;
+  /* A hash table holding mips_got_page_ref structures.  */
+  struct htab *got_page_refs;
   /* A hash table of mips_got_page_entry structures.  */
   struct htab *got_page_entries;
-  /* 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;
-  /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
-     for none, or MINUS_TWO for not yet assigned.  This is needed
-     because a single-GOT link may have multiple hash table entries
-     for the LDM.  It does not get initialized in multi-GOT mode.  */
-  bfd_vma tls_ldm_offset;
-};
-
-/* 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.  */
+/* Structure passed when merging bfds' 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.  */
@@ -210,23 +212,14 @@ struct mips_elf_got_per_bfd_arg
   unsigned int global_count;
 };
 
-/* Another structure used to pass arguments for got entries traversal.  */
+/* A structure used to pass information to htab_traverse callbacks
+   when laying out the GOT.  */
 
-struct mips_elf_set_global_got_offset_arg
+struct mips_elf_traverse_got_arg
 {
+  struct bfd_link_info *info;
   struct mips_got_info *g;
   int value;
-  unsigned int needed_relocs;
-  struct bfd_link_info *info;
-};
-
-/* A structure used to count TLS relocations or GOT entries, for GOT
-   entry or ELF symbol table traversal.  */
-
-struct mips_elf_count_tls_arg
-{
-  struct bfd_link_info *info;
-  unsigned int needed;
 };
 
 struct _mips_elf_section_data
@@ -234,7 +227,6 @@ struct _mips_elf_section_data
   struct bfd_elf_section_data elf;
   union
   {
-    struct mips_got_info *got_info;
     bfd_byte *tdata;
   } u;
 };
@@ -242,6 +234,74 @@ struct _mips_elf_section_data
 #define mips_elf_section_data(sec) \
   ((struct _mips_elf_section_data *) elf_section_data (sec))
 
+#define is_mips_elf(bfd)                               \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour     \
+   && elf_tdata (bfd) != NULL                          \
+   && elf_object_id (bfd) == MIPS_ELF_DATA)
+
+/* The ABI says that every symbol used by dynamic relocations must have
+   a global GOT entry.  Among other things, this provides the dynamic
+   linker with a free, directly-indexed cache.  The GOT can therefore
+   contain symbols that are not referenced by GOT relocations themselves
+   (in other words, it may have symbols that are not referenced by things
+   like R_MIPS_GOT16 and R_MIPS_GOT_PAGE).
+
+   GOT relocations are less likely to overflow if we put the associated
+   GOT entries towards the beginning.  We therefore divide the global
+   GOT entries into two areas: "normal" and "reloc-only".  Entries in
+   the first area can be used for both dynamic relocations and GP-relative
+   accesses, while those in the "reloc-only" area are for dynamic
+   relocations only.
+
+   These GGA_* ("Global GOT Area") values are organised so that lower
+   values are more general than higher values.  Also, non-GGA_NONE
+   values are ordered by the position of the area in the GOT.  */
+#define GGA_NORMAL 0
+#define GGA_RELOC_ONLY 1
+#define GGA_NONE 2
+
+/* Information about a non-PIC interface to a PIC function.  There are
+   two ways of creating these interfaces.  The first is to add:
+
+       lui     $25,%hi(func)
+       addiu   $25,$25,%lo(func)
+
+   immediately before a PIC function "func".  The second is to add:
+
+       lui     $25,%hi(func)
+       j       func
+       addiu   $25,$25,%lo(func)
+
+   to a separate trampoline section.
+
+   Stubs of the first kind go in a new section immediately before the
+   target function.  Stubs of the second kind go in a single section
+   pointed to by the hash table's "strampoline" field.  */
+struct mips_elf_la25_stub {
+  /* The generated section that contains this stub.  */
+  asection *stub_section;
+
+  /* The offset of the stub from the start of STUB_SECTION.  */
+  bfd_vma offset;
+
+  /* One symbol for the original function.  Its location is available
+     in H->root.root.u.def.  */
+  struct mips_elf_link_hash_entry *h;
+};
+
+/* Macros for populating a mips_elf_la25_stub.  */
+
+#define LA25_LUI(VAL) (0x3c190000 | (VAL))     /* lui t9,VAL */
+#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
+#define LA25_BC(VAL) (0xc8000000 | (((VAL) >> 2) & 0x3ffffff)) /* bc VAL */
+#define LA25_ADDIU(VAL) (0x27390000 | (VAL))   /* addiu t9,t9,VAL */
+#define LA25_LUI_MICROMIPS(VAL)                                                \
+  (0x41b90000 | (VAL))                         /* lui t9,VAL */
+#define LA25_J_MICROMIPS(VAL)                                          \
+  (0xd4000000 | (((VAL) >> 1) & 0x3ffffff))    /* j VAL */
+#define LA25_ADDIU_MICROMIPS(VAL)                                      \
+  (0x33390000 | (VAL))                         /* addiu t9,t9,VAL */
+
 /* This structure is passed to mips_elf_sort_hash_table_f when sorting
    the dynamic symbols.  */
 
@@ -252,14 +312,48 @@ struct mips_elf_hash_sort_data
   struct elf_link_hash_entry *low;
   /* The least dynamic symbol table index corresponding to a non-TLS
      symbol with a GOT entry.  */
-  long min_got_dynindx;
+  bfd_size_type 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
+  bfd_size_type max_unref_got_dynindx;
+  /* The greatest dynamic symbol table index corresponding to a local
+     symbol.  */
+  bfd_size_type max_local_dynindx;
+  /* The greatest dynamic symbol table index corresponding to an external
      symbol without a GOT entry.  */
-  long max_non_got_dynindx;
+  bfd_size_type max_non_got_dynindx;
+  /* If non-NULL, output BFD for .MIPS.xhash finalization.  */
+  bfd *output_bfd;
+  /* If non-NULL, pointer to contents of .MIPS.xhash for filling in
+     real final dynindx.  */
+  bfd_byte *mipsxhash;
+};
+
+/* We make up to two PLT entries if needed, one for standard MIPS code
+   and one for compressed code, either a MIPS16 or microMIPS one.  We
+   keep a separate record of traditional lazy-binding stubs, for easier
+   processing.  */
+
+struct plt_entry
+{
+  /* Traditional SVR4 stub offset, or -1 if none.  */
+  bfd_vma stub_offset;
+
+  /* Standard PLT entry offset, or -1 if none.  */
+  bfd_vma mips_offset;
+
+  /* Compressed PLT entry offset, or -1 if none.  */
+  bfd_vma comp_offset;
+
+  /* The corresponding .got.plt index, or -1 if none.  */
+  bfd_vma gotplt_index;
+
+  /* Whether we need a standard PLT entry.  */
+  unsigned int need_mips : 1;
+
+  /* Whether we need a compressed PLT entry.  */
+  unsigned int need_comp : 1;
 };
 
 /* The MIPS ELF linker needs additional information for each symbol in
@@ -272,28 +366,17 @@ struct mips_elf_link_hash_entry
   /* External symbol information.  */
   EXTR esym;
 
+  /* The la25 stub we have created for ths symbol, if any.  */
+  struct mips_elf_la25_stub *la25_stub;
+
   /* Number of R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 relocs against
      this symbol.  */
   unsigned int possibly_dynamic_relocs;
 
-  /* If the R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 reloc is against
-     a readonly section.  */
-  bfd_boolean readonly_reloc;
-
-  /* We must not create a stub for a symbol that has relocations
-     related to taking the function's address, i.e. any but
-     R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
-     p. 4-20.  */
-  bfd_boolean no_fn_stub;
-
   /* If there is a stub that 32 bit functions should use to call this
      16 bit function, this points to the section containing the stub.  */
   asection *fn_stub;
 
-  /* Whether we need the fn_stub; this is set if this symbol appears
-     in any relocs other than a 16 bit call.  */
-  bfd_boolean need_fn_stub;
-
   /* If there is a stub that 16 bit functions should use to call this
      32 bit function, this points to the section containing the stub.  */
   asection *call_stub;
@@ -302,30 +385,47 @@ struct mips_elf_link_hash_entry
      being called returns a floating point value.  */
   asection *call_fp_stub;
 
-  /* Are we forced local?  This will only be set if we have converted
-     the initial global GOT entry to a local GOT entry.  */
-  bfd_boolean forced_local;
+  /* If non-zero, location in .MIPS.xhash to write real final dynindx.  */
+  bfd_vma mipsxhash_loc;
 
-  /* Are we referenced by some kind of relocation?  */
-  bfd_boolean is_relocation_target;
+  /* The highest GGA_* value that satisfies all references to this symbol.  */
+  unsigned int global_got_area : 2;
 
-  /* Are we referenced by branch relocations?  */
-  bfd_boolean is_branch_target;
+  /* True if all GOT relocations against this symbol are for calls.  This is
+     a looser condition than no_fn_stub below, because there may be other
+     non-call non-GOT relocations against the symbol.  */
+  unsigned int got_only_for_calls : 1;
 
-#define GOT_NORMAL     0
-#define GOT_TLS_GD     1
-#define GOT_TLS_LDM    2
-#define GOT_TLS_IE     4
-#define GOT_TLS_OFFSET_DONE    0x40
-#define GOT_TLS_DONE    0x80
-  unsigned char tls_type;
-  /* This is only used in single-GOT mode; in multi-GOT mode there
-     is one mips_got_entry per GOT entry, so the offset is stored
-     there.  In single-GOT mode there may be many mips_got_entry
-     structures all referring to the same GOT slot.  It might be
-     possible to use root.got.offset instead, but that field is
-     overloaded already.  */
-  bfd_vma tls_got_offset;
+  /* True if one of the relocations described by possibly_dynamic_relocs
+     is against a readonly section.  */
+  unsigned int readonly_reloc : 1;
+
+  /* True if there is a relocation against this symbol that must be
+     resolved by the static linker (in other words, if the relocation
+     cannot possibly be made dynamic).  */
+  unsigned int has_static_relocs : 1;
+
+  /* True if we must not create a .MIPS.stubs entry for this symbol.
+     This is set, for example, if there are relocations related to
+     taking the function's address, i.e. any but R_MIPS_CALL*16 ones.
+     See "MIPS ABI Supplement, 3rd Edition", p. 4-20.  */
+  unsigned int no_fn_stub : 1;
+
+  /* Whether we need the fn_stub; this is true if this symbol appears
+     in any relocs other than a 16 bit call.  */
+  unsigned int need_fn_stub : 1;
+
+  /* True if this symbol is referenced by branch relocations from
+     any non-PIC input file.  This is used to determine whether an
+     la25 stub is required.  */
+  unsigned int has_nonpic_branches : 1;
+
+  /* Does this symbol need a traditional MIPS lazy-binding stub
+     (as opposed to a PLT entry)?  */
+  unsigned int needs_lazy_stub : 1;
+
+  /* Does this symbol resolve to a PLT entry?  */
+  unsigned int use_plt_entry : 1;
 };
 
 /* MIPS ELF linker hash table.  */
@@ -333,44 +433,169 @@ struct mips_elf_link_hash_entry
 struct mips_elf_link_hash_table
 {
   struct elf_link_hash_table root;
-#if 0
-  /* We no longer use this.  */
-  /* String section indices for the dynamic section symbols.  */
-  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES];
-#endif
+
   /* The number of .rtproc entries.  */
   bfd_size_type procedure_count;
+
   /* The size of the .compact_rel section (if SGI_COMPAT).  */
   bfd_size_type compact_rel_size;
-  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
-     entry is set to the address of __rld_obj_head as in IRIX5.  */
+
+  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic entry
+     is set to the address of __rld_obj_head as in IRIX5 and IRIX6.  */
   bfd_boolean use_rld_obj_head;
-  /* This is the value of the __rld_map or __rld_obj_head symbol.  */
-  bfd_vma rld_value;
+
+  /* The  __rld_map or __rld_obj_head symbol. */
+  struct elf_link_hash_entry *rld_symbol;
+
   /* This is set if we see any mips16 stub sections.  */
   bfd_boolean mips16_stubs_seen;
-  /* True if we've computed the size of the GOT.  */
-  bfd_boolean computed_got_sizes;
+
+  /* True if we can generate copy relocs and PLTs.  */
+  bfd_boolean use_plts_and_copy_relocs;
+
+  /* True if we can only use 32-bit microMIPS instructions.  */
+  bfd_boolean insn32;
+
+  /* True if we suppress checks for invalid branches between ISA modes.  */
+  bfd_boolean ignore_branch_isa;
+
+  /* True if we are targetting R6 compact branches.  */
+  bfd_boolean compact_branches;
+
   /* True if we're generating code for VxWorks.  */
   bfd_boolean is_vxworks;
+
   /* True if we already reported the small-data section overflow.  */
   bfd_boolean small_data_overflow_reported;
+
+  /* True if we use the special `__gnu_absolute_zero' symbol.  */
+  bfd_boolean use_absolute_zero;
+
+  /* True if we have been configured for a GNU target.  */
+  bfd_boolean gnu_target;
+
   /* Shortcuts to some dynamic sections, or NULL if they are not
      being used.  */
-  asection *srelbss;
-  asection *sdynbss;
-  asection *srelplt;
   asection *srelplt2;
-  asection *sgotplt;
-  asection *splt;
-  /* The size of the PLT header in bytes (VxWorks only).  */
+  asection *sstubs;
+
+  /* The master GOT information.  */
+  struct mips_got_info *got_info;
+
+  /* The global symbol in the GOT with the lowest index in the dynamic
+     symbol table.  */
+  struct elf_link_hash_entry *global_gotsym;
+
+  /* The size of the PLT header in bytes.  */
   bfd_vma plt_header_size;
-  /* The size of a PLT entry in bytes (VxWorks only).  */
-  bfd_vma plt_entry_size;
+
+  /* The size of a standard PLT entry in bytes.  */
+  bfd_vma plt_mips_entry_size;
+
+  /* The size of a compressed PLT entry in bytes.  */
+  bfd_vma plt_comp_entry_size;
+
+  /* The offset of the next standard PLT entry to create.  */
+  bfd_vma plt_mips_offset;
+
+  /* The offset of the next compressed PLT entry to create.  */
+  bfd_vma plt_comp_offset;
+
+  /* The index of the next .got.plt entry to create.  */
+  bfd_vma plt_got_index;
+
+  /* The number of functions that need a lazy-binding stub.  */
+  bfd_vma lazy_stub_count;
+
   /* The size of a function stub entry in bytes.  */
   bfd_vma function_stub_size;
+
+  /* The number of reserved entries at the beginning of the GOT.  */
+  unsigned int reserved_gotno;
+
+  /* The section used for mips_elf_la25_stub trampolines.
+     See the comment above that structure for details.  */
+  asection *strampoline;
+
+  /* A table of mips_elf_la25_stubs, indexed by (input_section, offset)
+     pairs.  */
+  htab_t la25_stubs;
+
+  /* A function FN (NAME, IS, OS) that creates a new input section
+     called NAME and links it to output section OS.  If IS is nonnull,
+     the new section should go immediately before it, otherwise it
+     should go at the (current) beginning of OS.
+
+     The function returns the new section on success, otherwise it
+     returns null.  */
+  asection *(*add_stub_section) (const char *, asection *, asection *);
+
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
+
+  /* Is the PLT header compressed?  */
+  unsigned int plt_header_is_comp : 1;
+};
+
+/* Get the MIPS ELF linker hash table from a link_info structure.  */
+
+#define mips_elf_hash_table(p) \
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL)
+
+/* A structure used to communicate with htab_traverse callbacks.  */
+struct mips_htab_traverse_info
+{
+  /* The usual link-wide information.  */
+  struct bfd_link_info *info;
+  bfd *output_bfd;
+
+  /* Starts off FALSE and is set to TRUE if the link should be aborted.  */
+  bfd_boolean error;
+};
+
+/* MIPS ELF private object data.  */
+
+struct mips_elf_obj_tdata
+{
+  /* Generic ELF private object data.  */
+  struct elf_obj_tdata root;
+
+  /* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output.  */
+  bfd *abi_fp_bfd;
+
+  /* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output.  */
+  bfd *abi_msa_bfd;
+
+  /* The abiflags for this object.  */
+  Elf_Internal_ABIFlags_v0 abiflags;
+  bfd_boolean abiflags_valid;
+
+  /* The GOT requirements of input bfds.  */
+  struct mips_got_info *got;
+
+  /* Used by _bfd_mips_elf_find_nearest_line.  The structure could be
+     included directly in this one, but there's no point to wasting
+     the memory just for the infrequently called find_nearest_line.  */
+  struct mips_elf_find_line *find_line_info;
+
+  /* An array of stub sections indexed by symbol number.  */
+  asection **local_stubs;
+  asection **local_call_stubs;
+
+  /* The Irix 5 support uses two virtual sections, which represent
+     text/data symbols defined in dynamic objects.  */
+  asymbol *elf_data_symbol;
+  asymbol *elf_text_symbol;
+  asection *elf_data_section;
+  asection *elf_text_section;
 };
 
+/* Get MIPS ELF private object data from BFD's tdata.  */
+
+#define mips_elf_tdata(bfd) \
+  ((struct mips_elf_obj_tdata *) (bfd)->tdata.any)
+
 #define TLS_RELOC_P(r_type) \
   (r_type == R_MIPS_TLS_DTPMOD32               \
    || r_type == R_MIPS_TLS_DTPMOD64            \
@@ -384,7 +609,21 @@ struct mips_elf_link_hash_table
    || r_type == R_MIPS_TLS_TPREL32             \
    || r_type == R_MIPS_TLS_TPREL64             \
    || r_type == R_MIPS_TLS_TPREL_HI16          \
-   || r_type == R_MIPS_TLS_TPREL_LO16)
+   || r_type == R_MIPS_TLS_TPREL_LO16          \
+   || r_type == R_MIPS16_TLS_GD                        \
+   || r_type == R_MIPS16_TLS_LDM               \
+   || r_type == R_MIPS16_TLS_DTPREL_HI16       \
+   || r_type == R_MIPS16_TLS_DTPREL_LO16       \
+   || r_type == R_MIPS16_TLS_GOTTPREL          \
+   || r_type == R_MIPS16_TLS_TPREL_HI16                \
+   || r_type == R_MIPS16_TLS_TPREL_LO16                \
+   || r_type == R_MICROMIPS_TLS_GD             \
+   || r_type == R_MICROMIPS_TLS_LDM            \
+   || r_type == R_MICROMIPS_TLS_DTPREL_HI16    \
+   || r_type == R_MICROMIPS_TLS_DTPREL_LO16    \
+   || r_type == R_MICROMIPS_TLS_GOTTPREL       \
+   || r_type == R_MICROMIPS_TLS_TPREL_HI16     \
+   || r_type == R_MICROMIPS_TLS_TPREL_LO16)
 
 /* Structure used to pass information to mips_elf_output_extsym.  */
 
@@ -519,28 +758,52 @@ typedef struct runtime_pdr {
 #define rpdNil ((pRPDR) 0)
 \f
 static struct mips_got_entry *mips_elf_create_local_got_entry
-  (bfd *, struct bfd_link_info *, bfd *, struct mips_got_info *, asection *,
-   bfd_vma, unsigned long, struct mips_elf_link_hash_entry *, int);
+  (bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long,
+   struct mips_elf_link_hash_entry *, int);
 static bfd_boolean mips_elf_sort_hash_table_f
   (struct mips_elf_link_hash_entry *, void *);
 static bfd_vma mips_elf_high
   (bfd_vma);
-static bfd_boolean mips16_stub_section_p
-  (bfd *, asection *);
 static bfd_boolean mips_elf_create_dynamic_relocation
   (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
    struct mips_elf_link_hash_entry *, asection *, bfd_vma,
    bfd_vma *, asection *);
-static hashval_t mips_elf_got_entry_hash
-  (const void *);
 static bfd_vma mips_elf_adjust_gp
   (bfd *, struct mips_got_info *, bfd *);
-static struct mips_got_info *mips_elf_got_for_ibfd
-  (struct mips_got_info *, bfd *);
 
 /* This will be used when we sort the dynamic relocation records.  */
 static bfd *reldyn_sorting_bfd;
 
+/* True if ABFD is for CPUs with load interlocking that include
+   non-MIPS1 CPUs and R3900.  */
+#define LOAD_INTERLOCKS_P(abfd) \
+  (   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) != E_MIPS_ARCH_1) \
+   || ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == E_MIPS_MACH_3900))
+
+/* True if ABFD is for CPUs that are faster if JAL is converted to BAL.
+   This should be safe for all architectures.  We enable this predicate
+   for RM9000 for now.  */
+#define JAL_TO_BAL_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == E_MIPS_MACH_9000)
+
+/* True if ABFD is for CPUs that are faster if JALR is converted to BAL.
+   This should be safe for all architectures.  We enable this predicate for
+   all CPUs.  */
+#define JALR_TO_BAL_P(abfd) 1
+
+/* True if ABFD is for CPUs that are faster if JR is converted to B.
+   This should be safe for all architectures.  We enable this predicate for
+   all CPUs.  */
+#define JR_TO_B_P(abfd) 1
+
+/* True if ABFD is a PIC object.  */
+#define PIC_OBJECT_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0)
+
+/* Nonzero if ABFD is using the O32 ABI.  */
+#define ABI_O32_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_O32)
+
 /* Nonzero if ABFD is using the N32 ABI.  */
 #define ABI_N32_P(abfd) \
   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
@@ -552,6 +815,15 @@ static bfd *reldyn_sorting_bfd;
 /* Nonzero if ABFD is using NewABI conventions.  */
 #define NEWABI_P(abfd) (ABI_N32_P (abfd) || ABI_64_P (abfd))
 
+/* Nonzero if ABFD has microMIPS code.  */
+#define MICROMIPS_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0)
+
+/* Nonzero if ABFD is MIPS R6.  */
+#define MIPSR6_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \
+    || (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6)
+
 /* The IRIX compatibility level we are striving for.  */
 #define IRIX_COMPAT(abfd) \
   (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd))
@@ -569,6 +841,10 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
   (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0)
 
+/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section.  */
+#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \
+  (strcmp (NAME, ".MIPS.abiflags") == 0)
+
 /* Whether the section is readonly.  */
 #define MIPS_ELF_READONLY_SECTION(sec) \
   ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))                \
@@ -593,6 +869,10 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_GOT_SIZE(abfd) \
   (get_elf_backend_data (abfd)->s->arch_size / 8)
 
+/* The size of the .rld_map section. */
+#define MIPS_ELF_RLD_MAP_SIZE(abfd) \
+  (get_elf_backend_data (abfd)->s->arch_size / 8)
+
 /* The size of a symbol-table entry.  */
 #define MIPS_ELF_SYM_SIZE(abfd) \
   (get_elf_backend_data (abfd)->s->sizeof_sym)
@@ -607,33 +887,20 @@ static bfd *reldyn_sorting_bfd;
 
 /* Put out word-sized data.  */
 #define MIPS_ELF_PUT_WORD(abfd, val, ptr)      \
-  (ABI_64_P (abfd)                             \
-   ? bfd_put_64 (abfd, val, ptr)               \
+  (ABI_64_P (abfd)                             \
+   ? bfd_put_64 (abfd, val, ptr)               \
    : bfd_put_32 (abfd, val, ptr))
 
+/* The opcode for word-sized loads (LW or LD).  */
+#define MIPS_ELF_LOAD_WORD(abfd) \
+  (ABI_64_P (abfd) ? 0xdc000000 : 0x8c000000)
+
 /* Add a dynamic symbol table-entry.  */
 #define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val)     \
   _bfd_elf_add_dynamic_entry (info, tag, val)
 
 #define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                     \
-  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
-
-/* Determine whether the internal relocation of index REL_IDX is REL
-   (zero) or RELA (non-zero).  The assumption is that, if there are
-   two relocation sections for this section, one of them is REL and
-   the other is RELA.  If the index of the relocation we're testing is
-   in range for the first relocation section, check that the external
-   relocation size is that for RELA.  It is also assumed that, if
-   rel_idx is not in range for the first section, and this first
-   section contains REL relocs, then the relocation is in the second
-   section, that is RELA.  */
-#define MIPS_RELOC_RELA_P(abfd, sec, rel_idx)                          \
-  ((NUM_SHDR_ENTRIES (&elf_section_data (sec)->rel_hdr)                        \
-    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel             \
-    > (bfd_vma)(rel_idx))                                              \
-   == (elf_section_data (sec)->rel_hdr.sh_entsize                      \
-       == (ABI_64_P (abfd) ? sizeof (Elf64_External_Rela)              \
-          : sizeof (Elf32_External_Rela))))
+  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (abfd, rtype, rela))
 
 /* The name of the dynamic relocation section.  */
 #define MIPS_ELF_REL_DYN_NAME(INFO) \
@@ -644,10 +911,6 @@ static bfd *reldyn_sorting_bfd;
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 #define MINUS_TWO      (((bfd_vma)0) - 2)
 
-/* The number of local .got entries we reserve.  */
-#define MIPS_RESERVED_GOTNO(INFO) \
-  (mips_elf_hash_table (INFO)->is_vxworks ? 3 : 2)
-
 /* The value to write into got[1] for SVR4 targets, to identify it is
    a GNU object.  The dynamic linker can then use got[1] to store the
    module pointer.  */
@@ -666,13 +929,11 @@ static bfd *reldyn_sorting_bfd;
 #define STUB_LW(abfd)                                                  \
   ((ABI_64_P (abfd)                                                    \
     ? 0xdf998010                               /* ld t9,0x8010(gp) */  \
-    : 0x8f998010))                             /* lw t9,0x8010(gp) */
-#define STUB_MOVE(abfd)                                                        \
-   ((ABI_64_P (abfd)                                                   \
-     ? 0x03e0782d                              /* daddu t7,ra */       \
-     : 0x03e07821))                            /* addu t7,ra */
+    : 0x8f998010))                             /* lw t9,0x8010(gp) */
+#define STUB_MOVE 0x03e07825                   /* or t7,ra,zero */
 #define STUB_LUI(VAL) (0x3c180000 + (VAL))     /* lui t8,VAL */
-#define STUB_JALR 0x0320f809                   /* jalr t9,ra */
+#define STUB_JALR 0x0320f809                   /* jalr ra,t9 */
+#define STUB_JALRC 0xf8190000                  /* jalrc ra,t9 */
 #define STUB_ORI(VAL) (0x37180000 + (VAL))     /* ori t8,t8,VAL */
 #define STUB_LI16U(VAL) (0x34180000 + (VAL))   /* ori t8,zero,VAL unsigned */
 #define STUB_LI16S(abfd, VAL)                                          \
@@ -680,15 +941,39 @@ static bfd *reldyn_sorting_bfd;
     ? (0x64180000 + (VAL))     /* daddiu t8,zero,VAL sign extended */  \
     : (0x24180000 + (VAL))))   /* addiu t8,zero,VAL sign extended */
 
+/* Likewise for the microMIPS ASE.  */
+#define STUB_LW_MICROMIPS(abfd)                                                \
+  (ABI_64_P (abfd)                                                     \
+   ? 0xdf3c8010                                        /* ld t9,0x8010(gp) */  \
+   : 0xff3c8010)                               /* lw t9,0x8010(gp) */
+#define STUB_MOVE_MICROMIPS 0x0dff             /* move t7,ra */
+#define STUB_MOVE32_MICROMIPS 0x001f7a90       /* or t7,ra,zero */
+#define STUB_LUI_MICROMIPS(VAL)                                                \
+   (0x41b80000 + (VAL))                                /* lui t8,VAL */
+#define STUB_JALR_MICROMIPS 0x45d9             /* jalr t9 */
+#define STUB_JALR32_MICROMIPS 0x03f90f3c       /* jalr ra,t9 */
+#define STUB_ORI_MICROMIPS(VAL)                                                \
+  (0x53180000 + (VAL))                         /* ori t8,t8,VAL */
+#define STUB_LI16U_MICROMIPS(VAL)                                      \
+  (0x53000000 + (VAL))                         /* ori t8,zero,VAL unsigned */
+#define STUB_LI16S_MICROMIPS(abfd, VAL)                                        \
+   (ABI_64_P (abfd)                                                    \
+    ? 0x5f000000 + (VAL)       /* daddiu t8,zero,VAL sign extended */  \
+    : 0x33000000 + (VAL))      /* addiu t8,zero,VAL sign extended */
+
 #define MIPS_FUNCTION_STUB_NORMAL_SIZE 16
 #define MIPS_FUNCTION_STUB_BIG_SIZE 20
+#define MICROMIPS_FUNCTION_STUB_NORMAL_SIZE 12
+#define MICROMIPS_FUNCTION_STUB_BIG_SIZE 16
+#define MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE 16
+#define MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE 20
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 
-#define ELF_DYNAMIC_INTERPRETER(abfd)          \
-   (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1"  \
-    : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1"         \
+#define ELF_DYNAMIC_INTERPRETER(abfd)          \
+   (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1"  \
+    : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1" \
     : "/usr/lib/libc.so.1")
 
 #ifdef BFD64
@@ -752,8 +1037,186 @@ static bfd *reldyn_sorting_bfd;
 #define CALL_STUB_P(name) CONST_STRNEQ (name, CALL_STUB)
 #define CALL_FP_STUB_P(name) CONST_STRNEQ (name, CALL_FP_STUB)
 \f
+/* The format of the first PLT entry in an O32 executable.  */
+static const bfd_vma mips_o32_exec_plt0_entry[] =
+{
+  0x3c1c0000,  /* lui $28, %hi(&GOTPLT[0])                             */
+  0x8f990000,  /* lw $25, %lo(&GOTPLT[0])($28)                         */
+  0x279c0000,  /* addiu $28, $28, %lo(&GOTPLT[0])                      */
+  0x031cc023,  /* subu $24, $24, $28                                   */
+  0x03e07825,  /* or t7, ra, zero                                      */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x0320f809,  /* jalr $25                                             */
+  0x2718fffe   /* subu $24, $24, 2                                     */
+};
+
+/* The format of the first PLT entry in an O32 executable using compact
+   jumps.  */
+static const bfd_vma mipsr6_o32_exec_plt0_entry_compact[] =
+{
+  0x3c1c0000,  /* lui $28, %hi(&GOTPLT[0])                             */
+  0x8f990000,  /* lw $25, %lo(&GOTPLT[0])($28)                         */
+  0x279c0000,  /* addiu $28, $28, %lo(&GOTPLT[0])                      */
+  0x031cc023,  /* subu $24, $24, $28                                   */
+  0x03e07821,  /* move $15, $31        # 32-bit move (addu)            */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
+/* The format of the first PLT entry in an N32 executable.  Different
+   because gp ($28) is not available; we use t2 ($14) instead.  */
+static const bfd_vma mips_n32_exec_plt0_entry[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  0x8dd90000,  /* lw $25, %lo(&GOTPLT[0])($14)                         */
+  0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
+  0x030ec023,  /* subu $24, $24, $14                                   */
+  0x03e07825,  /* or t7, ra, zero                                      */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x0320f809,  /* jalr $25                                             */
+  0x2718fffe   /* subu $24, $24, 2                                     */
+};
+
+/* The format of the first PLT entry in an N32 executable using compact
+   jumps.  Different because gp ($28) is not available; we use t2 ($14)
+   instead.  */
+static const bfd_vma mipsr6_n32_exec_plt0_entry_compact[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  0x8dd90000,  /* lw $25, %lo(&GOTPLT[0])($14)                         */
+  0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
+  0x030ec023,  /* subu $24, $24, $14                                   */
+  0x03e07821,  /* move $15, $31        # 32-bit move (addu)            */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
+/* The format of the first PLT entry in an N64 executable.  Different
+   from N32 because of the increased size of GOT entries.  */
+static const bfd_vma mips_n64_exec_plt0_entry[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  0xddd90000,  /* ld $25, %lo(&GOTPLT[0])($14)                         */
+  0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
+  0x030ec023,  /* subu $24, $24, $14                                   */
+  0x03e07825,  /* or t7, ra, zero                                      */
+  0x0018c0c2,  /* srl $24, $24, 3                                      */
+  0x0320f809,  /* jalr $25                                             */
+  0x2718fffe   /* subu $24, $24, 2                                     */
+};
+
+/* The format of the first PLT entry in an N64 executable using compact
+   jumps.  Different from N32 because of the increased size of GOT
+   entries.  */
+static const bfd_vma mipsr6_n64_exec_plt0_entry_compact[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  0xddd90000,  /* ld $25, %lo(&GOTPLT[0])($14)                         */
+  0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
+  0x030ec023,  /* subu $24, $24, $14                                   */
+  0x03e0782d,  /* move $15, $31        # 64-bit move (daddu)           */
+  0x0018c0c2,  /* srl $24, $24, 3                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
+
+/* The format of the microMIPS first PLT entry in an O32 executable.
+   We rely on v0 ($2) rather than t8 ($24) to contain the address
+   of the GOTPLT entry handled, so this stub may only be used when
+   all the subsequent PLT entries are microMIPS code too.
+
+   The trailing NOP is for alignment and correct disassembly only.  */
+static const bfd_vma micromips_o32_exec_plt0_entry[] =
+{
+  0x7980, 0x0000,      /* addiupc $3, (&GOTPLT[0]) - .                 */
+  0xff23, 0x0000,      /* lw $25, 0($3)                                */
+  0x0535,              /* subu $2, $2, $3                              */
+  0x2525,              /* srl $2, $2, 2                                */
+  0x3302, 0xfffe,      /* subu $24, $2, 2                              */
+  0x0dff,              /* move $15, $31                                */
+  0x45f9,              /* jalrs $25                                    */
+  0x0f83,              /* move $28, $3                                 */
+  0x0c00               /* nop                                          */
+};
+
+/* The format of the microMIPS first PLT entry in an O32 executable
+   in the insn32 mode.  */
+static const bfd_vma micromips_insn32_o32_exec_plt0_entry[] =
+{
+  0x41bc, 0x0000,      /* lui $28, %hi(&GOTPLT[0])                     */
+  0xff3c, 0x0000,      /* lw $25, %lo(&GOTPLT[0])($28)                 */
+  0x339c, 0x0000,      /* addiu $28, $28, %lo(&GOTPLT[0])              */
+  0x0398, 0xc1d0,      /* subu $24, $24, $28                           */
+  0x001f, 0x7a90,      /* or $15, $31, zero                            */
+  0x0318, 0x1040,      /* srl $24, $24, 2                              */
+  0x03f9, 0x0f3c,      /* jalr $25                                     */
+  0x3318, 0xfffe       /* subu $24, $24, 2                             */
+};
+
+/* The format of subsequent standard PLT entries.  */
+static const bfd_vma mips_exec_plt_entry[] =
+{
+  0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
+  0x01f90000,  /* l[wd] $25, %lo(.got.plt entry)($15)          */
+  0x25f80000,  /* addiu $24, $15, %lo(.got.plt entry)          */
+  0x03200008   /* jr $25                                       */
+};
+
+static const bfd_vma mipsr6_exec_plt_entry[] =
+{
+  0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
+  0x01f90000,  /* l[wd] $25, %lo(.got.plt entry)($15)          */
+  0x25f80000,  /* addiu $24, $15, %lo(.got.plt entry)          */
+  0x03200009   /* jr $25                                       */
+};
+
+static const bfd_vma mipsr6_exec_plt_entry_compact[] =
+{
+  0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
+  0x01f90000,  /* l[wd] $25, %lo(.got.plt entry)($15)          */
+  0x25f80000,  /* addiu $24, $15, %lo(.got.plt entry)          */
+  0xd8190000   /* jic $25, 0                                   */
+};
+
+/* The format of subsequent MIPS16 o32 PLT entries.  We use v0 ($2)
+   and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not
+   directly addressable.  */
+static const bfd_vma mips16_o32_exec_plt_entry[] =
+{
+  0xb203,              /* lw $2, 12($pc)                       */
+  0x9a60,              /* lw $3, 0($2)                         */
+  0x651a,              /* move $24, $2                         */
+  0xeb00,              /* jr $3                                */
+  0x653b,              /* move $25, $3                         */
+  0x6500,              /* nop                                  */
+  0x0000, 0x0000       /* .word (.got.plt entry)               */
+};
+
+/* The format of subsequent microMIPS o32 PLT entries.  We use v0 ($2)
+   as a temporary because t8 ($24) is not addressable with ADDIUPC.  */
+static const bfd_vma micromips_o32_exec_plt_entry[] =
+{
+  0x7900, 0x0000,      /* addiupc $2, (.got.plt entry) - .     */
+  0xff22, 0x0000,      /* lw $25, 0($2)                        */
+  0x4599,              /* jr $25                               */
+  0x0f02               /* move $24, $2                         */
+};
+
+/* The format of subsequent microMIPS o32 PLT entries in the insn32 mode.  */
+static const bfd_vma micromips_insn32_o32_exec_plt_entry[] =
+{
+  0x41af, 0x0000,      /* lui $15, %hi(.got.plt entry)         */
+  0xff2f, 0x0000,      /* lw $25, %lo(.got.plt entry)($15)     */
+  0x0019, 0x0f3c,      /* jr $25                               */
+  0x330f, 0x0000       /* addiu $24, $15, %lo(.got.plt entry)  */
+};
+
 /* The format of the first PLT entry in a VxWorks executable.  */
-static const bfd_vma mips_vxworks_exec_plt0_entry[] = {
+static const bfd_vma mips_vxworks_exec_plt0_entry[] =
+{
   0x3c190000,  /* lui t9, %hi(_GLOBAL_OFFSET_TABLE_)           */
   0x27390000,  /* addiu t9, t9, %lo(_GLOBAL_OFFSET_TABLE_)     */
   0x8f390008,  /* lw t9, 8(t9)                                 */
@@ -763,7 +1226,8 @@ static const bfd_vma mips_vxworks_exec_plt0_entry[] = {
 };
 
 /* The format of subsequent PLT entries.  */
-static const bfd_vma mips_vxworks_exec_plt_entry[] = {
+static const bfd_vma mips_vxworks_exec_plt_entry[] =
+{
   0x10000000,  /* b .PLT_resolver                      */
   0x24180000,  /* li t8, <pltindex>                    */
   0x3c190000,  /* lui t9, %hi(<.got.plt slot>)         */
@@ -775,7 +1239,8 @@ static const bfd_vma mips_vxworks_exec_plt_entry[] = {
 };
 
 /* The format of the first PLT entry in a VxWorks shared object.  */
-static const bfd_vma mips_vxworks_shared_plt0_entry[] = {
+static const bfd_vma mips_vxworks_shared_plt0_entry[] =
+{
   0x8f990008,  /* lw t9, 8(gp)         */
   0x00000000,  /* nop                  */
   0x03200008,  /* jr t9                */
@@ -785,11 +1250,29 @@ static const bfd_vma mips_vxworks_shared_plt0_entry[] = {
 };
 
 /* The format of subsequent PLT entries.  */
-static const bfd_vma mips_vxworks_shared_plt_entry[] = {
+static const bfd_vma mips_vxworks_shared_plt_entry[] =
+{
   0x10000000,  /* b .PLT_resolver      */
   0x24180000   /* li t8, <pltindex>    */
 };
 \f
+/* microMIPS 32-bit opcode helper installer.  */
+
+static void
+bfd_put_micromips_32 (const bfd *abfd, bfd_vma opcode, bfd_byte *ptr)
+{
+  bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
+  bfd_put_16 (abfd,  opcode       & 0xffff, ptr + 2);
+}
+
+/* microMIPS 32-bit opcode helper retriever.  */
+
+static bfd_vma
+bfd_get_micromips_32 (const bfd *abfd, const bfd_byte *ptr)
+{
+  return (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
+}
+\f
 /* Look up an entry in a MIPS ELF linker hash table.  */
 
 #define mips_elf_link_hash_lookup(table, string, create, copy, follow) \
@@ -805,11 +1288,6 @@ static const bfd_vma mips_vxworks_shared_plt_entry[] = {
     (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),   \
     (info)))
 
-/* Get the MIPS ELF linker hash table from a link_info structure.  */
-
-#define mips_elf_hash_table(p) \
-  ((struct mips_elf_link_hash_table *) ((p)->hash))
-
 /* Find the base offsets for thread-local storage in this object,
    for GD/LD and IE/LE respectively.  */
 
@@ -861,22 +1339,35 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       /* We use -2 as a marker to indicate that the information has
         not been set.  -1 means there is no associated ifd.  */
       ret->esym.ifd = -2;
+      ret->la25_stub = 0;
       ret->possibly_dynamic_relocs = 0;
-      ret->readonly_reloc = FALSE;
-      ret->no_fn_stub = FALSE;
       ret->fn_stub = NULL;
-      ret->need_fn_stub = FALSE;
       ret->call_stub = NULL;
       ret->call_fp_stub = NULL;
-      ret->forced_local = FALSE;
-      ret->is_branch_target = FALSE;
-      ret->is_relocation_target = FALSE;
-      ret->tls_type = GOT_NORMAL;
+      ret->mipsxhash_loc = 0;
+      ret->global_got_area = GGA_NONE;
+      ret->got_only_for_calls = TRUE;
+      ret->readonly_reloc = FALSE;
+      ret->has_static_relocs = FALSE;
+      ret->no_fn_stub = FALSE;
+      ret->need_fn_stub = FALSE;
+      ret->has_nonpic_branches = FALSE;
+      ret->needs_lazy_stub = FALSE;
+      ret->use_plt_entry = FALSE;
     }
 
   return (struct bfd_hash_entry *) ret;
 }
 
+/* Allocate MIPS ELF private object data.  */
+
+bfd_boolean
+_bfd_mips_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct mips_elf_obj_tdata),
+                                 MIPS_ELF_DATA);
+}
+
 bfd_boolean
 _bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
 {
@@ -1148,53 +1639,448 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd,
     free (sv);
   return FALSE;
 }
+\f
+/* We're going to create a stub for H.  Create a symbol for the stub's
+   value and size, to help make the disassembly easier to read.  */
+
+static bfd_boolean
+mips_elf_create_stub_symbol (struct bfd_link_info *info,
+                            struct mips_elf_link_hash_entry *h,
+                            const char *prefix, asection *s, bfd_vma value,
+                            bfd_vma size)
+{
+  bfd_boolean micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
+  struct bfd_link_hash_entry *bh;
+  struct elf_link_hash_entry *elfh;
+  char *name;
+  bfd_boolean res;
+
+  if (micromips_p)
+    value |= 1;
+
+  /* Create a new symbol.  */
+  name = concat (prefix, h->root.root.root.string, NULL);
+  bh = NULL;
+  res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
+                                         BSF_LOCAL, s, value, NULL,
+                                         TRUE, FALSE, &bh);
+  free (name);
+  if (! res)
+    return FALSE;
+
+  /* Make it a local function.  */
+  elfh = (struct elf_link_hash_entry *) bh;
+  elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+  elfh->size = size;
+  elfh->forced_local = 1;
+  if (micromips_p)
+    elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
+  return TRUE;
+}
+
+/* We're about to redefine H.  Create a symbol to represent H's
+   current value and size, to help make the disassembly easier
+   to read.  */
+
+static bfd_boolean
+mips_elf_create_shadow_symbol (struct bfd_link_info *info,
+                              struct mips_elf_link_hash_entry *h,
+                              const char *prefix)
+{
+  struct bfd_link_hash_entry *bh;
+  struct elf_link_hash_entry *elfh;
+  char *name;
+  asection *s;
+  bfd_vma value;
+  bfd_boolean res;
+
+  /* Read the symbol's value.  */
+  BFD_ASSERT (h->root.root.type == bfd_link_hash_defined
+             || h->root.root.type == bfd_link_hash_defweak);
+  s = h->root.root.u.def.section;
+  value = h->root.root.u.def.value;
+
+  /* Create a new symbol.  */
+  name = concat (prefix, h->root.root.root.string, NULL);
+  bh = NULL;
+  res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
+                                         BSF_LOCAL, s, value, NULL,
+                                         TRUE, FALSE, &bh);
+  free (name);
+  if (! res)
+    return FALSE;
+
+  /* Make it local and copy the other attributes from H.  */
+  elfh = (struct elf_link_hash_entry *) bh;
+  elfh->type = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (h->root.type));
+  elfh->other = h->root.other;
+  elfh->size = h->root.size;
+  elfh->forced_local = 1;
+  return TRUE;
+}
+
+/* Return TRUE if relocations in SECTION can refer directly to a MIPS16
+   function rather than to a hard-float stub.  */
+
+static bfd_boolean
+section_allows_mips16_refs_p (asection *section)
+{
+  const char *name;
+
+  name = bfd_section_name (section);
+  return (FN_STUB_P (name)
+         || CALL_STUB_P (name)
+         || CALL_FP_STUB_P (name)
+         || strcmp (name, ".pdr") == 0);
+}
+
+/* [RELOCS, RELEND) are the relocations against SEC, which is a MIPS16
+   stub section of some kind.  Return the R_SYMNDX of the target
+   function, or 0 if we can't decide which function that is.  */
+
+static unsigned long
+mips16_stub_symndx (const struct elf_backend_data *bed,
+                   asection *sec ATTRIBUTE_UNUSED,
+                   const Elf_Internal_Rela *relocs,
+                   const Elf_Internal_Rela *relend)
+{
+  int int_rels_per_ext_rel = bed->s->int_rels_per_ext_rel;
+  const Elf_Internal_Rela *rel;
+
+  /* Trust the first R_MIPS_NONE relocation, if any, but not a subsequent
+     one in a compound relocation.  */
+  for (rel = relocs; rel < relend; rel += int_rels_per_ext_rel)
+    if (ELF_R_TYPE (sec->owner, rel->r_info) == R_MIPS_NONE)
+      return ELF_R_SYM (sec->owner, rel->r_info);
+
+  /* Otherwise trust the first relocation, whatever its kind.  This is
+     the traditional behavior.  */
+  if (relocs < relend)
+    return ELF_R_SYM (sec->owner, relocs->r_info);
+
+  return 0;
+}
 
 /* Check the mips16 stubs for a particular symbol, and see if we can
    discard them.  */
 
-static bfd_boolean
-mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
-                            void *data ATTRIBUTE_UNUSED)
+static void
+mips_elf_check_mips16_stubs (struct bfd_link_info *info,
+                            struct mips_elf_link_hash_entry *h)
 {
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+  /* Dynamic symbols must use the standard call interface, in case other
+     objects try to call them.  */
+  if (h->fn_stub != NULL
+      && h->root.dynindx != -1)
+    {
+      mips_elf_create_shadow_symbol (info, h, ".mips16.");
+      h->need_fn_stub = TRUE;
+    }
 
   if (h->fn_stub != NULL
       && ! h->need_fn_stub)
     {
       /* We don't need the fn_stub; the only references to this symbol
-         are 16 bit calls.  Clobber the size to 0 to prevent it from
-         being included in the link.  */
+        are 16 bit calls.  Clobber the size to 0 to prevent it from
+        being included in the link.  */
       h->fn_stub->size = 0;
       h->fn_stub->flags &= ~SEC_RELOC;
       h->fn_stub->reloc_count = 0;
       h->fn_stub->flags |= SEC_EXCLUDE;
+      h->fn_stub->output_section = bfd_abs_section_ptr;
     }
 
   if (h->call_stub != NULL
       && ELF_ST_IS_MIPS16 (h->root.other))
     {
       /* We don't need the call_stub; this is a 16 bit function, so
-         calls from other 16 bit functions are OK.  Clobber the size
-         to 0 to prevent it from being included in the link.  */
+        calls from other 16 bit functions are OK.  Clobber the size
+        to 0 to prevent it from being included in the link.  */
       h->call_stub->size = 0;
       h->call_stub->flags &= ~SEC_RELOC;
       h->call_stub->reloc_count = 0;
       h->call_stub->flags |= SEC_EXCLUDE;
+      h->call_stub->output_section = bfd_abs_section_ptr;
     }
 
   if (h->call_fp_stub != NULL
       && ELF_ST_IS_MIPS16 (h->root.other))
     {
       /* We don't need the call_stub; this is a 16 bit function, so
-         calls from other 16 bit functions are OK.  Clobber the size
-         to 0 to prevent it from being included in the link.  */
+        calls from other 16 bit functions are OK.  Clobber the size
+        to 0 to prevent it from being included in the link.  */
       h->call_fp_stub->size = 0;
       h->call_fp_stub->flags &= ~SEC_RELOC;
       h->call_fp_stub->reloc_count = 0;
       h->call_fp_stub->flags |= SEC_EXCLUDE;
+      h->call_fp_stub->output_section = bfd_abs_section_ptr;
     }
+}
+
+/* Hashtable callbacks for mips_elf_la25_stubs.  */
+
+static hashval_t
+mips_elf_la25_stub_hash (const void *entry_)
+{
+  const struct mips_elf_la25_stub *entry;
+
+  entry = (struct mips_elf_la25_stub *) entry_;
+  return entry->h->root.root.u.def.section->id
+    + entry->h->root.root.u.def.value;
+}
+
+static int
+mips_elf_la25_stub_eq (const void *entry1_, const void *entry2_)
+{
+  const struct mips_elf_la25_stub *entry1, *entry2;
+
+  entry1 = (struct mips_elf_la25_stub *) entry1_;
+  entry2 = (struct mips_elf_la25_stub *) entry2_;
+  return ((entry1->h->root.root.u.def.section
+          == entry2->h->root.root.u.def.section)
+         && (entry1->h->root.root.u.def.value
+             == entry2->h->root.root.u.def.value));
+}
+
+/* Called by the linker to set up the la25 stub-creation code.  FN is
+   the linker's implementation of add_stub_function.  Return true on
+   success.  */
+
+bfd_boolean
+_bfd_mips_elf_init_stubs (struct bfd_link_info *info,
+                         asection *(*fn) (const char *, asection *,
+                                          asection *))
+{
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  htab->add_stub_section = fn;
+  htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
+                                     mips_elf_la25_stub_eq, NULL);
+  if (htab->la25_stubs == NULL)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return true if H is a locally-defined PIC function, in the sense
+   that it or its fn_stub might need $25 to be valid on entry.
+   Note that MIPS16 functions set up $gp using PC-relative instructions,
+   so they themselves never need $25 to be valid.  Only non-MIPS16
+   entry points are of interest here.  */
+
+static bfd_boolean
+mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
+{
+  return ((h->root.root.type == bfd_link_hash_defined
+          || h->root.root.type == bfd_link_hash_defweak)
+         && h->root.def_regular
+         && !bfd_is_abs_section (h->root.root.u.def.section)
+         && !bfd_is_und_section (h->root.root.u.def.section)
+         && (!ELF_ST_IS_MIPS16 (h->root.other)
+             || (h->fn_stub && h->need_fn_stub))
+         && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
+             || ELF_ST_IS_MIPS_PIC (h->root.other)));
+}
+
+/* Set *SEC to the input section that contains the target of STUB.
+   Return the offset of the target from the start of that section.  */
+
+static bfd_vma
+mips_elf_get_la25_target (struct mips_elf_la25_stub *stub,
+                         asection **sec)
+{
+  if (ELF_ST_IS_MIPS16 (stub->h->root.other))
+    {
+      BFD_ASSERT (stub->h->need_fn_stub);
+      *sec = stub->h->fn_stub;
+      return 0;
+    }
+  else
+    {
+      *sec = stub->h->root.root.u.def.section;
+      return stub->h->root.root.u.def.value;
+    }
+}
+
+/* STUB describes an la25 stub that we have decided to implement
+   by inserting an LUI/ADDIU pair before the target function.
+   Create the section and redirect the function symbol to it.  */
+
+static bfd_boolean
+mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
+                        struct bfd_link_info *info)
+{
+  struct mips_elf_link_hash_table *htab;
+  char *name;
+  asection *s, *input_section;
+  unsigned int align;
+
+  htab = mips_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  /* Create a unique name for the new section.  */
+  name = bfd_malloc (11 + sizeof (".text.stub."));
+  if (name == NULL)
+    return FALSE;
+  sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
+
+  /* Create the section.  */
+  mips_elf_get_la25_target (stub, &input_section);
+  s = htab->add_stub_section (name, input_section,
+                             input_section->output_section);
+  if (s == NULL)
+    return FALSE;
+
+  /* Make sure that any padding goes before the stub.  */
+  align = input_section->alignment_power;
+  if (!bfd_set_section_alignment (s, align))
+    return FALSE;
+  if (align > 3)
+    s->size = (1 << align) - 8;
+
+  /* Create a symbol for the stub.  */
+  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
+  stub->stub_section = s;
+  stub->offset = s->size;
+
+  /* Allocate room for it.  */
+  s->size += 8;
+  return TRUE;
+}
+
+/* STUB describes an la25 stub that we have decided to implement
+   with a separate trampoline.  Allocate room for it and redirect
+   the function symbol to it.  */
+
+static bfd_boolean
+mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
+                             struct bfd_link_info *info)
+{
+  struct mips_elf_link_hash_table *htab;
+  asection *s;
+
+  htab = mips_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  /* Create a trampoline section, if we haven't already.  */
+  s = htab->strampoline;
+  if (s == NULL)
+    {
+      asection *input_section = stub->h->root.root.u.def.section;
+      s = htab->add_stub_section (".text", NULL,
+                                 input_section->output_section);
+      if (s == NULL || !bfd_set_section_alignment (s, 4))
+       return FALSE;
+      htab->strampoline = s;
+    }
+
+  /* Create a symbol for the stub.  */
+  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 16);
+  stub->stub_section = s;
+  stub->offset = s->size;
+
+  /* Allocate room for it.  */
+  s->size += 16;
+  return TRUE;
+}
+
+/* H describes a symbol that needs an la25 stub.  Make sure that an
+   appropriate stub exists and point H at it.  */
+
+static bfd_boolean
+mips_elf_add_la25_stub (struct bfd_link_info *info,
+                       struct mips_elf_link_hash_entry *h)
+{
+  struct mips_elf_link_hash_table *htab;
+  struct mips_elf_la25_stub search, *stub;
+  bfd_boolean use_trampoline_p;
+  asection *s;
+  bfd_vma value;
+  void **slot;
+
+  /* Describe the stub we want.  */
+  search.stub_section = NULL;
+  search.offset = 0;
+  search.h = h;
+
+  /* See if we've already created an equivalent stub.  */
+  htab = mips_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
+  if (slot == NULL)
+    return FALSE;
+
+  stub = (struct mips_elf_la25_stub *) *slot;
+  if (stub != NULL)
+    {
+      /* We can reuse the existing stub.  */
+      h->la25_stub = stub;
+      return TRUE;
+    }
+
+  /* Create a permanent copy of ENTRY and add it to the hash table.  */
+  stub = bfd_malloc (sizeof (search));
+  if (stub == NULL)
+    return FALSE;
+  *stub = search;
+  *slot = stub;
+
+  /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
+     of the section and if we would need no more than 2 nops.  */
+  value = mips_elf_get_la25_target (stub, &s);
+  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+    value &= ~1;
+  use_trampoline_p = (value != 0 || s->alignment_power > 4);
+
+  h->la25_stub = stub;
+  return (use_trampoline_p
+         ? mips_elf_add_la25_trampoline (stub, info)
+         : mips_elf_add_la25_intro (stub, info));
+}
+
+/* A mips_elf_link_hash_traverse callback that is called before sizing
+   sections.  DATA points to a mips_htab_traverse_info structure.  */
+
+static bfd_boolean
+mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
+{
+  struct mips_htab_traverse_info *hti;
+
+  hti = (struct mips_htab_traverse_info *) data;
+  if (!bfd_link_relocatable (hti->info))
+    mips_elf_check_mips16_stubs (hti->info, h);
+
+  if (mips_elf_local_pic_function_p (h))
+    {
+      /* PR 12845: If H is in a section that has been garbage
+        collected it will have its output section set to *ABS*.  */
+      if (bfd_is_abs_section (h->root.root.u.def.section->output_section))
+       return TRUE;
 
+      /* H is a function that might need $25 to be valid on entry.
+        If we're creating a non-PIC relocatable object, mark H as
+        being PIC.  If we're creating a non-relocatable object with
+        non-PIC branches and jumps to H, make sure that H has an la25
+        stub.  */
+      if (bfd_link_relocatable (hti->info))
+       {
+         if (!PIC_OBJECT_P (hti->output_bfd))
+           h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other);
+       }
+      else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h))
+       {
+         hti->error = TRUE;
+         return FALSE;
+       }
+    }
   return TRUE;
 }
 \f
@@ -1207,7 +2093,7 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
    +--------------+--------------------------------+
    |     JALX     | X|   Imm 20:16  |   Imm 25:21  |
    +--------------+--------------------------------+
-   |                Immediate  15:0                |
+   |               Immediate  15:0                |
    +-----------------------------------------------+
 
    JALX is the 5-bit value 00011.  X is 0 for jal, 1 for jalx.
@@ -1237,16 +2123,16 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
 
    big-endian:
    +--------+----------------------+
-   |        |                      |
-   |        |    targ26-16         |
-   |31    26|25                   0|
+   |       |                      |
+   |       |    targ26-16         |
+   |31   26|25                   0|
    +--------+----------------------+
 
    little-endian:
    +----------+------+-------------+
-   |          |      |             |
-   |  sub1    |      |     sub2    |
-   |0        9|10  15|16         31|
+   |         |      |             |
+   |  sub1    |             |     sub2    |
+   |0       9|10  15|16         31|
    +----------+--------------------+
    where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is
    ((sub1 << 16) | sub2)).
@@ -1257,8 +2143,18 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
    let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
    ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
 
-   R_MIPS16_GPREL is used for GP-relative addressing in mips16
-   mode.  A typical instruction will have a format like this:
+   The table below lists the other MIPS16 instruction relocations.
+   Each one is calculated in the same way as the non-MIPS16 relocation
+   given on the right, but using the extended MIPS16 layout of 16-bit
+   immediate fields:
+
+       R_MIPS16_GPREL          R_MIPS_GPREL16
+       R_MIPS16_GOT16          R_MIPS_GOT16
+       R_MIPS16_CALL16         R_MIPS_CALL16
+       R_MIPS16_HI16           R_MIPS_HI16
+       R_MIPS16_LO16           R_MIPS_LO16
+
+   A typical instruction will have a format like this:
 
    +--------------+--------------------------------+
    |    EXTEND    |     Imm 10:5    |   Imm 15:11  |
@@ -1269,79 +2165,259 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
    EXTEND is the five bit value 11110.  Major is the instruction
    opcode.
 
-   This is handled exactly like R_MIPS_GPREL16, except that the
-   addend is retrieved and stored as shown in this diagram; that
-   is, the Imm fields above replace the V-rel16 field.
-
-   All we need to do here is shuffle the bits appropriately.  As
-   above, the two 16-bit halves must be swapped on a
+   All we need to do here is shuffle the bits appropriately.
+   As above, the two 16-bit halves must be swapped on a
    little-endian system.
 
-   R_MIPS16_HI16 and R_MIPS16_LO16 are used in mips16 mode to
-   access data when neither GP-relative nor PC-relative addressing
-   can be used.  They are handled like R_MIPS_HI16 and R_MIPS_LO16,
-   except that the addend is retrieved and stored as shown above
-   for R_MIPS16_GPREL.
-  */
+   Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
+   relocatable field is shifted by 1 rather than 2 and the same bit
+   shuffling is done as with the relocations above.  */
+
+static inline bfd_boolean
+mips16_reloc_p (int r_type)
+{
+  switch (r_type)
+    {
+    case R_MIPS16_26:
+    case R_MIPS16_GPREL:
+    case R_MIPS16_GOT16:
+    case R_MIPS16_CALL16:
+    case R_MIPS16_HI16:
+    case R_MIPS16_LO16:
+    case R_MIPS16_TLS_GD:
+    case R_MIPS16_TLS_LDM:
+    case R_MIPS16_TLS_DTPREL_HI16:
+    case R_MIPS16_TLS_DTPREL_LO16:
+    case R_MIPS16_TLS_GOTTPREL:
+    case R_MIPS16_TLS_TPREL_HI16:
+    case R_MIPS16_TLS_TPREL_LO16:
+    case R_MIPS16_PC16_S1:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
+/* Check if a microMIPS reloc.  */
+
+static inline bfd_boolean
+micromips_reloc_p (unsigned int r_type)
+{
+  return r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max;
+}
+
+/* Similar to MIPS16, the two 16-bit halves in microMIPS must be swapped
+   on a little-endian system.  This does not apply to R_MICROMIPS_PC7_S1
+   and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions.  */
+
+static inline bfd_boolean
+micromips_reloc_shuffle_p (unsigned int r_type)
+{
+  return (micromips_reloc_p (r_type)
+         && r_type != R_MICROMIPS_PC7_S1
+         && r_type != R_MICROMIPS_PC10_S1);
+}
+
+static inline bfd_boolean
+got16_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_GOT16
+         || r_type == R_MIPS16_GOT16
+         || r_type == R_MICROMIPS_GOT16);
+}
+
+static inline bfd_boolean
+call16_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_CALL16
+         || r_type == R_MIPS16_CALL16
+         || r_type == R_MICROMIPS_CALL16);
+}
+
+static inline bfd_boolean
+got_disp_reloc_p (unsigned int r_type)
+{
+  return r_type == R_MIPS_GOT_DISP || r_type == R_MICROMIPS_GOT_DISP;
+}
+
+static inline bfd_boolean
+got_page_reloc_p (unsigned int r_type)
+{
+  return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
+}
+
+static inline bfd_boolean
+got_lo16_reloc_p (unsigned int r_type)
+{
+  return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
+}
+
+static inline bfd_boolean
+call_hi16_reloc_p (unsigned int r_type)
+{
+  return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
+}
+
+static inline bfd_boolean
+call_lo16_reloc_p (unsigned int r_type)
+{
+  return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
+}
+
+static inline bfd_boolean
+hi16_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_HI16
+         || r_type == R_MIPS16_HI16
+         || r_type == R_MICROMIPS_HI16
+         || r_type == R_MIPS_PCHI16);
+}
+
+static inline bfd_boolean
+lo16_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_LO16
+         || r_type == R_MIPS16_LO16
+         || r_type == R_MICROMIPS_LO16
+         || r_type == R_MIPS_PCLO16);
+}
+
+static inline bfd_boolean
+mips16_call_reloc_p (int r_type)
+{
+  return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
+}
+
+static inline bfd_boolean
+jal_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_26
+         || r_type == R_MIPS16_26
+         || r_type == R_MICROMIPS_26_S1);
+}
+
+static inline bfd_boolean
+b_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2
+         || r_type == R_MIPS16_PC16_S1
+         || r_type == R_MICROMIPS_PC16_S1
+         || r_type == R_MICROMIPS_PC10_S1
+         || r_type == R_MICROMIPS_PC7_S1);
+}
+
+static inline bfd_boolean
+aligned_pcrel_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_PC18_S3
+         || r_type == R_MIPS_PC19_S2);
+}
+
+static inline bfd_boolean
+branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_26
+         || r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2);
+}
+
+static inline bfd_boolean
+mips16_branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS16_26
+         || r_type == R_MIPS16_PC16_S1);
+}
+
+static inline bfd_boolean
+micromips_branch_reloc_p (int r_type)
+{
+  return (r_type == R_MICROMIPS_26_S1
+         || r_type == R_MICROMIPS_PC16_S1
+         || r_type == R_MICROMIPS_PC10_S1
+         || r_type == R_MICROMIPS_PC7_S1);
+}
+
+static inline bfd_boolean
+tls_gd_reloc_p (unsigned int r_type)
+{
+  return (r_type == R_MIPS_TLS_GD
+         || r_type == R_MIPS16_TLS_GD
+         || r_type == R_MICROMIPS_TLS_GD);
+}
+
+static inline bfd_boolean
+tls_ldm_reloc_p (unsigned int r_type)
+{
+  return (r_type == R_MIPS_TLS_LDM
+         || r_type == R_MIPS16_TLS_LDM
+         || r_type == R_MICROMIPS_TLS_LDM);
+}
+
+static inline bfd_boolean
+tls_gottprel_reloc_p (unsigned int r_type)
+{
+  return (r_type == R_MIPS_TLS_GOTTPREL
+         || r_type == R_MIPS16_TLS_GOTTPREL
+         || r_type == R_MICROMIPS_TLS_GOTTPREL);
+}
+
 void
-_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
-                                bfd_boolean jal_shuffle, bfd_byte *data)
+_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
+                              bfd_boolean jal_shuffle, bfd_byte *data)
 {
-  bfd_vma extend, insn, val;
+  bfd_vma first, second, val;
 
-  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
-      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+  if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
     return;
 
-  /* Pick up the mips16 extend instruction and the real instruction.  */
-  extend = bfd_get_16 (abfd, data);
-  insn = bfd_get_16 (abfd, data + 2);
-  if (r_type == R_MIPS16_26)
-    {
-      if (jal_shuffle)
-       val = ((extend & 0xfc00) << 16) | ((extend & 0x3e0) << 11)
-             | ((extend & 0x1f) << 21) | insn;
-      else
-       val = extend << 16 | insn;
-    }
+  /* Pick up the first and second halfwords of the instruction.  */
+  first = bfd_get_16 (abfd, data);
+  second = bfd_get_16 (abfd, data + 2);
+  if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
+    val = first << 16 | second;
+  else if (r_type != R_MIPS16_26)
+    val = (((first & 0xf800) << 16) | ((second & 0xffe0) << 11)
+          | ((first & 0x1f) << 11) | (first & 0x7e0) | (second & 0x1f));
   else
-    val = ((extend & 0xf800) << 16) | ((insn & 0xffe0) << 11)
-         | ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+    val = (((first & 0xfc00) << 16) | ((first & 0x3e0) << 11)
+          | ((first & 0x1f) << 21) | second);
   bfd_put_32 (abfd, val, data);
 }
 
 void
-_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
-                              bfd_boolean jal_shuffle, bfd_byte *data)
+_bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
+                            bfd_boolean jal_shuffle, bfd_byte *data)
 {
-  bfd_vma extend, insn, val;
+  bfd_vma first, second, val;
 
-  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
-      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+  if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
     return;
 
   val = bfd_get_32 (abfd, data);
-  if (r_type == R_MIPS16_26)
+  if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
     {
-      if (jal_shuffle)
-       {
-         insn = val & 0xffff;
-         extend = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
-                  | ((val >> 21) & 0x1f);
-       }
-      else
-       {
-         insn = val & 0xffff;
-         extend = val >> 16;
-       }
+      second = val & 0xffff;
+      first = val >> 16;
+    }
+  else if (r_type != R_MIPS16_26)
+    {
+      second = ((val >> 11) & 0xffe0) | (val & 0x1f);
+      first = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
     }
   else
     {
-      insn = ((val >> 11) & 0xffe0) | (val & 0x1f);
-      extend = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
+      second = val & 0xffff;
+      first = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
+              | ((val >> 21) & 0x1f);
     }
-  bfd_put_16 (abfd, insn, data + 2);
-  bfd_put_16 (abfd, extend, data);
+  bfd_put_16 (abfd, second, data + 2);
+  bfd_put_16 (abfd, first, data);
 }
 
 bfd_reloc_status_type
@@ -1446,7 +2522,7 @@ _bfd_mips_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
   return bfd_reloc_ok;
 }
 
-/* A howto special_function for REL R_MIPS_GOT16 relocations.  This is just
+/* A howto special_function for REL R_MIPS*_GOT16 relocations.  This is just
    like any other 16-bit relocation when applied to global symbols, but is
    treated in the same as R_MIPS_HI16 when applied to local symbols.  */
 
@@ -1456,8 +2532,8 @@ _bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                           bfd *output_bfd, char **error_message)
 {
   if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
-      || bfd_is_und_section (bfd_get_section (symbol))
-      || bfd_is_com_section (bfd_get_section (symbol)))
+      || bfd_is_und_section (bfd_asymbol_section (symbol))
+      || bfd_is_com_section (bfd_asymbol_section (symbol)))
     /* The relocation is against a global symbol.  */
     return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                        input_section, output_bfd,
@@ -1482,11 +2558,11 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
     return bfd_reloc_outofrange;
 
-  _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
-                                  location);
-  vallo = bfd_get_32 (abfd, location);
-  _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+  _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
                                 location);
+  vallo = bfd_get_32 (abfd, location);
+  _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+                              location);
 
   while (mips_hi16_list != NULL)
     {
@@ -1495,13 +2571,17 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 
       hi = mips_hi16_list;
 
-      /* R_MIPS_GOT16 relocations are something of a special case.  We
-        want to install the addend in the same way as for a R_MIPS_HI16
+      /* R_MIPS*_GOT16 relocations are something of a special case.  We
+        want to install the addend in the same way as for a R_MIPS*_HI16
         relocation (with a rightshift of 16).  However, since GOT16
         relocations can also be used with global symbols, their howto
         has a rightshift of 0.  */
       if (hi->rel.howto->type == R_MIPS_GOT16)
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
+      else if (hi->rel.howto->type == R_MIPS16_GOT16)
+       hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
+      else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
+       hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, FALSE);
 
       /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
         carry or borrow will induce a change of +1 or -1 in the high part.  */
@@ -1579,12 +2659,12 @@ _bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
       val += reloc_entry->addend;
 
       /* Add VAL to the relocation field.  */
-      _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
-                                      location);
+      _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+                                    location);
       status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
                                       location);
-      _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
-                                    location);
+      _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+                                  location);
 
       if (status != bfd_reloc_ok)
        return status;
@@ -1725,6 +2805,46 @@ bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in,
   H_PUT_16 (abfd, in->section, ex->section);
   H_PUT_32 (abfd, in->info, ex->info);
 }
+
+/* Swap in an abiflags structure.  */
+
+void
+bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd,
+                                 const Elf_External_ABIFlags_v0 *ex,
+                                 Elf_Internal_ABIFlags_v0 *in)
+{
+  in->version = H_GET_16 (abfd, ex->version);
+  in->isa_level = H_GET_8 (abfd, ex->isa_level);
+  in->isa_rev = H_GET_8 (abfd, ex->isa_rev);
+  in->gpr_size = H_GET_8 (abfd, ex->gpr_size);
+  in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size);
+  in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size);
+  in->fp_abi = H_GET_8 (abfd, ex->fp_abi);
+  in->isa_ext = H_GET_32 (abfd, ex->isa_ext);
+  in->ases = H_GET_32 (abfd, ex->ases);
+  in->flags1 = H_GET_32 (abfd, ex->flags1);
+  in->flags2 = H_GET_32 (abfd, ex->flags2);
+}
+
+/* Swap out an abiflags structure.  */
+
+void
+bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd,
+                                  const Elf_Internal_ABIFlags_v0 *in,
+                                  Elf_External_ABIFlags_v0 *ex)
+{
+  H_PUT_16 (abfd, in->version, ex->version);
+  H_PUT_8 (abfd, in->isa_level, ex->isa_level);
+  H_PUT_8 (abfd, in->isa_rev, ex->isa_rev);
+  H_PUT_8 (abfd, in->gpr_size, ex->gpr_size);
+  H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size);
+  H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size);
+  H_PUT_8 (abfd, in->fp_abi, ex->fp_abi);
+  H_PUT_32 (abfd, in->isa_ext, ex->isa_ext);
+  H_PUT_32 (abfd, in->ases, ex->ases);
+  H_PUT_32 (abfd, in->flags1, ex->flags1);
+  H_PUT_32 (abfd, in->flags2, ex->flags2);
+}
 \f
 /* This function is called via qsort() to sort the dynamic relocation
    entries by increasing r_symndx value.  */
@@ -1802,9 +2922,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
   bfd_boolean strip;
   asection *sec, *output_section;
 
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
   if (h->root.indx == -2)
     strip = FALSE;
   else if ((h->root.def_dynamic
@@ -1841,7 +2958,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
          const char *name;
 
          /* Use undefined class.  Also, set class and type for some
-             special symbols.  */
+            special symbols.  */
          name = h->root.root.root.string;
          if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
              || strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0)
@@ -1857,12 +2974,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
              h->esym.asym.value =
                mips_elf_hash_table (einfo->info)->procedure_count;
            }
-         else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
-           {
-             h->esym.asym.sc = scAbs;
-             h->esym.asym.st = stLabel;
-             h->esym.asym.value = elf_gp (einfo->abfd);
-           }
          else
            h->esym.asym.sc = scUndefined;
        }
@@ -1882,7 +2993,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
            h->esym.asym.sc = scUndefined;
          else
            {
-             name = bfd_section_name (output_section->owner, output_section);
+             name = bfd_section_name (output_section);
 
              if (strcmp (name, ".text") == 0)
                h->esym.asym.sc = scText;
@@ -1929,19 +3040,17 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
       else
        h->esym.asym.value = 0;
     }
-  else if (h->root.needs_plt)
+  else
     {
       struct mips_elf_link_hash_entry *hd = h;
-      bfd_boolean no_fn_stub = h->no_fn_stub;
 
       while (hd->root.root.type == bfd_link_hash_indirect)
-       {
-         hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
-         no_fn_stub = no_fn_stub || hd->no_fn_stub;
-       }
+       hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
 
-      if (!no_fn_stub)
+      if (hd->needs_lazy_stub)
        {
+         BFD_ASSERT (hd->root.plt.plist != NULL);
+         BFD_ASSERT (hd->root.plt.plist->stub_offset != MINUS_ONE);
          /* Set type and value for a symbol with a function stub.  */
          h->esym.asym.st = stProc;
          sec = hd->root.root.u.def.section;
@@ -1951,7 +3060,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
            {
              output_section = sec->output_section;
              if (output_section != NULL)
-               h->esym.asym.value = (hd->root.plt.offset
+               h->esym.asym.value = (hd->root.plt.plist->stub_offset
                                      + sec->output_offset
                                      + output_section->vma);
              else
@@ -1997,21 +3106,18 @@ mips_elf_hash_bfd_vma (bfd_vma 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 (const void *entry_)
 {
   const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
 
-  return entry->symndx
-    + ((entry->tls_type & GOT_TLS_LDM) << 17)
-    + (! 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));
+  return (entry->symndx
+         + ((entry->tls_type == GOT_TLS_LDM) << 18)
+         + (entry->tls_type == GOT_TLS_LDM ? 0
+            : !entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
+            : entry->symndx >= 0 ? (entry->abfd->id
+                                    + mips_elf_hash_bfd_vma (entry->d.addend))
+            : entry->d.h->root.root.root.hash));
 }
 
 static int
@@ -2020,56 +3126,39 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2)
   const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
   const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
 
-  /* An LDM entry can only match another LDM entry.  */
-  if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
-    return 0;
-
-  return e1->abfd == e2->abfd && e1->symndx == e2->symndx
-    && (! e1->abfd ? e1->d.address == e2->d.address
-       : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
-       : e1->d.h == e2->d.h);
+  return (e1->symndx == e2->symndx
+         && e1->tls_type == e2->tls_type
+         && (e1->tls_type == GOT_TLS_LDM ? TRUE
+             : !e1->abfd ? !e2->abfd && e1->d.address == e2->d.address
+             : e1->symndx >= 0 ? (e1->abfd == e2->abfd
+                                  && e1->d.addend == e2->d.addend)
+             : e2->abfd && e1->d.h == e2->d.h));
 }
 
-/* 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 (const void *entry_)
+mips_got_page_ref_hash (const void *ref_)
 {
-  const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
+  const struct mips_got_page_ref *ref;
 
-  return entry->symndx
-    + (! entry->abfd
-       ? mips_elf_hash_bfd_vma (entry->d.address)
-       : entry->symndx >= 0
-       ? ((entry->tls_type & GOT_TLS_LDM)
-         ? (GOT_TLS_LDM << 17)
-         : (entry->abfd->id
-            + mips_elf_hash_bfd_vma (entry->d.addend)))
-       : entry->d.h->root.root.root.hash);
+  ref = (const struct mips_got_page_ref *) ref_;
+  return ((ref->symndx >= 0
+          ? (hashval_t) (ref->u.abfd->id + ref->symndx)
+          : ref->u.h->root.root.root.hash)
+         + mips_elf_hash_bfd_vma (ref->addend));
 }
 
 static int
-mips_elf_multi_got_entry_eq (const void *entry1, const void *entry2)
+mips_got_page_ref_eq (const void *ref1_, const void *ref2_)
 {
-  const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
-  const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
-
-  /* Any two LDM entries match.  */
-  if (e1->tls_type & e2->tls_type & GOT_TLS_LDM)
-    return 1;
-
-  /* Nothing else matches an LDM entry.  */
-  if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
-    return 0;
-
-  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);
+  const struct mips_got_page_ref *ref1, *ref2;
+
+  ref1 = (const struct mips_got_page_ref *) ref1_;
+  ref2 = (const struct mips_got_page_ref *) ref2_;
+  return (ref1->symndx == ref2->symndx
+         && (ref1->symndx < 0
+             ? ref1->u.h == ref2->u.h
+             : ref1->u.abfd == ref2->u.abfd)
+         && ref1->addend == ref2->addend);
 }
 
 static hashval_t
@@ -2078,7 +3167,7 @@ mips_got_page_entry_hash (const void *entry_)
   const struct mips_got_page_entry *entry;
 
   entry = (const struct mips_got_page_entry *) entry_;
-  return entry->abfd->id + entry->symndx;
+  return entry->sec->id;
 }
 
 static int
@@ -2088,72 +3177,137 @@ mips_got_page_entry_eq (const void *entry1_, const void *entry2_)
 
   entry1 = (const struct mips_got_page_entry *) entry1_;
   entry2 = (const struct mips_got_page_entry *) entry2_;
-  return entry1->abfd == entry2->abfd && entry1->symndx == entry2->symndx;
+  return entry1->sec == entry2->sec;
 }
 \f
-/* Return the dynamic relocation section.  If it doesn't exist, try to
-   create a new it if CREATE_P, otherwise return NULL.  Also return NULL
-   if creation fails.  */
+/* Create and return a new mips_got_info structure.  */
 
-static asection *
-mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
+static struct mips_got_info *
+mips_elf_create_got_info (bfd *abfd)
 {
-  const char *dname;
-  asection *sreloc;
-  bfd *dynobj;
+  struct mips_got_info *g;
 
-  dname = MIPS_ELF_REL_DYN_NAME (info);
+  g = bfd_zalloc (abfd, sizeof (struct mips_got_info));
+  if (g == NULL)
+    return NULL;
+
+  g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
+                                   mips_elf_got_entry_eq, NULL);
+  if (g->got_entries == NULL)
+    return NULL;
+
+  g->got_page_refs = htab_try_create (1, mips_got_page_ref_hash,
+                                     mips_got_page_ref_eq, NULL);
+  if (g->got_page_refs == NULL)
+    return NULL;
+
+  return g;
+}
+
+/* Return the GOT info for input bfd ABFD, trying to create a new one if
+   CREATE_P and if ABFD doesn't already have a GOT.  */
+
+static struct mips_got_info *
+mips_elf_bfd_got (bfd *abfd, bfd_boolean create_p)
+{
+  struct mips_elf_obj_tdata *tdata;
+
+  if (!is_mips_elf (abfd))
+    return NULL;
+
+  tdata = mips_elf_tdata (abfd);
+  if (!tdata->got && create_p)
+    tdata->got = mips_elf_create_got_info (abfd);
+  return tdata->got;
+}
+
+/* Record that ABFD should use output GOT G.  */
+
+static void
+mips_elf_replace_bfd_got (bfd *abfd, struct mips_got_info *g)
+{
+  struct mips_elf_obj_tdata *tdata;
+
+  BFD_ASSERT (is_mips_elf (abfd));
+  tdata = mips_elf_tdata (abfd);
+  if (tdata->got)
+    {
+      /* The GOT structure itself and the hash table entries are
+        allocated to a bfd, but the hash tables aren't.  */
+      htab_delete (tdata->got->got_entries);
+      htab_delete (tdata->got->got_page_refs);
+      if (tdata->got->got_page_entries)
+       htab_delete (tdata->got->got_page_entries);
+    }
+  tdata->got = g;
+}
+
+/* Return the dynamic relocation section.  If it doesn't exist, try to
+   create a new it if CREATE_P, otherwise return NULL.  Also return NULL
+   if creation fails.  */
+
+static asection *
+mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
+{
+  const char *dname;
+  asection *sreloc;
+  bfd *dynobj;
+
+  dname = MIPS_ELF_REL_DYN_NAME (info);
   dynobj = elf_hash_table (info)->dynobj;
-  sreloc = bfd_get_section_by_name (dynobj, dname);
+  sreloc = bfd_get_linker_section (dynobj, dname);
   if (sreloc == NULL && create_p)
     {
-      sreloc = bfd_make_section_with_flags (dynobj, dname,
-                                           (SEC_ALLOC
-                                            | SEC_LOAD
-                                            | SEC_HAS_CONTENTS
-                                            | SEC_IN_MEMORY
-                                            | SEC_LINKER_CREATED
-                                            | SEC_READONLY));
+      sreloc = bfd_make_section_anyway_with_flags (dynobj, dname,
+                                                  (SEC_ALLOC
+                                                   | SEC_LOAD
+                                                   | SEC_HAS_CONTENTS
+                                                   | SEC_IN_MEMORY
+                                                   | SEC_LINKER_CREATED
+                                                   | SEC_READONLY));
       if (sreloc == NULL
-         || ! bfd_set_section_alignment (dynobj, sreloc,
-                                         MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+         || !bfd_set_section_alignment (sreloc,
+                                        MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
        return NULL;
     }
   return sreloc;
 }
 
-/* Returns the GOT section for ABFD.  */
+/* Return the GOT_TLS_* type required by relocation type R_TYPE.  */
 
-static asection *
-mips_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
+static int
+mips_elf_reloc_tls_type (unsigned int r_type)
 {
-  asection *sgot = bfd_get_section_by_name (abfd, ".got");
-  if (sgot == NULL
-      || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
-    return NULL;
-  return sgot;
+  if (tls_gd_reloc_p (r_type))
+    return GOT_TLS_GD;
+
+  if (tls_ldm_reloc_p (r_type))
+    return GOT_TLS_LDM;
+
+  if (tls_gottprel_reloc_p (r_type))
+    return GOT_TLS_IE;
+
+  return GOT_TLS_NONE;
 }
 
-/* Returns the GOT information associated with the link indicated by
-   INFO.  If SGOTP is non-NULL, it is filled in with the GOT
-   section.  */
+/* Return the number of GOT slots needed for GOT TLS type TYPE.  */
 
-static struct mips_got_info *
-mips_elf_got_info (bfd *abfd, asection **sgotp)
+static int
+mips_tls_got_entries (unsigned int type)
 {
-  asection *sgot;
-  struct mips_got_info *g;
-
-  sgot = mips_elf_got_section (abfd, TRUE);
-  BFD_ASSERT (sgot != NULL);
-  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
-  g = mips_elf_section_data (sgot)->u.got_info;
-  BFD_ASSERT (g != NULL);
+  switch (type)
+    {
+    case GOT_TLS_GD:
+    case GOT_TLS_LDM:
+      return 2;
 
-  if (sgotp)
-    *sgotp = (sgot->flags & SEC_EXCLUDE) == 0 ? sgot : NULL;
+    case GOT_TLS_IE:
+      return 1;
 
-  return g;
+    case GOT_TLS_NONE:
+      return 0;
+    }
+  abort ();
 }
 
 /* Count the number of relocations needed for a TLS GOT entry, with
@@ -2165,85 +3319,59 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
                     struct elf_link_hash_entry *h)
 {
   int indx = 0;
-  int ret = 0;
   bfd_boolean need_relocs = FALSE;
   bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
 
-  if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-      && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h)))
+  if (h != NULL
+      && h->dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
     indx = h->dynindx;
 
-  if ((info->shared || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
     need_relocs = TRUE;
 
   if (!need_relocs)
-    return FALSE;
+    return 0;
 
-  if (tls_type & GOT_TLS_GD)
+  switch (tls_type)
     {
-      ret++;
-      if (indx != 0)
-       ret++;
-    }
-
-  if (tls_type & GOT_TLS_IE)
-    ret++;
-
-  if ((tls_type & GOT_TLS_LDM) && info->shared)
-    ret++;
-
-  return ret;
-}
-
-/* Count the number of TLS relocations required for the GOT entry in
-   ARG1, if it describes a local symbol.  */
-
-static int
-mips_elf_count_local_tls_relocs (void **arg1, void *arg2)
-{
-  struct mips_got_entry *entry = * (struct mips_got_entry **) arg1;
-  struct mips_elf_count_tls_arg *arg = arg2;
-
-  if (entry->abfd != NULL && entry->symndx != -1)
-    arg->needed += mips_tls_got_relocs (arg->info, entry->tls_type, NULL);
-
-  return 1;
-}
+    case GOT_TLS_GD:
+      return indx != 0 ? 2 : 1;
 
-/* Count the number of TLS GOT entries required for the global (or
-   forced-local) symbol in ARG1.  */
-
-static int
-mips_elf_count_global_tls_entries (void *arg1, void *arg2)
-{
-  struct mips_elf_link_hash_entry *hm
-    = (struct mips_elf_link_hash_entry *) arg1;
-  struct mips_elf_count_tls_arg *arg = arg2;
+    case GOT_TLS_IE:
+      return 1;
 
-  if (hm->tls_type & GOT_TLS_GD)
-    arg->needed += 2;
-  if (hm->tls_type & GOT_TLS_IE)
-    arg->needed += 1;
+    case GOT_TLS_LDM:
+      return bfd_link_dll (info) ? 1 : 0;
 
-  return 1;
+    default:
+      return 0;
+    }
 }
 
-/* Count the number of TLS relocations required for the global (or
-   forced-local) symbol in ARG1.  */
+/* Add the number of GOT entries and TLS relocations required by ENTRY
+   to G.  */
 
-static int
-mips_elf_count_global_tls_relocs (void *arg1, void *arg2)
+static void
+mips_elf_count_got_entry (struct bfd_link_info *info,
+                         struct mips_got_info *g,
+                         struct mips_got_entry *entry)
 {
-  struct mips_elf_link_hash_entry *hm
-    = (struct mips_elf_link_hash_entry *) arg1;
-  struct mips_elf_count_tls_arg *arg = arg2;
-
-  arg->needed += mips_tls_got_relocs (arg->info, hm->tls_type, &hm->root);
-
-  return 1;
+  if (entry->tls_type)
+    {
+      g->tls_gotno += mips_tls_got_entries (entry->tls_type);
+      g->relocs += mips_tls_got_relocs (info, entry->tls_type,
+                                       entry->symndx < 0
+                                       ? &entry->d.h->root : NULL);
+    }
+  else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE)
+    g->local_gotno += 1;
+  else
+    g->global_gotno += 1;
 }
 
 /* Output a simple dynamic relocation into SRELOC.  */
@@ -2251,6 +3379,7 @@ mips_elf_count_global_tls_relocs (void *arg1, void *arg2)
 static void
 mips_elf_output_dynamic_relocation (bfd *output_bfd,
                                    asection *sreloc,
+                                   unsigned long reloc_index,
                                    unsigned long indx,
                                    int r_type,
                                    bfd_vma offset)
@@ -2267,48 +3396,47 @@ mips_elf_output_dynamic_relocation (bfd *output_bfd,
       (*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
        (output_bfd, &rel[0],
         (sreloc->contents
-         + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+         + reloc_index * sizeof (Elf64_Mips_External_Rel)));
     }
   else
     bfd_elf32_swap_reloc_out
       (output_bfd, &rel[0],
        (sreloc->contents
-       + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
-  ++sreloc->reloc_count;
+       + reloc_index * sizeof (Elf32_External_Rel)));
 }
 
 /* Initialize a set of TLS GOT entries for one symbol.  */
 
 static void
-mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
-                              unsigned char *tls_type_p,
-                              struct bfd_link_info *info,
+mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
+                              struct mips_got_entry *entry,
                               struct mips_elf_link_hash_entry *h,
                               bfd_vma value)
 {
+  bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+  struct mips_elf_link_hash_table *htab;
   int indx;
   asection *sreloc, *sgot;
-  bfd_vma offset, offset2;
-  bfd *dynobj;
+  bfd_vma got_offset, got_offset2;
   bfd_boolean need_relocs = FALSE;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  sgot = mips_elf_got_section (dynobj, FALSE);
+  htab = mips_elf_hash_table (info);
+  if (htab == NULL)
+    return;
 
-  indx = 0;
-  if (h != NULL)
-    {
-      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+  sgot = htab->root.sgot;
 
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root)
-         && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
-       indx = h->root.dynindx;
-    }
+  indx = 0;
+  if (h != NULL
+      && h->root.dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->root)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+    indx = h->root.dynindx;
 
-  if (*tls_type_p & GOT_TLS_DONE)
+  if (entry->tls_initialized)
     return;
 
-  if ((info->shared || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
@@ -2322,122 +3450,82 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
 
   /* Emit necessary relocations.  */
   sreloc = mips_elf_rel_dyn_section (info, FALSE);
+  got_offset = entry->gotidx;
 
-  /* General Dynamic.  */
-  if (*tls_type_p & GOT_TLS_GD)
+  switch (entry->tls_type)
     {
-      offset = got_offset;
-      offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
+    case GOT_TLS_GD:
+      /* General Dynamic.  */
+      got_offset2 = got_offset + MIPS_ELF_GOT_SIZE (abfd);
 
       if (need_relocs)
        {
          mips_elf_output_dynamic_relocation
-           (abfd, sreloc, indx,
+           (abfd, sreloc, sreloc->reloc_count++, indx,
             ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
-            sgot->output_offset + sgot->output_section->vma + offset);
+            sgot->output_offset + sgot->output_section->vma + got_offset);
 
          if (indx)
            mips_elf_output_dynamic_relocation
-             (abfd, sreloc, indx,
+             (abfd, sreloc, sreloc->reloc_count++, indx,
               ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32,
-              sgot->output_offset + sgot->output_section->vma + offset2);
+              sgot->output_offset + sgot->output_section->vma + got_offset2);
          else
            MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
-                              sgot->contents + offset2);
+                              sgot->contents + got_offset2);
        }
       else
        {
          MIPS_ELF_PUT_WORD (abfd, 1,
-                            sgot->contents + offset);
+                            sgot->contents + got_offset);
          MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
-                            sgot->contents + offset2);
+                            sgot->contents + got_offset2);
        }
+      break;
 
-      got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd);
-    }
-
-  /* Initial Exec model.  */
-  if (*tls_type_p & GOT_TLS_IE)
-    {
-      offset = got_offset;
-
+    case GOT_TLS_IE:
+      /* Initial Exec model.  */
       if (need_relocs)
        {
          if (indx == 0)
            MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma,
-                              sgot->contents + offset);
+                              sgot->contents + got_offset);
          else
            MIPS_ELF_PUT_WORD (abfd, 0,
-                              sgot->contents + offset);
+                              sgot->contents + got_offset);
 
          mips_elf_output_dynamic_relocation
-           (abfd, sreloc, indx,
+           (abfd, sreloc, sreloc->reloc_count++, indx,
             ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32,
-            sgot->output_offset + sgot->output_section->vma + offset);
+            sgot->output_offset + sgot->output_section->vma + got_offset);
        }
       else
        MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info),
-                          sgot->contents + offset);
-    }
+                          sgot->contents + got_offset);
+      break;
 
-  if (*tls_type_p & GOT_TLS_LDM)
-    {
+    case GOT_TLS_LDM:
       /* The initial offset is zero, and the LD offsets will include the
         bias by DTP_OFFSET.  */
       MIPS_ELF_PUT_WORD (abfd, 0,
                         sgot->contents + got_offset
                         + MIPS_ELF_GOT_SIZE (abfd));
 
-      if (!info->shared)
+      if (!bfd_link_dll (info))
        MIPS_ELF_PUT_WORD (abfd, 1,
                           sgot->contents + got_offset);
       else
        mips_elf_output_dynamic_relocation
-         (abfd, sreloc, indx,
+         (abfd, sreloc, sreloc->reloc_count++, indx,
           ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
           sgot->output_offset + sgot->output_section->vma + got_offset);
-    }
-
-  *tls_type_p |= GOT_TLS_DONE;
-}
-
-/* Return the GOT index to use for a relocation of type R_TYPE against
-   a symbol accessed using TLS_TYPE models.  The GOT entries for this
-   symbol in this GOT start at GOT_INDEX.  This function initializes the
-   GOT entries and corresponding relocations.  */
-
-static bfd_vma
-mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
-                   int r_type, struct bfd_link_info *info,
-                   struct mips_elf_link_hash_entry *h, bfd_vma symbol)
-{
-  BFD_ASSERT (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MIPS_TLS_GD
-             || r_type == R_MIPS_TLS_LDM);
-
-  mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
-
-  if (r_type == R_MIPS_TLS_GOTTPREL)
-    {
-      BFD_ASSERT (*tls_type & GOT_TLS_IE);
-      if (*tls_type & GOT_TLS_GD)
-       return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
-      else
-       return got_index;
-    }
-
-  if (r_type == R_MIPS_TLS_GD)
-    {
-      BFD_ASSERT (*tls_type & GOT_TLS_GD);
-      return got_index;
-    }
+      break;
 
-  if (r_type == R_MIPS_TLS_LDM)
-    {
-      BFD_ASSERT (*tls_type & GOT_TLS_LDM);
-      return got_index;
+    default:
+      abort ();
     }
 
-  return got_index;
+  entry->tls_initialized = TRUE;
 }
 
 /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
@@ -2448,19 +3536,20 @@ static bfd_vma
 mips_elf_gotplt_index (struct bfd_link_info *info,
                       struct elf_link_hash_entry *h)
 {
-  bfd_vma plt_index, got_address, got_value;
+  bfd_vma got_address, got_value;
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
-  BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
+  BFD_ASSERT (htab != NULL);
 
-  /* Calculate the index of the symbol's PLT entry.  */
-  plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
+  BFD_ASSERT (h->plt.plist != NULL);
+  BFD_ASSERT (h->plt.plist->gotplt_index != MINUS_ONE);
 
   /* Calculate the address of the associated .got.plt entry.  */
-  got_address = (htab->sgotplt->output_section->vma
-                + htab->sgotplt->output_offset
-                + plt_index * 4);
+  got_address = (htab->root.sgotplt->output_section->vma
+                + htab->root.sgotplt->output_offset
+                + (h->plt.plist->gotplt_index
+                   * MIPS_ELF_GOT_SIZE (info->output_bfd)));
 
   /* Calculate the value of _GLOBAL_OFFSET_TABLE_.  */
   got_value = (htab->root.hgot->root.u.def.section->output_section->vma
@@ -2480,87 +3569,86 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                          bfd_vma value, unsigned long r_symndx,
                          struct mips_elf_link_hash_entry *h, int r_type)
 {
-  asection *sgot;
-  struct mips_got_info *g;
+  struct mips_elf_link_hash_table *htab;
   struct mips_got_entry *entry;
 
-  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
-                                          value, r_symndx, h, r_type);
+  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value,
+                                          r_symndx, h, r_type);
   if (!entry)
     return MINUS_ONE;
 
-  if (TLS_RELOC_P (r_type))
-    {
-      if (entry->symndx == -1 && g->next == NULL)
-       /* A type (3) entry in the single-GOT case.  We use the symbol's
-          hash table entry to track the index.  */
-       return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
-                                  r_type, info, h, value);
-      else
-       return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
-                                  r_type, info, h, value);
-    }
-  else
-    return entry->gotidx;
+  if (entry->tls_type)
+    mips_elf_initialize_tls_slots (abfd, info, entry, h, value);
+  return entry->gotidx;
 }
 
-/* Returns the GOT index for the global symbol indicated by H.  */
+/* Return the GOT index of global symbol H in the primary GOT.  */
 
 static bfd_vma
-mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
-                          int r_type, struct bfd_link_info *info)
+mips_elf_primary_global_got_index (bfd *obfd, struct bfd_link_info *info,
+                                  struct elf_link_hash_entry *h)
 {
-  bfd_vma index;
-  asection *sgot;
-  struct mips_got_info *g, *gg;
-  long global_got_dynindx = 0;
+  struct mips_elf_link_hash_table *htab;
+  long global_got_dynindx;
+  struct mips_got_info *g;
+  bfd_vma got_index;
 
-  gg = g = mips_elf_got_info (abfd, &sgot);
-  if (g->bfd2got && ibfd)
-    {
-      struct mips_got_entry e, *p;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  global_got_dynindx = 0;
+  if (htab->global_gotsym != NULL)
+    global_got_dynindx = htab->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
+     indices into the primary GOT.  That makes it easy to calculate the
+     GOT offset.  */
+  BFD_ASSERT (h->dynindx >= global_got_dynindx);
+  g = mips_elf_bfd_got (obfd, FALSE);
+  got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
+              * MIPS_ELF_GOT_SIZE (obfd));
+  BFD_ASSERT (got_index < htab->root.sgot->size);
+
+  return got_index;
+}
 
-      BFD_ASSERT (h->dynindx >= 0);
+/* Return the GOT index for the global symbol indicated by H, which is
+   referenced by a relocation of type R_TYPE in IBFD.  */
 
-      g = mips_elf_got_for_ibfd (g, ibfd);
-      if (g->next != gg || TLS_RELOC_P (r_type))
-       {
-         e.abfd = ibfd;
-         e.symndx = -1;
-         e.d.h = (struct mips_elf_link_hash_entry *)h;
-         e.tls_type = 0;
+static bfd_vma
+mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
+                          struct elf_link_hash_entry *h, int r_type)
+{
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_info *g;
+  struct mips_got_entry lookup, *entry;
+  bfd_vma gotidx;
 
-         p = htab_find (g->got_entries, &e);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-         BFD_ASSERT (p->gotidx > 0);
+  g = mips_elf_bfd_got (ibfd, FALSE);
+  BFD_ASSERT (g);
 
-         if (TLS_RELOC_P (r_type))
-           {
-             bfd_vma value = MINUS_ONE;
-             if ((h->root.type == bfd_link_hash_defined
-                  || h->root.type == bfd_link_hash_defweak)
-                 && h->root.u.def.section->output_section)
-               value = (h->root.u.def.value
-                        + h->root.u.def.section->output_offset
-                        + h->root.u.def.section->output_section->vma);
-
-             return mips_tls_got_index (abfd, p->gotidx, &p->tls_type, r_type,
-                                        info, e.d.h, value);
-           }
-         else
-           return p->gotidx;
-       }
-    }
+  lookup.tls_type = mips_elf_reloc_tls_type (r_type);
+  if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, FALSE))
+    return mips_elf_primary_global_got_index (obfd, info, h);
 
-  if (gg->global_gotsym != NULL)
-    global_got_dynindx = gg->global_gotsym->dynindx;
+  lookup.abfd = ibfd;
+  lookup.symndx = -1;
+  lookup.d.h = (struct mips_elf_link_hash_entry *) h;
+  entry = htab_find (g->got_entries, &lookup);
+  BFD_ASSERT (entry);
 
-  if (TLS_RELOC_P (r_type))
+  gotidx = entry->gotidx;
+  BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
+
+  if (lookup.tls_type)
     {
-      struct mips_elf_link_hash_entry *hm
-       = (struct mips_elf_link_hash_entry *) h;
       bfd_vma value = MINUS_ONE;
 
       if ((h->root.type == bfd_link_hash_defined
@@ -2570,22 +3658,9 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
                 + h->root.u.def.section->output_offset
                 + h->root.u.def.section->output_section->vma);
 
-      index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type,
-                                 r_type, info, hm, value);
-    }
-  else
-    {
-      /* Once we determine the global GOT entry with the lowest dynamic
-        symbol table index, we must put all dynamic symbols with greater
-        indices into the GOT.  That makes it easy to calculate the GOT
-        offset.  */
-      BFD_ASSERT (h->dynindx >= global_got_dynindx);
-      index = ((h->dynindx - global_got_dynindx + g->local_gotno)
-              * MIPS_ELF_GOT_SIZE (abfd));
+      mips_elf_initialize_tls_slots (obfd, info, entry, lookup.d.h, value);
     }
-  BFD_ASSERT (index < sgot->size);
-
-  return index;
+  return gotidx;
 }
 
 /* Find a GOT page entry that points to within 32KB of VALUE.  These
@@ -2598,38 +3673,32 @@ static bfd_vma
 mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                   bfd_vma value, bfd_vma *offsetp)
 {
-  asection *sgot;
-  struct mips_got_info *g;
-  bfd_vma page, index;
+  bfd_vma page, got_index;
   struct mips_got_entry *entry;
 
-  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
-
   page = (value + 0x8000) & ~(bfd_vma) 0xffff;
-  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
-                                          page, 0, NULL, R_MIPS_GOT_PAGE);
+  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
+                                          NULL, R_MIPS_GOT_PAGE);
 
   if (!entry)
     return MINUS_ONE;
 
-  index = entry->gotidx;
+  got_index = entry->gotidx;
 
   if (offsetp)
     *offsetp = value - entry->d.address;
 
-  return index;
+  return got_index;
 }
 
-/* Find a local GOT entry for an R_MIPS_GOT16 relocation against VALUE.
-   EXTERNAL is true if the relocation was against a global symbol
-   that has been forced local.  */
+/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE.
+   EXTERNAL is true if the relocation was originally against a global
+   symbol that binds locally.  */
 
 static bfd_vma
 mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                      bfd_vma value, bfd_boolean external)
 {
-  asection *sgot;
-  struct mips_got_info *g;
   struct mips_got_entry *entry;
 
   /* GOT16 relocations against local symbols are followed by a LO16
@@ -2639,10 +3708,11 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
   if (! external)
     value = mips_elf_high (value) << 16;
 
-  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
-
-  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
-                                          value, 0, NULL, R_MIPS_GOT16);
+  /* It doesn't matter whether the original relocation was R_MIPS_GOT16,
+     R_MIPS16_GOT16, R_MIPS_CALL16, etc.  The format of the entry is the
+     same in all cases.  */
+  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value, 0,
+                                          NULL, R_MIPS_GOT16);
   if (entry)
     return entry->gotidx;
   else
@@ -2653,18 +3723,21 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
    in the GOT.  */
 
 static bfd_vma
-mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd,
-                               bfd *input_bfd, bfd_vma index)
+mips_elf_got_offset_from_index (struct bfd_link_info *info, bfd *output_bfd,
+                               bfd *input_bfd, bfd_vma got_index)
 {
+  struct mips_elf_link_hash_table *htab;
   asection *sgot;
   bfd_vma gp;
-  struct mips_got_info *g;
 
-  g = mips_elf_got_info (dynobj, &sgot);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  sgot = htab->root.sgot;
   gp = _bfd_get_gp_value (output_bfd)
-    + mips_elf_adjust_gp (output_bfd, g, input_bfd);
+    + mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
 
-  return sgot->output_section->vma + sgot->output_offset + index - gp;
+  return sgot->output_section->vma + sgot->output_offset + got_index - gp;
 }
 
 /* Create and return a local GOT entry for VALUE, which was calculated
@@ -2674,156 +3747,200 @@ mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd,
 
 static struct mips_got_entry *
 mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
-                                bfd *ibfd, struct mips_got_info *gg,
-                                asection *sgot, bfd_vma value,
+                                bfd *ibfd, bfd_vma value,
                                 unsigned long r_symndx,
                                 struct mips_elf_link_hash_entry *h,
                                 int r_type)
 {
-  struct mips_got_entry entry, **loc;
+  struct mips_got_entry lookup, *entry;
+  void **loc;
   struct mips_got_info *g;
   struct mips_elf_link_hash_table *htab;
+  bfd_vma gotidx;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  entry.abfd = NULL;
-  entry.symndx = -1;
-  entry.d.address = value;
-  entry.tls_type = 0;
-
-  g = mips_elf_got_for_ibfd (gg, ibfd);
+  g = mips_elf_bfd_got (ibfd, FALSE);
   if (g == NULL)
     {
-      g = mips_elf_got_for_ibfd (gg, abfd);
+      g = mips_elf_bfd_got (abfd, FALSE);
       BFD_ASSERT (g != NULL);
     }
 
-  /* We might have a symbol, H, if it has been forced local.  Use the
-     global entry then.  It doesn't matter whether an entry is local
-     or global for TLS, since the dynamic linker does not
-     automatically relocate TLS GOT entries.  */
-  BFD_ASSERT (h == NULL || h->root.forced_local);
-  if (TLS_RELOC_P (r_type))
-    {
-      struct mips_got_entry *p;
+  /* This function shouldn't be called for symbols that live in the global
+     area of the GOT.  */
+  BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
 
-      entry.abfd = ibfd;
-      if (r_type == R_MIPS_TLS_LDM)
+  lookup.tls_type = mips_elf_reloc_tls_type (r_type);
+  if (lookup.tls_type)
+    {
+      lookup.abfd = ibfd;
+      if (tls_ldm_reloc_p (r_type))
        {
-         entry.tls_type = GOT_TLS_LDM;
-         entry.symndx = 0;
-         entry.d.addend = 0;
+         lookup.symndx = 0;
+         lookup.d.addend = 0;
        }
       else if (h == NULL)
        {
-         entry.symndx = r_symndx;
-         entry.d.addend = 0;
+         lookup.symndx = r_symndx;
+         lookup.d.addend = 0;
        }
       else
-       entry.d.h = h;
-
-      p = (struct mips_got_entry *)
-       htab_find (g->got_entries, &entry);
-
-      BFD_ASSERT (p);
-      return p;
-    }
+       {
+         lookup.symndx = -1;
+         lookup.d.h = h;
+       }
 
-  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
-                                                  INSERT);
-  if (*loc)
-    return *loc;
+      entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup);
+      BFD_ASSERT (entry);
 
-  entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
-  entry.tls_type = 0;
+      gotidx = entry->gotidx;
+      BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
 
-  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+      return entry;
+    }
 
-  if (! *loc)
+  lookup.abfd = NULL;
+  lookup.symndx = -1;
+  lookup.d.address = value;
+  loc = htab_find_slot (g->got_entries, &lookup, INSERT);
+  if (!loc)
     return NULL;
 
-  memcpy (*loc, &entry, sizeof entry);
+  entry = (struct mips_got_entry *) *loc;
+  if (entry)
+    return entry;
 
-  if (g->assigned_gotno > g->local_gotno)
+  if (g->assigned_low_gotno > g->assigned_high_gotno)
     {
-      (*loc)->gotidx = -1;
       /* We didn't allocate enough space in the GOT.  */
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("not enough GOT space for local GOT entries"));
       bfd_set_error (bfd_error_bad_value);
       return NULL;
     }
 
-  MIPS_ELF_PUT_WORD (abfd, value,
-                    (sgot->contents + entry.gotidx));
+  entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry));
+  if (!entry)
+    return NULL;
+
+  if (got16_reloc_p (r_type)
+      || call16_reloc_p (r_type)
+      || got_page_reloc_p (r_type)
+      || got_disp_reloc_p (r_type))
+    lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_low_gotno++;
+  else
+    lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_high_gotno--;
+
+  *entry = lookup;
+  *loc = entry;
+
+  MIPS_ELF_PUT_WORD (abfd, value, htab->root.sgot->contents + entry->gotidx);
 
   /* These GOT entries need a dynamic relocation on VxWorks.  */
   if (htab->is_vxworks)
     {
       Elf_Internal_Rela outrel;
       asection *s;
-      bfd_byte *loc;
+      bfd_byte *rloc;
       bfd_vma got_address;
 
       s = mips_elf_rel_dyn_section (info, FALSE);
-      got_address = (sgot->output_section->vma
-                    + sgot->output_offset
-                    + entry.gotidx);
+      got_address = (htab->root.sgot->output_section->vma
+                    + htab->root.sgot->output_offset
+                    + entry->gotidx);
 
-      loc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
+      rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
       outrel.r_offset = got_address;
       outrel.r_info = ELF32_R_INFO (STN_UNDEF, R_MIPS_32);
       outrel.r_addend = value;
-      bfd_elf32_swap_reloca_out (abfd, &outrel, loc);
+      bfd_elf32_swap_reloca_out (abfd, &outrel, rloc);
     }
 
-  return *loc;
+  return entry;
+}
+
+/* Return the number of dynamic section symbols required by OUTPUT_BFD.
+   The number might be exact or a worst-case estimate, depending on how
+   much information is available to elf_backend_omit_section_dynsym at
+   the current linking stage.  */
+
+static bfd_size_type
+count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
+{
+  bfd_size_type count;
+
+  count = 0;
+  if (bfd_link_pic (info)
+      || elf_hash_table (info)->is_relocatable_executable)
+    {
+      asection *p;
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (output_bfd);
+      for (p = output_bfd->sections; p ; p = p->next)
+       if ((p->flags & SEC_EXCLUDE) == 0
+           && (p->flags & SEC_ALLOC) != 0
+           && elf_hash_table (info)->dynamic_relocs
+           && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
+         ++count;
+    }
+  return count;
 }
 
 /* Sort the dynamic symbol table so that symbols that need GOT entries
-   appear towards the end.  This reduces the amount of GOT space
-   required.  MAX_LOCAL is used to set the number of local symbols
-   known to be in the dynamic symbol table.  During
-   _bfd_mips_elf_size_dynamic_sections, this value is 1.  Afterward, the
-   section symbols are added and the count is higher.  */
+   appear towards the end.  */
 
 static bfd_boolean
-mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local)
+mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
 {
+  struct mips_elf_link_hash_table *htab;
   struct mips_elf_hash_sort_data hsd;
   struct mips_got_info *g;
-  bfd *dynobj;
 
-  dynobj = elf_hash_table (info)->dynobj;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (htab->root.dynsymcount == 0)
+    return TRUE;
 
-  g = mips_elf_got_info (dynobj, NULL);
+  g = htab->got_info;
+  if (g == NULL)
+    return TRUE;
 
   hsd.low = NULL;
-  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)),
-                              mips_elf_sort_hash_table_f,
-                              &hsd);
+  hsd.max_unref_got_dynindx
+    = hsd.min_got_dynindx
+    = (htab->root.dynsymcount - g->reloc_only_gotno);
+  /* Add 1 to local symbol indices to account for the mandatory NULL entry
+     at the head of the table; see `_bfd_elf_link_renumber_dynsyms'.  */
+  hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
+  hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+  hsd.output_bfd = abfd;
+  if (htab->root.dynobj != NULL
+      && htab->root.dynamic_sections_created
+      && info->emit_gnu_hash)
+    {
+      asection *s = bfd_get_linker_section (htab->root.dynobj, ".MIPS.xhash");
+      BFD_ASSERT (s != NULL);
+      hsd.mipsxhash = s->contents;
+      BFD_ASSERT (hsd.mipsxhash != NULL);
+    }
+  else
+    hsd.mipsxhash = NULL;
+  mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
 
   /* There should have been enough room in the symbol table to
      accommodate both the GOT and non-GOT symbols.  */
+  BFD_ASSERT (hsd.max_local_dynindx <= htab->root.local_dynsymcount + 1);
   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);
+  BFD_ASSERT (hsd.max_unref_got_dynindx == htab->root.dynsymcount);
+  BFD_ASSERT (htab->root.dynsymcount - hsd.min_got_dynindx == g->global_gotno);
 
   /* Now we know which dynamic symbol has the lowest dynamic symbol
      table index in the GOT.  */
-  g->global_gotsym = hsd.low;
+  htab->global_gotsym = hsd.low;
 
   return TRUE;
 }
@@ -2837,51 +3954,109 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
 {
   struct mips_elf_hash_sort_data *hsd = data;
 
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
   /* Symbols without dynamic symbol table entries aren't interesting
      at all.  */
   if (h->root.dynindx == -1)
     return TRUE;
 
-  /* 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.  Forced local symbols may also be marked with got offset 1,
-     but are never given global GOT entries.  */
-  if (h->root.got.offset == 2)
+  switch (h->global_got_area)
     {
-      BFD_ASSERT (h->tls_type == GOT_NORMAL);
+    case GGA_NONE:
+      if (h->root.forced_local)
+       h->root.dynindx = hsd->max_local_dynindx++;
+      else
+       h->root.dynindx = hsd->max_non_got_dynindx++;
+      break;
+
+    case GGA_NORMAL:
+      h->root.dynindx = --hsd->min_got_dynindx;
+      hsd->low = (struct elf_link_hash_entry *) h;
+      break;
 
+    case GGA_RELOC_ONLY:
       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++;
+      break;
     }
-  else if (h->root.got.offset != 1 || h->forced_local)
-    h->root.dynindx = hsd->max_non_got_dynindx++;
-  else
-    {
-      BFD_ASSERT (h->tls_type == GOT_NORMAL);
 
-      h->root.dynindx = --hsd->min_got_dynindx;
-      hsd->low = (struct elf_link_hash_entry *) h;
-    }
+  /* Populate the .MIPS.xhash translation table entry with
+     the symbol dynindx.  */
+  if (h->mipsxhash_loc != 0 && hsd->mipsxhash != NULL)
+    bfd_put_32 (hsd->output_bfd, h->root.dynindx,
+               hsd->mipsxhash + h->mipsxhash_loc);
 
   return TRUE;
 }
 
-/* If H is a symbol that needs a global GOT entry, but has a dynamic
-   symbol table index lower than any we've seen to date, record it for
-   posterity.  */
+/* Record that input bfd ABFD requires a GOT entry like *LOOKUP
+   (which is owned by the caller and shouldn't be added to the
+   hash table directly).  */
+
+static bfd_boolean
+mips_elf_record_got_entry (struct bfd_link_info *info, bfd *abfd,
+                          struct mips_got_entry *lookup)
+{
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_entry *entry;
+  struct mips_got_info *g;
+  void **loc, **bfd_loc;
+
+  /* Make sure there's a slot for this entry in the master GOT.  */
+  htab = mips_elf_hash_table (info);
+  g = htab->got_info;
+  loc = htab_find_slot (g->got_entries, lookup, INSERT);
+  if (!loc)
+    return FALSE;
+
+  /* Populate the entry if it isn't already.  */
+  entry = (struct mips_got_entry *) *loc;
+  if (!entry)
+    {
+      entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry));
+      if (!entry)
+       return FALSE;
+
+      lookup->tls_initialized = FALSE;
+      lookup->gotidx = -1;
+      *entry = *lookup;
+      *loc = entry;
+    }
+
+  /* Reuse the same GOT entry for the BFD's GOT.  */
+  g = mips_elf_bfd_got (abfd, TRUE);
+  if (!g)
+    return FALSE;
+
+  bfd_loc = htab_find_slot (g->got_entries, lookup, INSERT);
+  if (!bfd_loc)
+    return FALSE;
+
+  if (!*bfd_loc)
+    *bfd_loc = entry;
+  return TRUE;
+}
+
+/* ABFD has a GOT relocation of type R_TYPE against H.  Reserve a GOT
+   entry for it.  FOR_CALL is true if the caller is only interested in
+   using the GOT entry for calls.  */
 
 static bfd_boolean
 mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
                                   bfd *abfd, struct bfd_link_info *info,
-                                  struct mips_got_info *g,
-                                  unsigned char tls_flag)
+                                  bfd_boolean for_call, int r_type)
 {
-  struct mips_got_entry entry, **loc;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_elf_link_hash_entry *hmips;
+  struct mips_got_entry entry;
+  unsigned char tls_type;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  hmips = (struct mips_elf_link_hash_entry *) h;
+  if (!for_call)
+    hmips->got_only_for_calls = FALSE;
 
   /* A global symbol in the GOT must also be in the dynamic symbol
      table.  */
@@ -2898,111 +4073,215 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
        return FALSE;
     }
 
-  /* Make sure we have a GOT to put this entry into.  */
-  BFD_ASSERT (g != NULL);
+  tls_type = mips_elf_reloc_tls_type (r_type);
+  if (tls_type == GOT_TLS_NONE && hmips->global_got_area > GGA_NORMAL)
+    hmips->global_got_area = GGA_NORMAL;
 
   entry.abfd = abfd;
   entry.symndx = -1;
   entry.d.h = (struct mips_elf_link_hash_entry *) h;
-  entry.tls_type = 0;
+  entry.tls_type = tls_type;
+  return mips_elf_record_got_entry (info, abfd, &entry);
+}
 
-  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
-                                                  INSERT);
+/* ABFD has a GOT relocation of type R_TYPE against symbol SYMNDX + ADDEND,
+   where SYMNDX is a local symbol.  Reserve a GOT entry for it.  */
 
-  /* If we've already marked this entry as needing GOT space, we don't
-     need to do it again.  */
-  if (*loc)
-    {
-      (*loc)->tls_type |= tls_flag;
-      return TRUE;
-    }
+static bfd_boolean
+mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
+                                 struct bfd_link_info *info, int r_type)
+{
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_info *g;
+  struct mips_got_entry entry;
 
-  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  if (! *loc)
-    return FALSE;
+  g = htab->got_info;
+  BFD_ASSERT (g != NULL);
+
+  entry.abfd = abfd;
+  entry.symndx = symndx;
+  entry.d.addend = addend;
+  entry.tls_type = mips_elf_reloc_tls_type (r_type);
+  return mips_elf_record_got_entry (info, abfd, &entry);
+}
 
-  entry.gotidx = -1;
-  entry.tls_type = tls_flag;
+/* Record that ABFD has a page relocation against SYMNDX + ADDEND.
+   H is the symbol's hash table entry, or null if SYMNDX is local
+   to ABFD.  */
+
+static bfd_boolean
+mips_elf_record_got_page_ref (struct bfd_link_info *info, bfd *abfd,
+                             long symndx, struct elf_link_hash_entry *h,
+                             bfd_signed_vma addend)
+{
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_info *g1, *g2;
+  struct mips_got_page_ref lookup, *entry;
+  void **loc, **bfd_loc;
 
-  memcpy (*loc, &entry, sizeof entry);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  if (h->got.offset != MINUS_ONE)
-    return TRUE;
+  g1 = htab->got_info;
+  BFD_ASSERT (g1 != NULL);
+
+  if (h)
+    {
+      lookup.symndx = -1;
+      lookup.u.h = (struct mips_elf_link_hash_entry *) h;
+    }
+  else
+    {
+      lookup.symndx = symndx;
+      lookup.u.abfd = abfd;
+    }
+  lookup.addend = addend;
+  loc = htab_find_slot (g1->got_page_refs, &lookup, INSERT);
+  if (loc == NULL)
+    return FALSE;
 
-  if (tls_flag == 0)
+  entry = (struct mips_got_page_ref *) *loc;
+  if (!entry)
     {
-      /* By setting this to a value other than -1, we are indicating that
-        there needs to be a GOT entry for H.  Avoid using zero, as the
-        generic ELF copy_indirect_symbol tests for <= 0.  */
-      h->got.offset = 1;
-      if (h->forced_local)
-       g->local_gotno++;
+      entry = bfd_alloc (abfd, sizeof (*entry));
+      if (!entry)
+       return FALSE;
+
+      *entry = lookup;
+      *loc = entry;
     }
 
+  /* Add the same entry to the BFD's GOT.  */
+  g2 = mips_elf_bfd_got (abfd, TRUE);
+  if (!g2)
+    return FALSE;
+
+  bfd_loc = htab_find_slot (g2->got_page_refs, &lookup, INSERT);
+  if (!bfd_loc)
+    return FALSE;
+
+  if (!*bfd_loc)
+    *bfd_loc = entry;
+
   return TRUE;
 }
 
-/* Reserve space in G for a GOT entry containing the value of symbol
-   SYMNDX in input bfd ABDF, plus ADDEND.  */
+/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
 
-static bfd_boolean
-mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
-                                 struct mips_got_info *g,
-                                 unsigned char tls_flag)
+static void
+mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
+                                      unsigned int n)
 {
-  struct mips_got_entry entry, **loc;
+  asection *s;
+  struct mips_elf_link_hash_table *htab;
 
-  entry.abfd = abfd;
-  entry.symndx = symndx;
-  entry.d.addend = addend;
-  entry.tls_type = tls_flag;
-  loc = (struct mips_got_entry **)
-    htab_find_slot (g->got_entries, &entry, INSERT);
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  s = mips_elf_rel_dyn_section (info, FALSE);
+  BFD_ASSERT (s != NULL);
 
-  if (*loc)
+  if (htab->is_vxworks)
+    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
+  else
     {
-      if (tls_flag == GOT_TLS_GD && !((*loc)->tls_type & GOT_TLS_GD))
-       {
-         g->tls_gotno += 2;
-         (*loc)->tls_type |= tls_flag;
-       }
-      else if (tls_flag == GOT_TLS_IE && !((*loc)->tls_type & GOT_TLS_IE))
+      if (s->size == 0)
        {
-         g->tls_gotno += 1;
-         (*loc)->tls_type |= tls_flag;
+         /* Make room for a null element.  */
+         s->size += MIPS_ELF_REL_SIZE (abfd);
+         ++s->reloc_count;
        }
-      return TRUE;
+      s->size += n * MIPS_ELF_REL_SIZE (abfd);
     }
+}
+\f
+/* A htab_traverse callback for GOT entries, with DATA pointing to a
+   mips_elf_traverse_got_arg structure.  Count the number of GOT
+   entries and TLS relocs.  Set DATA->value to true if we need
+   to resolve indirect or warning symbols and then recreate the GOT.  */
+
+static int
+mips_elf_check_recreate_got (void **entryp, void *data)
+{
+  struct mips_got_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
 
-  if (tls_flag != 0)
+  entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  if (entry->abfd != NULL && entry->symndx == -1)
     {
-      entry.gotidx = -1;
-      entry.tls_type = tls_flag;
-      if (tls_flag == GOT_TLS_IE)
-       g->tls_gotno += 1;
-      else if (tls_flag == GOT_TLS_GD)
-       g->tls_gotno += 2;
-      else if (g->tls_ldm_offset == MINUS_ONE)
+      struct mips_elf_link_hash_entry *h;
+
+      h = entry->d.h;
+      if (h->root.root.type == bfd_link_hash_indirect
+         || h->root.root.type == bfd_link_hash_warning)
        {
-         g->tls_ldm_offset = MINUS_TWO;
-         g->tls_gotno += 2;
+         arg->value = TRUE;
+         return 0;
        }
     }
-  else
-    {
-      entry.gotidx = g->local_gotno++;
-      entry.tls_type = 0;
-    }
+  mips_elf_count_got_entry (arg->info, arg->g, entry);
+  return 1;
+}
 
-  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+/* A htab_traverse callback for GOT entries, with DATA pointing to a
+   mips_elf_traverse_got_arg structure.  Add all entries to DATA->g,
+   converting entries for indirect and warning symbols into entries
+   for the target symbol.  Set DATA->g to null on error.  */
 
-  if (! *loc)
-    return FALSE;
+static int
+mips_elf_recreate_got (void **entryp, void *data)
+{
+  struct mips_got_entry new_entry, *entry;
+  struct mips_elf_traverse_got_arg *arg;
+  void **slot;
 
-  memcpy (*loc, &entry, sizeof entry);
+  entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  if (entry->abfd != NULL
+      && entry->symndx == -1
+      && (entry->d.h->root.root.type == bfd_link_hash_indirect
+         || entry->d.h->root.root.type == bfd_link_hash_warning))
+    {
+      struct mips_elf_link_hash_entry *h;
 
-  return TRUE;
+      new_entry = *entry;
+      entry = &new_entry;
+      h = entry->d.h;
+      do
+       {
+         BFD_ASSERT (h->global_got_area == GGA_NONE);
+         h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+       }
+      while (h->root.root.type == bfd_link_hash_indirect
+            || h->root.root.type == bfd_link_hash_warning);
+      entry->d.h = h;
+    }
+  slot = htab_find_slot (arg->g->got_entries, entry, INSERT);
+  if (slot == NULL)
+    {
+      arg->g = NULL;
+      return 0;
+    }
+  if (*slot == NULL)
+    {
+      if (entry == &new_entry)
+       {
+         entry = bfd_alloc (entry->abfd, sizeof (*entry));
+         if (!entry)
+           {
+             arg->g = NULL;
+             return 0;
+           }
+         *entry = new_entry;
+       }
+      *slot = entry;
+      mips_elf_count_got_entry (arg->info, arg->g, entry);
+    }
+  return 1;
 }
 
 /* Return the maximum number of GOT page entries required for RANGE.  */
@@ -3013,41 +4292,34 @@ mips_elf_pages_for_range (const struct mips_got_page_range *range)
   return (range->max_addend - range->min_addend + 0x1ffff) >> 16;
 }
 
-/* Record that ABFD has a page relocation against symbol SYMNDX and
-   that ADDEND is the addend for that relocation.  G is the GOT
-   information.  This function creates an upper bound on the number of
-   GOT slots required; no attempt is made to combine references to
-   non-overridable global symbols across multiple input files.  */
+/* Record that G requires a page entry that can reach SEC + ADDEND.  */
 
 static bfd_boolean
-mips_elf_record_got_page_entry (bfd *abfd, long symndx, bfd_signed_vma addend,
-                               struct mips_got_info *g)
+mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg,
+                               asection *sec, bfd_signed_vma addend)
 {
+  struct mips_got_info *g = arg->g;
   struct mips_got_page_entry lookup, *entry;
   struct mips_got_page_range **range_ptr, *range;
   bfd_vma old_pages, new_pages;
   void **loc;
 
-  /* Find the mips_got_page_entry hash table entry for this symbol.  */
-  lookup.abfd = abfd;
-  lookup.symndx = symndx;
+  /* Find the mips_got_page_entry hash table entry for this section.  */
+  lookup.sec = sec;
   loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
   if (loc == NULL)
     return FALSE;
 
   /* Create a mips_got_page_entry if this is the first time we've
-     seen the symbol.  */
+     seen the section.  */
   entry = (struct mips_got_page_entry *) *loc;
   if (!entry)
     {
-      entry = bfd_alloc (abfd, sizeof (*entry));
+      entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry));
       if (!entry)
        return FALSE;
 
-      entry->abfd = abfd;
-      entry->symndx = symndx;
-      entry->ranges = NULL;
-      entry->num_pages = 0;
+      entry->sec = sec;
       *loc = entry;
     }
 
@@ -3063,7 +4335,7 @@ mips_elf_record_got_page_entry (bfd *abfd, long symndx, bfd_signed_vma addend,
   range = *range_ptr;
   if (!range || addend < range->min_addend - 0xffff)
     {
-      range = bfd_alloc (abfd, sizeof (*range));
+      range = bfd_zalloc (arg->info->output_bfd, sizeof (*range));
       if (!range)
        return FALSE;
 
@@ -3105,184 +4377,279 @@ mips_elf_record_got_page_entry (bfd *abfd, long symndx, bfd_signed_vma addend,
 
   return TRUE;
 }
-\f
-/* Compute the hash value of the bfd in a bfd2got hash entry.  */
 
-static hashval_t
-mips_elf_bfd2got_entry_hash (const void *entry_)
+/* A htab_traverse callback for which *REFP points to a mips_got_page_ref
+   and for which DATA points to a mips_elf_traverse_got_arg.  Work out
+   whether the page reference described by *REFP needs a GOT page entry,
+   and record that entry in DATA->g if so.  Set DATA->g to null on failure.  */
+
+static bfd_boolean
+mips_elf_resolve_got_page_ref (void **refp, void *data)
 {
-  const struct mips_elf_bfd2got_hash *entry
-    = (struct mips_elf_bfd2got_hash *)entry_;
+  struct mips_got_page_ref *ref;
+  struct mips_elf_traverse_got_arg *arg;
+  struct mips_elf_link_hash_table *htab;
+  asection *sec;
+  bfd_vma addend;
 
-  return entry->bfd->id;
-}
+  ref = (struct mips_got_page_ref *) *refp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  htab = mips_elf_hash_table (arg->info);
 
-/* Check whether two hash entries have the same bfd.  */
+  if (ref->symndx < 0)
+    {
+      struct mips_elf_link_hash_entry *h;
 
-static int
-mips_elf_bfd2got_entry_eq (const void *entry1, const void *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;
+      /* Global GOT_PAGEs decay to GOT_DISP and so don't need page entries.  */
+      h = ref->u.h;
+      if (!SYMBOL_REFERENCES_LOCAL (arg->info, &h->root))
+       return 1;
 
-  return e1->bfd == e2->bfd;
-}
+      /* Ignore undefined symbols; we'll issue an error later if
+        appropriate.  */
+      if (!((h->root.root.type == bfd_link_hash_defined
+            || h->root.root.type == bfd_link_hash_defweak)
+           && h->root.root.u.def.section))
+       return 1;
+
+      sec = h->root.root.u.def.section;
+      addend = h->root.root.u.def.value + ref->addend;
+    }
+  else
+    {
+      Elf_Internal_Sym *isym;
 
-/* In a multi-got link, determine the GOT to be used for IBFD.  G must
-   be the master GOT data.  */
+      /* Read in the symbol.  */
+      isym = bfd_sym_from_r_symndx (&htab->sym_cache, ref->u.abfd,
+                                   ref->symndx);
+      if (isym == NULL)
+       {
+         arg->g = NULL;
+         return 0;
+       }
 
-static struct mips_got_info *
-mips_elf_got_for_ibfd (struct mips_got_info *g, bfd *ibfd)
-{
-  struct mips_elf_bfd2got_hash e, *p;
+      /* Get the associated input section.  */
+      sec = bfd_section_from_elf_index (ref->u.abfd, isym->st_shndx);
+      if (sec == NULL)
+       {
+         arg->g = NULL;
+         return 0;
+       }
 
-  if (! g->bfd2got)
-    return g;
+      /* If this is a mergable section, work out the section and offset
+        of the merged data.  For section symbols, the addend specifies
+        of the offset _of_ the first byte in the data, otherwise it
+        specifies the offset _from_ the first byte.  */
+      if (sec->flags & SEC_MERGE)
+       {
+         void *secinfo;
 
-  e.bfd = ibfd;
-  p = htab_find (g->bfd2got, &e);
-  return p ? p->g : NULL;
+         secinfo = elf_section_data (sec)->sec_info;
+         if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+           addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo,
+                                                isym->st_value + ref->addend);
+         else
+           addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo,
+                                                isym->st_value) + ref->addend;
+       }
+      else
+       addend = isym->st_value + ref->addend;
+    }
+  if (!mips_elf_record_got_page_entry (arg, sec, addend))
+    {
+      arg->g = NULL;
+      return 0;
+    }
+  return 1;
 }
 
-/* Use BFD2GOT to find ABFD's got entry, creating one if none exists.
-   Return NULL if an error occured.  */
+/* If any entries in G->got_entries are for indirect or warning symbols,
+   replace them with entries for the target symbol.  Convert g->got_page_refs
+   into got_page_entry structures and estimate the number of page entries
+   that they require.  */
 
-static struct mips_got_info *
-mips_elf_get_got_for_bfd (struct htab *bfd2got, bfd *output_bfd,
-                         bfd *input_bfd)
+static bfd_boolean
+mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
+                                   struct mips_got_info *g)
 {
-  struct mips_elf_bfd2got_hash bfdgot_entry, *bfdgot;
-  struct mips_got_info *g;
-  void **bfdgotp;
+  struct mips_elf_traverse_got_arg tga;
+  struct mips_got_info oldg;
 
-  bfdgot_entry.bfd = input_bfd;
-  bfdgotp = htab_find_slot (bfd2got, &bfdgot_entry, INSERT);
-  bfdgot = (struct mips_elf_bfd2got_hash *) *bfdgotp;
+  oldg = *g;
 
-  if (bfdgot == NULL)
+  tga.info = info;
+  tga.g = g;
+  tga.value = FALSE;
+  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &tga);
+  if (tga.value)
     {
-      bfdgot = ((struct mips_elf_bfd2got_hash *)
-               bfd_alloc (output_bfd, sizeof (struct mips_elf_bfd2got_hash)));
-      if (bfdgot == NULL)
-       return NULL;
+      *g = oldg;
+      g->got_entries = htab_create (htab_size (oldg.got_entries),
+                                   mips_elf_got_entry_hash,
+                                   mips_elf_got_entry_eq, NULL);
+      if (!g->got_entries)
+       return FALSE;
 
-      *bfdgotp = bfdgot;
+      htab_traverse (oldg.got_entries, mips_elf_recreate_got, &tga);
+      if (!tga.g)
+       return FALSE;
 
-      g = ((struct mips_got_info *)
-          bfd_alloc (output_bfd, sizeof (struct mips_got_info)));
-      if (g == NULL)
-       return NULL;
+      htab_delete (oldg.got_entries);
+    }
 
-      bfdgot->bfd = input_bfd;
-      bfdgot->g = g;
-
-      g->global_gotsym = NULL;
-      g->global_gotno = 0;
-      g->local_gotno = 0;
-      g->page_gotno = 0;
-      g->assigned_gotno = -1;
-      g->tls_gotno = 0;
-      g->tls_assigned_gotno = 0;
-      g->tls_ldm_offset = MINUS_ONE;
-      g->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
-                                       mips_elf_multi_got_entry_eq, NULL);
-      if (g->got_entries == NULL)
-       return NULL;
+  g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
+                                        mips_got_page_entry_eq, NULL);
+  if (g->got_page_entries == NULL)
+    return FALSE;
 
-      g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
-                                            mips_got_page_entry_eq, NULL);
-      if (g->got_page_entries == NULL)
-       return NULL;
+  tga.info = info;
+  tga.g = g;
+  htab_traverse (g->got_page_refs, mips_elf_resolve_got_page_ref, &tga);
 
-      g->bfd2got = NULL;
-      g->next = NULL;
-    }
+  return TRUE;
+}
+
+/* Return true if a GOT entry for H should live in the local rather than
+   global GOT area.  */
+
+static bfd_boolean
+mips_use_local_got_p (struct bfd_link_info *info,
+                     struct mips_elf_link_hash_entry *h)
+{
+  /* Symbols that aren't in the dynamic symbol table must live in the
+     local GOT.  This includes symbols that are completely undefined
+     and which therefore don't bind locally.  We'll report undefined
+     symbols later if appropriate.  */
+  if (h->root.dynindx == -1)
+    return TRUE;
+
+  /* Absolute symbols, if ever they need a GOT entry, cannot ever go
+     to the local GOT, as they would be implicitly relocated by the
+     base address by the dynamic loader.  */
+  if (bfd_is_abs_symbol (&h->root.root))
+    return FALSE;
+
+  /* Symbols that bind locally can (and in the case of forced-local
+     symbols, must) live in the local GOT.  */
+  if (h->got_only_for_calls
+      ? SYMBOL_CALLS_LOCAL (info, &h->root)
+      : SYMBOL_REFERENCES_LOCAL (info, &h->root))
+    return TRUE;
+
+  /* If this is an executable that must provide a definition of the symbol,
+     either though PLTs or copy relocations, then that address should go in
+     the local rather than global GOT.  */
+  if (bfd_link_executable (info) && h->has_static_relocs)
+    return TRUE;
 
-  return bfdgot->g;
+  return FALSE;
 }
 
-/* A htab_traverse callback for the entries in the master got.
-   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.  */
+/* A mips_elf_link_hash_traverse callback for which DATA points to the
+   link_info structure.  Decide whether the hash entry needs an entry in
+   the global part of the primary GOT, setting global_got_area accordingly.
+   Count the number of global symbols that are in the primary GOT only
+   because they have relocations against them (reloc_only_gotno).  */
 
 static int
-mips_elf_make_got_per_bfd (void **entryp, void *p)
+mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
 {
-  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;
+  struct bfd_link_info *info;
+  struct mips_elf_link_hash_table *htab;
   struct mips_got_info *g;
 
-  g = mips_elf_get_got_for_bfd (arg->bfd2got, arg->obfd, entry->abfd);
-  if (g == NULL)
+  info = (struct bfd_link_info *) data;
+  htab = mips_elf_hash_table (info);
+  g = htab->got_info;
+  if (h->global_got_area != GGA_NONE)
     {
-      arg->obfd = NULL;
-      return 0;
+      /* Make a final decision about whether the symbol belongs in the
+        local or global GOT.  */
+      if (mips_use_local_got_p (info, h))
+       /* The symbol belongs in the local GOT.  We no longer need this
+          entry if it was only used for relocations; those relocations
+          will be against the null or section symbol instead of H.  */
+       h->global_got_area = GGA_NONE;
+      else if (htab->is_vxworks
+              && h->got_only_for_calls
+              && h->root.plt.plist->mips_offset != MINUS_ONE)
+       /* On VxWorks, calls can refer directly to the .got.plt entry;
+          they don't need entries in the regular GOT.  .got.plt entries
+          will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
+       h->global_got_area = GGA_NONE;
+      else if (h->global_got_area == GGA_RELOC_ONLY)
+       {
+         g->reloc_only_gotno++;
+         g->global_gotno++;
+       }
     }
+  return 1;
+}
+\f
+/* A htab_traverse callback for GOT entries.  Add each one to the GOT
+   given in mips_elf_traverse_got_arg DATA.  Clear DATA->G on error.  */
 
-  /* 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;
+static int
+mips_elf_add_got_entry (void **entryp, void *data)
+{
+  struct mips_got_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
+  void **slot;
 
-  if (entry->tls_type)
+  entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  slot = htab_find_slot (arg->g->got_entries, entry, INSERT);
+  if (!slot)
     {
-      if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
-       g->tls_gotno += 2;
-      if (entry->tls_type & GOT_TLS_IE)
-       g->tls_gotno += 1;
+      arg->g = NULL;
+      return 0;
+    }
+  if (!*slot)
+    {
+      *slot = entry;
+      mips_elf_count_got_entry (arg->info, arg->g, entry);
     }
-  else if (entry->symndx >= 0 || entry->d.h->forced_local)
-    ++g->local_gotno;
-  else
-    ++g->global_gotno;
-
   return 1;
 }
 
-/* A htab_traverse callback for the page entries in the master got.
-   Associate each page entry with the bfd's got.  */
+/* A htab_traverse callback for GOT page entries.  Add each one to the GOT
+   given in mips_elf_traverse_got_arg DATA.  Clear DATA->G on error.  */
 
 static int
-mips_elf_make_got_pages_per_bfd (void **entryp, void *p)
+mips_elf_add_got_page_entry (void **entryp, void *data)
 {
-  struct mips_got_page_entry *entry = (struct mips_got_page_entry *) *entryp;
-  struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *) p;
-  struct mips_got_info *g;
-
-  g = mips_elf_get_got_for_bfd (arg->bfd2got, arg->obfd, entry->abfd);
-  if (g == NULL)
+  struct mips_got_page_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
+  void **slot;
+
+  entry = (struct mips_got_page_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  slot = htab_find_slot (arg->g->got_page_entries, entry, INSERT);
+  if (!slot)
     {
-      arg->obfd = NULL;
+      arg->g = NULL;
       return 0;
     }
-
-  /* Insert the GOT entry in the bfd's got entry hash table.  */
-  entryp = htab_find_slot (g->got_page_entries, entry, INSERT);
-  if (*entryp != NULL)
-    return 1;
-
-  *entryp = entry;
-  g->page_gotno += entry->num_pages;
+  if (!*slot)
+    {
+      *slot = entry;
+      arg->g->page_gotno += entry->num_pages;
+    }
   return 1;
 }
 
-/* Consider merging the got described by BFD2GOT with TO, using the
-   information given by ARG.  Return -1 if this would lead to overflow,
-   1 if they were merged successfully, and 0 if a merge failed due to
-   lack of memory.  (These values are chosen so that nonnegative return
-   values can be returned by a htab_traverse callback.)  */
+/* Consider merging FROM, which is ABFD's GOT, into TO.  Return -1 if
+   this would lead to overflow, 1 if they were merged successfully,
+   and 0 if a merge failed due to lack of memory.  (These values are chosen
+   so that nonnegative return values can be returned by a htab_traverse
+   callback.)  */
 
 static int
-mips_elf_merge_got_with (struct mips_elf_bfd2got_hash *bfd2got,
+mips_elf_merge_got_with (bfd *abfd, struct mips_got_info *from,
                         struct mips_got_info *to,
                         struct mips_elf_got_per_bfd_arg *arg)
 {
-  struct mips_got_info *from = bfd2got->g;
+  struct mips_elf_traverse_got_arg tga;
   unsigned int estimate;
 
   /* Work out how many page entries we would need for the combined GOT.  */
@@ -3290,57 +4657,54 @@ mips_elf_merge_got_with (struct mips_elf_bfd2got_hash *bfd2got,
   if (estimate >= from->page_gotno + to->page_gotno)
     estimate = from->page_gotno + to->page_gotno;
 
-  /* And conservatively estimate how many local, global and TLS entries
+  /* And conservatively estimate how many local and TLS entries
      would be needed.  */
-  estimate += (from->local_gotno
-              + from->global_gotno
-              + from->tls_gotno
-              + to->local_gotno
-              + to->global_gotno
-              + to->tls_gotno);
+  estimate += from->local_gotno + to->local_gotno;
+  estimate += from->tls_gotno + to->tls_gotno;
+
+  /* If we're merging with the primary got, any TLS relocations will
+     come after the full set of global entries.  Otherwise estimate those
+     conservatively as well.  */
+  if (to == arg->primary && from->tls_gotno + to->tls_gotno)
+    estimate += arg->global_count;
+  else
+    estimate += from->global_gotno + to->global_gotno;
 
   /* Bail out if the combined GOT might be too big.  */
   if (estimate > arg->max_count)
     return -1;
 
-  /* Commit to the merge.  Record that TO is now the bfd for this got.  */
-  bfd2got->g = to;
-
   /* Transfer the bfd's got information from FROM to TO.  */
-  htab_traverse (from->got_entries, mips_elf_make_got_per_bfd, arg);
-  if (arg->obfd == NULL)
+  tga.info = arg->info;
+  tga.g = to;
+  htab_traverse (from->got_entries, mips_elf_add_got_entry, &tga);
+  if (!tga.g)
     return 0;
 
-  htab_traverse (from->got_page_entries, mips_elf_make_got_pages_per_bfd, arg);
-  if (arg->obfd == NULL)
+  htab_traverse (from->got_page_entries, mips_elf_add_got_page_entry, &tga);
+  if (!tga.g)
     return 0;
 
-  /* 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.  */
-  htab_delete (from->got_entries);
-  htab_delete (from->got_page_entries);
+  mips_elf_replace_bfd_got (abfd, to);
   return 1;
 }
 
-/* Attempt to merge gots of different input bfds.  Try to use as much
+/* Attempt to merge GOT G, which belongs to ABFD.  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 (void **bfd2got_, void *p)
+static bfd_boolean
+mips_elf_merge_got (bfd *abfd, struct mips_got_info *g,
+                   struct mips_elf_got_per_bfd_arg *arg)
 {
-  struct mips_elf_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;
-  struct mips_got_info *g;
   unsigned int estimate;
   int result;
 
-  g = bfd2got->g;
+  if (!mips_elf_resolve_final_got_entries (arg->info, g))
+    return FALSE;
 
   /* Work out the number of page, local and TLS entries.  */
   estimate = arg->max_pages;
@@ -3360,12 +4724,12 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
         a starting point for the primary GOT.  */
       if (!arg->primary)
        {
-         arg->primary = bfd2got->g;
-         return 1;
+         arg->primary = g;
+         return TRUE;
        }
 
       /* Try merging with the primary GOT.  */
-      result = mips_elf_merge_got_with (bfd2got, arg->primary, arg);
+      result = mips_elf_merge_got_with (abfd, g, arg->primary, arg);
       if (result >= 0)
        return result;
     }
@@ -3373,7 +4737,7 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
   /* If we can merge with the last-created got, do it.  */
   if (arg->current)
     {
-      result = mips_elf_merge_got_with (bfd2got, arg->current, arg);
+      result = mips_elf_merge_got_with (abfd, g, arg->current, arg);
       if (result >= 0)
        return result;
     }
@@ -3384,189 +4748,140 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
   g->next = arg->current;
   arg->current = g;
 
-  return 1;
+  return TRUE;
 }
 
-/* Set the TLS GOT index for the GOT entry in ENTRYP.  ENTRYP's NEXT field
-   is null iff there is just a single GOT.  */
+/* ENTRYP is a hash table entry for a mips_got_entry.  Set its gotidx
+   to GOTIDX, duplicating the entry if it has already been assigned
+   an index in a different GOT.  */
 
-static int
-mips_elf_initialize_tls_index (void **entryp, void *p)
+static bfd_boolean
+mips_elf_set_gotidx (void **entryp, long gotidx)
 {
-  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
-  struct mips_got_info *g = p;
-  bfd_vma next_index;
-  unsigned char tls_type;
+  struct mips_got_entry *entry;
 
-  /* We're only interested in TLS symbols.  */
-  if (entry->tls_type == 0)
-    return 1;
+  entry = (struct mips_got_entry *) *entryp;
+  if (entry->gotidx > 0)
+    {
+      struct mips_got_entry *new_entry;
 
-  next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
+      new_entry = bfd_alloc (entry->abfd, sizeof (*entry));
+      if (!new_entry)
+       return FALSE;
 
-  if (entry->symndx == -1 && g->next == NULL)
-    {
-      /* A type (3) got entry in the single-GOT case.  We use the symbol's
-        hash table entry to track its index.  */
-      if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
-       return 1;
-      entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
-      entry->d.h->tls_got_offset = next_index;
-      tls_type = entry->d.h->tls_type;
-    }
-  else
-    {
-      if (entry->tls_type & GOT_TLS_LDM)
-       {
-         /* There are separate mips_got_entry objects for each input bfd
-            that requires an LDM entry.  Make sure that all LDM entries in
-            a GOT resolve to the same index.  */
-         if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
-           {
-             entry->gotidx = g->tls_ldm_offset;
-             return 1;
-           }
-         g->tls_ldm_offset = next_index;
-       }
-      entry->gotidx = next_index;
-      tls_type = entry->tls_type;
+      *new_entry = *entry;
+      *entryp = new_entry;
+      entry = new_entry;
     }
-
-  /* Account for the entries we've just allocated.  */
-  if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
-    g->tls_assigned_gotno += 2;
-  if (tls_type & GOT_TLS_IE)
-    g->tls_assigned_gotno += 1;
-
-  return 1;
+  entry->gotidx = gotidx;
+  return TRUE;
 }
 
-/* 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.
+/* Set the TLS GOT index for the GOT entry in ENTRYP.  DATA points to a
+   mips_elf_traverse_got_arg in which DATA->value is the size of one
+   GOT entry.  Set DATA->g to null on failure.  */
 
-   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 eligible for lazy resolution through a function
-   stub.  */
 static int
-mips_elf_set_global_got_offset (void **entryp, void *p)
+mips_elf_initialize_tls_index (void **entryp, void *data)
 {
-  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;
+  struct mips_got_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
 
-  if (g && entry->tls_type != GOT_NORMAL)
-    arg->needed_relocs +=
-      mips_tls_got_relocs (arg->info, entry->tls_type,
-                          entry->symndx == -1 ? &entry->d.h->root : NULL);
+  /* We're only interested in TLS symbols.  */
+  entry = (struct mips_got_entry *) *entryp;
+  if (entry->tls_type == GOT_TLS_NONE)
+    return 1;
 
-  if (entry->abfd != NULL && entry->symndx == -1
-      && entry->d.h->root.dynindx != -1
-      && !entry->d.h->forced_local
-      && entry->d.h->tls_type == GOT_NORMAL)
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->tls_assigned_gotno))
     {
-      if (g)
-       {
-         BFD_ASSERT (g->global_gotsym == NULL);
-
-         entry->gotidx = arg->value * (long) g->assigned_gotno++;
-         if (arg->info->shared
-             || (elf_hash_table (arg->info)->dynamic_sections_created
-                 && entry->d.h->root.def_dynamic
-                 && !entry->d.h->root.def_regular))
-           ++arg->needed_relocs;
-       }
-      else
-       entry->d.h->root.got.offset = arg->value;
+      arg->g = NULL;
+      return 0;
     }
 
+  /* Account for the entries we've just allocated.  */
+  arg->g->tls_assigned_gotno += mips_tls_got_entries (entry->tls_type);
   return 1;
 }
 
-/* Mark any global symbols referenced in the GOT we are iterating over
-   as inelligible for lazy resolution stubs.  */
+/* A htab_traverse callback for GOT entries, where DATA points to a
+   mips_elf_traverse_got_arg.  Set the global_got_area of each global
+   symbol to DATA->value.  */
+
 static int
-mips_elf_set_no_stub (void **entryp, void *p ATTRIBUTE_UNUSED)
+mips_elf_set_global_got_area (void **entryp, void *data)
 {
-  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+  struct mips_got_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
 
+  entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
   if (entry->abfd != NULL
       && entry->symndx == -1
-      && entry->d.h->root.dynindx != -1)
-    entry->d.h->no_fn_stub = TRUE;
-
+      && entry->d.h->global_got_area != GGA_NONE)
+    entry->d.h->global_got_area = 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.  */
+/* A htab_traverse callback for secondary GOT entries, where DATA points
+   to a mips_elf_traverse_got_arg.  Assign GOT indices to global entries
+   and record the number of relocations they require.  DATA->value is
+   the size of one GOT entry.  Set DATA->g to null on failure.  */
+
 static int
-mips_elf_resolve_final_got_entry (void **entryp, void *p)
+mips_elf_set_global_gotidx (void **entryp, void *data)
 {
-  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
-  htab_t got_entries = *(htab_t *)p;
+  struct mips_got_entry *entry;
+  struct mips_elf_traverse_got_arg *arg;
 
-  if (entry->abfd != NULL && entry->symndx == -1)
+  entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
+  if (entry->abfd != NULL
+      && entry->symndx == -1
+      && entry->d.h->global_got_area != GGA_NONE)
     {
-      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;
+      if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_low_gotno))
+       {
+         arg->g = 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.  */
+      arg->g->assigned_low_gotno += 1;
+
+      if (bfd_link_pic (arg->info)
+         || (elf_hash_table (arg->info)->dynamic_sections_created
+             && entry->d.h->root.def_dynamic
+             && !entry->d.h->root.def_regular))
+       arg->g->relocs += 1;
     }
 
   return 1;
 }
 
-/* Turn indirect got entries in a got_entries table into their final
-   locations.  */
-static void
-mips_elf_resolve_final_got_entries (struct mips_got_info *g)
+/* A htab_traverse callback for GOT entries for which DATA is the
+   bfd_link_info.  Forbid any global symbols from having traditional
+   lazy-binding stubs.  */
+
+static int
+mips_elf_forbid_lazy_stubs (void **entryp, void *data)
 {
-  htab_t got_entries;
+  struct bfd_link_info *info;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_entry *entry;
 
-  do
-    {
-      got_entries = g->got_entries;
+  entry = (struct mips_got_entry *) *entryp;
+  info = (struct bfd_link_info *) data;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-      htab_traverse (got_entries,
-                    mips_elf_resolve_final_got_entry,
-                    &got_entries);
+  if (entry->abfd != NULL
+      && entry->symndx == -1
+      && entry->d.h->needs_lazy_stub)
+    {
+      entry->d.h->needs_lazy_stub = FALSE;
+      htab->lazy_stub_count--;
     }
-  while (got_entries == NULL);
+
+  return 1;
 }
 
 /* Return the offset of an input bfd IBFD's GOT from the beginning of
@@ -3574,10 +4889,10 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g)
 static bfd_vma
 mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd)
 {
-  if (g->bfd2got == NULL)
+  if (!g->next)
     return 0;
 
-  g = mips_elf_got_for_ibfd (g, ibfd);
+  g = mips_elf_bfd_got (ibfd, FALSE);
   if (! g)
     return 0;
 
@@ -3594,81 +4909,47 @@ mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd)
 
 static bfd_boolean
 mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
-                   struct mips_got_info *g, asection *got,
-                   bfd_size_type pages)
+                   asection *got, bfd_size_type pages)
 {
+  struct mips_elf_link_hash_table *htab;
   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;
+  struct mips_elf_traverse_got_arg tga;
+  struct mips_got_info *g, *gg;
+  unsigned int assign, needed_relocs;
+  bfd *dynobj, *ibfd;
 
-  g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
-                               mips_elf_bfd2got_entry_eq, NULL);
-  if (g->bfd2got == NULL)
-    return FALSE;
+  dynobj = elf_hash_table (info)->dynobj;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  g = htab->got_info;
 
-  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.  */
-  htab_traverse (g->got_entries, mips_elf_make_got_per_bfd, &got_per_bfd_arg);
-  if (got_per_bfd_arg.obfd == NULL)
-    return FALSE;
-
-  /* Also count how many page entries each input bfd requires.  */
-  htab_traverse (g->got_page_entries, mips_elf_make_got_pages_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;
   got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (info)
                                / MIPS_ELF_GOT_SIZE (abfd))
-                              - MIPS_RESERVED_GOTNO (info));
+                              - htab->reserved_gotno);
   got_per_bfd_arg.max_pages = pages;
   /* The number of globals that will be included in the primary GOT.
-     See the calls to mips_elf_set_global_got_offset below for more
+     See the calls to mips_elf_set_global_got_area below for more
      information.  */
   got_per_bfd_arg.global_count = g->global_gotno;
 
   /* 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 do not find any suitable primary GOT, create an empty one.  */
-  if (got_per_bfd_arg.primary == NULL)
+  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
-      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->page_gotno = 0;
-      g->next->tls_gotno = 0;
-      g->next->assigned_gotno = 0;
-      g->next->tls_assigned_gotno = 0;
-      g->next->tls_ldm_offset = MINUS_ONE;
-      g->next->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
-                                             mips_elf_multi_got_entry_eq,
-                                             NULL);
-      if (g->next->got_entries == NULL)
-       return FALSE;
-      g->next->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
-                                                  mips_got_page_entry_eq,
-                                                  NULL);
-      if (g->next->got_page_entries == NULL)
+      gg = mips_elf_bfd_got (ibfd, FALSE);
+      if (gg && !mips_elf_merge_got (ibfd, gg, &got_per_bfd_arg))
        return FALSE;
-      g->next->bfd2got = NULL;
     }
+
+  /* If we do not find any suitable primary GOT, create an empty one.  */
+  if (got_per_bfd_arg.primary == NULL)
+    g->next = mips_elf_create_got_info (abfd);
   else
     g->next = got_per_bfd_arg.primary;
   g->next->next = got_per_bfd_arg.current;
@@ -3682,72 +4963,22 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
      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;
+  mips_elf_replace_bfd_got (abfd, g);
 
-    bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc
-      (abfd, sizeof (struct mips_elf_bfd2got_hash));
+  /* Every symbol that is referenced in a dynamic relocation must be
+     present in the primary GOT, so arrange for them to appear after
+     those that are actually referenced.  */
+  gg->reloc_only_gotno = gg->global_gotno - g->global_gotno;
+  g->global_gotno = gg->global_gotno;
 
-    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;
+  tga.info = info;
+  tga.value = GGA_RELOC_ONLY;
+  htab_traverse (gg->got_entries, mips_elf_set_global_got_area, &tga);
+  tga.value = GGA_NORMAL;
+  htab_traverse (g->got_entries, mips_elf_set_global_got_area, &tga);
 
   /* Now go through the GOTs assigning them offset ranges.
-     [assigned_gotno, local_gotno[ will be set to the range of local
+     [assigned_low_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
@@ -3769,10 +5000,11 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
     {
       struct mips_got_info *gn;
 
-      assign += MIPS_RESERVED_GOTNO (info);
-      g->assigned_gotno = assign;
+      assign += htab->reserved_gotno;
+      g->assigned_low_gotno = assign;
       g->local_gotno += assign;
       g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno);
+      g->assigned_high_gotno = g->local_gotno - 1;
       assign = g->local_gotno + g->global_gotno + g->tls_gotno;
 
       /* Take g out of the direct list, and push it onto the reversed
@@ -3785,21 +5017,58 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
       /* Set up any TLS entries.  We always place the TLS entries after
         all non-TLS entries.  */
       g->tls_assigned_gotno = g->local_gotno + g->global_gotno;
-      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
+      tga.g = g;
+      tga.value = MIPS_ELF_GOT_SIZE (abfd);
+      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, &tga);
+      if (!tga.g)
+       return FALSE;
+      BFD_ASSERT (g->tls_assigned_gotno == assign);
 
       /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
       g = gn;
 
-      /* Mark global symbols in every non-primary GOT as ineligible for
-        stubs.  */
+      /* Forbid global symbols in every non-primary GOT from having
+        lazy-binding stubs.  */
       if (g)
-       htab_traverse (g->got_entries, mips_elf_set_no_stub, NULL);
+       htab_traverse (g->got_entries, mips_elf_forbid_lazy_stubs, info);
     }
   while (g);
 
-  got->size = (gg->next->local_gotno
-                   + gg->next->global_gotno
-                   + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+  got->size = assign * MIPS_ELF_GOT_SIZE (abfd);
+
+  needed_relocs = 0;
+  for (g = gg->next; g && g->next != gg; g = g->next)
+    {
+      unsigned int save_assign;
+
+      /* Assign offsets to global GOT entries and count how many
+        relocations they need.  */
+      save_assign = g->assigned_low_gotno;
+      g->assigned_low_gotno = g->local_gotno;
+      tga.info = info;
+      tga.value = MIPS_ELF_GOT_SIZE (abfd);
+      tga.g = g;
+      htab_traverse (g->got_entries, mips_elf_set_global_gotidx, &tga);
+      if (!tga.g)
+       return FALSE;
+      BFD_ASSERT (g->assigned_low_gotno == g->local_gotno + g->global_gotno);
+      g->assigned_low_gotno = save_assign;
+
+      if (bfd_link_pic (info))
+       {
+         g->relocs += g->local_gotno - g->assigned_low_gotno;
+         BFD_ASSERT (g->assigned_low_gotno == g->next->local_gotno
+                     + g->next->global_gotno
+                     + g->next->tls_gotno
+                     + htab->reserved_gotno);
+       }
+      needed_relocs += g->relocs;
+    }
+  needed_relocs += g->relocs;
+
+  if (needed_relocs)
+    mips_elf_allocate_dynamic_relocations (dynobj, info,
+                                          needed_relocs);
 
   return TRUE;
 }
@@ -3828,17 +5097,15 @@ mips_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
   return NULL;
 }
 
-/* Return whether a relocation is against a local symbol.  */
+/* Return whether an input relocation is against a local symbol.  */
 
 static bfd_boolean
 mips_elf_local_relocation_p (bfd *input_bfd,
                             const Elf_Internal_Rela *relocation,
-                            asection **local_sections,
-                            bfd_boolean check_forced)
+                            asection **local_sections)
 {
   unsigned long r_symndx;
   Elf_Internal_Shdr *symtab_hdr;
-  struct mips_elf_link_hash_entry *h;
   size_t extsymoff;
 
   r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
@@ -3850,20 +5117,6 @@ mips_elf_local_relocation_p (bfd *input_bfd,
   if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
     return TRUE;
 
-  if (check_forced)
-    {
-      /* Look up the hash table to check whether the symbol
-        was forced local.  */
-      h = (struct mips_elf_link_hash_entry *)
-       elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
-      /* Find the real hash-table entry for this symbol.  */
-      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 (h->root.forced_local)
-       return TRUE;
-    }
-
   return FALSE;
 }
 \f
@@ -3942,15 +5195,14 @@ mips_elf_create_compact_rel_section
   flagword flags;
   register asection *s;
 
-  if (bfd_get_section_by_name (abfd, ".compact_rel") == NULL)
+  if (bfd_get_linker_section (abfd, ".compact_rel") == NULL)
     {
       flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED
               | SEC_READONLY);
 
-      s = bfd_make_section_with_flags (abfd, ".compact_rel", flags);
+      s = bfd_make_section_anyway_with_flags (abfd, ".compact_rel", flags);
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+         || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return FALSE;
 
       s->size = sizeof (Elf32_External_compact_rel);
@@ -3962,40 +5214,31 @@ mips_elf_create_compact_rel_section
 /* Create the .got section to hold the global offset table.  */
 
 static bfd_boolean
-mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info,
-                            bfd_boolean maybe_exclude)
+mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags;
   register asection *s;
   struct elf_link_hash_entry *h;
   struct bfd_link_hash_entry *bh;
-  struct mips_got_info *g;
-  bfd_size_type amt;
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
   /* This function may be called more than once.  */
-  s = mips_elf_got_section (abfd, TRUE);
-  if (s)
-    {
-      if (! maybe_exclude)
-       s->flags &= ~SEC_EXCLUDE;
-      return TRUE;
-    }
+  if (htab->root.sgot)
+    return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
-  if (maybe_exclude)
-    flags |= SEC_EXCLUDE;
-
   /* We have to use an alignment of 2**4 here because this is hardcoded
      in the function stub generation and in the linker script.  */
-  s = bfd_make_section_with_flags (abfd, ".got", flags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, 4))
+      || !bfd_set_section_alignment (s, 4))
     return FALSE;
+  htab->root.sgot = s;
 
   /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
      linker script because we don't want to define the symbol if we
@@ -4010,48 +5253,27 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info,
   h->non_elf = 0;
   h->def_regular = 1;
   h->type = STT_OBJECT;
+  h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
   elf_hash_table (info)->hgot = h;
 
-  if (info->shared
+  if (bfd_link_pic (info)
       && ! bfd_elf_link_record_dynamic_symbol (info, h))
     return FALSE;
 
-  amt = sizeof (struct mips_got_info);
-  g = bfd_alloc (abfd, amt);
-  if (g == NULL)
-    return FALSE;
-  g->global_gotsym = NULL;
-  g->global_gotno = 0;
-  g->tls_gotno = 0;
-  g->local_gotno = MIPS_RESERVED_GOTNO (info);
-  g->page_gotno = 0;
-  g->assigned_gotno = MIPS_RESERVED_GOTNO (info);
-  g->bfd2got = NULL;
-  g->next = NULL;
-  g->tls_ldm_offset = MINUS_ONE;
-  g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
-                                   mips_elf_got_entry_eq, NULL);
-  if (g->got_entries == NULL)
-    return FALSE;
-  g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
-                                        mips_got_page_entry_eq, NULL);
-  if (g->got_page_entries == NULL)
-    return FALSE;
-  mips_elf_section_data (s)->u.got_info = g;
+  htab->got_info = mips_elf_create_got_info (abfd);
   mips_elf_section_data (s)->elf.this_hdr.sh_flags
     |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
 
-  /* VxWorks also needs a .got.plt section.  */
-  if (htab->is_vxworks)
-    {
-      s = bfd_make_section_with_flags (abfd, ".got.plt",
-                                      SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                      | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      if (s == NULL || !bfd_set_section_alignment (abfd, s, 4))
-       return FALSE;
+  /* We also need a .got.plt section when generating PLTs.  */
+  s = bfd_make_section_anyway_with_flags (abfd, ".got.plt",
+                                         SEC_ALLOC | SEC_LOAD
+                                         | SEC_HAS_CONTENTS
+                                         | SEC_IN_MEMORY
+                                         | SEC_LINKER_CREATED);
+  if (s == NULL)
+    return FALSE;
+  htab->root.sgotplt = s;
 
-      htab->sgotplt = s;
-    }
   return TRUE;
 }
 \f
@@ -4063,18 +5285,135 @@ static bfd_boolean
 is_gott_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h)
 {
   return (mips_elf_hash_table (info)->is_vxworks
-         && info->shared
+         && bfd_link_pic (info)
          && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
              || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
 }
+
+/* Return TRUE if a relocation of type R_TYPE from INPUT_BFD might
+   require an la25 stub.  See also mips_elf_local_pic_function_p,
+   which determines whether the destination function ever requires a
+   stub.  */
+
+static bfd_boolean
+mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
+                                    bfd_boolean target_is_16_bit_code_p)
+{
+  /* We specifically ignore branches and jumps from EF_PIC objects,
+     where the onus is on the compiler or programmer to perform any
+     necessary initialization of $25.  Sometimes such initialization
+     is unnecessary; for example, -mno-shared functions do not use
+     the incoming value of $25, and may therefore be called directly.  */
+  if (PIC_OBJECT_P (input_bfd))
+    return FALSE;
+
+  switch (r_type)
+    {
+    case R_MIPS_26:
+    case R_MIPS_PC16:
+    case R_MIPS_PC21_S2:
+    case R_MIPS_PC26_S2:
+    case R_MICROMIPS_26_S1:
+    case R_MICROMIPS_PC7_S1:
+    case R_MICROMIPS_PC10_S1:
+    case R_MICROMIPS_PC16_S1:
+    case R_MICROMIPS_PC23_S2:
+      return TRUE;
+
+    case R_MIPS16_26:
+      return !target_is_16_bit_code_p;
+
+    default:
+      return FALSE;
+    }
+}
 \f
+/* Obtain the field relocated by RELOCATION.  */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+                         const Elf_Internal_Rela *relocation,
+                         bfd *input_bfd, bfd_byte *contents)
+{
+  bfd_vma x = 0;
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Obtain the bytes.  */
+  if (size != 0)
+    x = bfd_get (8 * size, input_bfd, location);
+
+  return x;
+}
+
+/* Store the field relocated by RELOCATION.  */
+
+static void
+mips_elf_store_contents (reloc_howto_type *howto,
+                        const Elf_Internal_Rela *relocation,
+                        bfd *input_bfd, bfd_byte *contents, bfd_vma x)
+{
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Put the value into the output.  */
+  if (size != 0)
+    bfd_put (8 * size, input_bfd, x, location);
+}
+
+/* Try to patch a load from GOT instruction in CONTENTS pointed to by
+   RELOCATION described by HOWTO, with a move of 0 to the load target
+   register, returning TRUE if that is successful and FALSE otherwise.
+   If DOIT is FALSE, then only determine it patching is possible and
+   return status without actually changing CONTENTS.
+*/
+
+static bfd_boolean
+mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
+                          const Elf_Internal_Rela *relocation,
+                          reloc_howto_type *howto, bfd_boolean doit)
+{
+  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+  bfd_byte *location = contents + relocation->r_offset;
+  bfd_boolean nullified = TRUE;
+  bfd_vma x;
+
+  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+
+  /* Obtain the current value.  */
+  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
+
+  /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
+     while RY is at bits [18:16] of the combined 32-bit instruction word.  */
+  if (mips16_reloc_p (r_type)
+      && (((x >> 22) & 0x3ff) == 0x3d3                         /* LW */
+         || ((x >> 22) & 0x3ff) == 0x3c7))                     /* LD */
+    x = (0x3cd << 22) | (x & (7 << 16)) << 3;                  /* LI */
+  else if (micromips_reloc_p (r_type)
+          && ((x >> 26) & 0x37) == 0x37)                       /* LW/LD */
+    x = (0xc << 26) | (x & (0x1f << 21));                      /* ADDIU */
+  else if (((x >> 26) & 0x3f) == 0x23                          /* LW */
+          || ((x >> 26) & 0x3f) == 0x37)                       /* LD */
+    x = (0x9 << 26) | (x & (0x1f << 16));                      /* ADDIU */
+  else
+    nullified = FALSE;
+
+  /* Put the value into the output.  */
+  if (doit && nullified)
+    mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+
+  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, FALSE, location);
+
+  return nullified;
+}
+
 /* Calculate the value produced by the RELOCATION (which comes from
    the INPUT_BFD).  The ADDEND is the addend to use for this
    RELOCATION; RELOCATION->R_ADDEND is ignored.
 
    The result of the relocation calculation is stored in VALUEP.
-   REQUIRE_JALXP indicates whether or not the opcode used with this
-   relocation must be JALX.
+   On exit, set *CROSS_MODE_JUMP_P to true if the relocation field
+   is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
 
    This function returns bfd_reloc_continue if the caller need take no
    further action regarding this relocation, bfd_reloc_notsupported if
@@ -4083,13 +5422,14 @@ is_gott_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h)
 
 static bfd_reloc_status_type
 mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
-                              asection *input_section,
+                              asection *input_section, bfd_byte *contents,
                               struct bfd_link_info *info,
                               const Elf_Internal_Rela *relocation,
                               bfd_vma addend, reloc_howto_type *howto,
                               Elf_Internal_Sym *local_syms,
                               asection **local_sections, bfd_vma *valuep,
-                              const char **namep, bfd_boolean *require_jalxp,
+                              const char **namep,
+                              bfd_boolean *cross_mode_jump_p,
                               bfd_boolean save_addend)
 {
   /* The eventual value we will return.  */
@@ -4116,6 +5456,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* TRUE if the symbol referred to by this relocation is a local
      symbol.  */
   bfd_boolean local_p, was_local_p;
+  /* TRUE if the symbol referred to by this relocation is a section
+     symbol.  */
+  bfd_boolean section_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is "_gp_disp".  */
   bfd_boolean gp_disp_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is
@@ -4130,11 +5473,14 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   bfd_boolean overflowed_p;
   /* TRUE if this relocation refers to a MIPS16 function.  */
   bfd_boolean target_is_16_bit_code_p = FALSE;
+  bfd_boolean target_is_micromips_code_p = FALSE;
   struct mips_elf_link_hash_table *htab;
   bfd *dynobj;
+  bfd_boolean resolved_to_zero;
 
   dynobj = elf_hash_table (info)->dynobj;
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
   /* Parse the relocation.  */
   r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
@@ -4150,7 +5496,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
      used in the array of hash table entries.  */
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   local_p = mips_elf_local_relocation_p (input_bfd, relocation,
-                                        local_sections, FALSE);
+                                        local_sections);
   was_local_p = local_p;
   if (! elf_bad_symtab (input_bfd))
     extsymoff = symtab_hdr->sh_info;
@@ -4164,35 +5510,55 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* Figure out the value of the symbol.  */
   if (local_p)
     {
+      bfd_boolean micromips_p = MICROMIPS_P (abfd);
       Elf_Internal_Sym *sym;
 
       sym = local_syms + r_symndx;
       sec = local_sections[r_symndx];
 
+      section_p = ELF_ST_TYPE (sym->st_info) == STT_SECTION;
+
       symbol = sec->output_section->vma + sec->output_offset;
-      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
-         || (sec->flags & SEC_MERGE))
+      if (!section_p || (sec->flags & SEC_MERGE))
        symbol += sym->st_value;
-      if ((sec->flags & SEC_MERGE)
-         && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+      if ((sec->flags & SEC_MERGE) && section_p)
        {
          addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
          addend -= symbol;
          addend += sec->output_section->vma + sec->output_offset;
        }
 
-      /* MIPS16 text labels should be treated as odd.  */
-      if (ELF_ST_IS_MIPS16 (sym->st_other))
+      /* MIPS16/microMIPS text labels should be treated as odd.  */
+      if (ELF_ST_IS_COMPRESSED (sym->st_other))
        ++symbol;
 
       /* Record the name of this symbol, for our caller.  */
       *namep = bfd_elf_string_from_elf_section (input_bfd,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
-      if (*namep == '\0')
-       *namep = bfd_section_name (input_bfd, sec);
+      if (*namep == NULL || **namep == '\0')
+       *namep = bfd_section_name (sec);
 
-      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
+      /* For relocations against a section symbol and ones against no
+        symbol (absolute relocations) infer the ISA mode from the addend.  */
+      if (section_p || r_symndx == STN_UNDEF)
+       {
+         target_is_16_bit_code_p = (addend & 1) && !micromips_p;
+         target_is_micromips_code_p = (addend & 1) && micromips_p;
+       }
+      /* For relocations against an absolute symbol infer the ISA mode
+        from the value of the symbol plus addend.  */
+      else if (bfd_is_abs_section (sec))
+       {
+         target_is_16_bit_code_p = ((symbol + addend) & 1) && !micromips_p;
+         target_is_micromips_code_p = ((symbol + addend) & 1) && micromips_p;
+       }
+      /* Otherwise just use the regular symbol annotation available.  */
+      else
+       {
+         target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
+         target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
+       }
     }
   else
     {
@@ -4216,8 +5582,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        {
          /* Relocations against _gp_disp are permitted only with
             R_MIPS_HI16 and R_MIPS_LO16 relocations.  */
-         if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16
-             && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+         if (!hi16_reloc_p (r_type) && !lo16_reloc_p (r_type))
            return bfd_reloc_notsupported;
 
          gp_disp_p = TRUE;
@@ -4258,11 +5623,11 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        {
          /* If this is a dynamic link, we should have created a
             _DYNAMIC_LINK symbol or _DYNAMIC_LINKING(for normal mips) symbol
-            in in _bfd_mips_elf_create_dynamic_sections.
+            in _bfd_mips_elf_create_dynamic_sections.
             Otherwise, we should define the symbol with a value of 0.
             FIXME: It should probably get into the symbol table
             somehow as well.  */
-         BFD_ASSERT (! info->shared);
+         BFD_ASSERT (! bfd_link_pic (info));
          BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL);
          symbol = 0;
        }
@@ -4279,54 +5644,85 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        }
       else
        {
-         if (! ((*info->callbacks->undefined_symbol)
-                (info, h->root.root.root.string, input_bfd,
-                 input_section, relocation->r_offset,
-                 (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
-                  || ELF_ST_VISIBILITY (h->root.other))))
+         bfd_boolean reject_undefined
+           = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
+              || ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT);
+
+         (*info->callbacks->undefined_symbol)
+           (info, h->root.root.root.string, input_bfd,
+            input_section, relocation->r_offset, reject_undefined);
+
+         if (reject_undefined)
            return bfd_reloc_undefined;
+
          symbol = 0;
        }
 
       target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
+      target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (h->root.other);
     }
 
-  /* 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->relocatable
-      && ((h != NULL && h->fn_stub != NULL)
+  /* If this is a reference to a 16-bit function with a stub, we need
+     to redirect the relocation to the stub unless:
+
+     (a) the relocation is for a MIPS16 JAL;
+
+     (b) the relocation is for a MIPS16 PIC call, and there are no
+        non-MIPS16 uses of the GOT slot; or
+
+     (c) the section allows direct references to MIPS16 functions.  */
+  if (r_type != R_MIPS16_26
+      && !bfd_link_relocatable (info)
+      && ((h != NULL
+          && h->fn_stub != NULL
+          && (r_type != R_MIPS16_CALL16 || h->need_fn_stub))
          || (local_p
-             && elf_tdata (input_bfd)->local_stubs != NULL
-             && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
-      && !mips16_stub_section_p (input_bfd, input_section))
+             && mips_elf_tdata (input_bfd)->local_stubs != NULL
+             && mips_elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
+      && !section_allows_mips16_refs_p (input_section))
     {
       /* This is a 32- or 64-bit call to a 16-bit function.  We should
         have already noticed that we were going to need the
         stub.  */
       if (local_p)
-       sec = elf_tdata (input_bfd)->local_stubs[r_symndx];
+       {
+         sec = mips_elf_tdata (input_bfd)->local_stubs[r_symndx];
+         value = 0;
+       }
       else
        {
          BFD_ASSERT (h->need_fn_stub);
-         sec = h->fn_stub;
+         if (h->la25_stub)
+           {
+             /* If a LA25 header for the stub itself exists, point to the
+                prepended LUI/ADDIU sequence.  */
+             sec = h->la25_stub->stub_section;
+             value = h->la25_stub->offset;
+           }
+         else
+           {
+             sec = h->fn_stub;
+             value = 0;
+           }
        }
 
-      symbol = sec->output_section->vma + sec->output_offset;
+      symbol = sec->output_section->vma + sec->output_offset + value;
       /* The target is 16-bit, but the stub isn't.  */
       target_is_16_bit_code_p = FALSE;
     }
-  /* 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->relocatable
+  /* If this is a MIPS16 call with a stub, that is made through the PLT or
+     to a standard MIPS function, we need to redirect the call to the stub.
+     Note that we specifically exclude R_MIPS16_CALL16 from this behavior;
+     indirect calls should use an indirect stub instead.  */
+  else if (r_type == R_MIPS16_26 && !bfd_link_relocatable (info)
           && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
               || (local_p
-                  && elf_tdata (input_bfd)->local_call_stubs != NULL
-                  && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
-          && !target_is_16_bit_code_p)
+                  && mips_elf_tdata (input_bfd)->local_call_stubs != NULL
+                  && mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
+          && ((h != NULL && h->use_plt_entry) || !target_is_16_bit_code_p))
     {
       if (local_p)
-       sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx];
+       sec = mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx];
       else
        {
          /* If both call_stub and call_fp_stub are defined, we can figure
@@ -4335,11 +5731,11 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
          if (h->call_stub != NULL && h->call_fp_stub != NULL)
            {
              asection *o;
-             
+
              sec = NULL;
              for (o = input_bfd->sections; o != NULL; o = o->next)
                {
-                 if (CALL_FP_STUB_P (bfd_get_section_name (input_bfd, o)))
+                 if (CALL_FP_STUB_P (bfd_section_name (o)))
                    {
                      sec = h->call_fp_stub;
                      break;
@@ -4352,43 +5748,144 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
            sec = h->call_stub;
          else
            sec = h->call_fp_stub;
-       }
+       }
 
       BFD_ASSERT (sec->size > 0);
       symbol = sec->output_section->vma + sec->output_offset;
     }
+  /* If this is a direct call to a PIC function, redirect to the
+     non-PIC stub.  */
+  else if (h != NULL && h->la25_stub
+          && mips_elf_relocation_needs_la25_stub (input_bfd, r_type,
+                                                  target_is_16_bit_code_p))
+    {
+       symbol = (h->la25_stub->stub_section->output_section->vma
+                 + h->la25_stub->stub_section->output_offset
+                 + h->la25_stub->offset);
+       if (ELF_ST_IS_MICROMIPS (h->root.other))
+         symbol |= 1;
+    }
+  /* For direct MIPS16 and microMIPS calls make sure the compressed PLT
+     entry is used if a standard PLT entry has also been made.  In this
+     case the symbol will have been set by mips_elf_set_plt_sym_value
+     to point to the standard PLT entry, so redirect to the compressed
+     one.  */
+  else if ((mips16_branch_reloc_p (r_type)
+           || micromips_branch_reloc_p (r_type))
+          && !bfd_link_relocatable (info)
+          && h != NULL
+          && h->use_plt_entry
+          && h->root.plt.plist->comp_offset != MINUS_ONE
+          && h->root.plt.plist->mips_offset != MINUS_ONE)
+    {
+      bfd_boolean micromips_p = MICROMIPS_P (abfd);
+
+      sec = htab->root.splt;
+      symbol = (sec->output_section->vma
+               + sec->output_offset
+               + htab->plt_header_size
+               + htab->plt_mips_offset
+               + h->root.plt.plist->comp_offset
+               + 1);
+
+      target_is_16_bit_code_p = !micromips_p;
+      target_is_micromips_code_p = micromips_p;
+    }
+
+  /* Make sure MIPS16 and microMIPS are not used together.  */
+  if ((mips16_branch_reloc_p (r_type) && target_is_micromips_code_p)
+      || (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
+   {
+      _bfd_error_handler
+       (_("MIPS16 and microMIPS functions cannot call each other"));
+      return bfd_reloc_notsupported;
+   }
 
   /* Calls from 16-bit code to 32-bit code and vice versa require the
-     special jalx instruction.  */
-  *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)));
+     mode change.  However, we can ignore calls to undefined weak symbols,
+     which should never be executed at runtime.  This exception is important
+     because the assembly writer may have "known" that any definition of the
+     symbol would be 16-bit code, and that direct jumps were therefore
+     acceptable.  */
+  *cross_mode_jump_p = (!bfd_link_relocatable (info)
+                       && !(h && h->root.root.type == bfd_link_hash_undefweak)
+                       && ((mips16_branch_reloc_p (r_type)
+                            && !target_is_16_bit_code_p)
+                           || (micromips_branch_reloc_p (r_type)
+                               && !target_is_micromips_code_p)
+                           || ((branch_reloc_p (r_type)
+                                || r_type == R_MIPS_JALR)
+                               && (target_is_16_bit_code_p
+                                   || target_is_micromips_code_p))));
+
+  resolved_to_zero = (h != NULL
+                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
 
-  local_p = mips_elf_local_relocation_p (input_bfd, relocation,
-                                        local_sections, TRUE);
+  switch (r_type)
+    {
+    case R_MIPS16_CALL16:
+    case R_MIPS16_GOT16:
+    case R_MIPS_CALL16:
+    case R_MIPS_GOT16:
+    case R_MIPS_GOT_PAGE:
+    case R_MIPS_GOT_DISP:
+    case R_MIPS_GOT_LO16:
+    case R_MIPS_CALL_LO16:
+    case R_MICROMIPS_CALL16:
+    case R_MICROMIPS_GOT16:
+    case R_MICROMIPS_GOT_PAGE:
+    case R_MICROMIPS_GOT_DISP:
+    case R_MICROMIPS_GOT_LO16:
+    case R_MICROMIPS_CALL_LO16:
+      if (resolved_to_zero
+         && !bfd_link_relocatable (info)
+         && mips_elf_nullify_got_load (input_bfd, contents,
+                                       relocation, howto, TRUE))
+       return bfd_reloc_continue;
+
+      /* Fall through.  */
+    case R_MIPS_GOT_HI16:
+    case R_MIPS_CALL_HI16:
+    case R_MICROMIPS_GOT_HI16:
+    case R_MICROMIPS_CALL_HI16:
+      if (resolved_to_zero
+         && htab->use_absolute_zero
+         && bfd_link_pic (info))
+       {
+         /* Redirect to the special `__gnu_absolute_zero' symbol.  */
+         h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
+                                        FALSE, FALSE, FALSE);
+         BFD_ASSERT (h != NULL);
+       }
+      break;
+    }
+
+  local_p = (h == NULL || mips_use_local_got_p (info, h));
 
   gp0 = _bfd_get_gp_value (input_bfd);
   gp = _bfd_get_gp_value (abfd);
-  if (dynobj)
-    gp += mips_elf_adjust_gp (abfd, mips_elf_got_info (dynobj, NULL),
-                             input_bfd);
+  if (htab->got_info)
+    gp += mips_elf_adjust_gp (abfd, htab->got_info, input_bfd);
 
   if (gnu_local_gp_p)
     symbol = gp;
 
-  /* If we haven't already determined the GOT offset, oand we're going
+  /* Global R_MIPS_GOT_PAGE/R_MICROMIPS_GOT_PAGE relocations are equivalent
+     to R_MIPS_GOT_DISP/R_MICROMIPS_GOT_DISP.  The addend is applied by the
+     corresponding R_MIPS_GOT_OFST/R_MICROMIPS_GOT_OFST.  */
+  if (got_page_reloc_p (r_type) && !local_p)
+    {
+      r_type = (micromips_reloc_p (r_type)
+               ? R_MICROMIPS_GOT_DISP : R_MIPS_GOT_DISP);
+      addend = 0;
+    }
+
+  /* If we haven't already determined the GOT offset, and we're going
      to need it, get it now.  */
   switch (r_type)
     {
-    case R_MIPS_GOT_PAGE:
-    case R_MIPS_GOT_OFST:
-      /* We need to decay to GOT_DISP/addend if the symbol doesn't
-        bind locally.  */
-      local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1);
-      if (local_p || r_type == R_MIPS_GOT_OFST)
-       break;
-      /* Fall through.  */
-
+    case R_MIPS16_CALL16:
+    case R_MIPS16_GOT16:
     case R_MIPS_CALL16:
     case R_MIPS_GOT16:
     case R_MIPS_GOT_DISP:
@@ -4396,11 +5893,24 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_CALL_HI16:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MICROMIPS_CALL16:
+    case R_MICROMIPS_GOT16:
+    case R_MICROMIPS_GOT_DISP:
+    case R_MICROMIPS_GOT_HI16:
+    case R_MICROMIPS_CALL_HI16:
+    case R_MICROMIPS_GOT_LO16:
+    case R_MICROMIPS_CALL_LO16:
     case R_MIPS_TLS_GD:
     case R_MIPS_TLS_GOTTPREL:
     case R_MIPS_TLS_LDM:
+    case R_MIPS16_TLS_GD:
+    case R_MIPS16_TLS_GOTTPREL:
+    case R_MIPS16_TLS_LDM:
+    case R_MICROMIPS_TLS_GD:
+    case R_MICROMIPS_TLS_GOTTPREL:
+    case R_MICROMIPS_TLS_LDM:
       /* Find the index into the GOT where this value is located.  */
-      if (r_type == R_MIPS_TLS_LDM)
+      if (tls_ldm_reloc_p (r_type))
        {
          g = mips_elf_local_got_index (abfd, input_bfd, info,
                                        0, 0, NULL, r_type);
@@ -4412,9 +5922,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
          /* On VxWorks, CALL relocations should refer to the .got.plt
             entry, which is initialized to point at the PLT stub.  */
          if (htab->is_vxworks
-             && (r_type == R_MIPS_CALL_HI16
-                 || r_type == R_MIPS_CALL_LO16
-                 || r_type == R_MIPS_CALL16))
+             && (call_hi16_reloc_p (r_type)
+                 || call_lo16_reloc_p (r_type)
+                 || call16_reloc_p (r_type)))
            {
              BFD_ASSERT (addend == 0);
              BFD_ASSERT (h->root.needs_plt);
@@ -4422,29 +5932,17 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
            }
          else
            {
-             /* 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 (dynobj, input_bfd,
-                                            &h->root, r_type, info);
-             if (h->tls_type == GOT_NORMAL
-                 && (! elf_hash_table(info)->dynamic_sections_created
-                     || (info->shared
-                         && (info->symbolic || h->root.forced_local)
-                         && h->root.def_regular)))
-               {
-                 /* This is a static link or a -Bsymbolic link.  The
-                    symbol is defined locally, or was forced to be local.
-                    We must initialize this entry in the GOT.  */
-                 asection *sgot = mips_elf_got_section (dynobj, FALSE);
-                 MIPS_ELF_PUT_WORD (dynobj, symbol, sgot->contents + g);
-               }
+             BFD_ASSERT (addend == 0);
+             g = mips_elf_global_got_index (abfd, info, input_bfd,
+                                            &h->root, r_type);
+             if (!TLS_RELOC_P (r_type)
+                 && !elf_hash_table (info)->dynamic_sections_created)
+               /* This is a static link.  We must initialize the GOT entry.  */
+               MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
            }
        }
       else if (!htab->is_vxworks
-              && (r_type == R_MIPS_CALL16 || (r_type == R_MIPS_GOT16)))
+              && (call16_reloc_p (r_type) || got16_reloc_p (r_type)))
        /* The calculation below does not involve "g".  */
        break;
       else
@@ -4456,7 +5954,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        }
 
       /* Convert GOT indices to actual offsets.  */
-      g = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, g);
+      g = mips_elf_got_offset_from_index (info, abfd, input_bfd, g);
       break;
     }
 
@@ -4495,31 +5993,34 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       return bfd_reloc_continue;
 
     case R_MIPS_16:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 16);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = symbol + addend;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
     case R_MIPS_32:
     case R_MIPS_REL32:
     case R_MIPS_64:
-      if ((info->shared
-          || (!htab->is_vxworks
-              && htab->root.dynamic_sections_created
+      if ((bfd_link_pic (info)
+          || (htab->root.dynamic_sections_created
               && h != NULL
               && h->root.def_dynamic
-              && !h->root.def_regular))
-         && r_symndx != 0
+              && !h->root.def_regular
+              && !h->has_static_relocs))
+         && r_symndx != STN_UNDEF
+         && (h == NULL
+             || h->root.root.type != bfd_link_hash_undefweak
+             || (ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
+                 && !resolved_to_zero))
          && (input_section->flags & SEC_ALLOC) != 0)
        {
-         /* If we're creating a shared library, or this relocation is
-            against a symbol in a shared library, then we can't know
+         /* If we're creating a shared library, then we can't know
             where the symbol will end up.  So, we create a relocation
             record in the output, and leave the job up to the dynamic
-            linker.
-
-            In VxWorks executables, references to external symbols
-            are handled using copy relocs or PLT stubs, so there's
-            no need to add a dynamic relocation here.  */
+            linker.  We must do the same for executable references to
+            shared library symbols, unless we've decided to use copy
+            relocs or PLTs instead.  */
          value = addend;
          if (!mips_elf_create_dynamic_relocation (abfd,
                                                   info,
@@ -4553,18 +6054,38 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         mips_elf_perform_relocation.  So, we just fall through to the
         R_MIPS_26 case here.  */
     case R_MIPS_26:
-      if (local_p)
-       value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
-      else
-       {
-         value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
-         if (h->root.root.type != bfd_link_hash_undefweak)
-           overflowed_p = (value >> 26) != ((p + 4) >> 28);
-       }
-      value &= howto->dst_mask;
+    case R_MICROMIPS_26_S1:
+      {
+       unsigned int shift;
+
+       /* Shift is 2, unusually, for microMIPS JALX.  */
+       shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
+
+       if (howto->partial_inplace && !section_p)
+         value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
+       else
+         value = addend;
+       value += symbol;
+
+       /* Make sure the target of a jump is suitably aligned.  Bit 0 must
+          be the correct ISA mode selector except for weak undefined
+          symbols.  */
+       if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+           && (*cross_mode_jump_p
+               ? (value & 3) != (r_type == R_MIPS_26)
+               : (value & ((1 << shift) - 1)) != (r_type != R_MIPS_26)))
+         return bfd_reloc_outofrange;
+
+       value >>= shift;
+       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
+       value &= howto->dst_mask;
+      }
       break;
 
     case R_MIPS_TLS_DTPREL_HI16:
+    case R_MIPS16_TLS_DTPREL_HI16:
+    case R_MICROMIPS_TLS_DTPREL_HI16:
       value = (mips_elf_high (addend + symbol - dtprel_base (info))
               & howto->dst_mask);
       break;
@@ -4572,20 +6093,29 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_TLS_DTPREL_LO16:
     case R_MIPS_TLS_DTPREL32:
     case R_MIPS_TLS_DTPREL64:
+    case R_MIPS16_TLS_DTPREL_LO16:
+    case R_MICROMIPS_TLS_DTPREL_LO16:
       value = (symbol + addend - dtprel_base (info)) & howto->dst_mask;
       break;
 
     case R_MIPS_TLS_TPREL_HI16:
+    case R_MIPS16_TLS_TPREL_HI16:
+    case R_MICROMIPS_TLS_TPREL_HI16:
       value = (mips_elf_high (addend + symbol - tprel_base (info))
               & howto->dst_mask);
       break;
 
     case R_MIPS_TLS_TPREL_LO16:
+    case R_MIPS_TLS_TPREL32:
+    case R_MIPS_TLS_TPREL64:
+    case R_MIPS16_TLS_TPREL_LO16:
+    case R_MICROMIPS_TLS_TPREL_LO16:
       value = (symbol + addend - tprel_base (info)) & howto->dst_mask;
       break;
 
     case R_MIPS_HI16:
     case R_MIPS16_HI16:
+    case R_MICROMIPS_HI16:
       if (!gp_disp_p)
        {
          value = mips_elf_high (addend + symbol);
@@ -4594,24 +6124,31 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       else
        {
          /* For MIPS16 ABI code we generate this sequence
-               0: li      $v0,%hi(_gp_disp)
-               4: addiupc $v1,%lo(_gp_disp)
-               8: sll     $v0,16
+               0: li      $v0,%hi(_gp_disp)
+               4: addiupc $v1,%lo(_gp_disp)
+               8: sll     $v0,16
               12: addu    $v0,$v1
               14: move    $gp,$v0
             So the offsets of hi and lo relocs are the same, but the
-            $pc is four higher than $t9 would be, so reduce
-            both reloc addends by 4. */
+            base $pc is that used by the ADDIUPC instruction at $t9 + 4.
+            ADDIUPC clears the low two bits of the instruction address,
+            so the base is ($t9 + 4) & ~3.  */
          if (r_type == R_MIPS16_HI16)
-           value = mips_elf_high (addend + gp - p - 4);
+           value = mips_elf_high (addend + gp - ((p + 4) & ~(bfd_vma) 0x3));
+         /* The microMIPS .cpload sequence uses the same assembly
+            instructions as the traditional psABI version, but the
+            incoming $t9 has the low bit set.  */
+         else if (r_type == R_MICROMIPS_HI16)
+           value = mips_elf_high (addend + gp - p - 1);
          else
            value = mips_elf_high (addend + gp - p);
-         overflowed_p = mips_elf_overflow_p (value, 16);
        }
       break;
 
     case R_MIPS_LO16:
     case R_MIPS16_LO16:
+    case R_MICROMIPS_LO16:
+    case R_MICROMIPS_HI0_LO16:
       if (!gp_disp_p)
        value = (symbol + addend) & howto->dst_mask;
       else
@@ -4619,7 +6156,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
          /* See the comment for R_MIPS16_HI16 above for the reason
             for this conditional.  */
          if (r_type == R_MIPS16_LO16)
-           value = addend + gp - p;
+           value = addend + gp - (p & ~(bfd_vma) 0x3);
+         else if (r_type == R_MICROMIPS_LO16
+                  || r_type == R_MICROMIPS_HI0_LO16)
+           value = addend + gp - p + 3;
          else
            value = addend + gp - p + 4;
          /* The MIPS ABI requires checking the R_MIPS_LO16 relocation
@@ -4642,6 +6182,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       break;
 
     case R_MIPS_LITERAL:
+    case R_MICROMIPS_LITERAL:
       /* Because we don't merge literal sections, we can handle this
         just like R_MIPS_GPREL16.  In the long run, we should merge
         shared literals, and then we will need to additional work
@@ -4655,6 +6196,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         order.  We don't need to do anything special here; the
         differences are handled in mips_elf_perform_relocation.  */
     case R_MIPS_GPREL16:
+    case R_MICROMIPS_GPREL7_S2:
+    case R_MICROMIPS_GPREL16:
       /* Only sign-extend the addend if it was extracted from the
         instruction.  If the addend was separate, leave it alone,
         otherwise we may lose significant bits.  */
@@ -4668,25 +6211,26 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         to them before.  */
       if (was_local_p)
        value += gp0;
-      overflowed_p = mips_elf_overflow_p (value, 16);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
+    case R_MIPS16_GOT16:
+    case R_MIPS16_CALL16:
     case R_MIPS_GOT16:
     case R_MIPS_CALL16:
+    case R_MICROMIPS_GOT16:
+    case R_MICROMIPS_CALL16:
       /* VxWorks does not have separate local and global semantics for
-        R_MIPS_GOT16; every relocation evaluates to "G".  */
+        R_MIPS*_GOT16; every relocation evaluates to "G".  */
       if (!htab->is_vxworks && local_p)
        {
-         bfd_boolean forced;
-
-         forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
-                                                 local_sections, FALSE);
          value = mips_elf_got16_entry (abfd, input_bfd, info,
-                                       symbol + addend, forced);
+                                       symbol + addend, !was_local_p);
          if (value == MINUS_ONE)
            return bfd_reloc_outofrange;
          value
-           = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, value);
+           = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
          overflowed_p = mips_elf_overflow_p (value, 16);
          break;
        }
@@ -4697,7 +6241,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_TLS_GOTTPREL:
     case R_MIPS_TLS_LDM:
     case R_MIPS_GOT_DISP:
-    got_disp:
+    case R_MIPS16_TLS_GD:
+    case R_MIPS16_TLS_GOTTPREL:
+    case R_MIPS16_TLS_LDM:
+    case R_MICROMIPS_TLS_GD:
+    case R_MICROMIPS_TLS_GOTTPREL:
+    case R_MICROMIPS_TLS_LDM:
+    case R_MICROMIPS_GOT_DISP:
       value = g;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
@@ -4710,14 +6260,174 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
     case R_MIPS_PC16:
     case R_MIPS_GNU_REL16_S2:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p;
-      overflowed_p = mips_elf_overflow_p (value, 18);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 18);
+
+      /* No need to exclude weak undefined symbols here as they resolve
+        to 0 and never set `*cross_mode_jump_p', so this alignment check
+        will never trigger for them.  */
+      if (*cross_mode_jump_p
+         ? ((symbol + addend) & 3) != 1
+         : ((symbol + addend) & 3) != 0)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 18);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS16_PC16_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 17);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC21_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 23);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 23);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC26_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 28);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 28);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC18_S3:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 21);
+
+      if ((symbol + addend) & 7)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - ((p | 7) ^ 7);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 21);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC19_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 21);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 21);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PCHI16:
+      value = mips_elf_high (symbol + addend - p);
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PCLO16:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = symbol + addend - p;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC7_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 8);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 8);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC10_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 11);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 11);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC16_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 17);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MICROMIPS_PC23_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 25);
+      value = symbol + addend - ((p | 3) ^ 3);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 25);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
 
     case R_MIPS_GOT_HI16:
     case R_MIPS_CALL_HI16:
+    case R_MICROMIPS_GOT_HI16:
+    case R_MICROMIPS_CALL_HI16:
       /* We're allowed to handle these two relocations identically.
         The dynamic linker is allowed to handle the CALL relocations
         differently by creating a lazy evaluation stub.  */
@@ -4728,23 +6438,22 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MICROMIPS_GOT_LO16:
+    case R_MICROMIPS_CALL_LO16:
       value = g & howto->dst_mask;
       break;
 
     case R_MIPS_GOT_PAGE:
-      /* 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;
+    case R_MICROMIPS_GOT_PAGE:
       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 (dynobj, abfd, input_bfd, value);
+      value = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
     case R_MIPS_GOT_OFST:
+    case R_MICROMIPS_GOT_OFST:
       if (local_p)
        mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
       else
@@ -4753,32 +6462,43 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       break;
 
     case R_MIPS_SUB:
+    case R_MICROMIPS_SUB:
       value = symbol - addend;
       value &= howto->dst_mask;
       break;
 
     case R_MIPS_HIGHER:
+    case R_MICROMIPS_HIGHER:
       value = mips_elf_higher (addend + symbol);
       value &= howto->dst_mask;
       break;
 
     case R_MIPS_HIGHEST:
+    case R_MICROMIPS_HIGHEST:
       value = mips_elf_highest (addend + symbol);
       value &= howto->dst_mask;
       break;
 
     case R_MIPS_SCN_DISP:
+    case R_MICROMIPS_SCN_DISP:
       value = symbol + addend - sec->output_offset;
       value &= howto->dst_mask;
       break;
 
     case R_MIPS_JALR:
+    case R_MICROMIPS_JALR:
       /* This relocation is only a hint.  In some cases, we optimize
         it into a bal instruction.  But we don't try to optimize
-        branches to the PLT; that will wind up wasting time.  */
-      if (h != NULL && h->root.plt.offset != (bfd_vma) -1)
+        when the symbol does not resolve locally.  */
+      if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
+       return bfd_reloc_continue;
+      /* We can't optimize cross-mode jumps either.  */
+      if (*cross_mode_jump_p)
        return bfd_reloc_continue;
       value = symbol + addend;
+      /* Neither we can non-instruction-aligned targets.  */
+      if (r_type == R_MIPS_JALR ? (value & 3) != 0 : (value & 1) == 0)
+       return bfd_reloc_continue;
       break;
 
     case R_MIPS_PJUMP:
@@ -4797,28 +6517,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
 }
 
-/* Obtain the field relocated by RELOCATION.  */
-
-static bfd_vma
-mips_elf_obtain_contents (reloc_howto_type *howto,
-                         const Elf_Internal_Rela *relocation,
-                         bfd *input_bfd, bfd_byte *contents)
-{
-  bfd_vma x;
-  bfd_byte *location = contents + relocation->r_offset;
-
-  /* Obtain the bytes.  */
-  x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location);
-
-  return x;
-}
-
 /* It has been determined that the result of the RELOCATION is the
    VALUE.  Use HOWTO to place VALUE into the output file at the
    appropriate position.  The SECTION is the section to which the
-   relocation applies.  If REQUIRE_JALX is TRUE, then the opcode used
-   for the relocation must be either JAL or JALX, and it is
-   unconditionally converted to JALX.
+   relocation applies.
+   CROSS_MODE_JUMP_P is true if the relocation field
+   is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
 
    Returns FALSE if anything goes wrong.  */
 
@@ -4828,7 +6532,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
                             const Elf_Internal_Rela *relocation,
                             bfd_vma value, bfd *input_bfd,
                             asection *input_section, bfd_byte *contents,
-                            bfd_boolean require_jalx)
+                            bfd_boolean cross_mode_jump_p)
 {
   bfd_vma x;
   bfd_byte *location;
@@ -4837,7 +6541,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   /* Figure out where the relocation is occurring.  */
   location = contents + relocation->r_offset;
 
-  _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
 
   /* Obtain the current value.  */
   x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
@@ -4848,8 +6552,22 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   /* Set the field.  */
   x |= (value & howto->dst_mask);
 
-  /* If required, turn JAL into JALX.  */
-  if (require_jalx)
+  /* Detect incorrect JALX usage.  If required, turn JAL or BAL into JALX.  */
+  if (!cross_mode_jump_p && jal_reloc_p (r_type))
+    {
+      bfd_vma opcode = x >> 26;
+
+      if (r_type == R_MIPS16_26 ? opcode == 0x7
+         : r_type == R_MICROMIPS_26_S1 ? opcode == 0x3c
+         : opcode == 0x1d)
+       {
+         info->callbacks->einfo
+           (_("%X%H: unsupported JALX to the same ISA mode\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
+    }
+  if (cross_mode_jump_p && jal_reloc_p (r_type))
     {
       bfd_boolean ok;
       bfd_vma opcode = x >> 26;
@@ -4861,37 +6579,98 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
          ok = ((opcode == 0x6) || (opcode == 0x7));
          jalx_opcode = 0x7;
        }
+      else if (r_type == R_MICROMIPS_26_S1)
+       {
+         ok = ((opcode == 0x3d) || (opcode == 0x3c));
+         jalx_opcode = 0x3c;
+       }
       else
        {
          ok = ((opcode == 0x3) || (opcode == 0x1d));
          jalx_opcode = 0x1d;
        }
 
-      /* If the opcode is not JAL or JALX, there's a problem.  */
+      /* If the opcode is not JAL or JALX, there's a problem.  We cannot
+        convert J or JALS to JALX.  */
       if (!ok)
        {
-         (*_bfd_error_handler)
-           (_("%B: %A+0x%lx: jump to stub routine which is not jal"),
-            input_bfd,
-            input_section,
-            (unsigned long) relocation->r_offset);
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         info->callbacks->einfo
+           (_("%X%H: unsupported jump between ISA modes; "
+              "consider recompiling with interlinking enabled\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
        }
 
       /* Make this the JALX opcode.  */
-      x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
+      x = (x & ~(0x3fu << 26)) | (jalx_opcode << 26);
+    }
+  else if (cross_mode_jump_p && b_reloc_p (r_type))
+    {
+      bfd_boolean ok = FALSE;
+      bfd_vma opcode = x >> 16;
+      bfd_vma jalx_opcode = 0;
+      bfd_vma sign_bit = 0;
+      bfd_vma addr;
+      bfd_vma dest;
+
+      if (r_type == R_MICROMIPS_PC16_S1)
+       {
+         ok = opcode == 0x4060;
+         jalx_opcode = 0x3c;
+         sign_bit = 0x10000;
+         value <<= 1;
+       }
+      else if (r_type == R_MIPS_PC16 || r_type == R_MIPS_GNU_REL16_S2)
+       {
+         ok = opcode == 0x411;
+         jalx_opcode = 0x1d;
+         sign_bit = 0x20000;
+         value <<= 2;
+       }
+
+      if (ok && !bfd_link_pic (info))
+       {
+         addr = (input_section->output_section->vma
+                 + input_section->output_offset
+                 + relocation->r_offset
+                 + 4);
+         dest = (addr
+                 + (((value & ((sign_bit << 1) - 1)) ^ sign_bit) - sign_bit));
+
+         if ((addr >> 28) << 28 != (dest >> 28) << 28)
+           {
+             info->callbacks->einfo
+               (_("%X%H: cannot convert branch between ISA modes "
+                  "to JALX: relocation out of range\n"),
+                input_bfd, input_section, relocation->r_offset);
+             return TRUE;
+           }
+
+         /* Make this the JALX opcode.  */
+         x = ((dest >> 2) & 0x3ffffff) | jalx_opcode << 26;
+       }
+      else if (!mips_elf_hash_table (info)->ignore_branch_isa)
+       {
+         info->callbacks->einfo
+           (_("%X%H: unsupported branch between ISA modes\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
     }
 
-  /* On the RM9000, bal is faster than jal, because bal uses branch
-     prediction hardware.  If we are linking for the RM9000, and we
-     see jal, and bal fits, use it instead.  Note that this
-     transformation should be safe for all architectures.  */
-  if (bfd_get_mach (input_bfd) == bfd_mach_mips9000
-      && !info->relocatable
-      && !require_jalx
-      && ((r_type == R_MIPS_26 && (x >> 26) == 0x3)        /* jal addr */
-         || (r_type == R_MIPS_JALR && x == 0x0320f809)))   /* jalr t9 */
+  /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
+     range.  */
+  if (!bfd_link_relocatable (info)
+      && !cross_mode_jump_p
+      && ((JAL_TO_BAL_P (input_bfd)
+          && r_type == R_MIPS_26
+          && (x >> 26) == 0x3)                 /* jal addr */
+         || (JALR_TO_BAL_P (input_bfd)
+             && r_type == R_MIPS_JALR
+             && x == 0x0320f809)               /* jalr t9 */
+         || (JR_TO_B_P (input_bfd)
+             && r_type == R_MIPS_JALR
+             && (x & ~1) == 0x03200008)))      /* jr t9 / jalr zero, t9 */
     {
       bfd_vma addr;
       bfd_vma dest;
@@ -4907,55 +6686,23 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
        dest = value;
       off = dest - addr;
       if (off <= 0x1ffff && off >= -0x20000)
-       x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff);   /* bal addr */
+       {
+         if ((x & ~1) == 0x03200008)           /* jr t9 / jalr zero, t9 */
+           x = 0x10000000 | (((bfd_vma) off >> 2) & 0xffff);   /* b addr */
+         else
+           x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff);   /* bal addr */
+       }
     }
 
   /* Put the value into the output.  */
-  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
+  mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
 
-  _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
-                               location);
+  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
+                              location);
 
   return TRUE;
 }
-
-/* Returns TRUE if SECTION is a MIPS16 stub section.  */
-
-static bfd_boolean
-mips16_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
-{
-  const char *name = bfd_get_section_name (abfd, section);
-
-  return FN_STUB_P (name) || CALL_STUB_P (name) || CALL_FP_STUB_P (name);
-}
 \f
-/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
-
-static void
-mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
-                                      unsigned int n)
-{
-  asection *s;
-  struct mips_elf_link_hash_table *htab;
-
-  htab = mips_elf_hash_table (info);
-  s = mips_elf_rel_dyn_section (info, FALSE);
-  BFD_ASSERT (s != NULL);
-
-  if (htab->is_vxworks)
-    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
-  else
-    {
-      if (s->size == 0)
-       {
-         /* Make room for a null element.  */
-         s->size += MIPS_ELF_REL_SIZE (abfd);
-         ++s->reloc_count;
-       }
-      s->size += n * MIPS_ELF_REL_SIZE (abfd);
-    }
-}
-
 /* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
    is the original relocation, which is now being transformed into a
    dynamic relocation.  The ADDENDP is adjusted if necessary; the
@@ -4978,6 +6725,8 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   r_type = ELF_R_TYPE (output_bfd, rel->r_info);
   dynobj = elf_hash_table (info)->dynobj;
   sreloc = mips_elf_rel_dyn_section (info, FALSE);
@@ -5011,10 +6760,9 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
 
   /* We must now calculate the dynamic symbol table index to use
      in the relocation.  */
-  if (h != NULL
-      && (!h->root.def_regular
-         || (info->shared && !info->symbolic && !h->root.forced_local)))
+  if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
     {
+      BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE);
       indx = h->root.dynindx;
       if (SGI_COMPAT (output_bfd))
        defined_p = h->root.def_regular;
@@ -5144,7 +6892,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
   /* On IRIX5, make an entry of compact relocation info.  */
   if (IRIX_COMPAT (output_bfd) == ict_irix5)
     {
-      asection *scpt = bfd_get_section_by_name (dynobj, ".compact_rel");
+      asection *scpt = bfd_get_linker_section (dynobj, ".compact_rel");
       bfd_byte *cr;
 
       if (scpt)
@@ -5212,6 +6960,9 @@ _bfd_elf_mips_mach (flagword flags)
     case E_MIPS_MACH_5500:
       return bfd_mach_mips5500;
 
+    case E_MIPS_MACH_5900:
+      return bfd_mach_mips5900;
+
     case E_MIPS_MACH_9000:
       return bfd_mach_mips9000;
 
@@ -5224,9 +6975,30 @@ _bfd_elf_mips_mach (flagword flags)
     case E_MIPS_MACH_LS2F:
       return bfd_mach_mips_loongson_2f;
 
+    case E_MIPS_MACH_GS464:
+      return bfd_mach_mips_gs464;
+
+    case E_MIPS_MACH_GS464E:
+      return bfd_mach_mips_gs464e;
+
+    case E_MIPS_MACH_GS264E:
+      return bfd_mach_mips_gs264e;
+
+    case E_MIPS_MACH_OCTEON3:
+      return bfd_mach_mips_octeon3;
+
+    case E_MIPS_MACH_OCTEON2:
+      return bfd_mach_mips_octeon2;
+
     case E_MIPS_MACH_OCTEON:
       return bfd_mach_mips_octeon;
 
+    case E_MIPS_MACH_XLR:
+      return bfd_mach_mips_xlr;
+
+    case E_MIPS_MACH_IAMR2:
+      return bfd_mach_mips_interaptiv_mr2;
+
     default:
       switch (flags & EF_MIPS_ARCH)
        {
@@ -5257,6 +7029,12 @@ _bfd_elf_mips_mach (flagword flags)
 
        case E_MIPS_ARCH_64R2:
          return bfd_mach_mipsisa64r2;
+
+       case E_MIPS_ARCH_32R6:
+         return bfd_mach_mipsisa32r6;
+
+       case E_MIPS_ARCH_64R6:
+         return bfd_mach_mipsisa64r6;
        }
     }
 
@@ -5309,14 +7087,14 @@ static asection mips_elf_acom_section;
 static asymbol mips_elf_acom_symbol;
 static asymbol *mips_elf_acom_symbol_ptr;
 
-/* Handle the special MIPS section numbers that a symbol may use.
-   This is used for both the 32-bit and the 64-bit ABI.  */
+/* This is used for both the 32-bit and the 64-bit ABI.  */
 
 void
 _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
 {
   elf_symbol_type *elfsym;
 
+  /* Handle the special MIPS section numbers that a symbol may use.  */
   elfsym = (elf_symbol_type *) asym;
   switch (elfsym->internal_elf_sym.st_shndx)
     {
@@ -5376,12 +7154,11 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
       {
        asection *section = bfd_get_section_by_name (abfd, ".text");
 
-       BFD_ASSERT (SGI_COMPAT (abfd));
        if (section != NULL)
          {
            asym->section = section;
            /* MIPS_TEXT is a bit special, the address is not an offset
-              to the base of the .text section.  So substract the section
+              to the base of the .text section.  So subtract the section
               base address to make it an offset.  */
            asym->value -= section->vma;
          }
@@ -5392,18 +7169,31 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
       {
        asection *section = bfd_get_section_by_name (abfd, ".data");
 
-       BFD_ASSERT (SGI_COMPAT (abfd));
        if (section != NULL)
          {
            asym->section = section;
            /* MIPS_DATA is a bit special, the address is not an offset
-              to the base of the .data section.  So substract the section
+              to the base of the .data section.  So subtract the section
               base address to make it an offset.  */
            asym->value -= section->vma;
          }
       }
       break;
     }
+
+  /* If this is an odd-valued function symbol, assume it's a MIPS16
+     or microMIPS one.  */
+  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
+      && (asym->value & 1) != 0)
+    {
+      asym->value--;
+      if (MICROMIPS_P (abfd))
+       elfsym->internal_elf_sym.st_other
+         = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
+      else
+       elfsym->internal_elf_sym.st_other
+         = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
+    }
 }
 \f
 /* Implement elf_backend_eh_frame_address_size.  This differs from
@@ -5426,10 +7216,10 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
    We therefore take the following approach:
 
       - If ABFD contains a .gcc_compiled_longXX section, use it to
-        determine the pointer size.
+       determine the pointer size.
 
       - Otherwise check the type of the first relocation.  Assume that
-        the LP64 ABI is being used if the relocation is of type R_MIPS_64.
+       the LP64 ABI is being used if the relocation is of type R_MIPS_64.
 
       - Otherwise punt.
 
@@ -5444,7 +7234,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
    did so.  */
 
 unsigned int
-_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec)
+_bfd_mips_elf_eh_frame_address_size (bfd *abfd, const asection *sec)
 {
   if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
     return 8;
@@ -5505,9 +7295,19 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
     {
       bfd_byte buf[4];
 
-      BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo));
       BFD_ASSERT (hdr->contents == NULL);
 
+      if (hdr->sh_size != sizeof (Elf32_External_RegInfo))
+       {
+         _bfd_error_handler
+           (_("%pB: incorrect `.reginfo' section size; "
+              "expected %" PRIu64 ", got %" PRIu64),
+            abfd, (uint64_t) sizeof (Elf32_External_RegInfo),
+            (uint64_t) hdr->sh_size);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+
       if (bfd_seek (abfd,
                    hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
                    SEEK_SET) != 0)
@@ -5542,8 +7342,10 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
-               (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: warning: bad `%s' option size %u smaller than"
+                  " its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
            }
@@ -5583,30 +7385,23 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
 
   if (hdr->bfd_section != NULL)
     {
-      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
-
+      const char *name = bfd_section_name (hdr->bfd_section);
+
+      /* .sbss is not handled specially here because the GNU/Linux
+        prelinker can convert .sbss from NOBITS to PROGBITS and
+        changing it back to NOBITS breaks the binary.  The entry in
+        _bfd_mips_elf_special_sections will ensure the correct flags
+        are set on .sbss if BFD creates it without reading it from an
+        input file, and without special handling here the flags set
+        on it in an input file will be followed.  */
       if (strcmp (name, ".sdata") == 0
          || strcmp (name, ".lit8") == 0
          || strcmp (name, ".lit4") == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_PROGBITS;
-       }
-      else if (strcmp (name, ".sbss") == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_NOBITS;
-       }
+       hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
       else if (strcmp (name, ".srdata") == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_PROGBITS;
-       }
+       hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
       else if (strcmp (name, ".compact_rel") == 0)
-       {
-         hdr->sh_flags = 0;
-         hdr->sh_type = SHT_PROGBITS;
-       }
+       hdr->sh_flags = 0;
       else if (strcmp (name, ".rtproc") == 0)
        {
          if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
@@ -5688,9 +7483,14 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
       if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
        return FALSE;
       break;
+    case SHT_MIPS_ABIFLAGS:
+      if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name))
+       return FALSE;
+      flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
+      break;
     case SHT_MIPS_DWARF:
       if (! CONST_STRNEQ (name, ".debug_")
-          && ! CONST_STRNEQ (name, ".zdebug_"))
+         && ! CONST_STRNEQ (name, ".zdebug_"))
        return FALSE;
       break;
     case SHT_MIPS_SYMBOL_LIB:
@@ -5702,6 +7502,9 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
          && ! CONST_STRNEQ (name, ".MIPS.post_rel"))
        return FALSE;
       break;
+    case SHT_MIPS_XHASH:
+      if (strcmp (name, ".MIPS.xhash") != 0)
+       return FALSE;
     default:
       break;
     }
@@ -5711,11 +7514,24 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
 
   if (flags)
     {
-      if (! bfd_set_section_flags (abfd, hdr->bfd_section,
-                                  (bfd_get_section_flags (abfd,
-                                                          hdr->bfd_section)
-                                   | flags)))
+      if (!bfd_set_section_flags (hdr->bfd_section,
+                                 (bfd_section_flags (hdr->bfd_section)
+                                  | flags)))
+       return FALSE;
+    }
+
+  if (hdr->sh_type == SHT_MIPS_ABIFLAGS)
+    {
+      Elf_External_ABIFlags_v0 ext;
+
+      if (! bfd_get_section_contents (abfd, hdr->bfd_section,
+                                     &ext, 0, sizeof ext))
        return FALSE;
+      bfd_mips_elf_swap_abiflags_v0_in (abfd, &ext,
+                                       &mips_elf_tdata (abfd)->abiflags);
+      if (mips_elf_tdata (abfd)->abiflags.version != 0)
+       return FALSE;
+      mips_elf_tdata (abfd)->abiflags_valid = TRUE;
     }
 
   /* FIXME: We should record sh_info for a .gptab section.  */
@@ -5763,8 +7579,10 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
-               (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: warning: bad `%s' option size %u smaller than"
+                  " its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
            }
@@ -5805,7 +7623,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
 bfd_boolean
 _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
 {
-  const char *name = bfd_get_section_name (abfd, sec);
+  const char *name = bfd_section_name (sec);
 
   if (strcmp (name, ".liblist") == 0)
     {
@@ -5827,7 +7645,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_DEBUG;
       /* In a shared object on IRIX 5.3, the .mdebug section has an
-         entsize of 0.  FIXME: Does this matter?  */
+        entsize of 0.  FIXME: Does this matter?  */
       if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0)
        hdr->sh_entsize = 0;
       else
@@ -5837,7 +7655,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_REGINFO;
       /* In a shared object on IRIX 5.3, the .reginfo section has an
-         entsize of 0x18.  FIXME: Does this matter?  */
+        entsize of 0x18.  FIXME: Does this matter?  */
       if (SGI_COMPAT (abfd))
        {
          if ((abfd->flags & DYNAMIC) != 0)
@@ -5884,8 +7702,13 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_entsize = 1;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
     }
+  else if (CONST_STRNEQ (name, ".MIPS.abiflags"))
+    {
+      hdr->sh_type = SHT_MIPS_ABIFLAGS;
+      hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
+    }
   else if (CONST_STRNEQ (name, ".debug_")
-           || CONST_STRNEQ (name, ".zdebug_"))
+          || CONST_STRNEQ (name, ".zdebug_"))
     {
       hdr->sh_type = SHT_MIPS_DWARF;
 
@@ -5899,7 +7722,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_SYMBOL_LIB;
       /* The sh_link and sh_info fields are set in
-         final_write_processing.  */
+        final_write_processing.  */
     }
   else if (CONST_STRNEQ (name, ".MIPS.events")
           || CONST_STRNEQ (name, ".MIPS.post_rel"))
@@ -5914,6 +7737,12 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_flags |= SHF_ALLOC;
       hdr->sh_entsize = 8;
     }
+  else if (strcmp (name, ".MIPS.xhash") == 0)
+    {
+      hdr->sh_type = SHT_MIPS_XHASH;
+      hdr->sh_flags |= SHF_ALLOC;
+      hdr->sh_entsize = get_elf_backend_data(abfd)->s->arch_size == 64 ? 0 : 4;
+    }
 
   /* The generic elf_fake_sections will set up REL_HDR using the default
    kind of relocations.  We used to set up a second header for the
@@ -5934,12 +7763,12 @@ bfd_boolean
 _bfd_mips_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
                                        asection *sec, int *retval)
 {
-  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+  if (strcmp (bfd_section_name (sec), ".scommon") == 0)
     {
       *retval = SHN_MIPS_SCOMMON;
       return TRUE;
     }
-  if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0)
+  if (strcmp (bfd_section_name (sec), ".acommon") == 0)
     {
       *retval = SHN_MIPS_ACOMMON;
       return TRUE;
@@ -5997,7 +7826,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
     case SHN_MIPS_TEXT:
       /* This section is used in a shared object.  */
-      if (elf_tdata (abfd)->elf_text_section == NULL)
+      if (mips_elf_tdata (abfd)->elf_text_section == NULL)
        {
          asymbol *elf_text_symbol;
          asection *elf_text_section;
@@ -6014,11 +7843,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
          /* Initialize the section.  */
 
-         elf_tdata (abfd)->elf_text_section = elf_text_section;
-         elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
+         mips_elf_tdata (abfd)->elf_text_section = elf_text_section;
+         mips_elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
 
          elf_text_section->symbol = elf_text_symbol;
-         elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol;
+         elf_text_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_text_symbol;
 
          elf_text_section->name = ".text";
          elf_text_section->flags = SEC_NO_FLAGS;
@@ -6029,16 +7858,16 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
          elf_text_symbol->section = elf_text_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
-         info->shared.  I don't know why, and that doesn't make sense,
-         so I took it out.  */
-      *secp = elf_tdata (abfd)->elf_text_section;
+        bfd_link_pic (info).  I don't know why, and that doesn't make sense,
+        so I took it out.  */
+      *secp = mips_elf_tdata (abfd)->elf_text_section;
       break;
 
     case SHN_MIPS_ACOMMON:
       /* Fall through. XXX Can we treat this as allocated data?  */
     case SHN_MIPS_DATA:
       /* This section is used in a shared object.  */
-      if (elf_tdata (abfd)->elf_data_section == NULL)
+      if (mips_elf_tdata (abfd)->elf_data_section == NULL)
        {
          asymbol *elf_data_symbol;
          asection *elf_data_section;
@@ -6055,11 +7884,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
          /* Initialize the section.  */
 
-         elf_tdata (abfd)->elf_data_section = elf_data_section;
-         elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
+         mips_elf_tdata (abfd)->elf_data_section = elf_data_section;
+         mips_elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
 
          elf_data_section->symbol = elf_data_symbol;
-         elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol;
+         elf_data_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_data_symbol;
 
          elf_data_section->name = ".data";
          elf_data_section->flags = SEC_NO_FLAGS;
@@ -6070,9 +7899,9 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
          elf_data_symbol->section = elf_data_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
-         info->shared.  I don't know why, and that doesn't make sense,
-         so I took it out.  */
-      *secp = elf_tdata (abfd)->elf_data_section;
+        bfd_link_pic (info).  I don't know why, and that doesn't make sense,
+        so I took it out.  */
+      *secp = mips_elf_tdata (abfd)->elf_data_section;
       break;
 
     case SHN_MIPS_SUNDEFINED:
@@ -6081,7 +7910,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
     }
 
   if (SGI_COMPAT (abfd)
-      && ! info->shared
+      && ! bfd_link_pic (info)
       && info->output_bfd->xvec == abfd->xvec
       && strcmp (*namep, "__rld_obj_head") == 0)
     {
@@ -6104,12 +7933,13 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        return FALSE;
 
       mips_elf_hash_table (info)->use_rld_obj_head = TRUE;
+      mips_elf_hash_table (info)->rld_symbol = h;
     }
 
   /* If this is a mips16 text symbol, add 1 to the value to make it
      odd.  This will cause something like .word SYM to come up with
      the right value when it is loaded into the PC.  */
-  if (ELF_ST_IS_MIPS16 (sym->st_other))
+  if (ELF_ST_IS_COMPRESSED (sym->st_other))
     ++*valp;
 
   return TRUE;
@@ -6119,7 +7949,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
    symbol.  We mark symbols as small common if appropriate.  This is
    also where we undo the increment of the value for a mips16 symbol.  */
 
-bfd_boolean
+int
 _bfd_mips_elf_link_output_symbol_hook
   (struct bfd_link_info *info ATTRIBUTE_UNUSED,
    const char *name ATTRIBUTE_UNUSED, Elf_Internal_Sym *sym,
@@ -6132,10 +7962,10 @@ _bfd_mips_elf_link_output_symbol_hook
       && strcmp (input_sec->name, ".scommon") == 0)
     sym->st_shndx = SHN_MIPS_SCOMMON;
 
-  if (ELF_ST_IS_MIPS16 (sym->st_other))
+  if (ELF_ST_IS_COMPRESSED (sym->st_other))
     sym->st_value &= ~1;
 
-  return TRUE;
+  return 1;
 }
 \f
 /* Functions for the dynamic linker.  */
@@ -6153,6 +7983,8 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED | SEC_READONLY);
 
@@ -6160,46 +7992,46 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      EABI doesn't.  */
   if (!htab->is_vxworks)
     {
-      s = bfd_get_section_by_name (abfd, ".dynamic");
+      s = bfd_get_linker_section (abfd, ".dynamic");
       if (s != NULL)
        {
-         if (! bfd_set_section_flags (abfd, s, flags))
+         if (!bfd_set_section_flags (s, flags))
            return FALSE;
        }
     }
 
   /* We need to create .got section.  */
-  if (! mips_elf_create_got_section (abfd, info, FALSE))
+  if (!mips_elf_create_got_section (abfd, info))
     return FALSE;
 
   if (! mips_elf_rel_dyn_section (info, TRUE))
     return FALSE;
 
   /* Create .stub section.  */
-  if (bfd_get_section_by_name (abfd,
-                              MIPS_ELF_STUB_SECTION_NAME (abfd)) == NULL)
-    {
-      s = bfd_make_section_with_flags (abfd,
-                                      MIPS_ELF_STUB_SECTION_NAME (abfd),
-                                      flags | SEC_CODE);
-      if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
-       return FALSE;
-    }
+  s = bfd_make_section_anyway_with_flags (abfd,
+                                         MIPS_ELF_STUB_SECTION_NAME (abfd),
+                                         flags | SEC_CODE);
+  if (s == NULL
+      || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+    return FALSE;
+  htab->sstubs = s;
 
-  if ((IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none)
-      && !info->shared
-      && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
+  if (!mips_elf_hash_table (info)->use_rld_obj_head
+      && bfd_link_executable (info)
+      && bfd_get_linker_section (abfd, ".rld_map") == NULL)
     {
-      s = bfd_make_section_with_flags (abfd, ".rld_map",
-                                      flags &~ (flagword) SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
+                                             flags &~ (flagword) SEC_READONLY);
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+         || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return FALSE;
     }
 
+  /* Create .MIPS.xhash section.  */
+  if (info->emit_gnu_hash)
+    s = bfd_make_section_anyway_with_flags (abfd, ".MIPS.xhash",
+                                           flags | SEC_READONLY);
+
   /* On IRIX5, we adjust add some additional symbols and change the
      alignments of several sections.  There is no ABI documentation
      indicating that this is necessary on IRIX6, nor any evidence that
@@ -6215,6 +8047,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
            return FALSE;
 
          h = (struct elf_link_hash_entry *) bh;
+         h->mark = 1;
          h->non_elf = 0;
          h->def_regular = 1;
          h->type = STT_SECTION;
@@ -6231,24 +8064,29 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        }
 
       /* Change alignments of some sections.  */
-      s = bfd_get_section_by_name (abfd, ".hash");
+      s = bfd_get_linker_section (abfd, ".hash");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
-      s = bfd_get_section_by_name (abfd, ".dynsym");
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
+      s = bfd_get_linker_section (abfd, ".dynsym");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
-      s = bfd_get_section_by_name (abfd, ".dynstr");
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
+      s = bfd_get_linker_section (abfd, ".dynstr");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
+      /* ??? */
       s = bfd_get_section_by_name (abfd, ".reginfo");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
-      s = bfd_get_section_by_name (abfd, ".dynamic");
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
+      s = bfd_get_linker_section (abfd, ".dynamic");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
     }
 
-  if (!info->shared)
+  if (bfd_link_executable (info))
     {
       const char *name;
 
@@ -6273,7 +8111,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
             and is filled in by the rtld to contain a pointer to
             the _r_debug structure. Its symbol value will be set in
             _bfd_mips_elf_finish_dynamic_symbol.  */
-         s = bfd_get_section_by_name (abfd, ".rld_map");
+         s = bfd_get_linker_section (abfd, ".rld_map");
          BFD_ASSERT (s != NULL);
 
          name = SGI_COMPAT (abfd) ? "__rld_map" : "__RLD_MAP";
@@ -6290,47 +8128,19 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
+         mips_elf_hash_table (info)->rld_symbol = h;
        }
     }
 
-  if (htab->is_vxworks)
-    {
-      /* Create the .plt, .rela.plt, .dynbss and .rela.bss sections.
-        Also create the _PROCEDURE_LINKAGE_TABLE symbol.  */
-      if (!_bfd_elf_create_dynamic_sections (abfd, info))
-       return FALSE;
-
-      /* Cache the sections created above.  */
-      htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
-      htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
-      htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
-      htab->splt = bfd_get_section_by_name (abfd, ".plt");
-      if (!htab->sdynbss
-         || (!htab->srelbss && !info->shared)
-         || !htab->srelplt
-         || !htab->splt)
-       abort ();
-
-      /* Do the usual VxWorks handling.  */
-      if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
-       return FALSE;
+  /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
+     Also, on VxWorks, create the _PROCEDURE_LINKAGE_TABLE_ symbol.  */
+  if (!_bfd_elf_create_dynamic_sections (abfd, info))
+    return FALSE;
 
-      /* Work out the PLT sizes.  */
-      if (info->shared)
-       {
-         htab->plt_header_size
-           = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
-         htab->plt_entry_size
-           = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
-       }
-      else
-       {
-         htab->plt_header_size
-           = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
-         htab->plt_entry_size
-           = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
-       }
-    }
+  /* Do the usual VxWorks handling.  */
+  if (htab->is_vxworks
+      && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
+    return FALSE;
 
   return TRUE;
 }
@@ -6347,14 +8157,14 @@ mips_elf_rel_relocation_p (bfd *abfd, asection *sec,
   Elf_Internal_Shdr *rel_hdr;
   const struct elf_backend_data *bed;
 
-  /* To determine which flavor or relocation this is, we depend on the
-     fact that the INPUT_SECTION's REL_HDR is read before its REL_HDR2.  */
-  rel_hdr = &elf_section_data (sec)->rel_hdr;
+  /* To determine which flavor of relocation this is, we depend on the
+     fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR.  */
+  rel_hdr = elf_section_data (sec)->rel.hdr;
+  if (rel_hdr == NULL)
+    return FALSE;
   bed = get_elf_backend_data (abfd);
-  if ((size_t) (rel - relocs)
-      >= (NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel))
-    rel_hdr = elf_section_data (sec)->rel_hdr2;
-  return rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (abfd);
+  return ((size_t) (rel - relocs)
+         < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel);
 }
 
 /* Read the addend for REL relocation REL, which belongs to bfd ABFD.
@@ -6368,16 +8178,24 @@ mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel,
   bfd_byte *location;
   unsigned int r_type;
   bfd_vma addend;
+  bfd_vma bytes;
 
   r_type = ELF_R_TYPE (abfd, rel->r_info);
   location = contents + rel->r_offset;
 
   /* Get the addend, which is stored in the input file.  */
-  _bfd_mips16_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
-  addend = mips_elf_obtain_contents (howto, rel, abfd, contents);
-  _bfd_mips16_elf_reloc_shuffle (abfd, r_type, FALSE, location);
+  _bfd_mips_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
+  bytes = mips_elf_obtain_contents (howto, rel, abfd, contents);
+  _bfd_mips_elf_reloc_shuffle (abfd, r_type, FALSE, location);
 
-  return addend & howto->src_mask;
+  addend = bytes & howto->src_mask;
+
+  /* Shift is 2, unusually, for microMIPS JALX.  Adjust the addend
+     accordingly.  */
+  if (r_type == R_MICROMIPS_26_S1 && (bytes >> 26) == 0x3c)
+    addend <<= 1;
+
+  return addend;
 }
 
 /* REL is a relocation in ABFD that needs a partnering LO16 relocation
@@ -6398,8 +8216,12 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
   bfd_vma l;
 
   r_type = ELF_R_TYPE (abfd, rel->r_info);
-  if (r_type == R_MIPS16_HI16)
+  if (mips16_reloc_p (r_type))
     lo16_type = R_MIPS16_LO16;
+  else if (micromips_reloc_p (r_type))
+    lo16_type = R_MICROMIPS_LO16;
+  else if (r_type == R_MIPS_PCHI16)
+    lo16_type = R_MIPS_PCLO16;
   else
     lo16_type = R_MIPS_LO16;
 
@@ -6456,8 +8278,68 @@ mips_elf_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents)
   return bfd_malloc_and_get_section (abfd, sec, contents);
 }
 
+/* Make a new PLT record to keep internal data.  */
+
+static struct plt_entry *
+mips_elf_make_plt_record (bfd *abfd)
+{
+  struct plt_entry *entry;
+
+  entry = bfd_zalloc (abfd, sizeof (*entry));
+  if (entry == NULL)
+    return NULL;
+
+  entry->stub_offset = MINUS_ONE;
+  entry->mips_offset = MINUS_ONE;
+  entry->comp_offset = MINUS_ONE;
+  entry->gotplt_index = MINUS_ONE;
+  return entry;
+}
+
+/* Define the special `__gnu_absolute_zero' symbol.  We only need this
+   for PIC code, as otherwise there is no load-time relocation involved
+   and local GOT entries whose value is zero at static link time will
+   retain their value at load time.  */
+
+static bfd_boolean
+mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
+                              struct mips_elf_link_hash_table *htab,
+                              unsigned int r_type)
+{
+  union
+    {
+      struct elf_link_hash_entry *eh;
+      struct bfd_link_hash_entry *bh;
+    }
+  hzero;
+
+  BFD_ASSERT (!htab->use_absolute_zero);
+  BFD_ASSERT (bfd_link_pic (info));
+
+  hzero.bh = NULL;
+  if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
+                                        BSF_GLOBAL, bfd_abs_section_ptr, 0,
+                                        NULL, FALSE, FALSE, &hzero.bh))
+    return FALSE;
+
+  BFD_ASSERT (hzero.bh != NULL);
+  hzero.eh->size = 0;
+  hzero.eh->type = STT_NOTYPE;
+  hzero.eh->other = STV_PROTECTED;
+  hzero.eh->def_regular = 1;
+  hzero.eh->non_elf = 0;
+
+  if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, TRUE, r_type))
+    return FALSE;
+
+  htab->use_absolute_zero = TRUE;
+
+  return TRUE;
+}
+
 /* Look through the relocs for a section during the first phase, and
-   allocate space in the global offset table.  */
+   allocate space in the global offset table and record the need for
+   standard MIPS and compressed procedure linkage table entries.  */
 
 bfd_boolean
 _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
@@ -6467,11 +8349,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   bfd *dynobj;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
-  struct mips_got_info *g;
   size_t extsymoff;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
-  asection *sgot;
   asection *sreloc;
   const struct elf_backend_data *bed;
   struct mips_elf_link_hash_table *htab;
@@ -6479,26 +8359,41 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   bfd_vma addend;
   reloc_howto_type *howto;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   dynobj = elf_hash_table (info)->dynobj;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
   extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
 
+  bed = get_elf_backend_data (abfd);
+  rel_end = relocs + sec->reloc_count;
+
   /* Check for the mips16 stub sections.  */
 
-  name = bfd_get_section_name (abfd, sec);
+  name = bfd_section_name (sec);
   if (FN_STUB_P (name))
     {
       unsigned long r_symndx;
 
       /* Look at the relocation information to figure out which symbol
-         this is for.  */
+        this is for.  */
 
-      r_symndx = ELF_R_SYM (abfd, relocs->r_info);
+      r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
+      if (r_symndx == 0)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: warning: cannot determine the target function for"
+              " stub section `%s'"),
+            abfd, name);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
 
       if (r_symndx < extsymoff
          || sym_hashes[r_symndx - extsymoff] == NULL)
@@ -6506,8 +8401,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          asection *o;
 
          /* This stub is for a local symbol.  This stub will only be
-             needed if there is some relocation in this BFD, other
-             than a 16 bit function call, which refers to this symbol.  */
+            needed if there is some relocation in this BFD, other
+            than a 16 bit function call, which refers to this symbol.  */
          for (o = abfd->sections; o != NULL; o = o->next)
            {
              Elf_Internal_Rela *sec_relocs;
@@ -6516,7 +8411,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
-                 || mips16_stub_section_p (abfd, o))
+                 || section_allows_mips16_refs_p (o))
                continue;
 
              sec_relocs
@@ -6528,7 +8423,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              rend = sec_relocs + o->reloc_count;
              for (r = sec_relocs; r < rend; r++)
                if (ELF_R_SYM (abfd, r->r_info) == r_symndx
-                   && ELF_R_TYPE (abfd, r->r_info) != R_MIPS16_26)
+                   && !mips16_call_reloc_p (ELF_R_TYPE (abfd, r->r_info)))
                  break;
 
              if (elf_section_data (o)->relocs != sec_relocs)
@@ -6541,17 +8436,17 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (o == NULL)
            {
              /* There is no non-call reloc for this stub, so we do
-                 not need it.  Since this function is called before
-                 the linker maps input sections to output sections, we
-                 can easily discard it by setting the SEC_EXCLUDE
-                 flag.  */
+                not need it.  Since this function is called before
+                the linker maps input sections to output sections, we
+                can easily discard it by setting the SEC_EXCLUDE
+                flag.  */
              sec->flags |= SEC_EXCLUDE;
              return TRUE;
            }
 
          /* Record this stub in an array of local symbol stubs for
-             this BFD.  */
-         if (elf_tdata (abfd)->local_stubs == NULL)
+            this BFD.  */
+         if (mips_elf_tdata (abfd)->local_stubs == NULL)
            {
              unsigned long symcount;
              asection **n;
@@ -6565,16 +8460,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              n = bfd_zalloc (abfd, amt);
              if (n == NULL)
                return FALSE;
-             elf_tdata (abfd)->local_stubs = n;
+             mips_elf_tdata (abfd)->local_stubs = n;
            }
 
          sec->flags |= SEC_KEEP;
-         elf_tdata (abfd)->local_stubs[r_symndx] = sec;
+         mips_elf_tdata (abfd)->local_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
-             That flag is used to see whether we need to look through
-             the global symbol table for stubs.  We don't need to set
-             it here, because we just have a local stub.  */
+            That flag is used to see whether we need to look through
+            the global symbol table for stubs.  We don't need to set
+            it here, because we just have a local stub.  */
        }
       else
        {
@@ -6612,9 +8507,19 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       asection **loc;
 
       /* Look at the relocation information to figure out which symbol
-         this is for.  */
+        this is for.  */
 
-      r_symndx = ELF_R_SYM (abfd, relocs->r_info);
+      r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
+      if (r_symndx == 0)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: warning: cannot determine the target function for"
+              " stub section `%s'"),
+            abfd, name);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
 
       if (r_symndx < extsymoff
          || sym_hashes[r_symndx - extsymoff] == NULL)
@@ -6622,8 +8527,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          asection *o;
 
          /* This stub is for a local symbol.  This stub will only be
-             needed if there is some relocation (R_MIPS16_26) in this BFD
-             that refers to this symbol.  */
+            needed if there is some relocation (R_MIPS16_26) in this BFD
+            that refers to this symbol.  */
          for (o = abfd->sections; o != NULL; o = o->next)
            {
              Elf_Internal_Rela *sec_relocs;
@@ -6632,7 +8537,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
-                 || mips16_stub_section_p (abfd, o))
+                 || section_allows_mips16_refs_p (o))
                continue;
 
              sec_relocs
@@ -6657,17 +8562,17 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (o == NULL)
            {
              /* There is no non-call reloc for this stub, so we do
-                 not need it.  Since this function is called before
-                 the linker maps input sections to output sections, we
-                 can easily discard it by setting the SEC_EXCLUDE
-                 flag.  */
+                not need it.  Since this function is called before
+                the linker maps input sections to output sections, we
+                can easily discard it by setting the SEC_EXCLUDE
+                flag.  */
              sec->flags |= SEC_EXCLUDE;
              return TRUE;
            }
 
          /* Record this stub in an array of local symbol call_stubs for
-             this BFD.  */
-         if (elf_tdata (abfd)->local_call_stubs == NULL)
+            this BFD.  */
+         if (mips_elf_tdata (abfd)->local_call_stubs == NULL)
            {
              unsigned long symcount;
              asection **n;
@@ -6681,29 +8586,29 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              n = bfd_zalloc (abfd, amt);
              if (n == NULL)
                return FALSE;
-             elf_tdata (abfd)->local_call_stubs = n;
+             mips_elf_tdata (abfd)->local_call_stubs = n;
            }
 
          sec->flags |= SEC_KEEP;
-         elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
+         mips_elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
-             That flag is used to see whether we need to look through
-             the global symbol table for stubs.  We don't need to set
-             it here, because we just have a local stub.  */
+            That flag is used to see whether we need to look through
+            the global symbol table for stubs.  We don't need to set
+            it here, because we just have a local stub.  */
        }
       else
        {
          h = ((struct mips_elf_link_hash_entry *)
               sym_hashes[r_symndx - extsymoff]);
-         
+
          /* H is the symbol this stub is for.  */
-         
+
          if (CALL_FP_STUB_P (name))
            loc = &h->call_fp_stub;
          else
            loc = &h->call_stub;
-         
+
          /* If we already have an appropriate stub for this function, we
             don't need another one, so we can discard this one.  Since
             this function is called before the linker maps input sections
@@ -6721,33 +8626,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        }
     }
 
-  if (dynobj == NULL)
-    {
-      sgot = NULL;
-      g = NULL;
-    }
-  else
-    {
-      sgot = mips_elf_got_section (dynobj, FALSE);
-      if (sgot == NULL)
-       g = NULL;
-      else
-       {
-         BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
-         g = mips_elf_section_data (sgot)->u.got_info;
-         BFD_ASSERT (g != NULL);
-       }
-    }
-
   sreloc = NULL;
-  bed = get_elf_backend_data (abfd);
-  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
   contents = NULL;
   for (rel = relocs; rel < rel_end; ++rel)
     {
       unsigned long r_symndx;
       unsigned int r_type;
       struct elf_link_hash_entry *h;
+      bfd_boolean can_make_dynamic_p;
+      bfd_boolean call_reloc_p;
+      bfd_boolean constrain_symbol_p;
 
       r_symndx = ELF_R_SYM (abfd, rel->r_info);
       r_type = ELF_R_TYPE (abfd, rel->r_info);
@@ -6756,8 +8644,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        h = NULL;
       else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
        {
-         (*_bfd_error_handler)
-           (_("%B: Malformed reloc detected for section %s"),
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: malformed reloc detected for section %s"),
             abfd, name);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
@@ -6765,67 +8654,185 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       else
        {
          h = sym_hashes[r_symndx - extsymoff];
-
-         /* This may be an indirect symbol created because of a version.  */
          if (h != NULL)
            {
-             while (h->root.type == bfd_link_hash_indirect)
+             while (h->root.type == bfd_link_hash_indirect
+                    || h->root.type == bfd_link_hash_warning)
                h = (struct elf_link_hash_entry *) h->root.u.i.link;
            }
        }
 
-      /* Some relocs require a global offset table.  */
-      if (dynobj == NULL || sgot == NULL)
+      /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
+        relocation into a dynamic one.  */
+      can_make_dynamic_p = FALSE;
+
+      /* Set CALL_RELOC_P to true if the relocation is for a call,
+        and if pointer equality therefore doesn't matter.  */
+      call_reloc_p = FALSE;
+
+      /* Set CONSTRAIN_SYMBOL_P if we need to take the relocation
+        into account when deciding how to define the symbol.
+        Relocations in nonallocatable sections such as .pdr and
+        .debug* should have no effect.  */
+      constrain_symbol_p = ((sec->flags & SEC_ALLOC) != 0);
+
+      switch (r_type)
        {
-         switch (r_type)
+       case R_MIPS_CALL16:
+       case R_MIPS_CALL_HI16:
+       case R_MIPS_CALL_LO16:
+       case R_MIPS16_CALL16:
+       case R_MICROMIPS_CALL16:
+       case R_MICROMIPS_CALL_HI16:
+       case R_MICROMIPS_CALL_LO16:
+         call_reloc_p = TRUE;
+         /* Fall through.  */
+
+       case R_MIPS_GOT16:
+       case R_MIPS_GOT_LO16:
+       case R_MIPS_GOT_PAGE:
+       case R_MIPS_GOT_DISP:
+       case R_MIPS16_GOT16:
+       case R_MICROMIPS_GOT16:
+       case R_MICROMIPS_GOT_LO16:
+       case R_MICROMIPS_GOT_PAGE:
+       case R_MICROMIPS_GOT_DISP:
+         /* If we have a symbol that will resolve to zero at static link
+            time and it is used by a GOT relocation applied to code we
+            cannot relax to an immediate zero load, then we will be using
+            the special `__gnu_absolute_zero' symbol whose value is zero
+            at dynamic load time.  We ignore HI16-type GOT relocations at
+            this stage, because their handling will depend entirely on
+            the corresponding LO16-type GOT relocation.  */
+         if (!call_hi16_reloc_p (r_type)
+             && h != NULL
+             && bfd_link_pic (info)
+             && !htab->use_absolute_zero
+             && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            {
-           case R_MIPS_GOT16:
-           case R_MIPS_CALL16:
-           case R_MIPS_CALL_HI16:
-           case R_MIPS_CALL_LO16:
-           case R_MIPS_GOT_HI16:
-           case R_MIPS_GOT_LO16:
-           case R_MIPS_GOT_PAGE:
-           case R_MIPS_GOT_OFST:
-           case R_MIPS_GOT_DISP:
-           case R_MIPS_TLS_GOTTPREL:
-           case R_MIPS_TLS_GD:
-           case R_MIPS_TLS_LDM:
-             if (dynobj == NULL)
-               elf_hash_table (info)->dynobj = dynobj = abfd;
-             if (! mips_elf_create_got_section (dynobj, info, FALSE))
+             bfd_boolean rel_reloc;
+
+             if (!mips_elf_get_section_contents (abfd, sec, &contents))
                return FALSE;
-             g = mips_elf_got_info (dynobj, &sgot);
-             if (htab->is_vxworks && !info->shared)
-               {
-                 (*_bfd_error_handler)
-                   (_("%B: GOT reloc at 0x%lx not expected in executables"),
-                    abfd, (unsigned long) rel->r_offset);
-                 bfd_set_error (bfd_error_bad_value);
+
+             rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
+             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
+
+             if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+                                             FALSE))
+               if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
                  return FALSE;
-               }
-             break;
+           }
 
-           case R_MIPS_32:
-           case R_MIPS_REL32:
-           case R_MIPS_64:
-             /* In VxWorks executables, references to external symbols
-                are handled using copy relocs or PLT stubs, so there's
-                no need to add a dynamic relocation here.  */
-             if (dynobj == NULL
-                 && (info->shared || (h != NULL && !htab->is_vxworks))
-                 && (sec->flags & SEC_ALLOC) != 0)
-               elf_hash_table (info)->dynobj = dynobj = abfd;
-             break;
+         /* Fall through.  */
+       case R_MIPS_GOT_HI16:
+       case R_MIPS_GOT_OFST:
+       case R_MIPS_TLS_GOTTPREL:
+       case R_MIPS_TLS_GD:
+       case R_MIPS_TLS_LDM:
+       case R_MIPS16_TLS_GOTTPREL:
+       case R_MIPS16_TLS_GD:
+       case R_MIPS16_TLS_LDM:
+       case R_MICROMIPS_GOT_HI16:
+       case R_MICROMIPS_GOT_OFST:
+       case R_MICROMIPS_TLS_GOTTPREL:
+       case R_MICROMIPS_TLS_GD:
+       case R_MICROMIPS_TLS_LDM:
+         if (dynobj == NULL)
+           elf_hash_table (info)->dynobj = dynobj = abfd;
+         if (!mips_elf_create_got_section (dynobj, info))
+           return FALSE;
+         if (htab->is_vxworks && !bfd_link_pic (info))
+           {
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: GOT reloc at %#" PRIx64 " not expected in executables"),
+                abfd, (uint64_t) rel->r_offset);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+         can_make_dynamic_p = TRUE;
+         break;
 
-           default:
-             break;
+       case R_MIPS_NONE:
+       case R_MIPS_JALR:
+       case R_MICROMIPS_JALR:
+         /* These relocations have empty fields and are purely there to
+            provide link information.  The symbol value doesn't matter.  */
+         constrain_symbol_p = FALSE;
+         break;
+
+       case R_MIPS_GPREL16:
+       case R_MIPS_GPREL32:
+       case R_MIPS16_GPREL:
+       case R_MICROMIPS_GPREL16:
+         /* GP-relative relocations always resolve to a definition in a
+            regular input file, ignoring the one-definition rule.  This is
+            important for the GP setup sequence in NewABI code, which
+            always resolves to a local function even if other relocations
+            against the symbol wouldn't.  */
+         constrain_symbol_p = FALSE;
+         break;
+
+       case R_MIPS_32:
+       case R_MIPS_REL32:
+       case R_MIPS_64:
+         /* In VxWorks executables, references to external symbols
+            must be handled using copy relocs or PLT entries; it is not
+            possible to convert this relocation into a dynamic one.
+
+            For executables that use PLTs and copy-relocs, we have a
+            choice between converting the relocation into a dynamic
+            one or using copy relocations or PLT entries.  It is
+            usually better to do the former, unless the relocation is
+            against a read-only section.  */
+         if ((bfd_link_pic (info)
+              || (h != NULL
+                  && !htab->is_vxworks
+                  && strcmp (h->root.root.string, "__gnu_local_gp") != 0
+                  && !(!info->nocopyreloc
+                       && !PIC_OBJECT_P (abfd)
+                       && MIPS_ELF_READONLY_SECTION (sec))))
+             && (sec->flags & SEC_ALLOC) != 0)
+           {
+             can_make_dynamic_p = TRUE;
+             if (dynobj == NULL)
+               elf_hash_table (info)->dynobj = dynobj = abfd;
            }
+         break;
+
+       case R_MIPS_26:
+       case R_MIPS_PC16:
+       case R_MIPS_PC21_S2:
+       case R_MIPS_PC26_S2:
+       case R_MIPS16_26:
+       case R_MIPS16_PC16_S1:
+       case R_MICROMIPS_26_S1:
+       case R_MICROMIPS_PC7_S1:
+       case R_MICROMIPS_PC10_S1:
+       case R_MICROMIPS_PC16_S1:
+       case R_MICROMIPS_PC23_S2:
+         call_reloc_p = TRUE;
+         break;
        }
 
       if (h)
        {
-         ((struct mips_elf_link_hash_entry *) h)->is_relocation_target = TRUE;
+         if (constrain_symbol_p)
+           {
+             if (!can_make_dynamic_p)
+               ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = 1;
+
+             if (!call_reloc_p)
+               h->pointer_equality_needed = 1;
+
+             /* We must not create a stub for a symbol that has
+                relocations related to taking the function's address.
+                This doesn't apply to VxWorks, where CALL relocs refer
+                to a .got.plt entry instead of a normal .got entry.  */
+             if (!htab->is_vxworks && (!can_make_dynamic_p || !call_reloc_p))
+               ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
+           }
 
          /* Relocations against the special VxWorks __GOTT_BASE__ and
             __GOTT_INDEX__ symbols must be left to the loader.  Allocate
@@ -6845,32 +8852,40 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                info->flags |= DF_TEXTREL;
            }
        }
-      else if (r_type == R_MIPS_CALL_LO16
-              || r_type == R_MIPS_GOT_LO16
-              || r_type == R_MIPS_GOT_DISP
-              || (r_type == R_MIPS_GOT16 && htab->is_vxworks))
+      else if (call_lo16_reloc_p (r_type)
+              || got_lo16_reloc_p (r_type)
+              || got_disp_reloc_p (r_type)
+              || (got16_reloc_p (r_type) && htab->is_vxworks))
        {
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
             maximum number of pages needed by looking at the size of
-            the segment.  Similar comments apply to R_MIPS_GOT16 and
-            R_MIPS_CALL16, except on VxWorks, where GOT relocations
+            the segment.  Similar comments apply to R_MIPS*_GOT16 and
+            R_MIPS*_CALL16, except on VxWorks, where GOT relocations
             always evaluate to "G".  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.  */
-         if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
-                                                 rel->r_addend, g, 0))
+         if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
+                                                rel->r_addend, info, r_type))
            return FALSE;
        }
 
+      if (h != NULL
+         && mips_elf_relocation_needs_la25_stub (abfd, r_type,
+                                                 ELF_ST_IS_MIPS16 (h->other)))
+       ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE;
+
       switch (r_type)
        {
        case R_MIPS_CALL16:
+       case R_MIPS16_CALL16:
+       case R_MICROMIPS_CALL16:
          if (h == NULL)
            {
-             (*_bfd_error_handler)
-               (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
-                abfd, (unsigned long) rel->r_offset);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: CALL16 reloc at %#" PRIx64 " not against global symbol"),
+                abfd, (uint64_t) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
@@ -6878,13 +8893,15 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_LO16:
+       case R_MICROMIPS_CALL_HI16:
+       case R_MICROMIPS_CALL_LO16:
          if (h != NULL)
            {
-             /* VxWorks call relocations point the function's .got.plt
-                entry, which will be allocated by adjust_dynamic_symbol.
-                Otherwise, this symbol requires a global GOT entry.  */
-             if ((!htab->is_vxworks || h->forced_local)
-                 && !mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
+             /* Make sure there is room in the regular GOT to hold the
+                function's address.  We may eliminate it in favour of
+                a .got.plt entry later; see mips_elf_count_got_symbols.  */
+             if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE,
+                                                     r_type))
                return FALSE;
 
              /* We need a stub, not a plt entry for the undefined
@@ -6896,30 +8913,15 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          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)
-           {
-             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;
-
-             /* This symbol is definitely not overridable.  */
-             if (hmips->root.def_regular
-                 && ! (info->shared && ! info->symbolic
-                       && ! hmips->root.forced_local))
-               h = NULL;
-           }
-         /* Fall through.  */
-
+       case R_MICROMIPS_GOT_PAGE:
+       case R_MIPS16_GOT16:
        case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
-         if (!h || r_type == R_MIPS_GOT_PAGE)
+       case R_MICROMIPS_GOT16:
+       case R_MICROMIPS_GOT_HI16:
+       case R_MICROMIPS_GOT_LO16:
+         if (!h || got_page_reloc_p (r_type))
            {
              /* This relocation needs (or may need, if h != NULL) a
                 page entry in the GOT.  For R_MIPS_GOT_PAGE we do not
@@ -6932,7 +8934,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
                  addend = mips_elf_read_rel_addend (abfd, rel,
                                                     howto, contents);
-                 if (r_type == R_MIPS_GOT16)
+                 if (got16_reloc_p (r_type))
                    mips_elf_add_lo16_rel_addend (abfd, rel, rel_end,
                                                  contents, &addend);
                  else
@@ -6940,57 +8942,68 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                }
              else
                addend = rel->r_addend;
-             if (!mips_elf_record_got_page_entry (abfd, r_symndx, addend, g))
+             if (!mips_elf_record_got_page_ref (info, abfd, r_symndx,
+                                                h, addend))
                return FALSE;
-             break;
+
+             if (h)
+               {
+                 struct mips_elf_link_hash_entry *hmips =
+                   (struct mips_elf_link_hash_entry *) h;
+
+                 /* This symbol is definitely not overridable.  */
+                 if (hmips->root.def_regular
+                     && ! (bfd_link_pic (info) && ! info->symbolic
+                           && ! hmips->root.forced_local))
+                   h = NULL;
+               }
            }
+         /* If this is a global, overridable symbol, GOT_PAGE will
+            decay to GOT_DISP, so we'll need a GOT entry for it.  */
          /* Fall through.  */
 
        case R_MIPS_GOT_DISP:
-         if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
+       case R_MICROMIPS_GOT_DISP:
+         if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+                                                      FALSE, r_type))
            return FALSE;
          break;
 
        case R_MIPS_TLS_GOTTPREL:
-         if (info->shared)
+       case R_MIPS16_TLS_GOTTPREL:
+       case R_MICROMIPS_TLS_GOTTPREL:
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
 
        case R_MIPS_TLS_LDM:
-         if (r_type == R_MIPS_TLS_LDM)
+       case R_MIPS16_TLS_LDM:
+       case R_MICROMIPS_TLS_LDM:
+         if (tls_ldm_reloc_p (r_type))
            {
-             r_symndx = 0;
+             r_symndx = STN_UNDEF;
              h = NULL;
            }
          /* Fall through */
 
        case R_MIPS_TLS_GD:
+       case R_MIPS16_TLS_GD:
+       case R_MICROMIPS_TLS_GD:
          /* This symbol requires a global offset table entry, or two
             for TLS GD relocations.  */
-         {
-           unsigned char flag = (r_type == R_MIPS_TLS_GD
-                                 ? GOT_TLS_GD
-                                 : r_type == R_MIPS_TLS_LDM
-                                 ? GOT_TLS_LDM
-                                 : GOT_TLS_IE);
-           if (h != NULL)
-             {
-               struct mips_elf_link_hash_entry *hmips =
-                 (struct mips_elf_link_hash_entry *) h;
-               hmips->tls_type |= flag;
-
-               if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, flag))
-                 return FALSE;
-             }
-           else
-             {
-               BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
-
-               if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
-                                                       rel->r_addend, g, flag))
-                 return FALSE;
-             }
-         }
+         if (h != NULL)
+           {
+             if (!mips_elf_record_global_got_symbol (h, abfd, info,
+                                                     FALSE, r_type))
+               return FALSE;
+           }
+         else
+           {
+             if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
+                                                    rel->r_addend,
+                                                    info, r_type))
+               return FALSE;
+           }
          break;
 
        case R_MIPS_32:
@@ -6999,8 +9012,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* In VxWorks executables, references to external symbols
             are handled using copy relocs or PLT stubs, so there's
             no need to add a .rela.dyn entry for this relocation.  */
-         if ((info->shared || (h != NULL && !htab->is_vxworks))
-             && (sec->flags & SEC_ALLOC) != 0)
+         if (can_make_dynamic_p)
            {
              if (sreloc == NULL)
                {
@@ -7008,7 +9020,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (sreloc == NULL)
                    return FALSE;
                }
-             if (info->shared)
+             if (bfd_link_pic (info) && h == NULL)
                {
                  /* When creating a shared object, we must copy these
                     reloc types into the output file as R_MIPS_REL32
@@ -7023,8 +9035,17 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                {
                  struct mips_elf_link_hash_entry *hmips;
 
-                 /* We only need to copy this reloc if the symbol is
-                     defined in a dynamic object.  */
+                 /* For a shared object, we must copy this relocation
+                    unless the symbol turns out to be undefined and
+                    weak with non-default visibility, in which case
+                    it will be left as zero.
+
+                    We could elide R_MIPS_REL32 for locally binding symbols
+                    in shared libraries, but do not yet do so.
+
+                    For an executable, we only need to copy this
+                    reloc if the symbol is defined in a dynamic
+                    object.  */
                  hmips = (struct mips_elf_link_hash_entry *) h;
                  ++hmips->possibly_dynamic_relocs;
                  if (MIPS_ELF_READONLY_SECTION (sec))
@@ -7032,23 +9053,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                       are relocations against the text segment.  */
                    hmips->readonly_reloc = TRUE;
                }
-
-             /* Even though we don't directly need a GOT entry for
-                this symbol, a symbol must have a dynamic symbol
-                table index greater that DT_MIPS_GOTSYM if there are
-                dynamic relocations against it.  This does not apply
-                to VxWorks, which does not have the usual coupling
-                between global GOT entries and .dynsym entries.  */
-             if (h != NULL && !htab->is_vxworks)
-               {
-                 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, 0))
-                   return FALSE;
-               }
            }
 
          if (SGI_COMPAT (abfd))
@@ -7056,19 +9060,14 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              sizeof (Elf32_External_crinfo);
          break;
 
-       case R_MIPS_PC16:
-         if (h)
-           ((struct mips_elf_link_hash_entry *) h)->is_branch_target = TRUE;
-         break;
-
        case R_MIPS_26:
-         if (h)
-           ((struct mips_elf_link_hash_entry *) h)->is_branch_target = TRUE;
-         /* Fall through.  */
-
        case R_MIPS_GPREL16:
        case R_MIPS_LITERAL:
        case R_MIPS_GPREL32:
+       case R_MICROMIPS_26_S1:
+       case R_MICROMIPS_GPREL16:
+       case R_MICROMIPS_LITERAL:
+       case R_MICROMIPS_GPREL7_S2:
          if (SGI_COMPAT (abfd))
            mips_elf_hash_table (info)->compact_rel_size +=
              sizeof (Elf32_External_crinfo);
@@ -7084,9 +9083,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_MIPS_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
            return FALSE;
          break;
 
@@ -7094,201 +9091,198 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
        }
 
-      /* We must not create a stub for a symbol that has relocations
-        related to taking the function's address.  This doesn't apply to
-        VxWorks, where CALL relocs refer to a .got.plt entry instead of
-        a normal .got entry.  */
-      if (!htab->is_vxworks && h != NULL)
-       switch (r_type)
-         {
-         default:
-           ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
-           break;
-         case R_MIPS_CALL16:
-         case R_MIPS_CALL_HI16:
-         case R_MIPS_CALL_LO16:
-         case R_MIPS_JALR:
-           break;
-         }
+      /* Record the need for a PLT entry.  At this point we don't know
+        yet if we are going to create a PLT in the first place, but
+        we only record whether the relocation requires a standard MIPS
+        or a compressed code entry anyway.  If we don't make a PLT after
+        all, then we'll just ignore these arrangements.  Likewise if
+        a PLT entry is not created because the symbol is satisfied
+        locally.  */
+      if (h != NULL
+         && (branch_reloc_p (r_type)
+             || mips16_branch_reloc_p (r_type)
+             || micromips_branch_reloc_p (r_type))
+         && !SYMBOL_CALLS_LOCAL (info, h))
+       {
+         if (h->plt.plist == NULL)
+           h->plt.plist = mips_elf_make_plt_record (abfd);
+         if (h->plt.plist == NULL)
+           return FALSE;
+
+         if (branch_reloc_p (r_type))
+           h->plt.plist->need_mips = TRUE;
+         else
+           h->plt.plist->need_comp = TRUE;
+       }
 
-      /* If this reloc is not a 16 bit call, and it has a global
-         symbol, then we will need the fn_stub if there is one.
-         References from a stub section do not count.  */
+      /* See if this reloc would need to refer to a MIPS16 hard-float stub,
+        if there is one.  We only need to handle global symbols here;
+        we decide whether to keep or delete stubs for local symbols
+        when processing the stub's relocations.  */
       if (h != NULL
-         && r_type != R_MIPS16_26
-         && !mips16_stub_section_p (abfd, sec))
+         && !mips16_call_reloc_p (r_type)
+         && !section_allows_mips16_refs_p (sec))
        {
          struct mips_elf_link_hash_entry *mh;
 
          mh = (struct mips_elf_link_hash_entry *) h;
          mh->need_fn_stub = TRUE;
        }
+
+      /* Refuse some position-dependent relocations when creating a
+        shared library.  Do not refuse R_MIPS_32 / R_MIPS_64; they're
+        not PIC, but we can create dynamic relocations and the result
+        will be fine.  Also do not refuse R_MIPS_LO16, which can be
+        combined with R_MIPS_GOT16.  */
+      if (bfd_link_pic (info))
+       {
+         switch (r_type)
+           {
+           case R_MIPS_TLS_TPREL_HI16:
+           case R_MIPS16_TLS_TPREL_HI16:
+           case R_MICROMIPS_TLS_TPREL_HI16:
+           case R_MIPS_TLS_TPREL_LO16:
+           case R_MIPS16_TLS_TPREL_LO16:
+           case R_MICROMIPS_TLS_TPREL_LO16:
+             /* These are okay in PIE, but not in a shared library.  */
+             if (bfd_link_executable (info))
+               break;
+
+             /* FALLTHROUGH */
+
+           case R_MIPS16_HI16:
+           case R_MIPS_HI16:
+           case R_MIPS_HIGHER:
+           case R_MIPS_HIGHEST:
+           case R_MICROMIPS_HI16:
+           case R_MICROMIPS_HIGHER:
+           case R_MICROMIPS_HIGHEST:
+             /* Don't refuse a high part relocation if it's against
+                no symbol (e.g. part of a compound relocation).  */
+             if (r_symndx == STN_UNDEF)
+               break;
+
+             /* Likewise an absolute symbol.  */
+             if (h != NULL && bfd_is_abs_symbol (&h->root))
+               break;
+
+             /* R_MIPS_HI16 against _gp_disp is used for $gp setup,
+                and has a special meaning.  */
+             if (!NEWABI_P (abfd) && h != NULL
+                 && strcmp (h->root.root.string, "_gp_disp") == 0)
+               break;
+
+             /* Likewise __GOTT_BASE__ and __GOTT_INDEX__ on VxWorks.  */
+             if (is_gott_symbol (info, h))
+               break;
+
+             /* FALLTHROUGH */
+
+           case R_MIPS16_26:
+           case R_MIPS_26:
+           case R_MICROMIPS_26_S1:
+             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, NEWABI_P (abfd));
+             /* An error for unsupported relocations is raised as part
+                of the above search, so we can skip the following.  */
+             if (howto != NULL)
+               info->callbacks->einfo
+                 /* xgettext:c-format */
+                 (_("%X%H: relocation %s against `%s' cannot be used"
+                    " when making a shared object; recompile with -fPIC\n"),
+                  abfd, sec, rel->r_offset, howto->name,
+                  (h) ? h->root.root.string : "a local symbol");
+             break;
+           default:
+             break;
+           }
+       }
     }
 
   return TRUE;
 }
 \f
-bfd_boolean
-_bfd_mips_relax_section (bfd *abfd, asection *sec,
-                        struct bfd_link_info *link_info,
-                        bfd_boolean *again)
+/* Allocate space for global sym dynamic relocs.  */
+
+static bfd_boolean
+allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *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;
+  struct bfd_link_info *info = inf;
+  bfd *dynobj;
+  struct mips_elf_link_hash_entry *hmips;
+  struct mips_elf_link_hash_table *htab;
 
-  /* We are not currently changing any sizes, so only one pass.  */
-  *again = FALSE;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  if (link_info->relocatable)
-    return TRUE;
+  dynobj = elf_hash_table (info)->dynobj;
+  hmips = (struct mips_elf_link_hash_entry *) h;
 
-  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                              link_info->keep_memory);
-  if (internal_relocs == NULL)
+  /* VxWorks executables are handled elsewhere; we only need to
+     allocate relocations in shared objects.  */
+  if (htab->is_vxworks && !bfd_link_pic (info))
     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;
+  /* Ignore indirect symbols.  All relocations against such symbols
+     will be redirected to the target symbol.  */
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
 
-  for (irel = internal_relocs; irel < irelend; irel++)
+  /* If this symbol is defined in a dynamic object, or we are creating
+     a shared library, we will need to copy any R_MIPS_32 or
+     R_MIPS_REL32 relocs against it into the output file.  */
+  if (! bfd_link_relocatable (info)
+      && hmips->possibly_dynamic_relocs != 0
+      && (h->root.type == bfd_link_hash_defweak
+         || (!h->def_regular && !ELF_COMMON_DEF_P (h))
+         || bfd_link_pic (info)))
     {
-      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;
+      bfd_boolean do_copy = TRUE;
 
-      r_symndx = ELF_R_SYM (abfd, irel->r_info);
-      /* Compute the address of the jump target.  */
-      if (r_symndx >= extsymoff)
+      if (h->root.type == bfd_link_hash_undefweak)
        {
-         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.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;
+         /* Do not copy relocations for undefined weak symbols that
+            we are not going to export.  */
+         if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+           do_copy = FALSE;
+
+         /* Make sure undefined weak symbols are output as a dynamic
+            symbol in PIEs.  */
+         else if (h->dynindx == -1 && !h->forced_local)
+           {
+             if (! bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
        }
-      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)
+      if (do_copy)
+       {
+         /* Even though we don't directly need a GOT entry for this symbol,
+            the SVR4 psABI requires it to have a dynamic symbol table
+            index greater that DT_MIPS_GOTSYM if there are dynamic
+            relocations against it.
+
+            VxWorks does not enforce the same mapping between the GOT
+            and the symbol table, so the same requirement does not
+            apply there.  */
+         if (!htab->is_vxworks)
            {
-             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;
+             if (hmips->global_got_area > GGA_RELOC_ONLY)
+               hmips->global_got_area = GGA_RELOC_ONLY;
+             hmips->got_only_for_calls = FALSE;
            }
 
-         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;
+         mips_elf_allocate_dynamic_relocations
+           (dynobj, info, hmips->possibly_dynamic_relocs);
+         if (hmips->readonly_reloc)
+           /* We tell the dynamic linker that there are relocations
+              against the text segment.  */
+           info->flags |= DF_TEXTREL;
        }
+    }
 
-      /* 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 (!mips_elf_get_section_contents (abfd, sec, &contents))
-       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 (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    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
@@ -7301,40 +9295,34 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   bfd *dynobj;
   struct mips_elf_link_hash_entry *hmips;
-  asection *s;
   struct mips_elf_link_hash_table *htab;
+  asection *s, *srel;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   dynobj = elf_hash_table (info)->dynobj;
+  hmips = (struct mips_elf_link_hash_entry *) h;
 
   /* Make sure we know what is going on here.  */
   BFD_ASSERT (dynobj != NULL
              && (h->needs_plt
-                 || h->u.weakdef != NULL
+                 || h->is_weakalias
                  || (h->def_dynamic
                      && h->ref_regular
                      && !h->def_regular)));
 
-  /* If this symbol is defined in a dynamic object, we need to copy
-     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->relocatable
-      && hmips->possibly_dynamic_relocs != 0
-      && (h->root.type == bfd_link_hash_defweak
-         || !h->def_regular))
-    {
-      mips_elf_allocate_dynamic_relocations
-       (dynobj, info, hmips->possibly_dynamic_relocs);
-      if (hmips->readonly_reloc)
-       /* We tell the dynamic linker that there are relocations
-          against the text segment.  */
-       info->flags |= DF_TEXTREL;
-    }
 
-  /* For a function, create a stub, if allowed.  */
-  if (! hmips->no_fn_stub
-      && h->needs_plt)
+  /* If there are call relocations against an externally-defined symbol,
+     see whether we can create a MIPS lazy-binding stub for it.  We can
+     only do this if all references to the function are through call
+     relocations, and in that case, the traditional lazy-binding stubs
+     are much more efficient than PLT entries.
+
+     Traditional stubs are only available on SVR4 psABI-based systems;
+     VxWorks always uses PLTs instead.  */
+  if (!htab->is_vxworks && h->needs_plt && !hmips->no_fn_stub)
     {
       if (! elf_hash_table (info)->dynamic_sections_created)
        return TRUE;
@@ -7343,168 +9331,205 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         the symbol to the stub location.  This is required to make
         function pointers compare as equal between the normal
         executable and the shared library.  */
-      if (!h->def_regular)
+      if (!h->def_regular
+         && !bfd_is_abs_section (htab->sstubs->output_section))
        {
-         /* We need .stub section.  */
-         s = bfd_get_section_by_name (dynobj,
-                                      MIPS_ELF_STUB_SECTION_NAME (dynobj));
-         BFD_ASSERT (s != NULL);
-
-         h->root.u.def.section = s;
-         h->root.u.def.value = s->size;
-
-         /* XXX Write this stub address somewhere.  */
-         h->plt.offset = s->size;
-
-         /* Make room for this stub code.  */
-         s->size += htab->function_stub_size;
-
-         /* The last half word of the stub will be filled with the index
-            of this symbol in .dynsym section.  */
+         hmips->needs_lazy_stub = TRUE;
+         htab->lazy_stub_count++;
          return TRUE;
        }
     }
-  else if ((h->type == STT_FUNC)
-          && !h->needs_plt)
+  /* As above, VxWorks requires PLT entries for externally-defined
+     functions that are only accessed through call relocations.
+
+     Both VxWorks and non-VxWorks targets also need PLT entries if there
+     are static-only relocations against an externally-defined function.
+     This can technically occur for shared libraries if there are
+     branches to the symbol, although it is unlikely that this will be
+     used in practice due to the short ranges involved.  It can occur
+     for any relative or absolute relocation in executables; in that
+     case, the PLT entry becomes the function's canonical address.  */
+  else if (((h->needs_plt && !hmips->no_fn_stub)
+           || (h->type == STT_FUNC && hmips->has_static_relocs))
+          && htab->use_plts_and_copy_relocs
+          && !SYMBOL_CALLS_LOCAL (info, h)
+          && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+               && h->root.type == bfd_link_hash_undefweak))
     {
-      /* This will set the entry for this symbol in the GOT to 0, and
-         the dynamic linker will take care of this.  */
-      h->root.u.def.value = 0;
-      return TRUE;
-    }
+      bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
+      bfd_boolean newabi_p = NEWABI_P (info->output_bfd);
 
-  /* If this is a weak symbol, and there is a real definition, the
-     processor independent code will have arranged for us to see the
-     real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
-    {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
-      return TRUE;
-    }
+      /* If this is the first symbol to need a PLT entry, then make some
+        basic setup.  Also work out PLT entry sizes.  We'll need them
+        for PLT offset calculations.  */
+      if (htab->plt_mips_offset + htab->plt_comp_offset == 0)
+       {
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
+         BFD_ASSERT (htab->plt_got_index == 0);
+
+         /* If we're using the PLT additions to the psABI, each PLT
+            entry is 16 bytes and the PLT0 entry is 32 bytes.
+            Encourage better cache usage by aligning.  We do this
+            lazily to avoid pessimizing traditional objects.  */
+         if (!htab->is_vxworks
+             && !bfd_set_section_alignment (htab->root.splt, 5))
+           return FALSE;
 
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
+         /* Make sure that .got.plt is word-aligned.  We do this lazily
+            for the same reason as above.  */
+         if (!bfd_set_section_alignment (htab->root.sgotplt,
+                                         MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+           return FALSE;
 
-  return TRUE;
-}
+         /* On non-VxWorks targets, the first two entries in .got.plt
+            are reserved.  */
+         if (!htab->is_vxworks)
+           htab->plt_got_index
+             += (get_elf_backend_data (dynobj)->got_header_size
+                 / MIPS_ELF_GOT_SIZE (dynobj));
 
-/* Likewise, for VxWorks.  */
+         /* On VxWorks, also allocate room for the header's
+            .rela.plt.unloaded entries.  */
+         if (htab->is_vxworks && !bfd_link_pic (info))
+           htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
 
-bfd_boolean
-_bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info,
-                                        struct elf_link_hash_entry *h)
-{
-  bfd *dynobj;
-  struct mips_elf_link_hash_entry *hmips;
-  struct mips_elf_link_hash_table *htab;
+         /* Now work out the sizes of individual PLT entries.  */
+         if (htab->is_vxworks && bfd_link_pic (info))
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
+         else if (htab->is_vxworks)
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
+         else if (newabi_p)
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+         else if (!micromips_p)
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry);
+           }
+         else if (htab->insn32)
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry);
+           }
+         else
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry);
+           }
+       }
 
-  htab = mips_elf_hash_table (info);
-  dynobj = elf_hash_table (info)->dynobj;
-  hmips = (struct mips_elf_link_hash_entry *) h;
+      if (h->plt.plist == NULL)
+       h->plt.plist = mips_elf_make_plt_record (dynobj);
+      if (h->plt.plist == NULL)
+       return FALSE;
 
-  /* Make sure we know what is going on here.  */
-  BFD_ASSERT (dynobj != NULL
-             && (h->needs_plt
-                 || h->needs_copy
-                 || h->u.weakdef != NULL
-                 || (h->def_dynamic
-                     && h->ref_regular
-                     && !h->def_regular)));
+      /* There are no defined MIPS16 or microMIPS PLT entries for VxWorks,
+        n32 or n64, so always use a standard entry there.
+
+        If the symbol has a MIPS16 call stub and gets a PLT entry, then
+        all MIPS16 calls will go via that stub, and there is no benefit
+        to having a MIPS16 entry.  And in the case of call_stub a
+        standard entry actually has to be used as the stub ends with a J
+        instruction.  */
+      if (newabi_p
+         || htab->is_vxworks
+         || hmips->call_stub
+         || hmips->call_fp_stub)
+       {
+         h->plt.plist->need_mips = TRUE;
+         h->plt.plist->need_comp = FALSE;
+       }
 
-  /* If the symbol is defined by a dynamic object, we need a PLT stub if
-     either (a) we want to branch to the symbol or (b) we're linking an
-     executable that needs a canonical function address.  In the latter
-     case, the canonical address will be the address of the executable's
-     load stub.  */
-  if ((hmips->is_branch_target
-       || (!info->shared
-          && h->type == STT_FUNC
-          && hmips->is_relocation_target))
-      && h->def_dynamic
-      && h->ref_regular
-      && !h->def_regular
-      && !h->forced_local)
-    h->needs_plt = 1;
-
-  /* Locally-binding symbols do not need a PLT stub; we can refer to
-     the functions directly.  */
-  else if (h->needs_plt
-          && (SYMBOL_CALLS_LOCAL (info, h)
-              || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-                  && h->root.type == bfd_link_hash_undefweak)))
-    {
-      h->needs_plt = 0;
-      return TRUE;
-    }
+      /* Otherwise, if there are no direct calls to the function, we
+        have a free choice of whether to use standard or compressed
+        entries.  Prefer microMIPS entries if the object is known to
+        contain microMIPS code, so that it becomes possible to create
+        pure microMIPS binaries.  Prefer standard entries otherwise,
+        because MIPS16 ones are no smaller and are usually slower.  */
+      if (!h->plt.plist->need_mips && !h->plt.plist->need_comp)
+       {
+         if (micromips_p)
+           h->plt.plist->need_comp = TRUE;
+         else
+           h->plt.plist->need_mips = TRUE;
+       }
 
-  if (h->needs_plt)
-    {
-      /* If this is the first symbol to need a PLT entry, allocate room
-        for the header, and for the header's .rela.plt.unloaded entries.  */
-      if (htab->splt->size == 0)
+      if (h->plt.plist->need_mips)
        {
-         htab->splt->size += htab->plt_header_size;
-         if (!info->shared)
-           htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
+         h->plt.plist->mips_offset = htab->plt_mips_offset;
+         htab->plt_mips_offset += htab->plt_mips_entry_size;
+       }
+      if (h->plt.plist->need_comp)
+       {
+         h->plt.plist->comp_offset = htab->plt_comp_offset;
+         htab->plt_comp_offset += htab->plt_comp_entry_size;
        }
 
-      /* Assign the next .plt entry to this symbol.  */
-      h->plt.offset = htab->splt->size;
-      htab->splt->size += htab->plt_entry_size;
+      /* Reserve the corresponding .got.plt entry now too.  */
+      h->plt.plist->gotplt_index = htab->plt_got_index++;
 
       /* If the output file has no definition of the symbol, set the
-        symbol's value to the address of the stub.  Point at the PLT
-        load stub rather than the lazy resolution stub; this stub
-        will become the canonical function address.  */
-      if (!info->shared && !h->def_regular)
-       {
-         h->root.u.def.section = htab->splt;
-         h->root.u.def.value = h->plt.offset;
-         h->root.u.def.value += 8;
-       }
+        symbol's value to the address of the stub.  */
+      if (!bfd_link_pic (info) && !h->def_regular)
+       hmips->use_plt_entry = TRUE;
 
-      /* Make room for the .got.plt entry and the R_JUMP_SLOT relocation.  */
-      htab->sgotplt->size += 4;
-      htab->srelplt->size += sizeof (Elf32_External_Rela);
+      /* Make room for the R_MIPS_JUMP_SLOT relocation.  */
+      htab->root.srelplt->size += (htab->is_vxworks
+                                  ? MIPS_ELF_RELA_SIZE (dynobj)
+                                  : MIPS_ELF_REL_SIZE (dynobj));
 
       /* Make room for the .rela.plt.unloaded relocations.  */
-      if (!info->shared)
+      if (htab->is_vxworks && !bfd_link_pic (info))
        htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
 
-      return TRUE;
-    }
+      /* All relocations against this symbol that could have been made
+        dynamic will now refer to the PLT entry instead.  */
+      hmips->possibly_dynamic_relocs = 0;
 
-  /* If a function symbol is defined by a dynamic object, and we do not
-     need a PLT stub for it, the symbol's value should be zero.  */
-  if (h->type == STT_FUNC
-      && h->def_dynamic
-      && h->ref_regular
-      && !h->def_regular)
-    {
-      h->root.u.def.value = 0;
       return TRUE;
     }
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
+  if (h->is_weakalias)
     {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      struct elf_link_hash_entry *def = weakdef (h);
+      BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+      h->root.u.def.section = def->root.u.def.section;
+      h->root.u.def.value = def->root.u.def.value;
       return TRUE;
     }
 
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
-  if (info->shared)
+  /* Otherwise, there is nothing further to do for symbols defined
+     in regular objects.  */
+  if (h->def_regular)
     return TRUE;
 
+  /* There's also nothing more to do if we'll convert all relocations
+     against this symbol into dynamic relocations.  */
+  if (!hmips->has_static_relocs)
+    return TRUE;
+
+  /* We're now relying on copy relocations.  Complain if we have
+     some that we can't convert.  */
+  if (!htab->use_plts_and_copy_relocs || bfd_link_pic (info))
+    {
+      _bfd_error_handler (_("non-dynamic relocations refer to "
+                           "dynamic symbol %s"),
+                         h->root.root.string);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -7515,91 +9540,123 @@ _bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info,
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.  */
 
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->root.sdynrelro;
+      srel = htab->root.sreldynrelro;
+    }
+  else
+    {
+      s = htab->root.sdynbss;
+      srel = htab->root.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
-      htab->srelbss->size += sizeof (Elf32_External_Rela);
+      if (htab->is_vxworks)
+       srel->size += sizeof (Elf32_External_Rela);
+      else
+       mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
       h->needs_copy = 1;
     }
 
-  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
+  /* All relocations against this symbol that could have been made
+     dynamic will now refer to the local copy instead.  */
+  hmips->possibly_dynamic_relocs = 0;
+
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
-/* Return the number of dynamic section symbols required by OUTPUT_BFD.
-   The number might be exact or a worst-case estimate, depending on how
-   much information is available to elf_backend_omit_section_dynsym at
-   the current linking stage.  */
+/* This function is called after all the input files have been read,
+   and the input sections have been assigned to output sections.  We
+   check for any mips16 stub sections that we can discard.  */
 
-static bfd_size_type
-count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
+bfd_boolean
+_bfd_mips_elf_always_size_sections (bfd *output_bfd,
+                                   struct bfd_link_info *info)
 {
-  bfd_size_type count;
+  asection *sect;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_htab_traverse_info hti;
 
-  count = 0;
-  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  /* The .reginfo section has a fixed size.  */
+  sect = bfd_get_section_by_name (output_bfd, ".reginfo");
+  if (sect != NULL)
     {
-      asection *p;
-      const struct elf_backend_data *bed;
+      bfd_set_section_size (sect, sizeof (Elf32_External_RegInfo));
+      sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
+    }
 
-      bed = get_elf_backend_data (output_bfd);
-      for (p = output_bfd->sections; p ; p = p->next)
-       if ((p->flags & SEC_EXCLUDE) == 0
-           && (p->flags & SEC_ALLOC) != 0
-           && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
-         ++count;
+  /* The .MIPS.abiflags section has a fixed size.  */
+  sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
+  if (sect != NULL)
+    {
+      bfd_set_section_size (sect, sizeof (Elf_External_ABIFlags_v0));
+      sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
     }
-  return count;
+
+  hti.info = info;
+  hti.output_bfd = output_bfd;
+  hti.error = FALSE;
+  mips_elf_link_hash_traverse (mips_elf_hash_table (info),
+                              mips_elf_check_symbols, &hti);
+  if (hti.error)
+    return FALSE;
+
+  return TRUE;
 }
 
-/* This function is called after all the input files have been read,
-   and the input sections have been assigned to output sections.  We
-   check for any mips16 stub sections that we can discard.  */
+/* If the link uses a GOT, lay it out and work out its size.  */
 
-bfd_boolean
-_bfd_mips_elf_always_size_sections (bfd *output_bfd,
-                                   struct bfd_link_info *info)
+static bfd_boolean
+mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
 {
-  asection *ri;
-
   bfd *dynobj;
   asection *s;
   struct mips_got_info *g;
-  int i;
   bfd_size_type loadable_size = 0;
   bfd_size_type page_gotno;
-  bfd_size_type dynsymcount;
-  bfd *sub;
-  struct mips_elf_count_tls_arg count_tls_arg;
+  bfd *ibfd;
+  struct mips_elf_traverse_got_arg tga;
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-  /* 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, sizeof (Elf32_External_RegInfo));
-
-  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, NULL);
+  s = htab->root.sgot;
+  if (s == NULL)
+    return TRUE;
 
   dynobj = elf_hash_table (info)->dynobj;
-  if (dynobj == NULL)
-    /* Relocatable links don't have it.  */
-    return TRUE;
+  g = htab->got_info;
 
-  g = mips_elf_got_info (dynobj, &s);
-  if (s == NULL)
-    return TRUE;
+  /* Allocate room for the reserved entries.  VxWorks always reserves
+     3 entries; other objects only reserve 2 entries.  */
+  BFD_ASSERT (g->assigned_low_gotno == 0);
+  if (htab->is_vxworks)
+    htab->reserved_gotno = 3;
+  else
+    htab->reserved_gotno = 2;
+  g->local_gotno += htab->reserved_gotno;
+  g->assigned_low_gotno = htab->reserved_gotno;
+
+  /* Decide which symbols need to go in the global part of the GOT and
+     count the number of reloc-only GOT symbols.  */
+  mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
+
+  if (!mips_elf_resolve_final_got_entries (info, g))
+    return FALSE;
 
   /* Calculate the total loadable size of the output.  That
      will give us the maximum number of GOT_PAGE entries
      required.  */
-  for (sub = info->input_bfds; sub; sub = sub->link_next)
+  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       asection *subsection;
 
-      for (subsection = sub->sections;
+      for (subsection = ibfd->sections;
           subsection;
           subsection = subsection->next)
        {
@@ -7610,40 +9667,8 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
        }
     }
 
-  /* 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;
-
-  /* Get a worst-case estimate of the number of dynamic symbols needed.
-     At this point, dynsymcount does not account for section symbols
-     and count_section_dynsyms may overestimate the number that will
-     be needed.  */
-  dynsymcount = (elf_hash_table (info)->dynsymcount
-                + count_section_dynsyms (output_bfd, info));
-
-  /* Determine the size of one stub entry.  */
-  htab->function_stub_size = (dynsymcount > 0x10000
-                             ? MIPS_FUNCTION_STUB_BIG_SIZE
-                             : MIPS_FUNCTION_STUB_NORMAL_SIZE);
-
-  /* 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 += htab->function_stub_size * (i + 1);
-
   if (htab->is_vxworks)
-    /* There's no need to allocate page entries for VxWorks; R_MIPS_GOT16
+    /* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
        relocations against local symbols evaluate to "G", and the EABI does
        not include R_MIPS_GOT_PAGE.  */
     page_gotno = 0;
@@ -7652,111 +9677,376 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
        sections.  Is 5 enough?  */
     page_gotno = (loadable_size >> 16) + 5;
 
-  /* Choose the smaller of the two estimates; both are intended to be
+  /* Choose the smaller of the two page estimates; both are intended to be
      conservative.  */
   if (page_gotno > g->page_gotno)
     page_gotno = g->page_gotno;
 
   g->local_gotno += page_gotno;
-  s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+  g->assigned_high_gotno = g->local_gotno - 1;
 
-  g->global_gotno = i;
-  s->size += i * MIPS_ELF_GOT_SIZE (output_bfd);
-
-  /* We need to calculate tls_gotno for global symbols at this point
-     instead of building it up earlier, to avoid doublecounting
-     entries for one global symbol from multiple input files.  */
-  count_tls_arg.info = info;
-  count_tls_arg.needed = 0;
-  elf_link_hash_traverse (elf_hash_table (info),
-                         mips_elf_count_global_tls_entries,
-                         &count_tls_arg);
-  g->tls_gotno += count_tls_arg.needed;
+  s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+  s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
   s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
 
-  mips_elf_resolve_final_got_entries (g);
-
   /* VxWorks does not support multiple GOTs.  It initializes $gp to
      __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
      dynamic loader.  */
   if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
     {
-      if (! mips_elf_multi_got (output_bfd, info, g, s, page_gotno))
+      if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
        return FALSE;
     }
   else
     {
-      /* Set up TLS entries for the first GOT.  */
+      /* Record that all bfds use G.  This also has the effect of freeing
+        the per-bfd GOTs, which we no longer need.  */
+      for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
+       if (mips_elf_bfd_got (ibfd, FALSE))
+         mips_elf_replace_bfd_got (ibfd, g);
+      mips_elf_replace_bfd_got (output_bfd, g);
+
+      /* Set up TLS entries.  */
       g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
-      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
+      tga.info = info;
+      tga.g = g;
+      tga.value = MIPS_ELF_GOT_SIZE (output_bfd);
+      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, &tga);
+      if (!tga.g)
+       return FALSE;
+      BFD_ASSERT (g->tls_assigned_gotno
+                 == g->global_gotno + g->local_gotno + g->tls_gotno);
+
+      /* Each VxWorks GOT entry needs an explicit relocation.  */
+      if (htab->is_vxworks && bfd_link_pic (info))
+       g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno;
+
+      /* Allocate room for the TLS relocations.  */
+      if (g->relocs)
+       mips_elf_allocate_dynamic_relocations (dynobj, info, g->relocs);
     }
-  htab->computed_got_sizes = TRUE;
 
   return TRUE;
 }
 
-/* Set the sizes of the dynamic sections.  */
+/* Estimate the size of the .MIPS.stubs section.  */
 
-bfd_boolean
-_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
-                                    struct bfd_link_info *info)
+static void
+mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
 {
-  bfd *dynobj;
-  asection *s, *sreldyn;
-  bfd_boolean reltext;
   struct mips_elf_link_hash_table *htab;
+  bfd_size_type dynsymcount;
 
   htab = mips_elf_hash_table (info);
-  dynobj = elf_hash_table (info)->dynobj;
-  BFD_ASSERT (dynobj != NULL);
+  BFD_ASSERT (htab != NULL);
 
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (htab->lazy_stub_count == 0)
+    return;
+
+  /* IRIX rld assumes that a function stub isn't at the end of the .text
+     section, so add a dummy entry to the end.  */
+  htab->lazy_stub_count++;
+
+  /* Get a worst-case estimate of the number of dynamic symbols needed.
+     At this point, dynsymcount does not account for section symbols
+     and count_section_dynsyms may overestimate the number that will
+     be needed.  */
+  dynsymcount = (elf_hash_table (info)->dynsymcount
+                + count_section_dynsyms (output_bfd, info));
+
+  /* Determine the size of one stub entry.  There's no disadvantage
+     from using microMIPS code here, so for the sake of pure-microMIPS
+     binaries we prefer it whenever there's any microMIPS code in
+     output produced at all.  This has a benefit of stubs being
+     shorter by 4 bytes each too, unless in the insn32 mode.  */
+  if (!MICROMIPS_P (output_bfd))
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MIPS_FUNCTION_STUB_BIG_SIZE
+                               : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+  else if (htab->insn32)
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE
+                               : MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE);
+  else
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MICROMIPS_FUNCTION_STUB_BIG_SIZE
+                               : MICROMIPS_FUNCTION_STUB_NORMAL_SIZE);
+
+  htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
+}
+
+/* A mips_elf_link_hash_traverse callback for which DATA points to a
+   mips_htab_traverse_info.  If H needs a traditional MIPS lazy-binding
+   stub, allocate an entry in the stubs section.  */
+
+static bfd_boolean
+mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void *data)
+{
+  struct mips_htab_traverse_info *hti = data;
+  struct mips_elf_link_hash_table *htab;
+  struct bfd_link_info *info;
+  bfd *output_bfd;
+
+  info = hti->info;
+  output_bfd = hti->output_bfd;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (h->needs_lazy_stub)
     {
-      /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+      unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+      bfd_vma isa_bit = micromips_p;
+
+      BFD_ASSERT (htab->root.dynobj != NULL);
+      if (h->root.plt.plist == NULL)
+       h->root.plt.plist = mips_elf_make_plt_record (htab->sstubs->owner);
+      if (h->root.plt.plist == NULL)
        {
-         s = bfd_get_section_by_name (dynobj, ".interp");
-         BFD_ASSERT (s != NULL);
-         s->size
-           = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
-         s->contents
-           = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
+         hti->error = TRUE;
+         return FALSE;
        }
+      h->root.root.u.def.section = htab->sstubs;
+      h->root.root.u.def.value = htab->sstubs->size + isa_bit;
+      h->root.plt.plist->stub_offset = htab->sstubs->size;
+      h->root.other = other;
+      htab->sstubs->size += htab->function_stub_size;
     }
+  return TRUE;
+}
 
-  /* The check_relocs and adjust_dynamic_symbol entry points have
-     determined the sizes of the various dynamic sections.  Allocate
-     memory for them.  */
-  reltext = FALSE;
-  sreldyn = NULL;
-  for (s = dynobj->sections; s != NULL; s = s->next)
-    {
-      const char *name;
+/* Allocate offsets in the stubs section to each symbol that needs one.
+   Set the final size of the .MIPS.stub section.  */
 
-      /* It's OK to base decisions on the section name, because none
-        of the dynobj section names depend upon the input files.  */
-      name = bfd_get_section_name (dynobj, s);
+static bfd_boolean
+mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
+{
+  bfd *output_bfd = info->output_bfd;
+  bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+  unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+  bfd_vma isa_bit = micromips_p;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_htab_traverse_info hti;
+  struct elf_link_hash_entry *h;
+  bfd *dynobj;
 
-      if ((s->flags & SEC_LINKER_CREATED) == 0)
-       continue;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
-      if (CONST_STRNEQ (name, ".rel"))
-       {
-         if (s->size != 0)
-           {
-             const char *outname;
-             asection *target;
+  if (htab->lazy_stub_count == 0)
+    return TRUE;
 
-             /* If this relocation section applies to a read only
-                 section, then we probably need a DT_TEXTREL entry.
-                 If the relocation section is .rel(a).dyn, we always
-                 assert a DT_TEXTREL entry rather than testing whether
-                 there exists a relocation to a read only section or
-                 not.  */
-             outname = bfd_get_section_name (output_bfd,
-                                             s->output_section);
-             target = bfd_get_section_by_name (output_bfd, outname + 4);
-             if ((target != NULL
+  htab->sstubs->size = 0;
+  hti.info = info;
+  hti.output_bfd = output_bfd;
+  hti.error = FALSE;
+  mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, &hti);
+  if (hti.error)
+    return FALSE;
+  htab->sstubs->size += htab->function_stub_size;
+  BFD_ASSERT (htab->sstubs->size
+             == htab->lazy_stub_count * htab->function_stub_size);
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+  h = _bfd_elf_define_linkage_sym (dynobj, info, htab->sstubs, "_MIPS_STUBS_");
+  if (h == NULL)
+    return FALSE;
+  h->root.u.def.value = isa_bit;
+  h->other = other;
+  h->type = STT_FUNC;
+
+  return TRUE;
+}
+
+/* A mips_elf_link_hash_traverse callback for which DATA points to a
+   bfd_link_info.  If H uses the address of a PLT entry as the value
+   of the symbol, then set the entry in the symbol table now.  Prefer
+   a standard MIPS PLT entry.  */
+
+static bfd_boolean
+mips_elf_set_plt_sym_value (struct mips_elf_link_hash_entry *h, void *data)
+{
+  struct bfd_link_info *info = data;
+  bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
+  struct mips_elf_link_hash_table *htab;
+  unsigned int other;
+  bfd_vma isa_bit;
+  bfd_vma val;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (h->use_plt_entry)
+    {
+      BFD_ASSERT (h->root.plt.plist != NULL);
+      BFD_ASSERT (h->root.plt.plist->mips_offset != MINUS_ONE
+                 || h->root.plt.plist->comp_offset != MINUS_ONE);
+
+      val = htab->plt_header_size;
+      if (h->root.plt.plist->mips_offset != MINUS_ONE)
+       {
+         isa_bit = 0;
+         val += h->root.plt.plist->mips_offset;
+         other = 0;
+       }
+      else
+       {
+         isa_bit = 1;
+         val += htab->plt_mips_offset + h->root.plt.plist->comp_offset;
+         other = micromips_p ? STO_MICROMIPS : STO_MIPS16;
+       }
+      val += isa_bit;
+      /* For VxWorks, point at the PLT load stub rather than the lazy
+        resolution stub; this stub will become the canonical function
+        address.  */
+      if (htab->is_vxworks)
+       val += 8;
+
+      h->root.root.u.def.section = htab->root.splt;
+      h->root.root.u.def.value = val;
+      h->root.other = other;
+    }
+
+  return TRUE;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+bfd_boolean
+_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
+                                    struct bfd_link_info *info)
+{
+  bfd *dynobj;
+  asection *s, *sreldyn;
+  bfd_boolean reltext;
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (bfd_link_executable (info) && !info->nointerp)
+       {
+         s = bfd_get_linker_section (dynobj, ".interp");
+         BFD_ASSERT (s != NULL);
+         s->size
+           = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
+         s->contents
+           = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
+       }
+
+      /* Figure out the size of the PLT header if we know that we
+        are using it.  For the sake of cache alignment always use
+        a standard header whenever any standard entries are present
+        even if microMIPS entries are present as well.  This also
+        lets the microMIPS header rely on the value of $v0 only set
+        by microMIPS entries, for a small size reduction.
+
+        Set symbol table entry values for symbols that use the
+        address of their PLT entry now that we can calculate it.
+
+        Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
+        haven't already in _bfd_elf_create_dynamic_sections.  */
+      if (htab->root.splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
+       {
+         bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
+                                    && !htab->plt_mips_offset);
+         unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+         bfd_vma isa_bit = micromips_p;
+         struct elf_link_hash_entry *h;
+         bfd_vma size;
+
+         BFD_ASSERT (htab->use_plts_and_copy_relocs);
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
+         BFD_ASSERT (htab->root.splt->size == 0);
+
+         if (htab->is_vxworks && bfd_link_pic (info))
+           size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
+         else if (htab->is_vxworks)
+           size = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
+         else if (ABI_64_P (output_bfd))
+           size = 4 * ARRAY_SIZE (mips_n64_exec_plt0_entry);
+         else if (ABI_N32_P (output_bfd))
+           size = 4 * ARRAY_SIZE (mips_n32_exec_plt0_entry);
+         else if (!micromips_p)
+           size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
+         else if (htab->insn32)
+           size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry);
+         else
+           size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry);
+
+         htab->plt_header_is_comp = micromips_p;
+         htab->plt_header_size = size;
+         htab->root.splt->size = (size
+                                  + htab->plt_mips_offset
+                                  + htab->plt_comp_offset);
+         htab->root.sgotplt->size = (htab->plt_got_index
+                                     * MIPS_ELF_GOT_SIZE (dynobj));
+
+         mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info);
+
+         if (htab->root.hplt == NULL)
+           {
+             h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.splt,
+                                              "_PROCEDURE_LINKAGE_TABLE_");
+             htab->root.hplt = h;
+             if (h == NULL)
+               return FALSE;
+           }
+
+         h = htab->root.hplt;
+         h->root.u.def.value = isa_bit;
+         h->other = other;
+         h->type = STT_FUNC;
+       }
+    }
+
+  /* Allocate space for global sym dynamic relocs.  */
+  elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info);
+
+  mips_elf_estimate_stub_size (output_bfd, info);
+
+  if (!mips_elf_lay_out_got (output_bfd, info))
+    return FALSE;
+
+  mips_elf_lay_out_lazy_stubs (info);
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  reltext = FALSE;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+
+      /* It's OK to base decisions on the section name, because none
+        of the dynobj section names depend upon the input files.  */
+      name = bfd_section_name (s);
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+       continue;
+
+      if (CONST_STRNEQ (name, ".rel"))
+       {
+         if (s->size != 0)
+           {
+             const char *outname;
+             asection *target;
+
+             /* If this relocation section applies to a read only
+                section, then we probably need a DT_TEXTREL entry.
+                If the relocation section is .rel(a).dyn, we always
+                assert a DT_TEXTREL entry rather than testing whether
+                there exists a relocation to a read only section or
+                not.  */
+             outname = bfd_section_name (s->output_section);
+             target = bfd_get_section_by_name (output_bfd, outname + 4);
+             if ((target != NULL
                   && (target->flags & SEC_READONLY) != 0
                   && (target->flags & SEC_ALLOC) != 0)
                  || strcmp (outname, MIPS_ELF_REL_DYN_NAME (info)) == 0)
@@ -7776,110 +10066,32 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              info->combreloc = 0;
            }
        }
-      else if (htab->is_vxworks && strcmp (name, ".got") == 0)
-       {
-         /* Executables do not need a GOT.  */
-         if (info->shared)
-           {
-             /* Allocate relocations for all but the reserved entries.  */
-             struct mips_got_info *g;
-             unsigned int count;
-
-             g = mips_elf_got_info (dynobj, NULL);
-             count = (g->global_gotno
-                      + g->local_gotno
-                      - MIPS_RESERVED_GOTNO (info));
-             mips_elf_allocate_dynamic_relocations (dynobj, info, count);
-           }
-       }
-      else if (!htab->is_vxworks && CONST_STRNEQ (name, ".got"))
-       {
-         /* _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)
-           {
-             set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd);
-             set_got_offset_arg.info = info;
-
-             /* NOTE 2005-02-03: How can this call, or the next, ever
-                find any indirect entries to resolve?  They were all
-                resolved in mips_elf_multi_got.  */
-             mips_elf_resolve_final_got_entries (gg);
-             for (g = gg->next; g && g->next != gg; g = g->next)
-               {
-                 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
-                                 + g->next->tls_gotno
-                                 + MIPS_RESERVED_GOTNO (info));
-                   }
-               }
-           }
-         else
-           {
-             struct mips_elf_count_tls_arg arg;
-             arg.info = info;
-             arg.needed = 0;
-
-             htab_traverse (gg->got_entries, mips_elf_count_local_tls_relocs,
-                            &arg);
-             elf_link_hash_traverse (elf_hash_table (info),
-                                     mips_elf_count_global_tls_relocs,
-                                     &arg);
-
-             needed_relocs += arg.needed;
-           }
-
-         if (needed_relocs)
-           mips_elf_allocate_dynamic_relocations (dynobj, info,
-                                                  needed_relocs);
-       }
-      else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
-       {
-         /* IRIX rld assumes that the function stub isn't at the end
-            of .text section.  So put a dummy.  XXX  */
-         s->size += htab->function_stub_size;
-       }
-      else if (! info->shared
+      else if (bfd_link_executable (info)
               && ! mips_elf_hash_table (info)->use_rld_obj_head
               && CONST_STRNEQ (name, ".rld_map"))
        {
          /* We add a room for __rld_map.  It will be filled in by the
             rtld to contain a pointer to the _r_debug structure.  */
-         s->size += 4;
+         s->size += MIPS_ELF_RLD_MAP_SIZE (output_bfd);
        }
       else if (SGI_COMPAT (output_bfd)
               && CONST_STRNEQ (name, ".compact_rel"))
        s->size += mips_elf_hash_table (info)->compact_rel_size;
+      else if (s == htab->root.splt)
+       {
+         /* If the last PLT entry has a branch delay slot, allocate
+            room for an extra nop to fill the delay slot.  This is
+            for CPUs without load interlocking.  */
+         if (! LOAD_INTERLOCKS_P (output_bfd)
+             && ! htab->is_vxworks && s->size > 0)
+           s->size += 4;
+       }
       else if (! CONST_STRNEQ (name, ".init")
-              && s != htab->sgotplt
-              && s != htab->splt)
+              && s != htab->root.sgot
+              && s != htab->root.sgotplt
+              && s != htab->sstubs
+              && s != htab->root.sdynbss
+              && s != htab->root.sdynrelro)
        {
          /* It's not one of our sections, so don't allocate space.  */
          continue;
@@ -7894,14 +10106,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_HAS_CONTENTS) == 0)
        continue;
 
-      /* Allocate memory for this section last, since we may increase its
-        size above.  */
-      if (strcmp (name, MIPS_ELF_REL_DYN_NAME (info)) == 0)
-       {
-         sreldyn = s;
-         continue;
-       }
-
       /* Allocate memory for the section contents.  */
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
@@ -7911,17 +10115,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  /* Allocate memory for the .rel(a).dyn section.  */
-  if (sreldyn != NULL)
-    {
-      sreldyn->contents = bfd_zalloc (dynobj, sreldyn->size);
-      if (sreldyn->contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return FALSE;
-       }
-    }
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
@@ -7931,15 +10124,19 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* SGI object has the equivalence of DT_DEBUG in the
         DT_MIPS_RLD_MAP entry.  This must come first because glibc
-        only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and GDB only
-        looks at the first one it sees.  */
-      if (!info->shared
+        only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and some tools
+        may only look at the first one they see.  */
+      if (!bfd_link_pic (info)
          && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
        return FALSE;
 
+      if (bfd_link_executable (info)
+         && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP_REL, 0))
+       return FALSE;
+
       /* The DT_DEBUG entry may be filled in by the dynamic linker and
         used by the debugger.  */
-      if (info->executable
+      if (bfd_link_executable (info)
          && !SGI_COMPAT (output_bfd)
          && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
        return FALSE;
@@ -7962,11 +10159,12 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
        return FALSE;
 
+      sreldyn = mips_elf_rel_dyn_section (info, FALSE);
       if (htab->is_vxworks)
        {
          /* VxWorks uses .rela.dyn instead of .rel.dyn.  It does not
             use any of the DT_MIPS_* tags.  */
-         if (mips_elf_rel_dyn_section (info, FALSE))
+         if (sreldyn && sreldyn->size > 0)
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELA, 0))
                return FALSE;
@@ -7977,21 +10175,11 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELAENT, 0))
                return FALSE;
            }
-         if (htab->splt->size > 0)
-           {
-             if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
-               return FALSE;
-
-             if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0))
-               return FALSE;
-
-             if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0))
-               return FALSE;
-           }
        }
       else
        {
-         if (mips_elf_rel_dyn_section (info, FALSE))
+         if (sreldyn && sreldyn->size > 0
+             && !bfd_is_abs_section (sreldyn->output_section))
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
                return FALSE;
@@ -8024,16 +10212,34 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
            return FALSE;
 
+         if (info->emit_gnu_hash
+             && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_XHASH, 0))
+           return FALSE;
+
          if (IRIX_COMPAT (dynobj) == ict_irix5
              && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_HIPAGENO, 0))
            return FALSE;
 
          if (IRIX_COMPAT (dynobj) == ict_irix6
              && (bfd_get_section_by_name
-                 (dynobj, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
+                 (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
              && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
            return FALSE;
        }
+      if (htab->root.splt->size > 0)
+       {
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
+           return FALSE;
+
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0))
+           return FALSE;
+
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0))
+           return FALSE;
+
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0))
+           return FALSE;
+       }
       if (htab->is_vxworks
          && !elf_vxworks_add_dynamic_entries (output_bfd, info))
        return FALSE;
@@ -8056,13 +10262,12 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info,
   Elf_Internal_Sym *sym;
   asection *sec;
 
-  if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+  if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
     {
       r_type = ELF_R_TYPE (output_bfd, rel->r_info);
-      if (r_type == R_MIPS16_GPREL
-         || r_type == R_MIPS_GPREL16
+      if (gprel16_reloc_p (r_type)
          || r_type == R_MIPS_GPREL32
-         || r_type == R_MIPS_LITERAL)
+         || literal_reloc_p (r_type))
        {
          rel->r_addend += _bfd_get_gp_value (input_bfd);
          rel->r_addend -= _bfd_get_gp_value (output_bfd);
@@ -8072,7 +10277,7 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info,
       sym = local_syms + r_symndx;
 
       /* Adjust REL's addend to account for section merging.  */
-      if (!info->relocatable)
+      if (!bfd_link_relocatable (info))
        {
          sec = local_sections[r_symndx];
          _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
@@ -8084,6 +10289,55 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info,
     }
 }
 
+/* Handle relocations against symbols from removed linkonce sections,
+   or sections discarded by a linker script.  We use this wrapper around
+   RELOC_AGAINST_DISCARDED_SECTION to handle triplets of compound relocs
+   on 64-bit ELF targets.  In this case for any relocation handled, which
+   always be the first in a triplet, the remaining two have to be processed
+   together with the first, even if they are R_MIPS_NONE.  It is the symbol
+   index referred by the first reloc that applies to all the three and the
+   remaining two never refer to an object symbol.  And it is the final
+   relocation (the last non-null one) that determines the output field of
+   the whole relocation so retrieve the corresponding howto structure for
+   the relocatable field to be cleared by RELOC_AGAINST_DISCARDED_SECTION.
+
+   Note that RELOC_AGAINST_DISCARDED_SECTION is a macro that uses "continue"
+   and therefore requires to be pasted in a loop.  It also defines a block
+   and does not protect any of its arguments, hence the extra brackets.  */
+
+static void
+mips_reloc_against_discarded_section (bfd *output_bfd,
+                                     struct bfd_link_info *info,
+                                     bfd *input_bfd, asection *input_section,
+                                     Elf_Internal_Rela **rel,
+                                     const Elf_Internal_Rela **relend,
+                                     bfd_boolean rel_reloc,
+                                     reloc_howto_type *howto,
+                                     bfd_byte *contents)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+  int count = bed->s->int_rels_per_ext_rel;
+  unsigned int r_type;
+  int i;
+
+  for (i = count - 1; i > 0; i--)
+    {
+      r_type = ELF_R_TYPE (output_bfd, (*rel)[i].r_info);
+      if (r_type != R_MIPS_NONE)
+       {
+         howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
+         break;
+       }
+    }
+  do
+    {
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                       (*rel), count, (*relend),
+                                       howto, i, contents);
+    }
+  while (0);
+}
+
 /* Relocate a MIPS ELF section.  */
 
 bfd_boolean
@@ -8097,18 +10351,16 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *relend;
   bfd_vma addend = 0;
   bfd_boolean use_saved_addend_p = FALSE;
-  const struct elf_backend_data *bed;
 
-  bed = get_elf_backend_data (output_bfd);
-  relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
+  relend = relocs + input_section->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
     {
       const char *name;
       bfd_vma value = 0;
       reloc_howto_type *howto;
-      bfd_boolean require_jalx;
+      bfd_boolean cross_mode_jump_p = FALSE;
       /* TRUE if the relocation is a RELA relocation, rather than a
-         REL relocation.  */
+        REL relocation.  */
       bfd_boolean rela_relocation_p = TRUE;
       unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info);
       const char *msg;
@@ -8116,17 +10368,17 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       asection *sec;
       Elf_Internal_Shdr *symtab_hdr;
       struct elf_link_hash_entry *h;
+      bfd_boolean rel_reloc;
 
+      rel_reloc = (NEWABI_P (input_bfd)
+                  && mips_elf_rel_relocation_p (input_bfd, input_section,
+                                                relocs, rel));
       /* Find the relocation howto for this relocation.  */
-      howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type,
-                                      NEWABI_P (input_bfd)
-                                      && (MIPS_RELOC_RELA_P
-                                          (input_bfd, input_section,
-                                           rel - relocs)));
+      howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
 
       r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-      if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+      if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
        {
          sec = local_sections[r_symndx];
          h = NULL;
@@ -8149,14 +10401,11 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            sec = h->root.u.def.section;
        }
 
-      if (sec != NULL && elf_discarded_section (sec))
+      if (sec != NULL && discarded_section (sec))
        {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
+         mips_reloc_against_discarded_section (output_bfd, info, input_bfd,
+                                               input_section, &rel, &relend,
+                                               rel_reloc, howto, contents);
          continue;
        }
 
@@ -8188,27 +10437,26 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              rela_relocation_p = FALSE;
              addend = mips_elf_read_rel_addend (input_bfd, rel,
                                                 howto, contents);
-             if (r_type == R_MIPS_HI16
-                 || r_type == R_MIPS16_HI16
-                 || (r_type == R_MIPS_GOT16
+             if (hi16_reloc_p (r_type)
+                 || (got16_reloc_p (r_type)
                      && mips_elf_local_relocation_p (input_bfd, rel,
-                                                     local_sections, FALSE)))
+                                                     local_sections)))
                {
                  if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
                                                     contents, &addend))
                    {
-                     const char *name;
-
                      if (h)
                        name = h->root.root.string;
                      else
                        name = bfd_elf_sym_name (input_bfd, symtab_hdr,
                                                 local_syms + r_symndx,
                                                 sec);
-                     (*_bfd_error_handler)
-                       (_("%B: Can't find matching LO16 reloc against `%s' for %s at 0x%lx in section `%A'"),
-                        input_bfd, input_section, name, howto->name,
-                        rel->r_offset);
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: can't find matching LO16 reloc against `%s'"
+                          " for %s at %#" PRIx64 " in section `%pA'"),
+                        input_bfd, name,
+                        howto->name, (uint64_t) rel->r_offset, input_section);
                    }
                }
              else
@@ -8220,7 +10468,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                  local_syms, local_sections, rel);
        }
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        {
          if (r_type == R_MIPS_64 && ! NEWABI_P (output_bfd)
              && bfd_big_endian (input_bfd))
@@ -8229,8 +10477,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          if (!rela_relocation_p && rel->r_addend)
            {
              addend += rel->r_addend;
-             if (r_type == R_MIPS_HI16
-                 || r_type == R_MIPS_GOT16)
+             if (hi16_reloc_p (r_type) || got16_reloc_p (r_type))
                addend = mips_elf_high (addend);
              else if (r_type == R_MIPS_HIGHER)
                addend = mips_elf_higher (addend);
@@ -8307,10 +10554,10 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
       /* Figure out what value we are supposed to relocate.  */
       switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
-                                            input_section, info, rel,
-                                            addend, howto, local_syms,
-                                            local_sections, &value,
-                                            &name, &require_jalx,
+                                            input_section, contents,
+                                            info, rel, addend, howto,
+                                            local_syms, local_sections,
+                                            &value, &name, &cross_mode_jump_p,
                                             use_saved_addend_p))
        {
        case bfd_reloc_continue:
@@ -8340,28 +10587,51 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              struct mips_elf_link_hash_table *htab;
 
              htab = mips_elf_hash_table (info);
+             BFD_ASSERT (htab != NULL);
              BFD_ASSERT (name != NULL);
              if (!htab->small_data_overflow_reported
-                 && (howto->type == R_MIPS_GPREL16
-                     || howto->type == R_MIPS_LITERAL))
+                 && (gprel16_reloc_p (howto->type)
+                     || literal_reloc_p (howto->type)))
                {
-                 const char *msg =
-                   _("small-data section exceeds 64KB;"
-                     " lower small-data size limit (see option -G)");
+                 msg = _("small-data section exceeds 64KB;"
+                         " lower small-data size limit (see option -G)");
 
                  htab->small_data_overflow_reported = TRUE;
                  (*info->callbacks->einfo) ("%P: %s\n", msg);
                }
-             if (! ((*info->callbacks->reloc_overflow)
-                    (info, NULL, name, howto->name, (bfd_vma) 0,
-                     input_bfd, input_section, rel->r_offset)))
-               return FALSE;
+             (*info->callbacks->reloc_overflow)
+               (info, NULL, name, howto->name, (bfd_vma) 0,
+                input_bfd, input_section, rel->r_offset);
            }
          break;
 
        case bfd_reloc_ok:
          break;
 
+       case bfd_reloc_outofrange:
+         msg = NULL;
+         if (jal_reloc_p (howto->type))
+           msg = (cross_mode_jump_p
+                  ? _("cannot convert a jump to JALX "
+                      "for a non-word-aligned address")
+                  : (howto->type == R_MIPS16_26
+                     ? _("jump to a non-word-aligned address")
+                     : _("jump to a non-instruction-aligned address")));
+         else if (b_reloc_p (howto->type))
+           msg = (cross_mode_jump_p
+                  ? _("cannot convert a branch to JALX "
+                      "for a non-word-aligned address")
+                  : _("branch to a non-instruction-aligned address"));
+         else if (aligned_pcrel_reloc_p (howto->type))
+           msg = _("PC-relative load from unaligned address");
+         if (msg)
+           {
+             info->callbacks->einfo
+               ("%X%H: %s\n", input_bfd, input_section, rel->r_offset, msg);
+             break;
+           }
+         /* Fall through.  */
+
        default:
          abort ();
          break;
@@ -8423,13 +10693,123 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       /* Actually perform the relocation.  */
       if (! mips_elf_perform_relocation (info, howto, rel, value,
                                         input_bfd, input_section,
-                                        contents, require_jalx))
+                                        contents, cross_mode_jump_p))
        return FALSE;
     }
 
   return TRUE;
 }
 \f
+/* A function that iterates over each entry in la25_stubs and fills
+   in the code for each one.  DATA points to a mips_htab_traverse_info.  */
+
+static int
+mips_elf_create_la25_stub (void **slot, void *data)
+{
+  struct mips_htab_traverse_info *hti;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_elf_la25_stub *stub;
+  asection *s;
+  bfd_byte *loc;
+  bfd_vma offset, target, target_high, target_low;
+  bfd_vma branch_pc;
+  bfd_signed_vma pcrel_offset = 0;
+
+  stub = (struct mips_elf_la25_stub *) *slot;
+  hti = (struct mips_htab_traverse_info *) data;
+  htab = mips_elf_hash_table (hti->info);
+  BFD_ASSERT (htab != NULL);
+
+  /* Create the section contents, if we haven't already.  */
+  s = stub->stub_section;
+  loc = s->contents;
+  if (loc == NULL)
+    {
+      loc = bfd_malloc (s->size);
+      if (loc == NULL)
+       {
+         hti->error = TRUE;
+         return FALSE;
+       }
+      s->contents = loc;
+    }
+
+  /* Work out where in the section this stub should go.  */
+  offset = stub->offset;
+
+  /* We add 8 here to account for the LUI/ADDIU instructions
+     before the branch instruction.  This cannot be moved down to
+     where pcrel_offset is calculated as 's' is updated in
+     mips_elf_get_la25_target.  */
+  branch_pc = s->output_section->vma + s->output_offset + offset + 8;
+
+  /* Work out the target address.  */
+  target = mips_elf_get_la25_target (stub, &s);
+  target += s->output_section->vma + s->output_offset;
+
+  target_high = ((target + 0x8000) >> 16) & 0xffff;
+  target_low = (target & 0xffff);
+
+  /* Calculate the PC of the compact branch instruction (for the case where
+     compact branches are used for either microMIPSR6 or MIPSR6 with
+     compact branches.  Add 4-bytes to account for BC using the PC of the
+     next instruction as the base.  */
+  pcrel_offset = target - (branch_pc + 4);
+
+  if (stub->stub_section != htab->strampoline)
+    {
+      /* This is a simple LUI/ADDIU stub.  Zero out the beginning
+        of the section and write the two instructions at the end.  */
+      memset (loc, 0, offset);
+      loc += offset;
+      if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+       {
+         bfd_put_micromips_32 (hti->output_bfd,
+                               LA25_LUI_MICROMIPS (target_high),
+                               loc);
+         bfd_put_micromips_32 (hti->output_bfd,
+                               LA25_ADDIU_MICROMIPS (target_low),
+                               loc + 4);
+       }
+      else
+       {
+         bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
+         bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+       }
+    }
+  else
+    {
+      /* This is trampoline.  */
+      loc += offset;
+      if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+       {
+         bfd_put_micromips_32 (hti->output_bfd,
+                               LA25_LUI_MICROMIPS (target_high), loc);
+         bfd_put_micromips_32 (hti->output_bfd,
+                               LA25_J_MICROMIPS (target), loc + 4);
+         bfd_put_micromips_32 (hti->output_bfd,
+                               LA25_ADDIU_MICROMIPS (target_low), loc + 8);
+         bfd_put_32 (hti->output_bfd, 0, loc + 12);
+       }
+      else
+       {
+         bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
+         if (MIPSR6_P (hti->output_bfd) && htab->compact_branches)
+           {
+             bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+             bfd_put_32 (hti->output_bfd, LA25_BC (pcrel_offset), loc + 8);
+           }
+         else
+           {
+             bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
+             bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+           }
+         bfd_put_32 (hti->output_bfd, 0, loc + 12);
+       }
+    }
+  return TRUE;
+}
+
 /* If NAME is one of the special IRIX6 symbols defined by the linker,
    adjust it appropriately now.  */
 
@@ -8495,94 +10875,378 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   const char *name;
   int idx;
   struct mips_elf_link_hash_table *htab;
+  struct mips_elf_link_hash_entry *hmips;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
   dynobj = elf_hash_table (info)->dynobj;
+  hmips = (struct mips_elf_link_hash_entry *) h;
 
-  if (h->plt.offset != MINUS_ONE)
+  BFD_ASSERT (!htab->is_vxworks);
+
+  if (h->plt.plist != NULL
+      && (h->plt.plist->mips_offset != MINUS_ONE
+         || h->plt.plist->comp_offset != MINUS_ONE))
     {
-      asection *s;
-      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
+      /* We've decided to create a PLT entry for this symbol.  */
+      bfd_byte *loc;
+      bfd_vma header_address, got_address;
+      bfd_vma got_address_high, got_address_low, load;
+      bfd_vma got_index;
+      bfd_vma isa_bit;
 
-      /* This symbol has a stub.  Set it up.  */
+      got_index = h->plt.plist->gotplt_index;
 
+      BFD_ASSERT (htab->use_plts_and_copy_relocs);
       BFD_ASSERT (h->dynindx != -1);
+      BFD_ASSERT (htab->root.splt != NULL);
+      BFD_ASSERT (got_index != MINUS_ONE);
+      BFD_ASSERT (!h->def_regular);
 
-      s = bfd_get_section_by_name (dynobj,
-                                  MIPS_ELF_STUB_SECTION_NAME (dynobj));
-      BFD_ASSERT (s != NULL);
+      /* Calculate the address of the PLT header.  */
+      isa_bit = htab->plt_header_is_comp;
+      header_address = (htab->root.splt->output_section->vma
+                       + htab->root.splt->output_offset + isa_bit);
 
-      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-                  || (h->dynindx <= 0xffff));
+      /* Calculate the address of the .got.plt entry.  */
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
+                    + got_index * MIPS_ELF_GOT_SIZE (dynobj));
 
-      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
-        sign extension at runtime in the stub, resulting in a negative
-        index value.  */
-      if (h->dynindx & ~0x7fffffff)
-       return FALSE;
+      got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
+      got_address_low = got_address & 0xffff;
 
-      /* Fill the stub.  */
-      idx = 0;
-      bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx);
-      idx += 4;
-      bfd_put_32 (output_bfd, STUB_MOVE (output_bfd), stub + idx);
-      idx += 4;
-      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-        {
-          bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff),
-                      stub + idx);
-          idx += 4;
-        }
-      bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
-      idx += 4;
-
-      /* If a large stub is not required and sign extension is not a
-         problem, then use legacy code in the stub.  */
-      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-       bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff), stub + idx);
-      else if (h->dynindx & ~0x7fff)
-        bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx);
+      /* The PLT sequence is not safe for N64 if .got.plt entry's address
+        cannot be loaded in two instructions.  */
+      if (ABI_64_P (output_bfd)
+         && ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
+              "supported; consider using `-Ttext-segment=...'"),
+            output_bfd,
+            htab->root.sgotplt->output_section,
+            (int64_t) got_address);
+         bfd_set_error (bfd_error_no_error);
+         return FALSE;
+       }
+
+      /* Initially point the .got.plt entry at the PLT header.  */
+      loc = (htab->root.sgotplt->contents
+            + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+      if (ABI_64_P (output_bfd))
+       bfd_put_64 (output_bfd, header_address, loc);
       else
-        bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
-                   stub + idx);
+       bfd_put_32 (output_bfd, header_address, loc);
 
-      BFD_ASSERT (h->plt.offset <= s->size);
-      memcpy (s->contents + h->plt.offset, stub, htab->function_stub_size);
+      /* Now handle the PLT itself.  First the standard entry (the order
+        does not matter, we just have to pick one).  */
+      if (h->plt.plist->mips_offset != MINUS_ONE)
+       {
+         const bfd_vma *plt_entry;
+         bfd_vma plt_offset;
 
-      /* Mark the symbol as undefined.  plt.offset != -1 occurs
-        only for the referenced symbol.  */
-      sym->st_shndx = SHN_UNDEF;
+         plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
 
-      /* The run-time linker uses the st_value field of the symbol
-        to reset the global offset table entry for this external
-        to its stub address when unlinking a shared object.  */
-      sym->st_value = (s->output_section->vma + s->output_offset
-                      + h->plt.offset);
-    }
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
-  BFD_ASSERT (h->dynindx != -1
-             || h->forced_local);
+         /* Find out where the .plt entry should go.  */
+         loc = htab->root.splt->contents + plt_offset;
 
-  sgot = mips_elf_got_section (dynobj, FALSE);
-  BFD_ASSERT (sgot != NULL);
-  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
-  g = mips_elf_section_data (sgot)->u.got_info;
-  BFD_ASSERT (g != NULL);
+         /* Pick the load opcode.  */
+         load = MIPS_ELF_LOAD_WORD (output_bfd);
 
-  /* Run through the global symbol table, creating GOT entries for all
-     the symbols that need them.  */
-  if (g->global_gotsym != NULL
-      && h->dynindx >= g->global_gotsym->dynindx)
-    {
-      bfd_vma offset;
-      bfd_vma value;
+         /* Fill in the PLT entry itself.  */
 
-      value = sym->st_value;
-      offset = mips_elf_global_got_index (dynobj, output_bfd, h, R_MIPS_GOT16, info);
-      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
-    }
+         if (MIPSR6_P (output_bfd))
+           plt_entry = htab->compact_branches ? mipsr6_exec_plt_entry_compact
+                                              : mipsr6_exec_plt_entry;
+         else
+           plt_entry = mips_exec_plt_entry;
+         bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc);
+         bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load,
+                     loc + 4);
 
-  if (g->next && h->dynindx != -1 && h->type != STT_TLS)
+         if (! LOAD_INTERLOCKS_P (output_bfd)
+             || (MIPSR6_P (output_bfd) && htab->compact_branches))
+           {
+             bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
+             bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
+           }
+         else
+           {
+             bfd_put_32 (output_bfd, plt_entry[3], loc + 8);
+             bfd_put_32 (output_bfd, plt_entry[2] | got_address_low,
+                         loc + 12);
+           }
+       }
+
+      /* Now the compressed entry.  They come after any standard ones.  */
+      if (h->plt.plist->comp_offset != MINUS_ONE)
+       {
+         bfd_vma plt_offset;
+
+         plt_offset = (htab->plt_header_size + htab->plt_mips_offset
+                       + h->plt.plist->comp_offset);
+
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
+
+         /* Find out where the .plt entry should go.  */
+         loc = htab->root.splt->contents + plt_offset;
+
+         /* Fill in the PLT entry itself.  */
+         if (!MICROMIPS_P (output_bfd))
+           {
+             const bfd_vma *plt_entry = mips16_o32_exec_plt_entry;
+
+             bfd_put_16 (output_bfd, plt_entry[0], loc);
+             bfd_put_16 (output_bfd, plt_entry[1], loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, plt_entry[3], loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+             bfd_put_32 (output_bfd, got_address, loc + 12);
+           }
+         else if (htab->insn32)
+           {
+             const bfd_vma *plt_entry = micromips_insn32_o32_exec_plt_entry;
+
+             bfd_put_16 (output_bfd, plt_entry[0], loc);
+             bfd_put_16 (output_bfd, got_address_high, loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, got_address_low, loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+             bfd_put_16 (output_bfd, plt_entry[6], loc + 12);
+             bfd_put_16 (output_bfd, got_address_low, loc + 14);
+           }
+         else
+           {
+             const bfd_vma *plt_entry = micromips_o32_exec_plt_entry;
+             bfd_signed_vma gotpc_offset;
+             bfd_vma loc_address;
+
+             BFD_ASSERT (got_address % 4 == 0);
+
+             loc_address = (htab->root.splt->output_section->vma
+                            + htab->root.splt->output_offset + plt_offset);
+             gotpc_offset = got_address - ((loc_address | 3) ^ 3);
+
+             /* ADDIUPC has a span of +/-16MB, check we're in range.  */
+             if (gotpc_offset + 0x1000000 >= 0x2000000)
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
+                      "beyond the range of ADDIUPC"),
+                    output_bfd,
+                    htab->root.sgotplt->output_section,
+                    (int64_t) gotpc_offset,
+                    htab->root.splt->output_section);
+                 bfd_set_error (bfd_error_no_error);
+                 return FALSE;
+               }
+             bfd_put_16 (output_bfd,
+                         plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
+             bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, plt_entry[3], loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+           }
+       }
+
+      /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
+      mips_elf_output_dynamic_relocation (output_bfd, htab->root.srelplt,
+                                         got_index - 2, h->dynindx,
+                                         R_MIPS_JUMP_SLOT, got_address);
+
+      /* We distinguish between PLT entries and lazy-binding stubs by
+        giving the former an st_other value of STO_MIPS_PLT.  Set the
+        flag and leave the value if there are any relocations in the
+        binary where pointer equality matters.  */
+      sym->st_shndx = SHN_UNDEF;
+      if (h->pointer_equality_needed)
+       sym->st_other = ELF_ST_SET_MIPS_PLT (sym->st_other);
+      else
+       {
+         sym->st_value = 0;
+         sym->st_other = 0;
+       }
+    }
+
+  if (h->plt.plist != NULL && h->plt.plist->stub_offset != MINUS_ONE)
+    {
+      /* We've decided to create a lazy-binding stub.  */
+      bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+      unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+      bfd_vma stub_size = htab->function_stub_size;
+      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
+      bfd_vma isa_bit = micromips_p;
+      bfd_vma stub_big_size;
+
+      if (!micromips_p)
+       stub_big_size = MIPS_FUNCTION_STUB_BIG_SIZE;
+      else if (htab->insn32)
+       stub_big_size = MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE;
+      else
+       stub_big_size = MICROMIPS_FUNCTION_STUB_BIG_SIZE;
+
+      /* This symbol has a stub.  Set it up.  */
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      BFD_ASSERT (stub_size == stub_big_size || h->dynindx <= 0xffff);
+
+      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
+        sign extension at runtime in the stub, resulting in a negative
+        index value.  */
+      if (h->dynindx & ~0x7fffffff)
+       return FALSE;
+
+      /* Fill the stub.  */
+      if (micromips_p)
+       {
+         idx = 0;
+         bfd_put_micromips_32 (output_bfd, STUB_LW_MICROMIPS (output_bfd),
+                               stub + idx);
+         idx += 4;
+         if (htab->insn32)
+           {
+             bfd_put_micromips_32 (output_bfd,
+                                   STUB_MOVE32_MICROMIPS, stub + idx);
+             idx += 4;
+           }
+         else
+           {
+             bfd_put_16 (output_bfd, STUB_MOVE_MICROMIPS, stub + idx);
+             idx += 2;
+           }
+         if (stub_size == stub_big_size)
+           {
+             long dynindx_hi = (h->dynindx >> 16) & 0x7fff;
+
+             bfd_put_micromips_32 (output_bfd,
+                                   STUB_LUI_MICROMIPS (dynindx_hi),
+                                   stub + idx);
+             idx += 4;
+           }
+         if (htab->insn32)
+           {
+             bfd_put_micromips_32 (output_bfd, STUB_JALR32_MICROMIPS,
+                                   stub + idx);
+             idx += 4;
+           }
+         else
+           {
+             bfd_put_16 (output_bfd, STUB_JALR_MICROMIPS, stub + idx);
+             idx += 2;
+           }
+
+         /* If a large stub is not required and sign extension is not a
+            problem, then use legacy code in the stub.  */
+         if (stub_size == stub_big_size)
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_ORI_MICROMIPS (h->dynindx & 0xffff),
+                                 stub + idx);
+         else if (h->dynindx & ~0x7fff)
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_LI16U_MICROMIPS (h->dynindx & 0xffff),
+                                 stub + idx);
+         else
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_LI16S_MICROMIPS (output_bfd,
+                                                       h->dynindx),
+                                 stub + idx);
+       }
+      else
+       {
+         idx = 0;
+         bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx);
+         idx += 4;
+         bfd_put_32 (output_bfd, STUB_MOVE, stub + idx);
+         idx += 4;
+         if (stub_size == stub_big_size)
+           {
+             bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff),
+                         stub + idx);
+             idx += 4;
+           }
+
+         if (!(MIPSR6_P (output_bfd) && htab->compact_branches))
+           {
+             bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+             idx += 4;
+           }
+
+         /* If a large stub is not required and sign extension is not a
+            problem, then use legacy code in the stub.  */
+         if (stub_size == stub_big_size)
+           bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff),
+                       stub + idx);
+         else if (h->dynindx & ~0x7fff)
+           bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff),
+                       stub + idx);
+         else
+           bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
+                       stub + idx);
+         idx += 4;
+
+         if (MIPSR6_P (output_bfd) && htab->compact_branches)
+           bfd_put_32 (output_bfd, STUB_JALRC, stub + idx);
+       }
+
+      BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size);
+      memcpy (htab->sstubs->contents + h->plt.plist->stub_offset,
+             stub, stub_size);
+
+      /* Mark the symbol as undefined.  stub_offset != -1 occurs
+        only for the referenced symbol.  */
+      sym->st_shndx = SHN_UNDEF;
+
+      /* The run-time linker uses the st_value field of the symbol
+        to reset the global offset table entry for this external
+        to its stub address when unlinking a shared object.  */
+      sym->st_value = (htab->sstubs->output_section->vma
+                      + htab->sstubs->output_offset
+                      + h->plt.plist->stub_offset
+                      + isa_bit);
+      sym->st_other = other;
+    }
+
+  /* If we have a MIPS16 function with a stub, the dynamic symbol must
+     refer to the stub, since only the stub uses the standard calling
+     conventions.  */
+  if (h->dynindx != -1 && hmips->fn_stub != NULL)
+    {
+      BFD_ASSERT (hmips->need_fn_stub);
+      sym->st_value = (hmips->fn_stub->output_section->vma
+                      + hmips->fn_stub->output_offset);
+      sym->st_size = hmips->fn_stub->size;
+      sym->st_other = ELF_ST_VISIBILITY (sym->st_other);
+    }
+
+  BFD_ASSERT (h->dynindx != -1
+             || h->forced_local);
+
+  sgot = htab->root.sgot;
+  g = htab->got_info;
+  BFD_ASSERT (g != NULL);
+
+  /* Run through the global symbol table, creating GOT entries for all
+     the symbols that need them.  */
+  if (hmips->global_got_area != GGA_NONE)
+    {
+      bfd_vma offset;
+      bfd_vma value;
+
+      value = sym->st_value;
+      offset = mips_elf_primary_global_got_index (output_bfd, info, h);
+      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
+    }
+
+  if (hmips->global_got_area != GGA_NONE && g->next)
     {
       struct mips_got_entry e, *p;
       bfd_vma entry;
@@ -8592,8 +11256,8 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       e.abfd = output_bfd;
       e.symndx = -1;
-      e.d.h = (struct mips_elf_link_hash_entry *)h;
-      e.tls_type = 0;
+      e.d.h = hmips;
+      e.tls_type = GOT_TLS_NONE;
 
       for (g = g->next; g->next != gg; g = g->next)
        {
@@ -8602,7 +11266,8 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                                           &e)))
            {
              offset = p->gotidx;
-             if (info->shared
+             BFD_ASSERT (offset > 0 && offset < htab->root.sgot->size);
+             if (bfd_link_pic (info)
                  || (elf_hash_table (info)->dynamic_sections_created
                      && p->d.h != NULL
                      && p->d.h->root.def_dynamic
@@ -8637,7 +11302,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
   name = h->root.root.string;
-  if (strcmp (name, "_DYNAMIC") == 0
+  if (h == elf_hash_table (info)->hdynamic
       || h == elf_hash_table (info)->hgot)
     sym->st_shndx = SHN_ABS;
   else if (strcmp (name, "_DYNAMIC_LINK") == 0
@@ -8647,12 +11312,6 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
       sym->st_value = 1;
     }
-  else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
-    {
-      sym->st_shndx = SHN_ABS;
-      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
-      sym->st_value = elf_gp (output_bfd);
-    }
   else if (SGI_COMPAT (output_bfd))
     {
       if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
@@ -8679,38 +11338,39 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
     }
 
+  /* Emit a copy reloc, if needed.  */
+  if (h->needs_copy)
+    {
+      asection *s;
+      bfd_vma symval;
+
+      BFD_ASSERT (h->dynindx != -1);
+      BFD_ASSERT (htab->use_plts_and_copy_relocs);
+
+      s = mips_elf_rel_dyn_section (info, FALSE);
+      symval = (h->root.u.def.section->output_section->vma
+               + h->root.u.def.section->output_offset
+               + h->root.u.def.value);
+      mips_elf_output_dynamic_relocation (output_bfd, s, s->reloc_count++,
+                                         h->dynindx, R_MIPS_COPY, symval);
+    }
+
   /* Handle the IRIX6-specific symbols.  */
   if (IRIX_COMPAT (output_bfd) == ict_irix6)
     mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym);
 
-  if (! info->shared)
+  /* Keep dynamic compressed symbols odd.  This allows the dynamic linker
+     to treat compressed symbols like any other.  */
+  if (ELF_ST_IS_MIPS16 (sym->st_other))
     {
-      if (! mips_elf_hash_table (info)->use_rld_obj_head
-         && (strcmp (name, "__rld_map") == 0
-             || strcmp (name, "__RLD_MAP") == 0))
-       {
-         asection *s = bfd_get_section_by_name (dynobj, ".rld_map");
-         BFD_ASSERT (s != NULL);
-         sym->st_value = s->output_section->vma + s->output_offset;
-         bfd_put_32 (output_bfd, 0, s->contents);
-         if (mips_elf_hash_table (info)->rld_value == 0)
-           mips_elf_hash_table (info)->rld_value = sym->st_value;
-       }
-      else if (mips_elf_hash_table (info)->use_rld_obj_head
-              && strcmp (name, "__rld_obj_head") == 0)
-       {
-         /* IRIX6 does not use a .rld_map section.  */
-         if (IRIX_COMPAT (output_bfd) == ict_irix5
-              || IRIX_COMPAT (output_bfd) == ict_none)
-           BFD_ASSERT (bfd_get_section_by_name (dynobj, ".rld_map")
-                       != NULL);
-         mips_elf_hash_table (info)->rld_value = sym->st_value;
-       }
+      BFD_ASSERT (sym->st_value & 1);
+      sym->st_other -= STO_MIPS16;
+    }
+  else if (ELF_ST_IS_MICROMIPS (sym->st_other))
+    {
+      BFD_ASSERT (sym->st_value & 1);
+      sym->st_other -= STO_MICROMIPS;
     }
-
-  /* If this is a mips16 symbol, force the value to be even.  */
-  if (ELF_ST_IS_MIPS16 (sym->st_other))
-    sym->st_value &= ~1;
 
   return TRUE;
 }
@@ -8727,34 +11387,39 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
   asection *sgot;
   struct mips_got_info *g;
   struct mips_elf_link_hash_table *htab;
+  struct mips_elf_link_hash_entry *hmips;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
   dynobj = elf_hash_table (info)->dynobj;
+  hmips = (struct mips_elf_link_hash_entry *) h;
 
-  if (h->plt.offset != (bfd_vma) -1)
+  if (h->plt.plist != NULL && h->plt.plist->mips_offset != MINUS_ONE)
     {
       bfd_byte *loc;
-      bfd_vma plt_address, plt_index, got_address, got_offset, branch_offset;
+      bfd_vma plt_address, got_address, got_offset, branch_offset;
       Elf_Internal_Rela rel;
       static const bfd_vma *plt_entry;
+      bfd_vma gotplt_index;
+      bfd_vma plt_offset;
+
+      plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
+      gotplt_index = h->plt.plist->gotplt_index;
 
       BFD_ASSERT (h->dynindx != -1);
-      BFD_ASSERT (htab->splt != NULL);
-      BFD_ASSERT (h->plt.offset <= htab->splt->size);
+      BFD_ASSERT (htab->root.splt != NULL);
+      BFD_ASSERT (gotplt_index != MINUS_ONE);
+      BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
       /* Calculate the address of the .plt entry.  */
-      plt_address = (htab->splt->output_section->vma
-                    + htab->splt->output_offset
-                    + h->plt.offset);
-
-      /* Calculate the index of the entry.  */
-      plt_index = ((h->plt.offset - htab->plt_header_size)
-                  / htab->plt_entry_size);
+      plt_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset
+                    + plt_offset);
 
       /* Calculate the address of the .got.plt entry.  */
-      got_address = (htab->sgotplt->output_section->vma
-                    + htab->sgotplt->output_offset
-                    + plt_index * 4);
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
+                    + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd));
 
       /* Calculate the offset of the .got.plt entry from
         _GLOBAL_OFFSET_TABLE_.  */
@@ -8762,20 +11427,21 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
       /* Calculate the offset for the branch at the start of the PLT
         entry.  The branch jumps to the beginning of .plt.  */
-      branch_offset = -(h->plt.offset / 4 + 1) & 0xffff;
+      branch_offset = -(plt_offset / 4 + 1) & 0xffff;
 
       /* Fill in the initial value of the .got.plt entry.  */
       bfd_put_32 (output_bfd, plt_address,
-                 htab->sgotplt->contents + plt_index * 4);
+                 (htab->root.sgotplt->contents
+                  + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd)));
 
       /* Find out where the .plt entry should go.  */
-      loc = htab->splt->contents + h->plt.offset;
+      loc = htab->root.splt->contents + plt_offset;
 
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          plt_entry = mips_vxworks_shared_plt_entry;
          bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc);
-         bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4);
+         bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4);
        }
       else
        {
@@ -8786,7 +11452,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
          got_address_low = got_address & 0xffff;
 
          bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc);
-         bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4);
+         bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4);
          bfd_put_32 (output_bfd, plt_entry[2] | got_address_high, loc + 8);
          bfd_put_32 (output_bfd, plt_entry[3] | got_address_low, loc + 12);
          bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
@@ -8795,12 +11461,12 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
          bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
 
          loc = (htab->srelplt2->contents
-                + (plt_index * 3 + 2) * sizeof (Elf32_External_Rela));
+                + (gotplt_index * 3 + 2) * sizeof (Elf32_External_Rela));
 
          /* Emit a relocation for the .got.plt entry.  */
          rel.r_offset = got_address;
          rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_MIPS_32);
-         rel.r_addend = h->plt.offset;
+         rel.r_addend = plt_offset;
          bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
 
          /* Emit a relocation for the lui of %hi(<.got.plt slot>).  */
@@ -8818,7 +11484,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
        }
 
       /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
-      loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rela);
+      loc = (htab->root.srelplt->contents
+            + gotplt_index * sizeof (Elf32_External_Rela));
       rel.r_offset = got_address;
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_JUMP_SLOT);
       rel.r_addend = 0;
@@ -8830,15 +11497,12 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
   BFD_ASSERT (h->dynindx != -1 || h->forced_local);
 
-  sgot = mips_elf_got_section (dynobj, FALSE);
-  BFD_ASSERT (sgot != NULL);
-  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
-  g = mips_elf_section_data (sgot)->u.got_info;
+  sgot = htab->root.sgot;
+  g = htab->got_info;
   BFD_ASSERT (g != NULL);
 
   /* See if this symbol has an entry in the GOT.  */
-  if (g->global_gotsym != NULL
-      && h->dynindx >= g->global_gotsym->dynindx)
+  if (hmips->global_got_area != GGA_NONE)
     {
       bfd_vma offset;
       Elf_Internal_Rela outrel;
@@ -8846,8 +11510,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
       asection *s;
 
       /* Install the symbol value in the GOT.   */
-      offset = mips_elf_global_got_index (dynobj, output_bfd, h,
-                                         R_MIPS_GOT16, info);
+      offset = mips_elf_primary_global_got_index (output_bfd, info, h);
       MIPS_ELF_PUT_WORD (output_bfd, sym->st_value, sgot->contents + offset);
 
       /* Add a dynamic relocation for it.  */
@@ -8865,6 +11528,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
   if (h->needs_copy)
     {
       Elf_Internal_Rela rel;
+      asection *srel;
+      bfd_byte *loc;
 
       BFD_ASSERT (h->dynindx != -1);
 
@@ -8873,20 +11538,136 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
                      + h->root.u.def.value);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_COPY);
       rel.r_addend = 0;
-      bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                                htab->srelbss->contents
-                                + (htab->srelbss->reloc_count
-                                   * sizeof (Elf32_External_Rela)));
-      ++htab->srelbss->reloc_count;
+      if (h->root.u.def.section == htab->root.sdynrelro)
+       srel = htab->root.sreldynrelro;
+      else
+       srel = htab->root.srelbss;
+      loc = srel->contents + srel->reloc_count * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+      ++srel->reloc_count;
     }
 
-  /* If this is a mips16 symbol, force the value to be even.  */
-  if (ELF_ST_IS_MIPS16 (sym->st_other))
+  /* If this is a mips16/microMIPS symbol, force the value to be even.  */
+  if (ELF_ST_IS_COMPRESSED (sym->st_other))
     sym->st_value &= ~1;
 
   return TRUE;
 }
 
+/* Write out a plt0 entry to the beginning of .plt.  */
+
+static bfd_boolean
+mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
+{
+  bfd_byte *loc;
+  bfd_vma gotplt_value, gotplt_value_high, gotplt_value_low;
+  static const bfd_vma *plt_entry;
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (ABI_64_P (output_bfd))
+    plt_entry = (htab->compact_branches
+                ? mipsr6_n64_exec_plt0_entry_compact
+                : mips_n64_exec_plt0_entry);
+  else if (ABI_N32_P (output_bfd))
+    plt_entry = (htab->compact_branches
+                ? mipsr6_n32_exec_plt0_entry_compact
+                : mips_n32_exec_plt0_entry);
+  else if (!htab->plt_header_is_comp)
+    plt_entry = (htab->compact_branches
+                ? mipsr6_o32_exec_plt0_entry_compact
+                : mips_o32_exec_plt0_entry);
+  else if (htab->insn32)
+    plt_entry = micromips_insn32_o32_exec_plt0_entry;
+  else
+    plt_entry = micromips_o32_exec_plt0_entry;
+
+  /* Calculate the value of .got.plt.  */
+  gotplt_value = (htab->root.sgotplt->output_section->vma
+                 + htab->root.sgotplt->output_offset);
+  gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff;
+  gotplt_value_low = gotplt_value & 0xffff;
+
+  /* The PLT sequence is not safe for N64 if .got.plt's address can
+     not be loaded in two instructions.  */
+  if (ABI_64_P (output_bfd)
+      && ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+    {
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
+          "supported; consider using `-Ttext-segment=...'"),
+        output_bfd,
+        htab->root.sgotplt->output_section,
+        (int64_t) gotplt_value);
+      bfd_set_error (bfd_error_no_error);
+      return FALSE;
+    }
+
+  /* Install the PLT header.  */
+  loc = htab->root.splt->contents;
+  if (plt_entry == micromips_o32_exec_plt0_entry)
+    {
+      bfd_vma gotpc_offset;
+      bfd_vma loc_address;
+      size_t i;
+
+      BFD_ASSERT (gotplt_value % 4 == 0);
+
+      loc_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset);
+      gotpc_offset = gotplt_value - ((loc_address | 3) ^ 3);
+
+      /* ADDIUPC has a span of +/-16MB, check we're in range.  */
+      if (gotpc_offset + 0x1000000 >= 0x2000000)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
+              "beyond the range of ADDIUPC"),
+            output_bfd,
+            htab->root.sgotplt->output_section,
+            (int64_t) gotpc_offset,
+            htab->root.splt->output_section);
+         bfd_set_error (bfd_error_no_error);
+         return FALSE;
+       }
+      bfd_put_16 (output_bfd,
+                 plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
+      bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2);
+      for (i = 2; i < ARRAY_SIZE (micromips_o32_exec_plt0_entry); i++)
+       bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2));
+    }
+  else if (plt_entry == micromips_insn32_o32_exec_plt0_entry)
+    {
+      size_t i;
+
+      bfd_put_16 (output_bfd, plt_entry[0], loc);
+      bfd_put_16 (output_bfd, gotplt_value_high, loc + 2);
+      bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+      bfd_put_16 (output_bfd, gotplt_value_low, loc + 6);
+      bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+      bfd_put_16 (output_bfd, gotplt_value_low, loc + 10);
+      for (i = 6; i < ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); i++)
+       bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2));
+    }
+  else
+    {
+      bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc);
+      bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4);
+      bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8);
+      bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
+      bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
+      bfd_put_32 (output_bfd, plt_entry[5], loc + 20);
+      bfd_put_32 (output_bfd, plt_entry[6], loc + 24);
+      bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
+    }
+
+  return TRUE;
+}
+
 /* Install the PLT header for a VxWorks executable and finalize the
    contents of .rela.plt.unloaded.  */
 
@@ -8900,6 +11681,8 @@ mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   plt_entry = mips_vxworks_exec_plt0_entry;
 
   /* Calculate the value of _GLOBAL_OFFSET_TABLE_.  */
@@ -8911,10 +11694,11 @@ mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
   got_value_low = got_value & 0xffff;
 
   /* Calculate the address of the PLT header.  */
-  plt_address = htab->splt->output_section->vma + htab->splt->output_offset;
+  plt_address = (htab->root.splt->output_section->vma
+                + htab->root.splt->output_offset);
 
   /* Install the PLT header.  */
-  loc = htab->splt->contents;
+  loc = htab->root.splt->contents;
   bfd_put_32 (output_bfd, plt_entry[0] | got_value_high, loc);
   bfd_put_32 (output_bfd, plt_entry[1] | got_value_low, loc + 4);
   bfd_put_32 (output_bfd, plt_entry[2], loc + 8);
@@ -8970,11 +11754,12 @@ mips_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
 
   /* We just need to copy the entry byte-by-byte.  */
   for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
     bfd_put_32 (output_bfd, mips_vxworks_shared_plt0_entry[i],
-               htab->splt->contents + i * 4);
+               htab->root.splt->contents + i * 4);
 }
 
 /* Finish up the dynamic sections.  */
@@ -8990,21 +11775,14 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   dynobj = elf_hash_table (info)->dynobj;
 
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
-  sgot = mips_elf_got_section (dynobj, FALSE);
-  if (sgot == NULL)
-    gg = g = NULL;
-  else
-    {
-      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);
-    }
+  sgot = htab->root.sgot;
+  gg = htab->got_info;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
@@ -9012,6 +11790,9 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
       int dyn_to_skip = 0, dyn_skipped = 0;
 
       BFD_ASSERT (sdyn != NULL);
+      BFD_ASSERT (gg != NULL);
+
+      g = mips_elf_bfd_got (output_bfd, FALSE);
       BFD_ASSERT (g != NULL);
 
       for (b = sdyn->contents;
@@ -9048,21 +11829,13 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_PLTGOT:
-             name = ".got";
-             if (htab->is_vxworks)
-               {
-                 /* _GLOBAL_OFFSET_TABLE_ is defined to be the beginning
-                    of the ".got" section in DYNOBJ.  */
-                 s = bfd_get_section_by_name (dynobj, name);
-                 BFD_ASSERT (s != NULL);
-                 dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
-               }
-             else
-               {
-                 s = bfd_get_section_by_name (output_bfd, name);
-                 BFD_ASSERT (s != NULL);
-                 dyn.d_un.d_ptr = s->vma;
-               }
+             s = htab->root.sgot;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+             break;
+
+           case DT_MIPS_PLTGOT:
+             s = htab->root.sgotplt;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_MIPS_RLD_VERSION:
@@ -9109,30 +11882,71 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_MIPS_GOTSYM:
-             if (gg->global_gotsym)
+             if (htab->global_gotsym)
                {
-                 dyn.d_un.d_val = gg->global_gotsym->dynindx;
+                 dyn.d_un.d_val = htab->global_gotsym->dynindx;
                  break;
                }
              /* In case if we don't have global got symbols we default
                 to setting DT_MIPS_GOTSYM to the same value as
-                DT_MIPS_SYMTABNO, so we just fall through.  */
+                DT_MIPS_SYMTABNO.  */
+             /* Fall through.  */
 
            case DT_MIPS_SYMTABNO:
              name = ".dynsym";
              elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
-             s = bfd_get_section_by_name (output_bfd, name);
-             BFD_ASSERT (s != NULL);
+             s = bfd_get_linker_section (dynobj, name);
 
-             dyn.d_un.d_val = s->size / elemsize;
+             if (s != NULL)
+               dyn.d_un.d_val = s->size / elemsize;
+             else
+               dyn.d_un.d_val = 0;
              break;
 
            case DT_MIPS_HIPAGENO:
-             dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO (info);
+             dyn.d_un.d_val = g->local_gotno - htab->reserved_gotno;
              break;
 
            case DT_MIPS_RLD_MAP:
-             dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
+             {
+               struct elf_link_hash_entry *h;
+               h = mips_elf_hash_table (info)->rld_symbol;
+               if (!h)
+                 {
+                   dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+                   swap_out_p = FALSE;
+                   break;
+                 }
+               s = h->root.u.def.section;
+
+               /* The MIPS_RLD_MAP tag stores the absolute address of the
+                  debug pointer.  */
+               dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset
+                                 + h->root.u.def.value);
+             }
+             break;
+
+           case DT_MIPS_RLD_MAP_REL:
+             {
+               struct elf_link_hash_entry *h;
+               bfd_vma dt_addr, rld_addr;
+               h = mips_elf_hash_table (info)->rld_symbol;
+               if (!h)
+                 {
+                   dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+                   swap_out_p = FALSE;
+                   break;
+                 }
+               s = h->root.u.def.section;
+
+               /* The MIPS_RLD_MAP_REL tag stores the offset to the debug
+                  pointer, relative to the address of the tag.  */
+               dt_addr = (sdyn->output_section->vma + sdyn->output_offset
+                          + (b - sdyn->contents));
+               rld_addr = (s->output_section->vma + s->output_offset
+                           + h->root.u.def.value);
+               dyn.d_un.d_ptr = rld_addr - dt_addr;
+             }
              break;
 
            case DT_MIPS_OPTIONS:
@@ -9141,27 +11955,23 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              dyn.d_un.d_ptr = s->vma;
              break;
 
-           case DT_RELASZ:
-             BFD_ASSERT (htab->is_vxworks);
-             /* The count does not include the JUMP_SLOT relocations.  */
-             if (htab->srelplt)
-               dyn.d_un.d_val -= htab->srelplt->size;
-             break;
-
            case DT_PLTREL:
-             BFD_ASSERT (htab->is_vxworks);
-             dyn.d_un.d_val = DT_RELA;
+             BFD_ASSERT (htab->use_plts_and_copy_relocs);
+             if (htab->is_vxworks)
+               dyn.d_un.d_val = DT_RELA;
+             else
+               dyn.d_un.d_val = DT_REL;
              break;
 
            case DT_PLTRELSZ:
-             BFD_ASSERT (htab->is_vxworks);
-             dyn.d_un.d_val = htab->srelplt->size;
+             BFD_ASSERT (htab->use_plts_and_copy_relocs);
+             dyn.d_un.d_val = htab->root.srelplt->size;
              break;
 
            case DT_JMPREL:
-             BFD_ASSERT (htab->is_vxworks);
-             dyn.d_un.d_val = (htab->srelplt->output_section->vma
-                               + htab->srelplt->output_offset);
+             BFD_ASSERT (htab->use_plts_and_copy_relocs);
+             dyn.d_un.d_ptr = (htab->root.srelplt->output_section->vma
+                               + htab->root.srelplt->output_offset);
              break;
 
            case DT_TEXTREL:
@@ -9183,6 +11993,12 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                swap_out_p = FALSE;
              break;
 
+           case DT_MIPS_XHASH:
+             name = ".MIPS.xhash";
+             s = bfd_get_linker_section (dynobj, name);
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+             break;
+
            default:
              swap_out_p = FALSE;
              if (htab->is_vxworks
@@ -9251,22 +12067,26 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
       for (g = gg->next; g->next != gg; g = g->next)
        {
-         bfd_vma index = g->next->local_gotno + g->next->global_gotno
+         bfd_vma got_index = g->next->local_gotno + g->next->global_gotno
            + g->next->tls_gotno;
 
          MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents
-                            + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
+                            + got_index++ * MIPS_ELF_GOT_SIZE (output_bfd));
          MIPS_ELF_PUT_WORD (output_bfd, MIPS_ELF_GNU_GOT1_MASK (output_bfd),
                             sgot->contents
-                            + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
+                            + got_index++ * MIPS_ELF_GOT_SIZE (output_bfd));
 
-         if (! info->shared)
+         if (! bfd_link_pic (info))
            continue;
 
-         while (index < g->assigned_gotno)
+         for (; got_index < g->local_gotno; got_index++)
            {
+             if (got_index >= g->assigned_low_gotno
+                 && got_index <= g->assigned_high_gotno)
+               continue;
+
              rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
-               = index++ * MIPS_ELF_GOT_SIZE (output_bfd);
+               = got_index * MIPS_ELF_GOT_SIZE (output_bfd);
              if (!(mips_elf_create_dynamic_relocation
                    (output_bfd, info, rel, NULL,
                     bfd_abs_section_ptr,
@@ -9315,6 +12135,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                   : sizeof (Elf32_External_Rel)));
              /* Adjust the section size too.  Tools like the prelinker
                 can reasonably expect the values to the same.  */
+             BFD_ASSERT (!bfd_is_abs_section (s->output_section));
              elf_section_data (s->output_section)->this_hdr.sh_size
                = dyn.d_un.d_val;
              break;
@@ -9337,7 +12158,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
     if (SGI_COMPAT (output_bfd))
       {
        /* Write .compact_rel section out.  */
-       s = bfd_get_section_by_name (dynobj, ".compact_rel");
+       s = bfd_get_linker_section (dynobj, ".compact_rel");
        if (s != NULL)
          {
            cpt.id1 = 1;
@@ -9352,15 +12173,13 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                             s->contents));
 
            /* Clean up a dummy stub function entry in .text.  */
-           s = bfd_get_section_by_name (dynobj,
-                                        MIPS_ELF_STUB_SECTION_NAME (dynobj));
-           if (s != NULL)
+           if (htab->sstubs != NULL)
              {
                file_ptr dummy_offset;
 
-               BFD_ASSERT (s->size >= htab->function_stub_size);
-               dummy_offset = s->size - htab->function_stub_size;
-               memset (s->contents + dummy_offset, 0,
+               BFD_ASSERT (htab->sstubs->size >= htab->function_stub_size);
+               dummy_offset = htab->sstubs->size - htab->function_stub_size;
+               memset (htab->sstubs->contents + dummy_offset, 0,
                        htab->function_stub_size);
              }
          }
@@ -9390,12 +12209,21 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
       }
   }
 
-  if (htab->is_vxworks && htab->splt->size > 0)
+  if (htab->root.splt && htab->root.splt->size > 0)
     {
-      if (info->shared)
-       mips_vxworks_finish_shared_plt (output_bfd, info);
+      if (htab->is_vxworks)
+       {
+         if (bfd_link_pic (info))
+           mips_vxworks_finish_shared_plt (output_bfd, info);
+         else
+           mips_vxworks_finish_exec_plt (output_bfd, info);
+       }
       else
-       mips_vxworks_finish_exec_plt (output_bfd, info);
+       {
+         BFD_ASSERT (!bfd_link_pic (info));
+         if (!mips_finish_exec_plt (output_bfd, info))
+           return FALSE;
+       }
     }
   return TRUE;
 }
@@ -9411,6 +12239,12 @@ mips_set_isa_flags (bfd *abfd)
   switch (bfd_get_mach (abfd))
     {
     default:
+      if (ABI_N32_P (abfd) || ABI_64_P (abfd))
+        val = E_MIPS_ARCH_3;
+      else
+        val = E_MIPS_ARCH_1;
+      break;
+
     case bfd_mach_mips3000:
       val = E_MIPS_ARCH_1;
       break;
@@ -9423,6 +12257,10 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_2;
       break;
 
+    case bfd_mach_mips4010:
+      val = E_MIPS_ARCH_2 | E_MIPS_MACH_4010;
+      break;
+
     case bfd_mach_mips4000:
     case bfd_mach_mips4300:
     case bfd_mach_mips4400:
@@ -9430,10 +12268,6 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_3;
       break;
 
-    case bfd_mach_mips4010:
-      val = E_MIPS_ARCH_3 | E_MIPS_MACH_4010;
-      break;
-
     case bfd_mach_mips4100:
       val = E_MIPS_ARCH_3 | E_MIPS_MACH_4100;
       break;
@@ -9458,6 +12292,10 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_4 | E_MIPS_MACH_5500;
       break;
 
+    case bfd_mach_mips5900:
+      val = E_MIPS_ARCH_3 | E_MIPS_MACH_5900;
+      break;
+
     case bfd_mach_mips9000:
       val = E_MIPS_ARCH_4 | E_MIPS_MACH_9000;
       break;
@@ -9467,6 +12305,8 @@ mips_set_isa_flags (bfd *abfd)
     case bfd_mach_mips8000:
     case bfd_mach_mips10000:
     case bfd_mach_mips12000:
+    case bfd_mach_mips14000:
+    case bfd_mach_mips16000:
       val = E_MIPS_ARCH_4;
       break;
 
@@ -9486,10 +12326,35 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
       break;
 
+    case bfd_mach_mips_gs464:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464;
+      break;
+
+    case bfd_mach_mips_gs464e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464E;
+      break;
+
+    case bfd_mach_mips_gs264e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS264E;
+      break;
+
     case bfd_mach_mips_octeon:
+    case bfd_mach_mips_octeonp:
       val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
       break;
 
+    case bfd_mach_mips_octeon3:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON3;
+      break;
+
+    case bfd_mach_mips_xlr:
+      val = E_MIPS_ARCH_64 | E_MIPS_MACH_XLR;
+      break;
+
+    case bfd_mach_mips_octeon2:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON2;
+      break;
+
     case bfd_mach_mipsisa32:
       val = E_MIPS_ARCH_32;
       break;
@@ -9499,12 +12364,28 @@ mips_set_isa_flags (bfd *abfd)
       break;
 
     case bfd_mach_mipsisa32r2:
+    case bfd_mach_mipsisa32r3:
+    case bfd_mach_mipsisa32r5:
       val = E_MIPS_ARCH_32R2;
       break;
 
+    case bfd_mach_mips_interaptiv_mr2:
+      val = E_MIPS_ARCH_32R2 | E_MIPS_MACH_IAMR2;
+      break;
+
     case bfd_mach_mipsisa64r2:
+    case bfd_mach_mipsisa64r3:
+    case bfd_mach_mipsisa64r5:
       val = E_MIPS_ARCH_64R2;
       break;
+
+    case bfd_mach_mipsisa32r6:
+      val = E_MIPS_ARCH_32R6;
+      break;
+
+    case bfd_mach_mipsisa64r6:
+      val = E_MIPS_ARCH_64R6;
+      break;
     }
   elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
   elf_elfheader (abfd)->e_flags |= val;
@@ -9512,13 +12393,24 @@ mips_set_isa_flags (bfd *abfd)
 }
 
 
-/* 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.  */
+/* Whether to sort relocs output by ld -r or ld --emit-relocs, by r_offset.
+   Don't do so for code sections.  We want to keep ordering of HI16/LO16
+   as is.  On the other hand, elf-eh-frame.c processing requires .eh_frame
+   relocs to be sorted.  */
 
-void
-_bfd_mips_elf_final_write_processing (bfd *abfd,
-                                     bfd_boolean linker ATTRIBUTE_UNUSED)
+bfd_boolean
+_bfd_mips_elf_sort_relocs_p (asection *sec)
+{
+  return (sec->flags & SEC_CODE) == 0;
+}
+
+
+/* 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_final_write_processing (bfd *abfd)
 {
   unsigned int i;
   Elf_Internal_Shdr **hdrpp;
@@ -9548,7 +12440,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_GPTAB:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
                      && CONST_STRNEQ (name, ".gptab."));
          sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
@@ -9558,7 +12450,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_CONTENT:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
                      && CONST_STRNEQ (name, ".MIPS.content"));
          sec = bfd_get_section_by_name (abfd,
@@ -9578,7 +12470,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_EVENTS:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL);
          if (CONST_STRNEQ (name, ".MIPS.events"))
            sec = bfd_get_section_by_name (abfd,
@@ -9594,9 +12486,20 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
          (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
          break;
 
+       case SHT_MIPS_XHASH:
+         sec = bfd_get_section_by_name (abfd, ".dynsym");
+         if (sec != NULL)
+           (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
        }
     }
 }
+
+bfd_boolean
+_bfd_mips_elf_final_write_processing (bfd *abfd)
+{
+  _bfd_mips_final_write_processing (abfd);
+  return _bfd_elf_final_write_processing (abfd);
+}
 \f
 /* When creating an IRIX5 executable, we need REGINFO and RTPROC
    segments.  */
@@ -9613,6 +12516,10 @@ _bfd_mips_elf_additional_program_headers (bfd *abfd,
   if (s && (s->flags & SEC_LOAD))
     ++ret;
 
+  /* See if we need a PT_MIPS_ABIFLAGS segment.  */
+  if (bfd_get_section_by_name (abfd, ".MIPS.abiflags"))
+    ++ret;
+
   /* See if we need a PT_MIPS_OPTIONS segment.  */
   if (IRIX_COMPAT (abfd) == ict_irix6
       && bfd_get_section_by_name (abfd,
@@ -9649,7 +12556,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
   s = bfd_get_section_by_name (abfd, ".reginfo");
   if (s != NULL && (s->flags & SEC_LOAD) != 0)
     {
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+      for (m = elf_seg_map (abfd); m != NULL; m = m->next)
        if (m->p_type == PT_MIPS_REGINFO)
          break;
       if (m == NULL)
@@ -9664,7 +12571,38 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
          m->sections[0] = s;
 
          /* We want to put it after the PHDR and INTERP segments.  */
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
+         while (*pm != NULL
+                && ((*pm)->p_type == PT_PHDR
+                    || (*pm)->p_type == PT_INTERP))
+           pm = &(*pm)->next;
+
+         m->next = *pm;
+         *pm = m;
+       }
+    }
+
+  /* If there is a .MIPS.abiflags section, we need a PT_MIPS_ABIFLAGS
+     segment.  */
+  s = bfd_get_section_by_name (abfd, ".MIPS.abiflags");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0)
+    {
+      for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+       if (m->p_type == PT_MIPS_ABIFLAGS)
+         break;
+      if (m == NULL)
+       {
+         amt = sizeof *m;
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           return FALSE;
+
+         m->p_type = PT_MIPS_ABIFLAGS;
+         m->count = 1;
+         m->sections[0] = s;
+
+         /* We want to put it after the PHDR and INTERP segments.  */
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -9694,7 +12632,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
        {
          struct elf_segment_map *options_segment;
 
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -9724,7 +12662,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
              && bfd_get_section_by_name (abfd, ".dynamic") != NULL
              && bfd_get_section_by_name (abfd, ".mdebug") != NULL)
            {
-             for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+             for (m = elf_seg_map (abfd); m != NULL; m = m->next)
                if (m->p_type == PT_MIPS_RTPROC)
                  break;
              if (m == NULL)
@@ -9750,7 +12688,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
                    }
 
                  /* We want to put it after the DYNAMIC segment.  */
-                 pm = &elf_tdata (abfd)->segment_map;
+                 pm = &elf_seg_map (abfd);
                  while (*pm != NULL && (*pm)->p_type != PT_DYNAMIC)
                    pm = &(*pm)->next;
                  if (*pm != NULL)
@@ -9764,23 +12702,11 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic,
         .dynstr, .dynsym, and .hash sections, and everything in
         between.  */
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL;
+      for (pm = &elf_seg_map (abfd); *pm != NULL;
           pm = &(*pm)->next)
        if ((*pm)->p_type == PT_DYNAMIC)
          break;
       m = *pm;
-      if (m != NULL && IRIX_COMPAT (abfd) == ict_none)
-       {
-         /* For a normal mips executable the permissions for the PT_DYNAMIC
-            segment are read, write and execute. We do that here since
-            the code in elf.c sets only the read permission. This matters
-            sometimes for the dynamic linker.  */
-         if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
-           {
-             m->p_flags = PF_R | PF_W | PF_X;
-             m->p_flags_valid = 1;
-           }
-       }
       /* GNU/Linux binaries do not need the extended PT_DYNAMIC section.
         glibc's dynamic linker has traditionally derived the number of
         tags from the p_filesz field, and sometimes allocates stack
@@ -9871,7 +12797,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       && !SGI_COMPAT (abfd)
       && bfd_get_section_by_name (abfd, ".dynamic"))
     {
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next)
+      for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next)
        if ((*pm)->p_type == PT_NULL)
          break;
       if (*pm == NULL)
@@ -9911,51 +12837,31 @@ _bfd_mips_elf_gc_mark_hook (asection *sec,
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
-/* Update the got entry reference counts for the section being removed.  */
+/* Prevent .MIPS.abiflags from being discarded with --gc-sections.  */
 
 bfd_boolean
-_bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
-                            struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                            asection *sec ATTRIBUTE_UNUSED,
-                            const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
+_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
+                                     elf_gc_mark_hook_fn gc_mark_hook)
 {
-#if 0
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
-  unsigned long r_symndx;
-  struct elf_link_hash_entry *h;
+  bfd *sub;
 
-  if (info->relocatable)
-    return TRUE;
+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
+    {
+      asection *o;
 
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    switch (ELF_R_TYPE (abfd, rel->r_info))
-      {
-      case R_MIPS_GOT16:
-      case R_MIPS_CALL16:
-      case R_MIPS_CALL_HI16:
-      case R_MIPS_CALL_LO16:
-      case R_MIPS_GOT_HI16:
-      case R_MIPS_GOT_LO16:
-      case R_MIPS_GOT_DISP:
-      case R_MIPS_GOT_PAGE:
-      case R_MIPS_GOT_OFST:
-       /* ??? It would seem that the existing MIPS code does no sort
-          of reference counting or whatnot on its GOT and PLT entries,
-          so it is not possible to garbage collect them at this time.  */
-       break;
+      if (! is_mips_elf (sub))
+       continue;
 
-      default:
-       break;
-      }
-#endif
+      for (o = sub->sections; o != NULL; o = o->next)
+       if (!o->gc_mark
+           && MIPS_ELF_ABIFLAGS_SECTION_NAME_P (bfd_section_name (o)))
+         {
+           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+             return FALSE;
+         }
+    }
 
   return TRUE;
 }
@@ -9974,103 +12880,68 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
 
   _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 
+  dirmips = (struct mips_elf_link_hash_entry *) dir;
+  indmips = (struct mips_elf_link_hash_entry *) ind;
+  /* Any absolute non-dynamic relocations against an indirect or weak
+     definition will be against the target symbol.  */
+  if (indmips->has_static_relocs)
+    dirmips->has_static_relocs = TRUE;
+
   if (ind->root.type != bfd_link_hash_indirect)
     return;
 
-  dirmips = (struct mips_elf_link_hash_entry *) dir;
-  indmips = (struct mips_elf_link_hash_entry *) ind;
   dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
   if (indmips->readonly_reloc)
     dirmips->readonly_reloc = TRUE;
   if (indmips->no_fn_stub)
     dirmips->no_fn_stub = TRUE;
-
-  if (dirmips->tls_type == 0)
-    dirmips->tls_type = indmips->tls_type;
+  if (indmips->fn_stub)
+    {
+      dirmips->fn_stub = indmips->fn_stub;
+      indmips->fn_stub = NULL;
+    }
+  if (indmips->need_fn_stub)
+    {
+      dirmips->need_fn_stub = TRUE;
+      indmips->need_fn_stub = FALSE;
+    }
+  if (indmips->call_stub)
+    {
+      dirmips->call_stub = indmips->call_stub;
+      indmips->call_stub = NULL;
+    }
+  if (indmips->call_fp_stub)
+    {
+      dirmips->call_fp_stub = indmips->call_fp_stub;
+      indmips->call_fp_stub = NULL;
+    }
+  if (indmips->global_got_area < dirmips->global_got_area)
+    dirmips->global_got_area = indmips->global_got_area;
+  if (indmips->global_got_area < GGA_NONE)
+    indmips->global_got_area = GGA_NONE;
+  if (indmips->has_nonpic_branches)
+    dirmips->has_nonpic_branches = TRUE;
 }
 
+/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
+   to hide it.  It has to remain global (it will also be protected) so as to
+   be assigned a global GOT entry, which will then remain unchanged at load
+   time.  */
+
 void
 _bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
                           struct elf_link_hash_entry *entry,
                           bfd_boolean force_local)
 {
-  bfd *dynobj;
-  asection *got;
-  struct mips_got_info *g;
-  struct mips_elf_link_hash_entry *h;
   struct mips_elf_link_hash_table *htab;
 
-  h = (struct mips_elf_link_hash_entry *) entry;
-  if (h->forced_local)
-    return;
-  h->forced_local = force_local;
-
-  dynobj = elf_hash_table (info)->dynobj;
   htab = mips_elf_hash_table (info);
-  if (dynobj != NULL && force_local && h->root.type != STT_TLS
-      && (got = mips_elf_got_section (dynobj, TRUE)) != NULL
-      && (g = mips_elf_section_data (got)->u.got_info) != NULL)
-    {
-      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;
-         e.tls_type = 0;
-
-         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 (h->root.got.offset == 1)
-       {
-         /* check_relocs didn't know that this symbol would be
-            forced-local, so add an extra local got entry.  */
-         g->local_gotno++;
-         if (htab->computed_got_sizes)
-           {
-             /* We'll have treated this symbol as global rather
-                than local.  */
-             BFD_ASSERT (g->global_gotno > 0);
-             g->global_gotno--;
-           }
-       }
-      else if (htab->is_vxworks && h->root.needs_plt)
-       {
-         /* check_relocs didn't know that this symbol would be
-            forced-local, so add an extra local got entry.  */
-         g->local_gotno++;
-         if (htab->computed_got_sizes)
-           /* The symbol is only used in call relocations, so we'll
-              have assumed it only needs a .got.plt entry.  Increase
-              the size of .got accordingly.  */
-           got->size += MIPS_ELF_GOT_SIZE (dynobj);
-        }
-    }
+  BFD_ASSERT (htab != NULL);
+  if (htab->use_absolute_zero
+      && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
+    return;
 
-  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
+  _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
 }
 \f
 #define PDR_SIZE 32
@@ -10122,6 +12993,8 @@ _bfd_mips_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
   if (skip != 0)
     {
       mips_elf_section_data (o)->u.tdata = tdata;
+      if (o->rawsize == 0)
+       o->rawsize = o->size;
       o->size -= skip * PDR_SIZE;
       ret = TRUE;
     }
@@ -10145,7 +13018,7 @@ _bfd_mips_elf_ignore_discarded_relocs (asection *sec)
 bfd_boolean
 _bfd_mips_elf_write_section (bfd *output_bfd,
                             struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
-                             asection *sec, bfd_byte *contents)
+                            asection *sec, bfd_byte *contents)
 {
   bfd_byte *to, *from, *end;
   int i;
@@ -10173,6 +13046,15 @@ _bfd_mips_elf_write_section (bfd *output_bfd,
   return TRUE;
 }
 \f
+/* microMIPS code retains local labels for linker relaxation.  Omit them
+   from output by default for clarity.  */
+
+bfd_boolean
+_bfd_mips_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
+{
+  return _bfd_elf_is_local_label_name (abfd, sym->name);
+}
+
 /* MIPS ELF uses a special find_nearest_line routine in order the
    handle the ECOFF debugging information.  */
 
@@ -10183,24 +13065,33 @@ struct mips_elf_find_line
 };
 
 bfd_boolean
-_bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
-                                asymbol **symbols, bfd_vma offset,
+_bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols,
+                                asection *section, bfd_vma offset,
                                 const char **filename_ptr,
                                 const char **functionname_ptr,
-                                unsigned int *line_ptr)
+                                unsigned int *line_ptr,
+                                unsigned int *discriminator_ptr)
 {
   asection *msec;
 
-  if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr))
+                                    line_ptr, discriminator_ptr,
+                                    dwarf_debug_sections,
+                                    &elf_tdata (abfd)->dwarf2_find_line_info)
+      == 1)
     return TRUE;
 
-  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr, ABI_64_P (abfd) ? 8 : 0,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info))
-    return TRUE;
+                                    line_ptr))
+    {
+      if (!*functionname_ptr)
+       _bfd_elf_find_function (abfd, symbols, section, offset,
+                               *filename_ptr ? NULL : filename_ptr,
+                               functionname_ptr);
+      return TRUE;
+    }
 
   msec = bfd_get_section_by_name (abfd, ".mdebug");
   if (msec != NULL)
@@ -10217,7 +13108,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
       if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS)
        msec->flags |= SEC_HAS_CONTENTS;
 
-      fi = elf_tdata (abfd)->find_line_info;
+      fi = mips_elf_tdata (abfd)->find_line_info;
       if (fi == NULL)
        {
          bfd_size_type external_fdr_size;
@@ -10255,14 +13146,14 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
          for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
            (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr);
 
-         elf_tdata (abfd)->find_line_info = fi;
+         mips_elf_tdata (abfd)->find_line_info = fi;
 
          /* Note that we don't bother to ever free this information.
-             find_nearest_line is either called all the time, as in
-             objdump -l, so the information should be saved, or it is
-             rarely called, as in ld error messages, so the memory
-             wasted is unimportant.  Still, it would probably be a
-             good idea for free_cached_info to throw it away.  */
+            find_nearest_line is either called all the time, as in
+            objdump -l, so the information should be saved, or it is
+            rarely called, as in ld error messages, so the memory
+            wasted is unimportant.  Still, it would probably be a
+            good idea for free_cached_info to throw it away.  */
        }
 
       if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
@@ -10278,9 +13169,9 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
 
   /* Fall back on the generic ELF find_nearest_line routine.  */
 
-  return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
+  return _bfd_elf_find_nearest_line (abfd, symbols, section, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr);
+                                    line_ptr, discriminator_ptr);
 }
 
 bfd_boolean
@@ -10459,25 +13350,22 @@ _bfd_elf_mips_get_relocated_section_contents
              switch (r)
                {
                case bfd_reloc_undefined:
-                 if (!((*link_info->callbacks->undefined_symbol)
-                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        input_bfd, input_section, (*parent)->address, TRUE)))
-                   goto error_return;
+                 (*link_info->callbacks->undefined_symbol)
+                   (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    input_bfd, input_section, (*parent)->address, TRUE);
                  break;
                case bfd_reloc_dangerous:
                  BFD_ASSERT (error_message != NULL);
-                 if (!((*link_info->callbacks->reloc_dangerous)
-                       (link_info, error_message, input_bfd, input_section,
-                        (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_dangerous)
+                   (link_info, error_message,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_overflow:
-                 if (!((*link_info->callbacks->reloc_overflow)
-                       (link_info, NULL,
-                        bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        (*parent)->howto->name, (*parent)->addend,
-                        input_bfd, input_section, (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_overflow)
+                   (link_info, NULL,
+                    bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    (*parent)->howto->name, (*parent)->addend,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_outofrange:
                default:
@@ -10498,211 +13386,1419 @@ error_return:
   return NULL;
 }
 \f
-/* Create a MIPS ELF linker hash table.  */
-
-struct bfd_link_hash_table *
-_bfd_mips_elf_link_hash_table_create (bfd *abfd)
+static bfd_boolean
+mips_elf_relax_delete_bytes (bfd *abfd,
+                            asection *sec, bfd_vma addr, int count)
 {
-  struct mips_elf_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct mips_elf_link_hash_table);
-
-  ret = bfd_malloc (amt);
-  if (ret == NULL)
-    return NULL;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned int sec_shndx;
+  bfd_byte *contents;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry **end_hashes;
+  struct elf_link_hash_entry **start_hashes;
+  unsigned int symcount;
 
-  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
-                                     mips_elf_link_hash_newfunc,
-                                     sizeof (struct mips_elf_link_hash_entry)))
-    {
-      free (ret);
-      return NULL;
-    }
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+  contents = elf_section_data (sec)->this_hdr.contents;
 
-#if 0
-  /* We no longer use this.  */
-  for (i = 0; i < SIZEOF_MIPS_DYNSYM_SECNAMES; i++)
-    ret->dynsym_sec_strindex[i] = (bfd_size_type) -1;
-#endif
-  ret->procedure_count = 0;
-  ret->compact_rel_size = 0;
-  ret->use_rld_obj_head = FALSE;
-  ret->rld_value = 0;
-  ret->mips16_stubs_seen = FALSE;
-  ret->computed_got_sizes = FALSE;
-  ret->is_vxworks = FALSE;
-  ret->small_data_overflow_reported = FALSE;
-  ret->srelbss = NULL;
-  ret->sdynbss = NULL;
-  ret->srelplt = NULL;
-  ret->srelplt2 = NULL;
-  ret->sgotplt = NULL;
-  ret->splt = NULL;
-  ret->plt_header_size = 0;
-  ret->plt_entry_size = 0;
-  ret->function_stub_size = 0;
+  irel = elf_section_data (sec)->relocs;
+  irelend = irel + sec->reloc_count;
 
-  return &ret->root.root;
-}
+  /* Actually delete the bytes.  */
+  memmove (contents + addr, contents + addr + count,
+          (size_t) (sec->size - addr - count));
+  sec->size -= count;
 
-/* Likewise, but indicate that the target is VxWorks.  */
+  /* Adjust all the relocs.  */
+  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+    {
+      /* Get the new reloc address.  */
+      if (irel->r_offset > addr)
+       irel->r_offset -= count;
+    }
 
-struct bfd_link_hash_table *
-_bfd_mips_vxworks_link_hash_table_create (bfd *abfd)
-{
-  struct bfd_link_hash_table *ret;
+  BFD_ASSERT (addr % 2 == 0);
+  BFD_ASSERT (count % 2 == 0);
 
-  ret = _bfd_mips_elf_link_hash_table_create (abfd);
-  if (ret)
+  /* Adjust the local symbols defined in this section.  */
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
+    if (isym->st_shndx == sec_shndx && isym->st_value > addr)
+      isym->st_value -= count;
+
+  /* Now adjust the global symbols defined in this section.  */
+  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+             - symtab_hdr->sh_info);
+  sym_hashes = start_hashes = elf_sym_hashes (abfd);
+  end_hashes = sym_hashes + symcount;
+
+  for (; sym_hashes < end_hashes; sym_hashes++)
     {
-      struct mips_elf_link_hash_table *htab;
+      struct elf_link_hash_entry *sym_hash = *sym_hashes;
 
-      htab = (struct mips_elf_link_hash_table *) ret;
-      htab->is_vxworks = 1;
+      if ((sym_hash->root.type == bfd_link_hash_defined
+          || sym_hash->root.type == bfd_link_hash_defweak)
+         && sym_hash->root.u.def.section == sec)
+       {
+         bfd_vma value = sym_hash->root.u.def.value;
+
+         if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+           value &= MINUS_TWO;
+         if (value > addr)
+           sym_hash->root.u.def.value -= count;
+       }
     }
-  return ret;
+
+  return TRUE;
 }
-\f
-/* We need to use a special link routine to handle the .reginfo and
-   the .mdebug sections.  We need to merge all instances of these
-   sections together, not write them all out sequentially.  */
 
-bfd_boolean
-_bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
-{
-  asection *o;
-  struct bfd_link_order *p;
-  asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
-  asection *rtproc_sec;
-  Elf32_RegInfo reginfo;
-  struct ecoff_debug_info debug;
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap;
-  HDRR *symhdr = &debug.symbolic_header;
-  void *mdebug_handle = NULL;
-  asection *s;
-  EXTR esym;
-  unsigned int i;
-  bfd_size_type amt;
-  struct mips_elf_link_hash_table *htab;
 
-  static const char * const secname[] =
-  {
-    ".text", ".init", ".fini", ".data",
-    ".rodata", ".sdata", ".sbss", ".bss"
-  };
-  static const int sc[] =
-  {
-    scText, scInit, scFini, scData,
-    scRData, scSData, scSBss, scBss
-  };
+/* Opcodes needed for microMIPS relaxation as found in
+   opcodes/micromips-opc.c.  */
 
-  /* 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
-     the sort again.  */
-  htab = mips_elf_hash_table (info);
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      bfd *dynobj;
-      asection *got;
-      struct mips_got_info *g;
-      bfd_size_type dynsecsymcount;
+struct opcode_descriptor {
+  unsigned long match;
+  unsigned long mask;
+};
 
-      /* When we resort, we must tell mips_elf_sort_hash_table what
-        the lowest index it may use is.  That's the number of section
-        symbols we're going to add.  The generic ELF linker only
-        adds these symbols when building a shared object.  Note that
-        we count the sections after (possibly) removing the .options
-        section above.  */
+/* The $ra register aka $31.  */
 
-      dynsecsymcount = count_section_dynsyms (abfd, info);
-      if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1))
-       return FALSE;
+#define RA 31
 
-      /* Make sure we didn't grow the global .got region.  */
-      dynobj = elf_hash_table (info)->dynobj;
-      got = mips_elf_got_section (dynobj, FALSE);
-      g = mips_elf_section_data (got)->u.got_info;
+/* 32-bit instruction format register fields.  */
 
-      if (g->global_gotsym != NULL)
-       BFD_ASSERT ((elf_hash_table (info)->dynsymcount
-                    - g->global_gotsym->dynindx)
-                   <= g->global_gotno);
-    }
+#define OP32_SREG(opcode) (((opcode) >> 16) & 0x1f)
+#define OP32_TREG(opcode) (((opcode) >> 21) & 0x1f)
 
-  /* Get a value for the GP register.  */
-  if (elf_gp (abfd) == 0)
-    {
-      struct bfd_link_hash_entry *h;
+/* Check if a 5-bit register index can be abbreviated to 3 bits.  */
 
-      h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE);
-      if (h != NULL && h->type == bfd_link_hash_defined)
-       elf_gp (abfd) = (h->u.def.value
-                        + h->u.def.section->output_section->vma
-                        + h->u.def.section->output_offset);
-      else if (htab->is_vxworks
-              && (h = bfd_link_hash_lookup (info->hash,
-                                            "_GLOBAL_OFFSET_TABLE_",
-                                            FALSE, FALSE, TRUE))
-              && h->type == bfd_link_hash_defined)
-       elf_gp (abfd) = (h->u.def.section->output_section->vma
-                        + h->u.def.section->output_offset
-                        + h->u.def.value);
-      else if (info->relocatable)
-       {
-         bfd_vma lo = MINUS_ONE;
+#define OP16_VALID_REG(r) \
+  ((2 <= (r) && (r) <= 7) || (16 <= (r) && (r) <= 17))
 
-         /* Find the GP-relative section with the lowest offset.  */
-         for (o = abfd->sections; o != NULL; o = o->next)
-           if (o->vma < lo
-               && (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL))
-             lo = o->vma;
 
-         /* And calculate GP relative to that.  */
-         elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (info);
-       }
-      else
-       {
-         /* If the relocate_section function needs to do a reloc
-            involving the GP value, it should make a reloc_dangerous
-            callback to warn that GP is not defined.  */
-       }
-    }
+/* 32-bit and 16-bit branches.  */
 
-  /* Go through the sections and collect the .reginfo and .mdebug
-     information.  */
-  reginfo_sec = NULL;
-  mdebug_sec = NULL;
-  gptab_data_sec = NULL;
-  gptab_bss_sec = NULL;
-  for (o = abfd->sections; o != NULL; o = o->next)
-    {
-      if (strcmp (o->name, ".reginfo") == 0)
-       {
-         memset (&reginfo, 0, sizeof reginfo);
+static const struct opcode_descriptor b_insns_32[] = {
+  { /* "b",    "p",            */ 0x40400000, 0xffff0000 }, /* bgez 0 */
+  { /* "b",    "p",            */ 0x94000000, 0xffff0000 }, /* beq 0, 0 */
+  { 0, 0 }  /* End marker for find_match().  */
+};
 
-         /* We have found the .reginfo section in the output file.
-            Look through all the link_orders comprising it and merge
-            the information together.  */
-         for (p = o->map_head.link_order; p != NULL; p = p->next)
-           {
-             asection *input_section;
-             bfd *input_bfd;
-             Elf32_External_RegInfo ext;
-             Elf32_RegInfo sub;
+static const struct opcode_descriptor bc_insn_32 =
+  { /* "bc(1|2)(ft)", "N,p",   */ 0x42800000, 0xfec30000 };
 
-             if (p->type != bfd_indirect_link_order)
-               {
-                 if (p->type == bfd_data_link_order)
-                   continue;
-                 abort ();
-               }
+static const struct opcode_descriptor bz_insn_32 =
+  { /* "b(g|l)(e|t)z", "s,p",  */ 0x40000000, 0xff200000 };
 
-             input_section = p->u.indirect.section;
-             input_bfd = input_section->owner;
+static const struct opcode_descriptor bzal_insn_32 =
+  { /* "b(ge|lt)zal", "s,p",   */ 0x40200000, 0xffa00000 };
 
+static const struct opcode_descriptor beq_insn_32 =
+  { /* "b(eq|ne)", "s,t,p",    */ 0x94000000, 0xdc000000 };
+
+static const struct opcode_descriptor b_insn_16 =
+  { /* "b",    "mD",           */ 0xcc00,     0xfc00 };
+
+static const struct opcode_descriptor bz_insn_16 =
+  { /* "b(eq|ne)z", "md,mE",   */ 0x8c00,     0xdc00 };
+
+
+/* 32-bit and 16-bit branch EQ and NE zero.  */
+
+/* NOTE: All opcode tables have BEQ/BNE in the same order: first the
+   eq and second the ne.  This convention is used when replacing a
+   32-bit BEQ/BNE with the 16-bit version.  */
+
+#define BZC32_REG_FIELD(r) (((r) & 0x1f) << 16)
+
+static const struct opcode_descriptor bz_rs_insns_32[] = {
+  { /* "beqz", "s,p",          */ 0x94000000, 0xffe00000 },
+  { /* "bnez", "s,p",          */ 0xb4000000, 0xffe00000 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+static const struct opcode_descriptor bz_rt_insns_32[] = {
+  { /* "beqz", "t,p",          */ 0x94000000, 0xfc01f000 },
+  { /* "bnez", "t,p",          */ 0xb4000000, 0xfc01f000 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+static const struct opcode_descriptor bzc_insns_32[] = {
+  { /* "beqzc",        "s,p",          */ 0x40e00000, 0xffe00000 },
+  { /* "bnezc",        "s,p",          */ 0x40a00000, 0xffe00000 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+static const struct opcode_descriptor bz_insns_16[] = {
+  { /* "beqz", "md,mE",        */ 0x8c00,     0xfc00 },
+  { /* "bnez", "md,mE",        */ 0xac00,     0xfc00 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+/* Switch between a 5-bit register index and its 3-bit shorthand.  */
+
+#define BZ16_REG(opcode) ((((((opcode) >> 7) & 7) + 0x1e) & 0xf) + 2)
+#define BZ16_REG_FIELD(r) (((r) & 7) << 7)
+
+
+/* 32-bit instructions with a delay slot.  */
+
+static const struct opcode_descriptor jal_insn_32_bd16 =
+  { /* "jals", "a",            */ 0x74000000, 0xfc000000 };
+
+static const struct opcode_descriptor jal_insn_32_bd32 =
+  { /* "jal",  "a",            */ 0xf4000000, 0xfc000000 };
+
+static const struct opcode_descriptor jal_x_insn_32_bd32 =
+  { /* "jal[x]", "a",          */ 0xf0000000, 0xf8000000 };
+
+static const struct opcode_descriptor j_insn_32 =
+  { /* "j",    "a",            */ 0xd4000000, 0xfc000000 };
+
+static const struct opcode_descriptor jalr_insn_32 =
+  { /* "jalr[.hb]", "t,s",     */ 0x00000f3c, 0xfc00efff };
+
+/* This table can be compacted, because no opcode replacement is made.  */
+
+static const struct opcode_descriptor ds_insns_32_bd16[] = {
+  { /* "jals", "a",            */ 0x74000000, 0xfc000000 },
+
+  { /* "jalrs[.hb]", "t,s",    */ 0x00004f3c, 0xfc00efff },
+  { /* "b(ge|lt)zals", "s,p",  */ 0x42200000, 0xffa00000 },
+
+  { /* "b(g|l)(e|t)z", "s,p",  */ 0x40000000, 0xff200000 },
+  { /* "b(eq|ne)", "s,t,p",    */ 0x94000000, 0xdc000000 },
+  { /* "j",    "a",            */ 0xd4000000, 0xfc000000 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+/* This table can be compacted, because no opcode replacement is made.  */
+
+static const struct opcode_descriptor ds_insns_32_bd32[] = {
+  { /* "jal[x]", "a",          */ 0xf0000000, 0xf8000000 },
+
+  { /* "jalr[.hb]", "t,s",     */ 0x00000f3c, 0xfc00efff },
+  { /* "b(ge|lt)zal", "s,p",   */ 0x40200000, 0xffa00000 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+
+/* 16-bit instructions with a delay slot.  */
+
+static const struct opcode_descriptor jalr_insn_16_bd16 =
+  { /* "jalrs",        "my,mj",        */ 0x45e0,     0xffe0 };
+
+static const struct opcode_descriptor jalr_insn_16_bd32 =
+  { /* "jalr", "my,mj",        */ 0x45c0,     0xffe0 };
+
+static const struct opcode_descriptor jr_insn_16 =
+  { /* "jr",   "mj",           */ 0x4580,     0xffe0 };
+
+#define JR16_REG(opcode) ((opcode) & 0x1f)
+
+/* This table can be compacted, because no opcode replacement is made.  */
+
+static const struct opcode_descriptor ds_insns_16_bd16[] = {
+  { /* "jalrs",        "my,mj",        */ 0x45e0,     0xffe0 },
+
+  { /* "b",    "mD",           */ 0xcc00,     0xfc00 },
+  { /* "b(eq|ne)z", "md,mE",   */ 0x8c00,     0xdc00 },
+  { /* "jr",   "mj",           */ 0x4580,     0xffe0 },
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+
+/* LUI instruction.  */
+
+static const struct opcode_descriptor lui_insn =
+ { /* "lui",   "s,u",          */ 0x41a00000, 0xffe00000 };
+
+
+/* ADDIU instruction.  */
+
+static const struct opcode_descriptor addiu_insn =
+  { /* "addiu",        "t,r,j",        */ 0x30000000, 0xfc000000 };
+
+static const struct opcode_descriptor addiupc_insn =
+  { /* "addiu",        "mb,$pc,mQ",    */ 0x78000000, 0xfc000000 };
+
+#define ADDIUPC_REG_FIELD(r) \
+  (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 23)
+
+
+/* Relaxable instructions in a JAL delay slot: MOVE.  */
+
+/* The 16-bit move has rd in 9:5 and rs in 4:0.  The 32-bit moves
+   (ADDU, OR) have rd in 15:11 and rs in 10:16.  */
+#define MOVE32_RD(opcode) (((opcode) >> 11) & 0x1f)
+#define MOVE32_RS(opcode) (((opcode) >> 16) & 0x1f)
+
+#define MOVE16_RD_FIELD(r) (((r) & 0x1f) << 5)
+#define MOVE16_RS_FIELD(r) (((r) & 0x1f)     )
+
+static const struct opcode_descriptor move_insns_32[] = {
+  { /* "move", "d,s",          */ 0x00000290, 0xffe007ff }, /* or   d,s,$0 */
+  { /* "move", "d,s",          */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */
+  { 0, 0 }  /* End marker for find_match().  */
+};
+
+static const struct opcode_descriptor move_insn_16 =
+  { /* "move", "mp,mj",        */ 0x0c00,     0xfc00 };
+
+
+/* NOP instructions.  */
+
+static const struct opcode_descriptor nop_insn_32 =
+  { /* "nop",  "",             */ 0x00000000, 0xffffffff };
+
+static const struct opcode_descriptor nop_insn_16 =
+  { /* "nop",  "",             */ 0x0c00,     0xffff };
+
+
+/* Instruction match support.  */
+
+#define MATCH(opcode, insn) ((opcode & insn.mask) == insn.match)
+
+static int
+find_match (unsigned long opcode, const struct opcode_descriptor insn[])
+{
+  unsigned long indx;
+
+  for (indx = 0; insn[indx].mask != 0; indx++)
+    if (MATCH (opcode, insn[indx]))
+      return indx;
+
+  return -1;
+}
+
+
+/* Branch and delay slot decoding support.  */
+
+/* If PTR points to what *might* be a 16-bit branch or jump, then
+   return the minimum length of its delay slot, otherwise return 0.
+   Non-zero results are not definitive as we might be checking against
+   the second half of another instruction.  */
+
+static int
+check_br16_dslot (bfd *abfd, bfd_byte *ptr)
+{
+  unsigned long opcode;
+  int bdsize;
+
+  opcode = bfd_get_16 (abfd, ptr);
+  if (MATCH (opcode, jalr_insn_16_bd32) != 0)
+    /* 16-bit branch/jump with a 32-bit delay slot.  */
+    bdsize = 4;
+  else if (MATCH (opcode, jalr_insn_16_bd16) != 0
+          || find_match (opcode, ds_insns_16_bd16) >= 0)
+    /* 16-bit branch/jump with a 16-bit delay slot.  */
+    bdsize = 2;
+  else
+    /* No delay slot.  */
+    bdsize = 0;
+
+  return bdsize;
+}
+
+/* If PTR points to what *might* be a 32-bit branch or jump, then
+   return the minimum length of its delay slot, otherwise return 0.
+   Non-zero results are not definitive as we might be checking against
+   the second half of another instruction.  */
+
+static int
+check_br32_dslot (bfd *abfd, bfd_byte *ptr)
+{
+  unsigned long opcode;
+  int bdsize;
+
+  opcode = bfd_get_micromips_32 (abfd, ptr);
+  if (find_match (opcode, ds_insns_32_bd32) >= 0)
+    /* 32-bit branch/jump with a 32-bit delay slot.  */
+    bdsize = 4;
+  else if (find_match (opcode, ds_insns_32_bd16) >= 0)
+    /* 32-bit branch/jump with a 16-bit delay slot.  */
+    bdsize = 2;
+  else
+    /* No delay slot.  */
+    bdsize = 0;
+
+  return bdsize;
+}
+
+/* If PTR points to a 16-bit branch or jump with a 32-bit delay slot
+   that doesn't fiddle with REG, then return TRUE, otherwise FALSE.  */
+
+static bfd_boolean
+check_br16 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
+{
+  unsigned long opcode;
+
+  opcode = bfd_get_16 (abfd, ptr);
+  if (MATCH (opcode, b_insn_16)
+                                               /* B16  */
+      || (MATCH (opcode, jr_insn_16) && reg != JR16_REG (opcode))
+                                               /* JR16  */
+      || (MATCH (opcode, bz_insn_16) && reg != BZ16_REG (opcode))
+                                               /* BEQZ16, BNEZ16  */
+      || (MATCH (opcode, jalr_insn_16_bd32)
+                                               /* JALR16  */
+         && reg != JR16_REG (opcode) && reg != RA))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
+   then return TRUE, otherwise FALSE.  */
+
+static bfd_boolean
+check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
+{
+  unsigned long opcode;
+
+  opcode = bfd_get_micromips_32 (abfd, ptr);
+  if (MATCH (opcode, j_insn_32)
+                                               /* J  */
+      || MATCH (opcode, bc_insn_32)
+                                               /* BC1F, BC1T, BC2F, BC2T  */
+      || (MATCH (opcode, jal_x_insn_32_bd32) && reg != RA)
+                                               /* JAL, JALX  */
+      || (MATCH (opcode, bz_insn_32) && reg != OP32_SREG (opcode))
+                                               /* BGEZ, BGTZ, BLEZ, BLTZ  */
+      || (MATCH (opcode, bzal_insn_32)
+                                               /* BGEZAL, BLTZAL  */
+         && reg != OP32_SREG (opcode) && reg != RA)
+      || ((MATCH (opcode, jalr_insn_32) || MATCH (opcode, beq_insn_32))
+                                               /* JALR, JALR.HB, BEQ, BNE  */
+         && reg != OP32_SREG (opcode) && reg != OP32_TREG (opcode)))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+   IRELEND) at OFFSET indicate that there must be a compact branch there,
+   then return TRUE, otherwise FALSE.  */
+
+static bfd_boolean
+check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+                    const Elf_Internal_Rela *internal_relocs,
+                    const Elf_Internal_Rela *irelend)
+{
+  const Elf_Internal_Rela *irel;
+  unsigned long opcode;
+
+  opcode = bfd_get_micromips_32 (abfd, ptr);
+  if (find_match (opcode, bzc_insns_32) < 0)
+    return FALSE;
+
+  for (irel = internal_relocs; irel < irelend; irel++)
+    if (irel->r_offset == offset
+       && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+      return TRUE;
+
+  return FALSE;
+}
+
+/* Bitsize checking.  */
+#define IS_BITSIZE(val, N)                                             \
+  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))              \
+    - (1ULL << ((N) - 1))) == (val))
+
+\f
+bfd_boolean
+_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
+                            struct bfd_link_info *link_info,
+                            bfd_boolean *again)
+{
+  bfd_boolean insn32 = mips_elf_hash_table (link_info)->insn32;
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel, *irelend;
+  bfd_byte *contents = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
+
+  /* Assume nothing changes.  */
+  *again = FALSE;
+
+  /* We don't have to do anything for a relocatable link, if
+     this section does not have relocs, or if this is not a
+     code section.  */
+
+  if (bfd_link_relocatable (link_info)
+      || (sec->flags & SEC_RELOC) == 0
+      || sec->reloc_count == 0
+      || (sec->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+  /* Get a copy of the native relocations.  */
+  internal_relocs = (_bfd_elf_link_read_relocs
+                    (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
+                     link_info->keep_memory));
+  if (internal_relocs == NULL)
+    goto error_return;
+
+  /* Walk through them looking for relaxing opportunities.  */
+  irelend = internal_relocs + sec->reloc_count;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
+      unsigned int r_type = ELF32_R_TYPE (irel->r_info);
+      bfd_boolean target_is_micromips_code_p;
+      unsigned long opcode;
+      bfd_vma symval;
+      bfd_vma pcrval;
+      bfd_byte *ptr;
+      int fndopc;
+
+      /* The number of bytes to delete for relaxation and from where
+        to delete these bytes starting at irel->r_offset.  */
+      int delcnt = 0;
+      int deloff = 0;
+
+      /* If this isn't something that can be relaxed, then ignore
+        this reloc.  */
+      if (r_type != R_MICROMIPS_HI16
+         && r_type != R_MICROMIPS_PC16_S1
+         && r_type != R_MICROMIPS_26_S1)
+       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;
+         /* Go get them off disk.  */
+         else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+           goto error_return;
+       }
+      ptr = contents + irel->r_offset;
+
+      /* Read this BFD's local 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 error_return;
+       }
+
+      /* Get the value of the symbol referred to by the reloc.  */
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         /* A local symbol.  */
+         Elf_Internal_Sym *isym;
+         asection *sym_sec;
+
+         isym = isymbuf + r_symndx;
+         if (isym->st_shndx == SHN_UNDEF)
+           sym_sec = bfd_und_section_ptr;
+         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);
+         target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
+       }
+      else
+       {
+         unsigned long indx;
+         struct elf_link_hash_entry *h;
+
+         /* An external symbol.  */
+         indx = r_symndx - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+         BFD_ASSERT (h != NULL);
+
+         if (h->root.type != bfd_link_hash_defined
+             && h->root.type != bfd_link_hash_defweak)
+           /* This appears to be a reference to an undefined
+              symbol.  Just ignore it -- it will be caught by the
+              regular reloc processing.  */
+           continue;
+
+         symval = (h->root.u.def.value
+                   + h->root.u.def.section->output_section->vma
+                   + h->root.u.def.section->output_offset);
+         target_is_micromips_code_p = (!h->needs_plt
+                                       && ELF_ST_IS_MICROMIPS (h->other));
+       }
+
+
+      /* For simplicity of coding, we are going to modify the
+        section contents, the section relocs, and the BFD symbol
+        table.  We must tell the rest of the code not to free up this
+        information.  It would be possible to instead create a table
+        of changes which have to be made, as is done in coff-mips.c;
+        that would be more work, but would require less memory when
+        the linker is run.  */
+
+      /* Only 32-bit instructions relaxed.  */
+      if (irel->r_offset + 4 > sec->size)
+       continue;
+
+      opcode = bfd_get_micromips_32 (abfd, ptr);
+
+      /* This is the pc-relative distance from the instruction the
+        relocation is applied to, to the symbol referred.  */
+      pcrval = (symval
+               - (sec->output_section->vma + sec->output_offset)
+               - irel->r_offset);
+
+      /* R_MICROMIPS_HI16 / LUI relaxation to nil, performing relaxation
+        of corresponding R_MICROMIPS_LO16 to R_MICROMIPS_HI0_LO16 or
+        R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
+
+          (symval % 4 == 0 && IS_BITSIZE (pcrval, 25))
+
+        where pcrval has first to be adjusted to apply against the LO16
+        location (we make the adjustment later on, when we have figured
+        out the offset).  */
+      if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
+       {
+         bfd_boolean bzc = FALSE;
+         unsigned long nextopc;
+         unsigned long reg;
+         bfd_vma offset;
+
+         /* Give up if the previous reloc was a HI16 against this symbol
+            too.  */
+         if (irel > internal_relocs
+             && ELF32_R_TYPE (irel[-1].r_info) == R_MICROMIPS_HI16
+             && ELF32_R_SYM (irel[-1].r_info) == r_symndx)
+           continue;
+
+         /* Or if the next reloc is not a LO16 against this symbol.  */
+         if (irel + 1 >= irelend
+             || ELF32_R_TYPE (irel[1].r_info) != R_MICROMIPS_LO16
+             || ELF32_R_SYM (irel[1].r_info) != r_symndx)
+           continue;
+
+         /* Or if the second next reloc is a LO16 against this symbol too.  */
+         if (irel + 2 >= irelend
+             && ELF32_R_TYPE (irel[2].r_info) == R_MICROMIPS_LO16
+             && ELF32_R_SYM (irel[2].r_info) == r_symndx)
+           continue;
+
+         /* See if the LUI instruction *might* be in a branch delay slot.
+            We check whether what looks like a 16-bit branch or jump is
+            actually an immediate argument to a compact branch, and let
+            it through if so.  */
+         if (irel->r_offset >= 2
+             && check_br16_dslot (abfd, ptr - 2)
+             && !(irel->r_offset >= 4
+                  && (bzc = check_relocated_bzc (abfd,
+                                                 ptr - 4, irel->r_offset - 4,
+                                                 internal_relocs, irelend))))
+           continue;
+         if (irel->r_offset >= 4
+             && !bzc
+             && check_br32_dslot (abfd, ptr - 4))
+           continue;
+
+         reg = OP32_SREG (opcode);
+
+         /* We only relax adjacent instructions or ones separated with
+            a branch or jump that has a delay slot.  The branch or jump
+            must not fiddle with the register used to hold the address.
+            Subtract 4 for the LUI itself.  */
+         offset = irel[1].r_offset - irel[0].r_offset;
+         switch (offset - 4)
+           {
+           case 0:
+             break;
+           case 2:
+             if (check_br16 (abfd, ptr + 4, reg))
+               break;
+             continue;
+           case 4:
+             if (check_br32 (abfd, ptr + 4, reg))
+               break;
+             continue;
+           default:
+             continue;
+           }
+
+         nextopc = bfd_get_micromips_32 (abfd, contents + irel[1].r_offset);
+
+         /* Give up unless the same register is used with both
+            relocations.  */
+         if (OP32_SREG (nextopc) != reg)
+           continue;
+
+         /* Now adjust pcrval, subtracting the offset to the LO16 reloc
+            and rounding up to take masking of the two LSBs into account.  */
+         pcrval = ((pcrval - offset + 3) | 3) ^ 3;
+
+         /* R_MICROMIPS_LO16 relaxation to R_MICROMIPS_HI0_LO16.  */
+         if (IS_BITSIZE (symval, 16))
+           {
+             /* Fix the relocation's type.  */
+             irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_HI0_LO16);
+
+             /* Instructions using R_MICROMIPS_LO16 have the base or
+                source register in bits 20:16.  This register becomes $0
+                (zero) as the result of the R_MICROMIPS_HI16 being 0.  */
+             nextopc &= ~0x001f0000;
+             bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
+                         contents + irel[1].r_offset);
+           }
+
+         /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.
+            We add 4 to take LUI deletion into account while checking
+            the PC-relative distance.  */
+         else if (symval % 4 == 0
+                  && IS_BITSIZE (pcrval + 4, 25)
+                  && MATCH (nextopc, addiu_insn)
+                  && OP32_TREG (nextopc) == OP32_SREG (nextopc)
+                  && OP16_VALID_REG (OP32_TREG (nextopc)))
+           {
+             /* Fix the relocation's type.  */
+             irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC23_S2);
+
+             /* Replace ADDIU with the ADDIUPC version.  */
+             nextopc = (addiupc_insn.match
+                        | ADDIUPC_REG_FIELD (OP32_TREG (nextopc)));
+
+             bfd_put_micromips_32 (abfd, nextopc,
+                                   contents + irel[1].r_offset);
+           }
+
+         /* Can't do anything, give up, sigh...  */
+         else
+           continue;
+
+         /* Fix the relocation's type.  */
+         irel->r_info = ELF32_R_INFO (r_symndx, R_MIPS_NONE);
+
+         /* Delete the LUI instruction: 4 bytes at irel->r_offset.  */
+         delcnt = 4;
+         deloff = 0;
+       }
+
+      /* Compact branch relaxation -- due to the multitude of macros
+        employed by the compiler/assembler, compact branches are not
+        always generated.  Obviously, this can/will be fixed elsewhere,
+        but there is no drawback in double checking it here.  */
+      else if (r_type == R_MICROMIPS_PC16_S1
+              && irel->r_offset + 5 < sec->size
+              && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
+                  || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
+              && ((!insn32
+                   && (delcnt = MATCH (bfd_get_16 (abfd, ptr + 4),
+                                       nop_insn_16) ? 2 : 0))
+                  || (irel->r_offset + 7 < sec->size
+                      && (delcnt = MATCH (bfd_get_micromips_32 (abfd,
+                                                                ptr + 4),
+                                          nop_insn_32) ? 4 : 0))))
+       {
+         unsigned long reg;
+
+         reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
+
+         /* Replace BEQZ/BNEZ with the compact version.  */
+         opcode = (bzc_insns_32[fndopc].match
+                   | BZC32_REG_FIELD (reg)
+                   | (opcode & 0xffff));               /* Addend value.  */
+
+         bfd_put_micromips_32 (abfd, opcode, ptr);
+
+         /* Delete the delay slot NOP: two or four bytes from
+            irel->offset + 4; delcnt has already been set above.  */
+         deloff = 4;
+       }
+
+      /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1.  We need
+        to check the distance from the next instruction, so subtract 2.  */
+      else if (!insn32
+              && r_type == R_MICROMIPS_PC16_S1
+              && IS_BITSIZE (pcrval - 2, 11)
+              && find_match (opcode, b_insns_32) >= 0)
+       {
+         /* Fix the relocation's type.  */
+         irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC10_S1);
+
+         /* Replace the 32-bit opcode with a 16-bit opcode.  */
+         bfd_put_16 (abfd,
+                     (b_insn_16.match
+                      | (opcode & 0x3ff)),             /* Addend value.  */
+                     ptr);
+
+         /* Delete 2 bytes from irel->r_offset + 2.  */
+         delcnt = 2;
+         deloff = 2;
+       }
+
+      /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1.  We need
+        to check the distance from the next instruction, so subtract 2.  */
+      else if (!insn32
+              && r_type == R_MICROMIPS_PC16_S1
+              && IS_BITSIZE (pcrval - 2, 8)
+              && (((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
+                   && OP16_VALID_REG (OP32_SREG (opcode)))
+                  || ((fndopc = find_match (opcode, bz_rt_insns_32)) >= 0
+                      && OP16_VALID_REG (OP32_TREG (opcode)))))
+       {
+         unsigned long reg;
+
+         reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
+
+         /* Fix the relocation's type.  */
+         irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC7_S1);
+
+         /* Replace the 32-bit opcode with a 16-bit opcode.  */
+         bfd_put_16 (abfd,
+                     (bz_insns_16[fndopc].match
+                      | BZ16_REG_FIELD (reg)
+                      | (opcode & 0x7f)),              /* Addend value.  */
+                     ptr);
+
+         /* Delete 2 bytes from irel->r_offset + 2.  */
+         delcnt = 2;
+         deloff = 2;
+       }
+
+      /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets.  */
+      else if (!insn32
+              && r_type == R_MICROMIPS_26_S1
+              && target_is_micromips_code_p
+              && irel->r_offset + 7 < sec->size
+              && MATCH (opcode, jal_insn_32_bd32))
+       {
+         unsigned long n32opc;
+         bfd_boolean relaxed = FALSE;
+
+         n32opc = bfd_get_micromips_32 (abfd, ptr + 4);
+
+         if (MATCH (n32opc, nop_insn_32))
+           {
+             /* Replace delay slot 32-bit NOP with a 16-bit NOP.  */
+             bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
+
+             relaxed = TRUE;
+           }
+         else if (find_match (n32opc, move_insns_32) >= 0)
+           {
+             /* Replace delay slot 32-bit MOVE with 16-bit MOVE.  */
+             bfd_put_16 (abfd,
+                         (move_insn_16.match
+                          | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
+                          | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
+                         ptr + 4);
+
+             relaxed = TRUE;
+           }
+         /* Other 32-bit instructions relaxable to 16-bit
+            instructions will be handled here later.  */
+
+         if (relaxed)
+           {
+             /* JAL with 32-bit delay slot that is changed to a JALS
+                with 16-bit delay slot.  */
+             bfd_put_micromips_32 (abfd, jal_insn_32_bd16.match, ptr);
+
+             /* Delete 2 bytes from irel->r_offset + 6.  */
+             delcnt = 2;
+             deloff = 6;
+           }
+       }
+
+      if (delcnt != 0)
+       {
+         /* Note that we've changed the relocs, section contents, etc.  */
+         elf_section_data (sec)->relocs = internal_relocs;
+         elf_section_data (sec)->this_hdr.contents = contents;
+         symtab_hdr->contents = (unsigned char *) isymbuf;
+
+         /* Delete bytes depending on the delcnt and deloff.  */
+         if (!mips_elf_relax_delete_bytes (abfd, sec,
+                                           irel->r_offset + deloff, delcnt))
+           goto error_return;
+
+         /* That will change things, so we should relax again.
+            Note that this is not required, and it may be slow.  */
+         *again = TRUE;
+       }
+    }
+
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
+    {
+      if (! link_info->keep_memory)
+       free (isymbuf);
+      else
+       {
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
+       }
+    }
+
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    {
+      if (! link_info->keep_memory)
+       free (contents);
+      else
+       {
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
+       }
+    }
+
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
+
+  return TRUE;
+
+ error_return:
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
+    free (isymbuf);
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
+
+  return FALSE;
+}
+\f
+/* Create a MIPS ELF linker hash table.  */
+
+struct bfd_link_hash_table *
+_bfd_mips_elf_link_hash_table_create (bfd *abfd)
+{
+  struct mips_elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct mips_elf_link_hash_table);
+
+  ret = bfd_zmalloc (amt);
+  if (ret == NULL)
+    return NULL;
+
+  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+                                     mips_elf_link_hash_newfunc,
+                                     sizeof (struct mips_elf_link_hash_entry),
+                                     MIPS_ELF_DATA))
+    {
+      free (ret);
+      return NULL;
+    }
+  ret->root.init_plt_refcount.plist = NULL;
+  ret->root.init_plt_offset.plist = NULL;
+
+  return &ret->root.root;
+}
+
+/* Likewise, but indicate that the target is VxWorks.  */
+
+struct bfd_link_hash_table *
+_bfd_mips_vxworks_link_hash_table_create (bfd *abfd)
+{
+  struct bfd_link_hash_table *ret;
+
+  ret = _bfd_mips_elf_link_hash_table_create (abfd);
+  if (ret)
+    {
+      struct mips_elf_link_hash_table *htab;
+
+      htab = (struct mips_elf_link_hash_table *) ret;
+      htab->use_plts_and_copy_relocs = TRUE;
+      htab->is_vxworks = TRUE;
+    }
+  return ret;
+}
+
+/* A function that the linker calls if we are allowed to use PLTs
+   and copy relocs.  */
+
+void
+_bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
+{
+  mips_elf_hash_table (info)->use_plts_and_copy_relocs = TRUE;
+}
+
+/* A function that the linker calls to select between all or only
+   32-bit microMIPS instructions, and between making or ignoring
+   branch relocation checks for invalid transitions between ISA modes.
+   Also record whether we have been configured for a GNU target.  */
+
+void
+_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
+                           bfd_boolean ignore_branch_isa,
+                           bfd_boolean gnu_target)
+{
+  mips_elf_hash_table (info)->insn32 = insn32;
+  mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+  mips_elf_hash_table (info)->gnu_target = gnu_target;
+}
+
+/* A function that the linker calls to enable use of compact branches in
+   linker generated code for MIPSR6.  */
+
+void
+_bfd_mips_elf_compact_branches (struct bfd_link_info *info, bfd_boolean on)
+{
+  mips_elf_hash_table (info)->compact_branches = on;
+}
+
+\f
+/* 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[] =
+{
+  /* MIPS64r2 extensions.  */
+  { bfd_mach_mips_octeon3, bfd_mach_mips_octeon2 },
+  { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
+  { bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
+  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
+  { bfd_mach_mips_gs264e, bfd_mach_mips_gs464e },
+  { bfd_mach_mips_gs464e, bfd_mach_mips_gs464 },
+  { bfd_mach_mips_gs464, bfd_mach_mipsisa64r2 },
+
+  /* MIPS64 extensions.  */
+  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
+  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
+  { bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
+
+  /* MIPS V extensions.  */
+  { bfd_mach_mipsisa64, bfd_mach_mips5 },
+
+  /* R10000 extensions.  */
+  { bfd_mach_mips12000, bfd_mach_mips10000 },
+  { bfd_mach_mips14000, bfd_mach_mips10000 },
+  { bfd_mach_mips16000, 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 },
+  { bfd_mach_mips7000, bfd_mach_mips8000 },
+  { bfd_mach_mips9000, bfd_mach_mips8000 },
+
+  /* VR4100 extensions.  */
+  { bfd_mach_mips4120, bfd_mach_mips4100 },
+  { bfd_mach_mips4111, bfd_mach_mips4100 },
+
+  /* MIPS III extensions.  */
+  { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 },
+  { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 },
+  { 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_mips5900, bfd_mach_mips4000 },
+
+  /* MIPS32r3 extensions.  */
+  { bfd_mach_mips_interaptiv_mr2, bfd_mach_mipsisa32r3 },
+
+  /* MIPS32r2 extensions.  */
+  { bfd_mach_mipsisa32r3, bfd_mach_mipsisa32r2 },
+
+  /* MIPS32 extensions.  */
+  { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
+
+  /* MIPS II extensions.  */
+  { bfd_mach_mips4000, bfd_mach_mips6000 },
+  { bfd_mach_mipsisa32, bfd_mach_mips6000 },
+  { bfd_mach_mips4010, 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 (unsigned long base, unsigned long extension)
+{
+  size_t i;
+
+  if (extension == base)
+    return TRUE;
+
+  if (base == bfd_mach_mipsisa32
+      && mips_mach_extends_p (bfd_mach_mipsisa64, extension))
+    return TRUE;
+
+  if (base == bfd_mach_mipsisa32r2
+      && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension))
+    return TRUE;
+
+  for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++)
+    if (extension == mips_mach_extensions[i].extension)
+      {
+       extension = mips_mach_extensions[i].base;
+       if (extension == base)
+         return TRUE;
+      }
+
+  return FALSE;
+}
+
+/* Return the BFD mach for each .MIPS.abiflags ISA Extension.  */
+
+static unsigned long
+bfd_mips_isa_ext_mach (unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case AFL_EXT_3900:       return bfd_mach_mips3900;
+    case AFL_EXT_4010:       return bfd_mach_mips4010;
+    case AFL_EXT_4100:       return bfd_mach_mips4100;
+    case AFL_EXT_4111:       return bfd_mach_mips4111;
+    case AFL_EXT_4120:       return bfd_mach_mips4120;
+    case AFL_EXT_4650:       return bfd_mach_mips4650;
+    case AFL_EXT_5400:       return bfd_mach_mips5400;
+    case AFL_EXT_5500:       return bfd_mach_mips5500;
+    case AFL_EXT_5900:       return bfd_mach_mips5900;
+    case AFL_EXT_10000:              return bfd_mach_mips10000;
+    case AFL_EXT_LOONGSON_2E: return bfd_mach_mips_loongson_2e;
+    case AFL_EXT_LOONGSON_2F: return bfd_mach_mips_loongson_2f;
+    case AFL_EXT_SB1:        return bfd_mach_mips_sb1;
+    case AFL_EXT_OCTEON:      return bfd_mach_mips_octeon;
+    case AFL_EXT_OCTEONP:     return bfd_mach_mips_octeonp;
+    case AFL_EXT_OCTEON2:     return bfd_mach_mips_octeon2;
+    case AFL_EXT_XLR:        return bfd_mach_mips_xlr;
+    default:                 return bfd_mach_mips3000;
+    }
+}
+
+/* Return the .MIPS.abiflags value representing each ISA Extension.  */
+
+unsigned int
+bfd_mips_isa_ext (bfd *abfd)
+{
+  switch (bfd_get_mach (abfd))
+    {
+    case bfd_mach_mips3900:        return AFL_EXT_3900;
+    case bfd_mach_mips4010:        return AFL_EXT_4010;
+    case bfd_mach_mips4100:        return AFL_EXT_4100;
+    case bfd_mach_mips4111:        return AFL_EXT_4111;
+    case bfd_mach_mips4120:        return AFL_EXT_4120;
+    case bfd_mach_mips4650:        return AFL_EXT_4650;
+    case bfd_mach_mips5400:        return AFL_EXT_5400;
+    case bfd_mach_mips5500:        return AFL_EXT_5500;
+    case bfd_mach_mips5900:        return AFL_EXT_5900;
+    case bfd_mach_mips10000:       return AFL_EXT_10000;
+    case bfd_mach_mips_loongson_2e: return AFL_EXT_LOONGSON_2E;
+    case bfd_mach_mips_loongson_2f: return AFL_EXT_LOONGSON_2F;
+    case bfd_mach_mips_sb1:        return AFL_EXT_SB1;
+    case bfd_mach_mips_octeon:     return AFL_EXT_OCTEON;
+    case bfd_mach_mips_octeonp:            return AFL_EXT_OCTEONP;
+    case bfd_mach_mips_octeon3:            return AFL_EXT_OCTEON3;
+    case bfd_mach_mips_octeon2:            return AFL_EXT_OCTEON2;
+    case bfd_mach_mips_xlr:        return AFL_EXT_XLR;
+    case bfd_mach_mips_interaptiv_mr2:
+      return AFL_EXT_INTERAPTIV_MR2;
+    default:                       return 0;
+    }
+}
+
+/* Encode ISA level and revision as a single value.  */
+#define LEVEL_REV(LEV,REV) ((LEV) << 3 | (REV))
+
+/* Decode a single value into level and revision.  */
+#define ISA_LEVEL(LEVREV)  ((LEVREV) >> 3)
+#define ISA_REV(LEVREV)    ((LEVREV) & 0x7)
+
+/* Update the isa_level, isa_rev, isa_ext fields of abiflags.  */
+
+static void
+update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags)
+{
+  int new_isa = 0;
+  switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
+    {
+    case E_MIPS_ARCH_1:    new_isa = LEVEL_REV (1, 0); break;
+    case E_MIPS_ARCH_2:    new_isa = LEVEL_REV (2, 0); break;
+    case E_MIPS_ARCH_3:    new_isa = LEVEL_REV (3, 0); break;
+    case E_MIPS_ARCH_4:    new_isa = LEVEL_REV (4, 0); break;
+    case E_MIPS_ARCH_5:    new_isa = LEVEL_REV (5, 0); break;
+    case E_MIPS_ARCH_32:   new_isa = LEVEL_REV (32, 1); break;
+    case E_MIPS_ARCH_32R2: new_isa = LEVEL_REV (32, 2); break;
+    case E_MIPS_ARCH_32R6: new_isa = LEVEL_REV (32, 6); break;
+    case E_MIPS_ARCH_64:   new_isa = LEVEL_REV (64, 1); break;
+    case E_MIPS_ARCH_64R2: new_isa = LEVEL_REV (64, 2); break;
+    case E_MIPS_ARCH_64R6: new_isa = LEVEL_REV (64, 6); break;
+    default:
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: unknown architecture %s"),
+        abfd, bfd_printable_name (abfd));
+    }
+
+  if (new_isa > LEVEL_REV (abiflags->isa_level, abiflags->isa_rev))
+    {
+      abiflags->isa_level = ISA_LEVEL (new_isa);
+      abiflags->isa_rev = ISA_REV (new_isa);
+    }
+
+  /* Update the isa_ext if ABFD describes a further extension.  */
+  if (mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags->isa_ext),
+                          bfd_get_mach (abfd)))
+    abiflags->isa_ext = bfd_mips_isa_ext (abfd);
+}
+
+/* Return true if the given ELF header flags describe a 32-bit binary.  */
+
+static bfd_boolean
+mips_32bit_flags_p (flagword flags)
+{
+  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
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6);
+}
+
+/* Infer the content of the ABI flags based on the elf header.  */
+
+static void
+infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags)
+{
+  obj_attribute *in_attr;
+
+  memset (abiflags, 0, sizeof (Elf_Internal_ABIFlags_v0));
+  update_mips_abiflags_isa (abfd, abiflags);
+
+  if (mips_32bit_flags_p (elf_elfheader (abfd)->e_flags))
+    abiflags->gpr_size = AFL_REG_32;
+  else
+    abiflags->gpr_size = AFL_REG_64;
+
+  abiflags->cpr1_size = AFL_REG_NONE;
+
+  in_attr = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU];
+  abiflags->fp_abi = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+  if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_SINGLE
+      || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_XX
+      || (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+         && abiflags->gpr_size == AFL_REG_32))
+    abiflags->cpr1_size = AFL_REG_32;
+  else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+          || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64
+          || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64A)
+    abiflags->cpr1_size = AFL_REG_64;
+
+  abiflags->cpr2_size = AFL_REG_NONE;
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX)
+    abiflags->ases |= AFL_ASE_MDMX;
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
+    abiflags->ases |= AFL_ASE_MIPS16;
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+    abiflags->ases |= AFL_ASE_MICROMIPS;
+
+  if (abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_ANY
+      && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
+      && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
+      && abiflags->isa_level >= 32
+      && abiflags->ases != AFL_ASE_LOONGSON_EXT)
+    abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
+}
+
+/* We need to use a special link routine to handle the .reginfo and
+   the .mdebug sections.  We need to merge all instances of these
+   sections together, not write them all out sequentially.  */
+
+bfd_boolean
+_bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
+{
+  asection *o;
+  struct bfd_link_order *p;
+  asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
+  asection *rtproc_sec, *abiflags_sec;
+  Elf32_RegInfo reginfo;
+  struct ecoff_debug_info debug;
+  struct mips_htab_traverse_info hti;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap;
+  HDRR *symhdr = &debug.symbolic_header;
+  void *mdebug_handle = NULL;
+  asection *s;
+  EXTR esym;
+  unsigned int i;
+  bfd_size_type amt;
+  struct mips_elf_link_hash_table *htab;
+
+  static const char * const secname[] =
+  {
+    ".text", ".init", ".fini", ".data",
+    ".rodata", ".sdata", ".sbss", ".bss"
+  };
+  static const int sc[] =
+  {
+    scText, scInit, scFini, scData,
+    scRData, scSData, scSBss, scBss
+  };
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  /* Sort the dynamic symbols so that those with GOT entries come after
+     those without.  */
+  if (!mips_elf_sort_hash_table (abfd, info))
+    return FALSE;
+
+  /* Create any scheduled LA25 stubs.  */
+  hti.info = info;
+  hti.output_bfd = abfd;
+  hti.error = FALSE;
+  htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti);
+  if (hti.error)
+    return FALSE;
+
+  /* Get a value for the GP register.  */
+  if (elf_gp (abfd) == 0)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE);
+      if (h != NULL && h->type == bfd_link_hash_defined)
+       elf_gp (abfd) = (h->u.def.value
+                        + h->u.def.section->output_section->vma
+                        + h->u.def.section->output_offset);
+      else if (htab->is_vxworks
+              && (h = bfd_link_hash_lookup (info->hash,
+                                            "_GLOBAL_OFFSET_TABLE_",
+                                            FALSE, FALSE, TRUE))
+              && h->type == bfd_link_hash_defined)
+       elf_gp (abfd) = (h->u.def.section->output_section->vma
+                        + h->u.def.section->output_offset
+                        + h->u.def.value);
+      else if (bfd_link_relocatable (info))
+       {
+         bfd_vma lo = MINUS_ONE;
+
+         /* Find the GP-relative section with the lowest offset.  */
+         for (o = abfd->sections; o != NULL; o = o->next)
+           if (o->vma < lo
+               && (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL))
+             lo = o->vma;
+
+         /* And calculate GP relative to that.  */
+         elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (info);
+       }
+      else
+       {
+         /* If the relocate_section function needs to do a reloc
+            involving the GP value, it should make a reloc_dangerous
+            callback to warn that GP is not defined.  */
+       }
+    }
+
+  /* Go through the sections and collect the .reginfo and .mdebug
+     information.  */
+  abiflags_sec = NULL;
+  reginfo_sec = NULL;
+  mdebug_sec = NULL;
+  gptab_data_sec = NULL;
+  gptab_bss_sec = NULL;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if (strcmp (o->name, ".MIPS.abiflags") == 0)
+       {
+         /* We have found the .MIPS.abiflags section in the output file.
+            Look through all the link_orders comprising it and remove them.
+            The data is merged in _bfd_mips_elf_merge_private_bfd_data.  */
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
+           {
+             asection *input_section;
+
+             if (p->type != bfd_indirect_link_order)
+               {
+                 if (p->type == bfd_data_link_order)
+                   continue;
+                 abort ();
+               }
+
+             input_section = p->u.indirect.section;
+
+             /* Hack: reset the SEC_HAS_CONTENTS flag so that
+                elf_link_input_bfd ignores this section.  */
+             input_section->flags &= ~SEC_HAS_CONTENTS;
+           }
+
+         /* Size has been set in _bfd_mips_elf_always_size_sections.  */
+         BFD_ASSERT(o->size == sizeof (Elf_External_ABIFlags_v0));
+
+         /* Skip this section later on (I don't think this currently
+            matters, but someday it might).  */
+         o->map_head.link_order = NULL;
+
+         abiflags_sec = o;
+       }
+
+      if (strcmp (o->name, ".reginfo") == 0)
+       {
+         memset (&reginfo, 0, sizeof reginfo);
+
+         /* We have found the .reginfo section in the output file.
+            Look through all the link_orders comprising it and merge
+            the information together.  */
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
+           {
+             asection *input_section;
+             bfd *input_bfd;
+             Elf32_External_RegInfo ext;
+             Elf32_RegInfo sub;
+             bfd_size_type sz;
+
+             if (p->type != bfd_indirect_link_order)
+               {
+                 if (p->type == bfd_data_link_order)
+                   continue;
+                 abort ();
+               }
+
+             input_section = p->u.indirect.section;
+             input_bfd = input_section->owner;
+
+             sz = (input_section->size < sizeof (ext)
+                   ? input_section->size : sizeof (ext));
+             memset (&ext, 0, sizeof (ext));
              if (! bfd_get_section_contents (input_bfd, input_section,
-                                             &ext, 0, sizeof ext))
+                                             &ext, 0, sz))
                return FALSE;
 
              bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
@@ -10714,7 +14810,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
 
              /* ri_gp_value is set by the function
-                mips_elf32_section_processing when the section is
+                `_bfd_mips_elf_section_processing' when the section is
                 finally written out.  */
 
              /* Hack: reset the SEC_HAS_CONTENTS flag so that
@@ -10819,9 +14915,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
 
-             if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
-                 || (get_elf_backend_data (input_bfd)
-                     ->elf_backend_ecoff_debug_swap) == NULL)
+             if (!is_mips_elf (input_bfd))
                {
                  /* I don't know what a non MIPS ELF bfd would be
                     doing with a .mdebug section, but I don't really
@@ -10902,20 +14996,20 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section->flags &= ~SEC_HAS_CONTENTS;
            }
 
-         if (SGI_COMPAT (abfd) && info->shared)
+         if (SGI_COMPAT (abfd) && bfd_link_pic (info))
            {
              /* Create .rtproc section.  */
-             rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
+             rtproc_sec = bfd_get_linker_section (abfd, ".rtproc");
              if (rtproc_sec == NULL)
                {
                  flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
                                    | SEC_LINKER_CREATED | SEC_READONLY);
 
-                 rtproc_sec = bfd_make_section_with_flags (abfd,
-                                                           ".rtproc",
-                                                           flags);
+                 rtproc_sec = bfd_make_section_anyway_with_flags (abfd,
+                                                                  ".rtproc",
+                                                                  flags);
                  if (rtproc_sec == NULL
-                     || ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
+                     || !bfd_set_section_alignment (rtproc_sec, 4))
                    return FALSE;
                }
 
@@ -10958,7 +15052,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
             information describing how the small data area would
             change depending upon the -G switch.  These sections
             not used in executables files.  */
-         if (! info->relocatable)
+         if (! bfd_link_relocatable (info))
            {
              for (p = o->map_head.link_order; p != NULL; p = p->next)
                {
@@ -10997,9 +15091,9 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            gptab_bss_sec = o;
          else
            {
-             (*_bfd_error_handler)
-               (_("%s: illegal section name `%s'"),
-                bfd_get_filename (abfd), o->name);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: illegal section name `%pA'"), abfd, o);
              bfd_set_error (bfd_error_nonrepresentable_section);
              return FALSE;
            }
@@ -11151,388 +15245,103 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          o->size = c * sizeof (Elf32_External_gptab);
          o->contents = (bfd_byte *) ext_tab;
 
-         /* Skip this section later on (I don't think this currently
-            matters, but someday it might).  */
-         o->map_head.link_order = NULL;
-       }
-    }
-
-  /* Invoke the regular ELF backend linker to do all the work.  */
-  if (!bfd_elf_final_link (abfd, info))
-    return FALSE;
-
-  /* Now write out the computed sections.  */
-
-  if (reginfo_sec != NULL)
-    {
-      Elf32_External_RegInfo ext;
-
-      bfd_mips_elf32_swap_reginfo_out (abfd, &reginfo, &ext);
-      if (! bfd_set_section_contents (abfd, reginfo_sec, &ext, 0, sizeof ext))
-       return FALSE;
-    }
-
-  if (mdebug_sec != NULL)
-    {
-      BFD_ASSERT (abfd->output_has_begun);
-      if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug,
-                                              swap, info,
-                                              mdebug_sec->filepos))
-       return FALSE;
-
-      bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info);
-    }
-
-  if (gptab_data_sec != NULL)
-    {
-      if (! bfd_set_section_contents (abfd, gptab_data_sec,
-                                     gptab_data_sec->contents,
-                                     0, gptab_data_sec->size))
-       return FALSE;
-    }
-
-  if (gptab_bss_sec != NULL)
-    {
-      if (! bfd_set_section_contents (abfd, gptab_bss_sec,
-                                     gptab_bss_sec->contents,
-                                     0, gptab_bss_sec->size))
-       return FALSE;
-    }
-
-  if (SGI_COMPAT (abfd))
-    {
-      rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
-      if (rtproc_sec != NULL)
-       {
-         if (! bfd_set_section_contents (abfd, rtproc_sec,
-                                         rtproc_sec->contents,
-                                         0, rtproc_sec->size))
-           return FALSE;
-       }
-    }
-
-  return TRUE;
-}
-\f
-/* 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[] = {
-  /* MIPS64r2 extensions.  */
-  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
-
-  /* MIPS64 extensions.  */
-  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
-  { 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 },
-  { bfd_mach_mips7000, bfd_mach_mips8000 },
-  { bfd_mach_mips9000, bfd_mach_mips8000 },
-
-  /* VR4100 extensions.  */
-  { bfd_mach_mips4120, bfd_mach_mips4100 },
-  { bfd_mach_mips4111, bfd_mach_mips4100 },
-
-  /* MIPS III extensions.  */
-  { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 },
-  { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 },
-  { 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 (unsigned long base, unsigned long extension)
-{
-  size_t i;
-
-  if (extension == base)
-    return TRUE;
-
-  if (base == bfd_mach_mipsisa32
-      && mips_mach_extends_p (bfd_mach_mipsisa64, extension))
-    return TRUE;
-
-  if (base == bfd_mach_mipsisa32r2
-      && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension))
-    return TRUE;
-
-  for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++)
-    if (extension == mips_mach_extensions[i].extension)
-      {
-       extension = mips_mach_extensions[i].base;
-       if (extension == base)
-         return TRUE;
-      }
-
-  return FALSE;
-}
-
-
-/* Return true if the given ELF header flags describe a 32-bit binary.  */
-
-static bfd_boolean
-mips_32bit_flags_p (flagword flags)
-{
-  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 object attributes from IBFD into OBFD.  Raise an error if
-   there are conflicting attributes.  */
-static bfd_boolean
-mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
-{
-  obj_attribute *in_attr;
-  obj_attribute *out_attr;
-
-  if (!elf_known_obj_attributes_proc (obfd)[0].i)
-    {
-      /* This is the first object.  Copy the attributes.  */
-      _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
-      /* Use the Tag_null value to indicate the attributes have been
-        initialized.  */
-      elf_known_obj_attributes_proc (obfd)[0].i = 1;
-
-      return TRUE;
-    }
-
-  /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge
-     non-conflicting ones.  */
-  in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
-  out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
-  if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
-    {
-      out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
-      if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
-       out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
-      else if (in_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
-       ;
-      else if (in_attr[Tag_GNU_MIPS_ABI_FP].i > 4)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
-          in_attr[Tag_GNU_MIPS_ABI_FP].i);
-      else if (out_attr[Tag_GNU_MIPS_ABI_FP].i > 4)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), obfd,
-          out_attr[Tag_GNU_MIPS_ABI_FP].i);
-      else
-       switch (out_attr[Tag_GNU_MIPS_ABI_FP].i)
-         {
-         case 1:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 2:
-               _bfd_error_handler
-                 (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
-                  obfd, ibfd);
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses hard float, %B uses soft float"),
-                  obfd, ibfd);
-               break;
-
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses -msingle-float, %B uses -mips32r2 -mfp64"),
-                  obfd, ibfd);
-               break;
-
-             default:
-               abort ();
-             }
-           break;
-
-         case 2:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-               _bfd_error_handler
-                 (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
-                  ibfd, obfd);
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses hard float, %B uses soft float"),
-                  obfd, ibfd);
-               break;
-
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses -mdouble-float, %B uses -mips32r2 -mfp64"),
-                  obfd, ibfd);
-               break;
-
-             default:
-               abort ();
-             }
-           break;
-
-         case 3:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-             case 2:
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses hard float, %B uses soft float"),
-                  ibfd, obfd);
-               break;
-
-             default:
-               abort ();
-             }
-           break;
+         /* Skip this section later on (I don't think this currently
+            matters, but someday it might).  */
+         o->map_head.link_order = NULL;
+       }
+    }
 
-         case 4:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-               _bfd_error_handler
-                 (_("Warning: %B uses -msingle-float, %B uses -mips32r2 -mfp64"),
-                  ibfd, obfd);
-               break;
+  /* Invoke the regular ELF backend linker to do all the work.  */
+  if (!bfd_elf_final_link (abfd, info))
+    return FALSE;
 
-             case 2:
-               _bfd_error_handler
-                 (_("Warning: %B uses -mdouble-float, %B uses -mips32r2 -mfp64"),
-                  ibfd, obfd);
-               break;
+  /* Now write out the computed sections.  */
 
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses hard float, %B uses soft float"),
-                  obfd, ibfd);
-               break;
+  if (abiflags_sec != NULL)
+    {
+      Elf_External_ABIFlags_v0 ext;
+      Elf_Internal_ABIFlags_v0 *abiflags;
 
-             default:
-               abort ();
-             }
-           break;
+      abiflags = &mips_elf_tdata (abfd)->abiflags;
 
-         default:
-           abort ();
-         }
+      /* Set up the abiflags if no valid input sections were found.  */
+      if (!mips_elf_tdata (abfd)->abiflags_valid)
+       {
+         infer_mips_abiflags (abfd, abiflags);
+         mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+       }
+      bfd_mips_elf_swap_abiflags_v0_out (abfd, abiflags, &ext);
+      if (! bfd_set_section_contents (abfd, abiflags_sec, &ext, 0, sizeof ext))
+       return FALSE;
     }
 
-  /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  if (reginfo_sec != NULL)
+    {
+      Elf32_External_RegInfo ext;
 
-  return TRUE;
-}
+      bfd_mips_elf32_swap_reginfo_out (abfd, &reginfo, &ext);
+      if (! bfd_set_section_contents (abfd, reginfo_sec, &ext, 0, sizeof ext))
+       return FALSE;
+    }
 
-/* Merge backend specific data from an object file to the output
-   object file when linking.  */
+  if (mdebug_sec != NULL)
+    {
+      BFD_ASSERT (abfd->output_has_begun);
+      if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug,
+                                              swap, info,
+                                              mdebug_sec->filepos))
+       return FALSE;
 
-bfd_boolean
-_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
-{
-  flagword old_flags;
-  flagword new_flags;
-  bfd_boolean ok;
-  bfd_boolean null_input_bfd = TRUE;
-  asection *sec;
+      bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info);
+    }
 
-  /* Check if we have the same endianess */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+  if (gptab_data_sec != NULL)
     {
-      (*_bfd_error_handler)
-       (_("%B: endianness incompatible with that of the selected emulation"),
-        ibfd);
-      return FALSE;
+      if (! bfd_set_section_contents (abfd, gptab_data_sec,
+                                     gptab_data_sec->contents,
+                                     0, gptab_data_sec->size))
+       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)
+  if (gptab_bss_sec != NULL)
     {
-      (*_bfd_error_handler)
-       (_("%B: ABI is incompatible with that of the selected emulation"),
-        ibfd);
-      return FALSE;
+      if (! bfd_set_section_contents (abfd, gptab_bss_sec,
+                                     gptab_bss_sec->contents,
+                                     0, gptab_bss_sec->size))
+       return FALSE;
     }
 
-  if (!mips_elf_merge_obj_attributes (ibfd, obfd))
-    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;
-
-  if (! elf_flags_init (obfd))
+  if (SGI_COMPAT (abfd))
     {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = new_flags;
-      elf_elfheader (obfd)->e_ident[EI_CLASS]
-       = elf_elfheader (ibfd)->e_ident[EI_CLASS];
-
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-         && (bfd_get_arch_info (obfd)->the_default
-             || mips_mach_extends_p (bfd_get_mach (obfd), 
-                                     bfd_get_mach (ibfd))))
+      rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
+      if (rtproc_sec != NULL)
        {
-         if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
-                                  bfd_get_mach (ibfd)))
+         if (! bfd_set_section_contents (abfd, rtproc_sec,
+                                         rtproc_sec->contents,
+                                         0, rtproc_sec->size))
            return FALSE;
        }
-
-      return TRUE;
     }
 
+  return TRUE;
+}
+\f
+/* Merge object file header flags from IBFD into OBFD.  Raise an error
+   if there are conflicting settings.  */
+
+static bfd_boolean
+mips_elf_merge_obj_e_flags (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
+  flagword old_flags;
+  flagword new_flags;
+  bfd_boolean ok;
+
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
+  old_flags = elf_elfheader (obfd)->e_flags;
+
   /* Check flag compatibility.  */
 
   new_flags &= ~EF_MIPS_NOREORDER;
@@ -11548,43 +15357,20 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   new_flags &= ~EF_MIPS_UCODE;
   old_flags &= ~EF_MIPS_UCODE;
 
-  /* Don't care about the PIC flags from dynamic objects; they are
-     PIC by design.  */
-  if ((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0
-      && (ibfd->flags & DYNAMIC) != 0)
-    new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
+  /* DSOs should only be linked with CPIC code.  */
+  if ((ibfd->flags & DYNAMIC) != 0)
+    new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
 
   if (new_flags == old_flags)
     return TRUE;
 
-  /* Check to see if the input BFD actually contains any sections.
-     If not, its flags may not have been initialised either, but it cannot
-     actually cause any incompatibility.  */
-  for (sec = ibfd->sections; sec != NULL; sec = sec->next)
-    {
-      /* Ignore synthetic sections and empty .text, .data and .bss sections
-         which are automatically generated by gas.  */
-      if (strcmp (sec->name, ".reginfo")
-         && strcmp (sec->name, ".mdebug")
-         && (sec->size != 0
-             || (strcmp (sec->name, ".text")
-                 && strcmp (sec->name, ".data")
-                 && strcmp (sec->name, ".bss"))))
-       {
-         null_input_bfd = FALSE;
-         break;
-       }
-    }
-  if (null_input_bfd)
-    return TRUE;
-
   ok = TRUE;
 
   if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
       != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
     {
-      (*_bfd_error_handler)
-       (_("%B: warning: linking PIC files with non-PIC files"),
+      _bfd_error_handler
+       (_("%pB: warning: linking abicalls files with non-abicalls files"),
         ibfd);
       ok = TRUE;
     }
@@ -11600,8 +15386,8 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   /* Compare the ISAs.  */
   if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
     {
-      (*_bfd_error_handler)
-       (_("%B: linking 32-bit code with 64-bit code"),
+      _bfd_error_handler
+       (_("%pB: linking 32-bit code with 64-bit code"),
         ibfd);
       ok = FALSE;
     }
@@ -11618,6 +15404,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
          elf_elfheader (obfd)->e_flags
            |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
 
+         /* Update the ABI flags isa_level, isa_rev, isa_ext fields.  */
+         update_mips_abiflags_isa (obfd, &out_tdata->abiflags);
+
          /* 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
@@ -11628,8 +15417,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
       else
        {
          /* The ISAs aren't compatible.  */
-         (*_bfd_error_handler)
-           (_("%B: linking %s module with previous %s modules"),
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: linking %s module with previous %s modules"),
             ibfd,
             bfd_printable_name (ibfd),
             bfd_printable_name (obfd));
@@ -11637,51 +15427,442 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
        }
     }
 
-  new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
-  old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+  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]
+         != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+    {
+      /* Only error if both are set (to different values).  */
+      if (((new_flags & EF_MIPS_ABI) && (old_flags & EF_MIPS_ABI))
+         || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
+             != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: ABI mismatch: linking %s module with previous %s modules"),
+            ibfd,
+            elf_mips_abi_name (ibfd),
+            elf_mips_abi_name (obfd));
+         ok = FALSE;
+       }
+      new_flags &= ~EF_MIPS_ABI;
+      old_flags &= ~EF_MIPS_ABI;
+    }
+
+  /* Compare ASEs.  Forbid linking MIPS16 and microMIPS ASE modules together
+     and allow arbitrary mixing of the remaining ASEs (retain the union).  */
+  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
+    {
+      int old_micro = old_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+      int new_micro = new_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+      int old_m16 = old_flags & EF_MIPS_ARCH_ASE_M16;
+      int new_m16 = new_flags & EF_MIPS_ARCH_ASE_M16;
+      int micro_mis = old_m16 && new_micro;
+      int m16_mis = old_micro && new_m16;
+
+      if (m16_mis || micro_mis)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: ASE mismatch: linking %s module with previous %s modules"),
+            ibfd,
+            m16_mis ? "MIPS16" : "microMIPS",
+            m16_mis ? "microMIPS" : "MIPS16");
+         ok = FALSE;
+       }
+
+      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
+
+      new_flags &= ~ EF_MIPS_ARCH_ASE;
+      old_flags &= ~ EF_MIPS_ARCH_ASE;
+    }
+
+  /* Compare NaN encodings.  */
+  if ((new_flags & EF_MIPS_NAN2008) != (old_flags & EF_MIPS_NAN2008))
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
+                         ibfd,
+                         (new_flags & EF_MIPS_NAN2008
+                          ? "-mnan=2008" : "-mnan=legacy"),
+                         (old_flags & EF_MIPS_NAN2008
+                          ? "-mnan=2008" : "-mnan=legacy"));
+      ok = FALSE;
+      new_flags &= ~EF_MIPS_NAN2008;
+      old_flags &= ~EF_MIPS_NAN2008;
+    }
+
+  /* Compare FP64 state.  */
+  if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64))
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
+                         ibfd,
+                         (new_flags & EF_MIPS_FP64
+                          ? "-mfp64" : "-mfp32"),
+                         (old_flags & EF_MIPS_FP64
+                          ? "-mfp64" : "-mfp32"));
+      ok = FALSE;
+      new_flags &= ~EF_MIPS_FP64;
+      old_flags &= ~EF_MIPS_FP64;
+    }
+
+  /* Warn about any other mismatches */
+  if (new_flags != old_flags)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler
+       (_("%pB: uses different e_flags (%#x) fields than previous modules "
+          "(%#x)"),
+        ibfd, new_flags, old_flags);
+      ok = FALSE;
+    }
+
+  return ok;
+}
+
+/* Merge object attributes from IBFD into OBFD.  Raise an error if
+   there are conflicting attributes.  */
+static bfd_boolean
+mips_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  bfd *abi_fp_bfd;
+  bfd *abi_msa_bfd;
+
+  abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd;
+  in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+  if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY)
+    mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+
+  abi_msa_bfd = mips_elf_tdata (obfd)->abi_msa_bfd;
+  if (!abi_msa_bfd
+      && in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+    mips_elf_tdata (obfd)->abi_msa_bfd = ibfd;
+
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
+    {
+      /* This is the first object.  Copy the attributes.  */
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+      /* Use the Tag_null value to indicate the attributes have been
+        initialized.  */
+      elf_known_obj_attributes_proc (obfd)[0].i = 1;
+
+      return TRUE;
+    }
+
+  /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge
+     non-conflicting ones.  */
+  out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+  if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
+    {
+      int out_fp, in_fp;
+
+      out_fp = out_attr[Tag_GNU_MIPS_ABI_FP].i;
+      in_fp = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+      out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
+      if (out_fp == Val_GNU_MIPS_ABI_FP_ANY)
+       out_attr[Tag_GNU_MIPS_ABI_FP].i = in_fp;
+      else if (out_fp == Val_GNU_MIPS_ABI_FP_XX
+              && (in_fp == Val_GNU_MIPS_ABI_FP_DOUBLE
+                  || in_fp == Val_GNU_MIPS_ABI_FP_64
+                  || in_fp == Val_GNU_MIPS_ABI_FP_64A))
+       {
+         mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+         out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+       }
+      else if (in_fp == Val_GNU_MIPS_ABI_FP_XX
+              && (out_fp == Val_GNU_MIPS_ABI_FP_DOUBLE
+                  || out_fp == Val_GNU_MIPS_ABI_FP_64
+                  || out_fp == Val_GNU_MIPS_ABI_FP_64A))
+       /* Keep the current setting.  */;
+      else if (out_fp == Val_GNU_MIPS_ABI_FP_64A
+              && in_fp == Val_GNU_MIPS_ABI_FP_64)
+       {
+         mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+         out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+       }
+      else if (in_fp == Val_GNU_MIPS_ABI_FP_64A
+              && out_fp == Val_GNU_MIPS_ABI_FP_64)
+       /* Keep the current setting.  */;
+      else if (in_fp != Val_GNU_MIPS_ABI_FP_ANY)
+       {
+         const char *out_string, *in_string;
+
+         out_string = _bfd_mips_fp_abi_string (out_fp);
+         in_string = _bfd_mips_fp_abi_string (in_fp);
+         /* First warn about cases involving unrecognised ABIs.  */
+         if (!out_string && !in_string)
+           /* xgettext:c-format */
+           _bfd_error_handler
+             (_("warning: %pB uses unknown floating point ABI %d "
+                "(set by %pB), %pB uses unknown floating point ABI %d"),
+              obfd, out_fp, abi_fp_bfd, ibfd, in_fp);
+         else if (!out_string)
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses unknown floating point ABI %d "
+                "(set by %pB), %pB uses %s"),
+              obfd, out_fp, abi_fp_bfd, ibfd, in_string);
+         else if (!in_string)
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses %s (set by %pB), "
+                "%pB uses unknown floating point ABI %d"),
+              obfd, out_string, abi_fp_bfd, ibfd, in_fp);
+         else
+           {
+             /* If one of the bfds is soft-float, the other must be
+                hard-float.  The exact choice of hard-float ABI isn't
+                really relevant to the error message.  */
+             if (in_fp == Val_GNU_MIPS_ABI_FP_SOFT)
+               out_string = "-mhard-float";
+             else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT)
+               in_string = "-mhard-float";
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("warning: %pB uses %s (set by %pB), %pB uses %s"),
+                obfd, out_string, abi_fp_bfd, ibfd, in_string);
+           }
+       }
+    }
+
+  /* Check for conflicting Tag_GNU_MIPS_ABI_MSA attributes and merge
+     non-conflicting ones.  */
+  if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+    {
+      out_attr[Tag_GNU_MIPS_ABI_MSA].type = 1;
+      if (out_attr[Tag_GNU_MIPS_ABI_MSA].i == Val_GNU_MIPS_ABI_MSA_ANY)
+       out_attr[Tag_GNU_MIPS_ABI_MSA].i = in_attr[Tag_GNU_MIPS_ABI_MSA].i;
+      else if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+       switch (out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+         {
+         case Val_GNU_MIPS_ABI_MSA_128:
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses %s (set by %pB), "
+                "%pB uses unknown MSA ABI %d"),
+              obfd, "-mmsa", abi_msa_bfd,
+              ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
+           break;
+
+         default:
+           switch (in_attr[Tag_GNU_MIPS_ABI_MSA].i)
+             {
+             case Val_GNU_MIPS_ABI_MSA_128:
+               _bfd_error_handler
+                 /* xgettext:c-format */
+                 (_("warning: %pB uses unknown MSA ABI %d "
+                    "(set by %pB), %pB uses %s"),
+                    obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+                  abi_msa_bfd, ibfd, "-mmsa");
+                 break;
+
+             default:
+               _bfd_error_handler
+                 /* xgettext:c-format */
+                 (_("warning: %pB uses unknown MSA ABI %d "
+                    "(set by %pB), %pB uses unknown MSA ABI %d"),
+                  obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+                  abi_msa_bfd, ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
+               break;
+             }
+         }
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  return _bfd_elf_merge_object_attributes (ibfd, info);
+}
+
+/* Merge object ABI flags from IBFD into OBFD.  Raise an error if
+   there are conflicting settings.  */
+
+static bfd_boolean
+mips_elf_merge_obj_abiflags (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+  struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
+  struct mips_elf_obj_tdata *in_tdata = mips_elf_tdata (ibfd);
+
+  /* Update the output abiflags fp_abi using the computed fp_abi.  */
+  out_tdata->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+  /* Merge abiflags.  */
+  out_tdata->abiflags.isa_level = max (out_tdata->abiflags.isa_level,
+                                      in_tdata->abiflags.isa_level);
+  out_tdata->abiflags.isa_rev = max (out_tdata->abiflags.isa_rev,
+                                    in_tdata->abiflags.isa_rev);
+  out_tdata->abiflags.gpr_size = max (out_tdata->abiflags.gpr_size,
+                                     in_tdata->abiflags.gpr_size);
+  out_tdata->abiflags.cpr1_size = max (out_tdata->abiflags.cpr1_size,
+                                      in_tdata->abiflags.cpr1_size);
+  out_tdata->abiflags.cpr2_size = max (out_tdata->abiflags.cpr2_size,
+                                      in_tdata->abiflags.cpr2_size);
+#undef max
+  out_tdata->abiflags.ases |= in_tdata->abiflags.ases;
+  out_tdata->abiflags.flags1 |= in_tdata->abiflags.flags1;
+
+  return TRUE;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+bfd_boolean
+_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  struct mips_elf_obj_tdata *out_tdata;
+  struct mips_elf_obj_tdata *in_tdata;
+  bfd_boolean null_input_bfd = TRUE;
+  asection *sec;
+  bfd_boolean ok;
+
+  /* Check if we have the same endianness.  */
+  if (! _bfd_generic_verify_endian_match (ibfd, info))
+    {
+      _bfd_error_handler
+       (_("%pB: endianness incompatible with that of the selected emulation"),
+        ibfd);
+      return FALSE;
+    }
+
+  if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
+    return TRUE;
 
-  /* 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]
-         != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+  in_tdata = mips_elf_tdata (ibfd);
+  out_tdata = mips_elf_tdata (obfd);
+
+  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
     {
-      /* Only error if both are set (to different values).  */
-      if (((new_flags & EF_MIPS_ABI) && (old_flags & EF_MIPS_ABI))
-         || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
-             != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+      _bfd_error_handler
+       (_("%pB: ABI is incompatible with that of the selected emulation"),
+        ibfd);
+      return FALSE;
+    }
+
+  /* Check to see if the input BFD actually contains any sections.  If not,
+     then it has no attributes, and its flags may not have been initialized
+     either, but it cannot actually cause any incompatibility.  */
+  for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+    {
+      /* Ignore synthetic sections and empty .text, .data and .bss sections
+        which are automatically generated by gas.  Also ignore fake
+        (s)common sections, since merely defining a common symbol does
+        not affect compatibility.  */
+      if ((sec->flags & SEC_IS_COMMON) == 0
+         && strcmp (sec->name, ".reginfo")
+         && strcmp (sec->name, ".mdebug")
+         && (sec->size != 0
+             || (strcmp (sec->name, ".text")
+                 && strcmp (sec->name, ".data")
+                 && strcmp (sec->name, ".bss"))))
        {
-         (*_bfd_error_handler)
-           (_("%B: ABI mismatch: linking %s module with previous %s modules"),
-            ibfd,
-            elf_mips_abi_name (ibfd),
-            elf_mips_abi_name (obfd));
-         ok = FALSE;
+         null_input_bfd = FALSE;
+         break;
        }
-      new_flags &= ~EF_MIPS_ABI;
-      old_flags &= ~EF_MIPS_ABI;
     }
+  if (null_input_bfd)
+    return TRUE;
 
-  /* For now, allow arbitrary mixing of ASEs (retain the union).  */
-  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
+  /* Populate abiflags using existing information.  */
+  if (in_tdata->abiflags_valid)
     {
-      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
+      obj_attribute *in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+      Elf_Internal_ABIFlags_v0 in_abiflags;
+      Elf_Internal_ABIFlags_v0 abiflags;
 
-      new_flags &= ~ EF_MIPS_ARCH_ASE;
-      old_flags &= ~ EF_MIPS_ARCH_ASE;
+      /* Set up the FP ABI attribute from the abiflags if it is not already
+        set.  */
+      if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY)
+       in_attr[Tag_GNU_MIPS_ABI_FP].i = in_tdata->abiflags.fp_abi;
+
+      infer_mips_abiflags (ibfd, &abiflags);
+      in_abiflags = in_tdata->abiflags;
+
+      /* It is not possible to infer the correct ISA revision
+        for R3 or R5 so drop down to R2 for the checks.  */
+      if (in_abiflags.isa_rev == 3 || in_abiflags.isa_rev == 5)
+       in_abiflags.isa_rev = 2;
+
+      if (LEVEL_REV (in_abiflags.isa_level, in_abiflags.isa_rev)
+         < LEVEL_REV (abiflags.isa_level, abiflags.isa_rev))
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ISA between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY
+         && in_abiflags.fp_abi != abiflags.fp_abi)
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent FP ABI between .gnu.attributes and "
+            ".MIPS.abiflags"), ibfd);
+      if ((in_abiflags.ases & abiflags.ases) != abiflags.ases)
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ASEs between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      /* The isa_ext is allowed to be an extension of what can be inferred
+        from e_flags.  */
+      if (!mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags.isa_ext),
+                               bfd_mips_isa_ext_mach (in_abiflags.isa_ext)))
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ISA extensions between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      if (in_abiflags.flags2 != 0)
+       _bfd_error_handler
+         (_("%pB: warning: unexpected flag in the flags2 field of "
+            ".MIPS.abiflags (0x%lx)"), ibfd,
+          in_abiflags.flags2);
+    }
+  else
+    {
+      infer_mips_abiflags (ibfd, &in_tdata->abiflags);
+      in_tdata->abiflags_valid = TRUE;
     }
 
-  /* Warn about any other mismatches */
-  if (new_flags != old_flags)
+  if (!out_tdata->abiflags_valid)
     {
-      (*_bfd_error_handler)
-       (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-        ibfd, (unsigned long) new_flags,
-        (unsigned long) old_flags);
-      ok = FALSE;
+      /* Copy input abiflags if output abiflags are not already valid.  */
+      out_tdata->abiflags = in_tdata->abiflags;
+      out_tdata->abiflags_valid = TRUE;
+    }
+
+  if (! elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+      elf_elfheader (obfd)->e_ident[EI_CLASS]
+       = elf_elfheader (ibfd)->e_ident[EI_CLASS];
+
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+         && (bfd_get_arch_info (obfd)->the_default
+             || mips_mach_extends_p (bfd_get_mach (obfd),
+                                     bfd_get_mach (ibfd))))
+       {
+         if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+                                  bfd_get_mach (ibfd)))
+           return FALSE;
+
+         /* Update the ABI flags isa_level, isa_rev and isa_ext fields.  */
+         update_mips_abiflags_isa (obfd, &out_tdata->abiflags);
+       }
+
+      ok = TRUE;
     }
+  else
+    ok = mips_elf_merge_obj_e_flags (ibfd, info);
+
+  ok = mips_elf_merge_obj_attributes (ibfd, info) && ok;
+
+  ok = mips_elf_merge_obj_abiflags (ibfd, obfd) && ok;
 
-  if (! ok)
+  if (!ok)
     {
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
@@ -11743,6 +15924,8 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
       return "MIPS_HIPAGENO";
     case DT_MIPS_RLD_MAP:
       return "MIPS_RLD_MAP";
+    case DT_MIPS_RLD_MAP_REL:
+      return "MIPS_RLD_MAP_REL";
     case DT_MIPS_DELTA_CLASS:
       return "MIPS_DELTA_CLASS";
     case DT_MIPS_DELTA_CLASS_NO:
@@ -11795,9 +15978,218 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
       return "DT_MIPS_GP_VALUE";
     case DT_MIPS_AUX_DYNAMIC:
       return "DT_MIPS_AUX_DYNAMIC";
+    case DT_MIPS_PLTGOT:
+      return "DT_MIPS_PLTGOT";
+    case DT_MIPS_RWPLT:
+      return "DT_MIPS_RWPLT";
+    case DT_MIPS_XHASH:
+      return "DT_MIPS_XHASH";
+    }
+}
+
+/* Return the meaning of Tag_GNU_MIPS_ABI_FP value FP, or null if
+   not known.  */
+
+const char *
+_bfd_mips_fp_abi_string (int fp)
+{
+  switch (fp)
+    {
+      /* These strings aren't translated because they're simply
+        option lists.  */
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      return "-mdouble-float";
+
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      return "-msingle-float";
+
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      return "-msoft-float";
+
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      return _("-mips32r2 -mfp64 (12 callee-saved)");
+
+    case Val_GNU_MIPS_ABI_FP_XX:
+      return "-mfpxx";
+
+    case Val_GNU_MIPS_ABI_FP_64:
+      return "-mgp32 -mfp64";
+
+    case Val_GNU_MIPS_ABI_FP_64A:
+      return "-mgp32 -mfp64 -mno-odd-spreg";
+
+    default:
+      return 0;
+    }
+}
+
+static void
+print_mips_ases (FILE *file, unsigned int mask)
+{
+  if (mask & AFL_ASE_DSP)
+    fputs ("\n\tDSP ASE", file);
+  if (mask & AFL_ASE_DSPR2)
+    fputs ("\n\tDSP R2 ASE", file);
+  if (mask & AFL_ASE_DSPR3)
+    fputs ("\n\tDSP R3 ASE", file);
+  if (mask & AFL_ASE_EVA)
+    fputs ("\n\tEnhanced VA Scheme", file);
+  if (mask & AFL_ASE_MCU)
+    fputs ("\n\tMCU (MicroController) ASE", file);
+  if (mask & AFL_ASE_MDMX)
+    fputs ("\n\tMDMX ASE", file);
+  if (mask & AFL_ASE_MIPS3D)
+    fputs ("\n\tMIPS-3D ASE", file);
+  if (mask & AFL_ASE_MT)
+    fputs ("\n\tMT ASE", file);
+  if (mask & AFL_ASE_SMARTMIPS)
+    fputs ("\n\tSmartMIPS ASE", file);
+  if (mask & AFL_ASE_VIRT)
+    fputs ("\n\tVZ ASE", file);
+  if (mask & AFL_ASE_MSA)
+    fputs ("\n\tMSA ASE", file);
+  if (mask & AFL_ASE_MIPS16)
+    fputs ("\n\tMIPS16 ASE", file);
+  if (mask & AFL_ASE_MICROMIPS)
+    fputs ("\n\tMICROMIPS ASE", file);
+  if (mask & AFL_ASE_XPA)
+    fputs ("\n\tXPA ASE", file);
+  if (mask & AFL_ASE_MIPS16E2)
+    fputs ("\n\tMIPS16e2 ASE", file);
+  if (mask & AFL_ASE_CRC)
+    fputs ("\n\tCRC ASE", file);
+  if (mask & AFL_ASE_GINV)
+    fputs ("\n\tGINV ASE", file);
+  if (mask & AFL_ASE_LOONGSON_MMI)
+    fputs ("\n\tLoongson MMI ASE", file);
+  if (mask & AFL_ASE_LOONGSON_CAM)
+    fputs ("\n\tLoongson CAM ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT)
+    fputs ("\n\tLoongson EXT ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT2)
+    fputs ("\n\tLoongson EXT2 ASE", file);
+  if (mask == 0)
+    fprintf (file, "\n\t%s", _("None"));
+  else if ((mask & ~AFL_ASE_MASK) != 0)
+    fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~AFL_ASE_MASK);
+}
+
+static void
+print_mips_isa_ext (FILE *file, unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case 0:
+      fputs (_("None"), file);
+      break;
+    case AFL_EXT_XLR:
+      fputs ("RMI XLR", file);
+      break;
+    case AFL_EXT_OCTEON3:
+      fputs ("Cavium Networks Octeon3", file);
+      break;
+    case AFL_EXT_OCTEON2:
+      fputs ("Cavium Networks Octeon2", file);
+      break;
+    case AFL_EXT_OCTEONP:
+      fputs ("Cavium Networks OcteonP", file);
+      break;
+    case AFL_EXT_OCTEON:
+      fputs ("Cavium Networks Octeon", file);
+      break;
+    case AFL_EXT_5900:
+      fputs ("Toshiba R5900", file);
+      break;
+    case AFL_EXT_4650:
+      fputs ("MIPS R4650", file);
+      break;
+    case AFL_EXT_4010:
+      fputs ("LSI R4010", file);
+      break;
+    case AFL_EXT_4100:
+      fputs ("NEC VR4100", file);
+      break;
+    case AFL_EXT_3900:
+      fputs ("Toshiba R3900", file);
+      break;
+    case AFL_EXT_10000:
+      fputs ("MIPS R10000", file);
+      break;
+    case AFL_EXT_SB1:
+      fputs ("Broadcom SB-1", file);
+      break;
+    case AFL_EXT_4111:
+      fputs ("NEC VR4111/VR4181", file);
+      break;
+    case AFL_EXT_4120:
+      fputs ("NEC VR4120", file);
+      break;
+    case AFL_EXT_5400:
+      fputs ("NEC VR5400", file);
+      break;
+    case AFL_EXT_5500:
+      fputs ("NEC VR5500", file);
+      break;
+    case AFL_EXT_LOONGSON_2E:
+      fputs ("ST Microelectronics Loongson 2E", file);
+      break;
+    case AFL_EXT_LOONGSON_2F:
+      fputs ("ST Microelectronics Loongson 2F", file);
+      break;
+    case AFL_EXT_INTERAPTIV_MR2:
+      fputs ("Imagination interAptiv MR2", file);
+      break;
+    default:
+      fprintf (file, "%s (%d)", _("Unknown"), isa_ext);
+      break;
+    }
+}
+
+static void
+print_mips_fp_abi_value (FILE *file, int val)
+{
+  switch (val)
+    {
+    case Val_GNU_MIPS_ABI_FP_ANY:
+      fprintf (file, _("Hard or soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      fprintf (file, _("Hard float (double precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      fprintf (file, _("Hard float (single precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      fprintf (file, _("Soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      fprintf (file, _("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_XX:
+      fprintf (file, _("Hard float (32-bit CPU, Any FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64:
+      fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64A:
+      fprintf (file, _("Hard float compat (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    default:
+      fprintf (file, "??? (%d)\n", val);
+      break;
     }
 }
 
+static int
+get_mips_reg_size (int reg_size)
+{
+  return (reg_size == AFL_REG_NONE) ? 0
+        : (reg_size == AFL_REG_32) ? 32
+        : (reg_size == AFL_REG_64) ? 64
+        : (reg_size == AFL_REG_128) ? 128
+        : -1;
+}
+
 bfd_boolean
 _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 {
@@ -11846,6 +16238,10 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
     fprintf (file, " [mips32r2]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2)
     fprintf (file, " [mips64r2]");
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6)
+    fprintf (file, " [mips32r6]");
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6)
+    fprintf (file, " [mips64r6]");
   else
     fprintf (file, _(" [unknown ISA]"));
 
@@ -11855,6 +16251,15 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
     fprintf (file, " [mips16]");
 
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+    fprintf (file, " [micromips]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_NAN2008)
+    fprintf (file, " [nan2008]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64)
+    fprintf (file, " [old fp64]");
+
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
     fprintf (file, " [32bitmode]");
   else
@@ -11877,18 +16282,43 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 
   fputc ('\n', file);
 
+  if (mips_elf_tdata (abfd)->abiflags_valid)
+    {
+      Elf_Internal_ABIFlags_v0 *abiflags = &mips_elf_tdata (abfd)->abiflags;
+      fprintf (file, "\nMIPS ABI Flags Version: %d\n", abiflags->version);
+      fprintf (file, "\nISA: MIPS%d", abiflags->isa_level);
+      if (abiflags->isa_rev > 1)
+       fprintf (file, "r%d", abiflags->isa_rev);
+      fprintf (file, "\nGPR size: %d",
+              get_mips_reg_size (abiflags->gpr_size));
+      fprintf (file, "\nCPR1 size: %d",
+              get_mips_reg_size (abiflags->cpr1_size));
+      fprintf (file, "\nCPR2 size: %d",
+              get_mips_reg_size (abiflags->cpr2_size));
+      fputs ("\nFP ABI: ", file);
+      print_mips_fp_abi_value (file, abiflags->fp_abi);
+      fputs ("ISA Extension: ", file);
+      print_mips_isa_ext (file, abiflags->isa_ext);
+      fputs ("\nASEs:", file);
+      print_mips_ases (file, abiflags->ases);
+      fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1);
+      fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2);
+      fputc ('\n', file);
+    }
+
   return TRUE;
 }
 
 const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
 {
-  { STRING_COMMA_LEN (".lit4"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { STRING_COMMA_LEN (".lit8"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".lit4"),          0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".lit8"),          0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".mdebug"), 0, SHT_MIPS_DEBUG, 0 },
-  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".sbss"),         -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".ucode"),  0, SHT_MIPS_UCODE, 0 },
-  { NULL,                     0,  0, 0,              0 }
+  { STRING_COMMA_LEN (".MIPS.xhash"),  0, SHT_MIPS_XHASH,   SHF_ALLOC },
+  { NULL,                    0,  0, 0,              0 }
 };
 
 /* Merge non visibility st_other attributes.  Ensure that the
@@ -11929,3 +16359,343 @@ _bfd_mips_elf_common_definition (Elf_Internal_Sym *sym)
          || sym->st_shndx == SHN_MIPS_ACOMMON
          || sym->st_shndx == SHN_MIPS_SCOMMON);
 }
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+   or (bfd_vma) -1 if it should not be included.  */
+
+bfd_vma
+_bfd_mips_elf_plt_sym_val (bfd_vma i, const asection *plt,
+                          const arelent *rel ATTRIBUTE_UNUSED)
+{
+  return (plt->vma
+         + 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry)
+         + i * 4 * ARRAY_SIZE (mips_exec_plt_entry));
+}
+
+/* Build a table of synthetic symbols to represent the PLT.  As with MIPS16
+   and microMIPS PLT slots we may have a many-to-one mapping between .plt
+   and .got.plt and also the slots may be of a different size each we walk
+   the PLT manually fetching instructions and matching them against known
+   patterns.  To make things easier standard MIPS slots, if any, always come
+   first.  As we don't create proper ELF symbols we use the UDATA.I member
+   of ASYMBOL to carry ISA annotation.  The encoding used is the same as
+   with the ST_OTHER member of the ELF symbol.  */
+
+long
+_bfd_mips_elf_get_synthetic_symtab (bfd *abfd,
+                                   long symcount ATTRIBUTE_UNUSED,
+                                   asymbol **syms ATTRIBUTE_UNUSED,
+                                   long dynsymcount, asymbol **dynsyms,
+                                   asymbol **ret)
+{
+  static const char pltname[] = "_PROCEDURE_LINKAGE_TABLE_";
+  static const char microsuffix[] = "@micromipsplt";
+  static const char m16suffix[] = "@mips16plt";
+  static const char mipssuffix[] = "@plt";
+
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  bfd_boolean micromips_p = MICROMIPS_P (abfd);
+  Elf_Internal_Shdr *hdr;
+  bfd_byte *plt_data;
+  bfd_vma plt_offset;
+  unsigned int other;
+  bfd_vma entry_size;
+  bfd_vma plt0_size;
+  asection *relplt;
+  bfd_vma opcode;
+  asection *plt;
+  asymbol *send;
+  size_t size;
+  char *names;
+  long counti;
+  arelent *p;
+  asymbol *s;
+  char *nend;
+  long count;
+  long pi;
+  long i;
+  long n;
+
+  *ret = NULL;
+
+  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 || dynsymcount <= 0)
+    return 0;
+
+  relplt = bfd_get_section_by_name (abfd, ".rel.plt");
+  if (relplt == NULL)
+    return 0;
+
+  hdr = &elf_section_data (relplt)->this_hdr;
+  if (hdr->sh_link != elf_dynsymtab (abfd) || hdr->sh_type != SHT_REL)
+    return 0;
+
+  plt = bfd_get_section_by_name (abfd, ".plt");
+  if (plt == NULL)
+    return 0;
+
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (!(*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    return -1;
+  p = relplt->relocation;
+
+  /* Calculating the exact amount of space required for symbols would
+     require two passes over the PLT, so just pessimise assuming two
+     PLT slots per relocation.  */
+  count = relplt->size / hdr->sh_entsize;
+  counti = count * bed->s->int_rels_per_ext_rel;
+  size = 2 * count * sizeof (asymbol);
+  size += count * (sizeof (mipssuffix) +
+                  (micromips_p ? sizeof (microsuffix) : sizeof (m16suffix)));
+  for (pi = 0; pi < counti; pi += bed->s->int_rels_per_ext_rel)
+    size += 2 * strlen ((*p[pi].sym_ptr_ptr)->name);
+
+  /* Add the size of "_PROCEDURE_LINKAGE_TABLE_" too.  */
+  size += sizeof (asymbol) + sizeof (pltname);
+
+  if (!bfd_malloc_and_get_section (abfd, plt, &plt_data))
+    return -1;
+
+  if (plt->size < 16)
+    return -1;
+
+  s = *ret = bfd_malloc (size);
+  if (s == NULL)
+    return -1;
+  send = s + 2 * count + 1;
+
+  names = (char *) send;
+  nend = (char *) s + size;
+  n = 0;
+
+  opcode = bfd_get_micromips_32 (abfd, plt_data + 12);
+  if (opcode == 0x3302fffe)
+    {
+      if (!micromips_p)
+       return -1;
+      plt0_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry);
+      other = STO_MICROMIPS;
+    }
+  else if (opcode == 0x0398c1d0)
+    {
+      if (!micromips_p)
+       return -1;
+      plt0_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry);
+      other = STO_MICROMIPS;
+    }
+  else
+    {
+      plt0_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
+      other = 0;
+    }
+
+  s->the_bfd = abfd;
+  s->flags = BSF_SYNTHETIC | BSF_FUNCTION | BSF_LOCAL;
+  s->section = plt;
+  s->value = 0;
+  s->name = names;
+  s->udata.i = other;
+  memcpy (names, pltname, sizeof (pltname));
+  names += sizeof (pltname);
+  ++s, ++n;
+
+  pi = 0;
+  for (plt_offset = plt0_size;
+       plt_offset + 8 <= plt->size && s < send;
+       plt_offset += entry_size)
+    {
+      bfd_vma gotplt_addr;
+      const char *suffix;
+      bfd_vma gotplt_hi;
+      bfd_vma gotplt_lo;
+      size_t suffixlen;
+
+      opcode = bfd_get_micromips_32 (abfd, plt_data + plt_offset + 4);
+
+      /* Check if the second word matches the expected MIPS16 instruction.  */
+      if (opcode == 0x651aeb00)
+       {
+         if (micromips_p)
+           return -1;
+         /* Truncated table???  */
+         if (plt_offset + 16 > plt->size)
+           break;
+         gotplt_addr = bfd_get_32 (abfd, plt_data + plt_offset + 12);
+         entry_size = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry);
+         suffixlen = sizeof (m16suffix);
+         suffix = m16suffix;
+         other = STO_MIPS16;
+       }
+      /* Likewise the expected microMIPS instruction (no insn32 mode).  */
+      else if (opcode == 0xff220000)
+       {
+         if (!micromips_p)
+           return -1;
+         gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset) & 0x7f;
+         gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x40) - 0x40) << 18;
+         gotplt_lo <<= 2;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         gotplt_addr += ((plt->vma + plt_offset) | 3) ^ 3;
+         entry_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry);
+         suffixlen = sizeof (microsuffix);
+         suffix = microsuffix;
+         other = STO_MICROMIPS;
+       }
+      /* Likewise the expected microMIPS instruction (insn32 mode).  */
+      else if ((opcode & 0xffff0000) == 0xff2f0000)
+       {
+         gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff;
+         gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 6) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16;
+         gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         entry_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry);
+         suffixlen = sizeof (microsuffix);
+         suffix = microsuffix;
+         other = STO_MICROMIPS;
+       }
+      /* Otherwise assume standard MIPS code.  */
+      else
+       {
+         gotplt_hi = bfd_get_32 (abfd, plt_data + plt_offset) & 0xffff;
+         gotplt_lo = bfd_get_32 (abfd, plt_data + plt_offset + 4) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16;
+         gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+         suffixlen = sizeof (mipssuffix);
+         suffix = mipssuffix;
+         other = 0;
+       }
+      /* Truncated table???  */
+      if (plt_offset + entry_size > plt->size)
+       break;
+
+      for (i = 0;
+          i < count && p[pi].address != gotplt_addr;
+          i++, pi = (pi + bed->s->int_rels_per_ext_rel) % counti);
+
+      if (i < count)
+       {
+         size_t namelen;
+         size_t len;
+
+         *s = **p[pi].sym_ptr_ptr;
+         /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
+            we are defining a symbol, ensure one of them is set.  */
+         if ((s->flags & BSF_LOCAL) == 0)
+           s->flags |= BSF_GLOBAL;
+         s->flags |= BSF_SYNTHETIC;
+         s->section = plt;
+         s->value = plt_offset;
+         s->name = names;
+         s->udata.i = other;
+
+         len = strlen ((*p[pi].sym_ptr_ptr)->name);
+         namelen = len + suffixlen;
+         if (names + namelen > nend)
+           break;
+
+         memcpy (names, (*p[pi].sym_ptr_ptr)->name, len);
+         names += len;
+         memcpy (names, suffix, suffixlen);
+         names += suffixlen;
+
+         ++s, ++n;
+         pi = (pi + bed->s->int_rels_per_ext_rel) % counti;
+       }
+    }
+
+  free (plt_data);
+
+  return n;
+}
+
+/* Return the ABI flags associated with ABFD if available.  */
+
+Elf_Internal_ABIFlags_v0 *
+bfd_mips_elf_get_abiflags (bfd *abfd)
+{
+  struct mips_elf_obj_tdata *tdata = mips_elf_tdata (abfd);
+
+  return tdata->abiflags_valid ? &tdata->abiflags : NULL;
+}
+
+/* MIPS libc ABI versions, used with the EI_ABIVERSION ELF file header
+   field.  Taken from `libc-abis.h' generated at GNU libc build time.
+   Using a MIPS_ prefix as other libc targets use different values.  */
+enum
+{
+  MIPS_LIBC_ABI_DEFAULT = 0,
+  MIPS_LIBC_ABI_MIPS_PLT,
+  MIPS_LIBC_ABI_UNIQUE,
+  MIPS_LIBC_ABI_MIPS_O32_FP64,
+  MIPS_LIBC_ABI_ABSOLUTE,
+  MIPS_LIBC_ABI_XHASH,
+  MIPS_LIBC_ABI_MAX
+};
+
+bfd_boolean
+_bfd_mips_init_file_header (bfd *abfd, struct bfd_link_info *link_info)
+{
+  struct mips_elf_link_hash_table *htab = NULL;
+  Elf_Internal_Ehdr *i_ehdrp;
+
+  if (!_bfd_elf_init_file_header (abfd, link_info))
+    return FALSE;
+
+  i_ehdrp = elf_elfheader (abfd);
+  if (link_info)
+    {
+      htab = mips_elf_hash_table (link_info);
+      BFD_ASSERT (htab != NULL);
+    }
+
+  if (htab != NULL && htab->use_plts_and_copy_relocs && !htab->is_vxworks)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
+
+  if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
+      || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+
+  /* Mark that we need support for absolute symbols in the dynamic loader.  */
+  if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
+
+  /* Mark that we need support for .MIPS.xhash in the dynamic linker,
+     if it is the only hash section that will be created.  */
+  if (link_info && link_info->emit_gnu_hash && !link_info->emit_hash)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_XHASH;
+  return TRUE;
+}
+
+int
+_bfd_mips_elf_compact_eh_encoding
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+{
+  return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+}
+
+/* Return the opcode for can't unwind.  */
+
+int
+_bfd_mips_elf_cant_unwind_opcode
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+{
+  return COMPACT_EH_CANT_UNWIND_OPCODE;
+}
+
+/* Record a position XLAT_LOC in the xlat translation table, associated with
+   the hash entry H.  The entry in the translation table will later be
+   populated with the real symbol dynindx.  */
+
+void
+_bfd_mips_elf_record_xhash_symbol (struct elf_link_hash_entry *h,
+                                  bfd_vma xlat_loc)
+{
+  struct mips_elf_link_hash_entry *hmips;
+
+  hmips = (struct mips_elf_link_hash_entry *) h;
+  hmips->mipsxhash_loc = xlat_loc;
+}
This page took 0.205137 seconds and 4 git commands to generate.