* elf32-mips.c (mips_elf_obtain_contents): Swap 16-bit halves of
[deliverable/binutils-gdb.git] / bfd / elf32-mips.c
index 8800423ab0784ab5c106078dc66572db37d92f00..8f45fe114c99d5876b7f75e9b02f12505cec37ff 100644 (file)
@@ -3,6 +3,8 @@
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
+   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
+   <mark@codesourcery.com>
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -49,6 +51,8 @@ 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 local .got entries.  */
   unsigned int local_gotno;
   /* The number of local .got entries we have used.  */
@@ -65,8 +69,9 @@ struct mips_elf_link_hash_entry
   /* External symbol information.  */
   EXTR esym;
 
-  /* Number of MIPS_32 or MIPS_REL32 relocs against this symbol.  */
-  unsigned int mips_32_relocs;
+  /* Number of R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 relocs against
+     this symbol.  */ 
+  unsigned int possibly_dynamic_relocs;
 
   /* The index of the first dynamic relocation (in the .rel.dyn
      section) against this symbol.  */
@@ -106,28 +111,17 @@ static void bfd_mips_elf_swap_msym_in
 static void bfd_mips_elf_swap_msym_out
   PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
 static boolean mips_elf_sym_is_global PARAMS ((bfd *, asymbol *));
-static boolean mips_elf32_object_p PARAMS ((bfd *));
 static boolean mips_elf_create_procedure_table
   PARAMS ((PTR, bfd *, struct bfd_link_info *, asection *,
           struct ecoff_debug_info *));
-static int mips_elf_additional_program_headers PARAMS ((bfd *));
-static boolean mips_elf_modify_segment_map PARAMS ((bfd *));
 static INLINE int elf_mips_isa PARAMS ((flagword));
 static INLINE int elf_mips_mach PARAMS ((flagword));
-static INLINE char* elf_mips_abi_name PARAMS ((flagword));
-static boolean mips_elf32_section_from_shdr
-  PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
-static boolean mips_elf32_section_processing
-  PARAMS ((bfd *, Elf32_Internal_Shdr *));
+static INLINE char* elf_mips_abi_name PARAMS ((bfd *));
 static boolean mips_elf_is_local_label_name
   PARAMS ((bfd *, const char *));
 static struct bfd_hash_entry *mips_elf_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
-static struct bfd_link_hash_table *mips_elf_link_hash_table_create
-  PARAMS ((bfd *));
 static int gptab_compare PARAMS ((const void *, const void *));
-static boolean mips_elf_final_link
-  PARAMS ((bfd *, struct bfd_link_info *));
 static void mips_elf_relocate_hi16
   PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *,
           bfd_vma));
@@ -140,35 +134,10 @@ static bfd_reloc_status_type mips16_jump_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type mips16_gprel_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static boolean mips_elf_relocate_section
-  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
-          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
-static boolean mips_elf_link_output_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-          asection *));
-static boolean mips_elf_create_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean mips_elf_create_compact_rel_section
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean mips_elf_create_got_section
   PARAMS ((bfd *, struct bfd_link_info *));
-static boolean mips_elf_check_relocs
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-          const Elf_Internal_Rela *));
-static boolean mips_elf_adjust_dynamic_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static boolean mips_elf_always_size_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-static boolean mips_elf_size_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-static boolean mips_elf_finish_dynamic_symbol
-  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
-          Elf_Internal_Sym *));
-static boolean mips_elf_finish_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-static boolean mips_elf_add_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
-          const char **, flagword *, asection **, bfd_vma *));
 static bfd_reloc_status_type mips_elf_final_gp
   PARAMS ((bfd *, asymbol *, boolean, char **, bfd_vma *));
 static bfd_byte *elf32_mips_get_relocated_section_contents
@@ -195,22 +164,22 @@ static boolean mips_elf_record_global_got_symbol
 static bfd_vma mips_elf_got_page
   PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *));
 static boolean mips_elf_next_lo16_addend
-  PARAMS ((Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_vma *));
+  PARAMS ((const Elf_Internal_Rela *, const Elf_Internal_Rela *, bfd_vma *));
 static bfd_reloc_status_type mips_elf_calculate_relocation
   PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
-          Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
-          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **,
-          bfd_vma *, const char **));
+          const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
+          Elf_Internal_Sym *, asection **, bfd_vma *, const char **));
 static bfd_vma mips_elf_obtain_contents
-  PARAMS ((reloc_howto_type *, Elf_Internal_Rela *, bfd *, bfd_byte *));
+  PARAMS ((reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *));
 static void mips_elf_perform_relocation
-  PARAMS ((reloc_howto_type *, Elf_Internal_Rela *, bfd_vma,
+  PARAMS ((struct bfd_link_info *, reloc_howto_type *, 
+          const Elf_Internal_Rela *, bfd_vma,
           bfd *, bfd_byte *));
 static boolean mips_elf_assign_gp PARAMS ((bfd *, bfd_vma *));
 static boolean mips_elf_sort_hash_table_f 
   PARAMS ((struct mips_elf_link_hash_entry *, PTR));
 static boolean mips_elf_sort_hash_table 
-  PARAMS ((struct bfd_link_info *));
+  PARAMS ((struct bfd_link_info *, unsigned long));
 static asection * mips_elf_got_section PARAMS ((bfd *));
 static struct mips_got_info *mips_elf_got_info 
   PARAMS ((bfd *, asection **));
@@ -219,8 +188,10 @@ static bfd_vma mips_elf_create_local_got_entry
 static bfd_vma mips_elf_got16_entry 
   PARAMS ((bfd *, struct bfd_link_info *, bfd_vma));
 static unsigned int mips_elf_create_dynamic_relocation 
-  PARAMS ((bfd *, struct bfd_link_info *, Elf32_Internal_Rela *,
+  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
           long, bfd_vma, asection *));
+static void mips_elf_allocate_dynamic_relocations 
+  PARAMS ((bfd *, unsigned int));
 
 /* The level of IRIX compatibility we're striving for.  */
 
@@ -266,15 +237,63 @@ typedef enum {
 #define MIPS_ELF_STUB_SECTION_NAME(abfd) \
   (IRIX_COMPAT (abfd) == ict_irix6 ? ".MIPS.stubs" : ".stub")
 
+/* The name of the dynamic relocation section.  */
+#define MIPS_ELF_REL_DYN_SECTION_NAME(abfd) ".rel.dyn"
+
+/* The size of an external REL relocation.  */
+#define MIPS_ELF_REL_SIZE(abfd) \
+  (get_elf_backend_data (abfd)->s->sizeof_rel)
+
+/* The size of an external dynamic table entry.  */
+#define MIPS_ELF_DYN_SIZE(abfd) \
+  (get_elf_backend_data (abfd)->s->sizeof_dyn)
+
+/* The size of a GOT entry.  */
+#define MIPS_ELF_GOT_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)
+
+/* The default alignment for sections, as a power of two.  */
+#define MIPS_ELF_LOG_FILE_ALIGN(abfd)                          \
+  (get_elf_backend_data (abfd)->s->file_align == 8 ? 3 : 2)
+
+/* Get word-sized data.  */
+#define MIPS_ELF_GET_WORD(abfd, ptr) \
+  (ABI_64_P (abfd) ? bfd_get_64 (abfd, ptr) : bfd_get_32 (abfd, ptr))
+
+/* Put out word-sized data.  */
+#define MIPS_ELF_PUT_WORD(abfd, val, ptr)      \
+  (ABI_64_P (abfd)                             \
+   ? bfd_put_64 (abfd, val, ptr)               \
+   : bfd_put_32 (abfd, val, ptr))
+
+/* Add a dynamic symbol table-entry.  */
+#ifdef BFD64
+#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
+  (ABI_64_P (elf_hash_table (info)->dynobj)       \
+   ? bfd_elf64_add_dynamic_entry (info, tag, val)  \
+   : bfd_elf32_add_dynamic_entry (info, tag, val))
+#else
+#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
+  (ABI_64_P (elf_hash_table (info)->dynobj)       \
+   ? (abort (), false)                             \
+   : bfd_elf32_add_dynamic_entry (info, tag, val))
+#endif
+
 /* The number of local .got entries we reserve.  */
 #define MIPS_RESERVED_GOTNO (2)
 
 /* Instructions which appear in a stub.  For some reason the stub is
    slightly different on an SGI system.  */
 #define ELF_MIPS_GP_OFFSET(abfd) (SGI_COMPAT (abfd) ? 0x7ff0 : 0x8000)
-#define STUB_LW(abfd)                                  \
-  (SGI_COMPAT (abfd)                                   \
-   ? 0x8f998010                        /* lw t9,0x8010(gp) */  \
+#define STUB_LW(abfd)                                          \
+  (SGI_COMPAT (abfd)                                           \
+   ? (ABI_64_P (abfd)                                                  \
+      ? 0xdf998010             /* ld t9,0x8010(gp) */          \
+      : 0x8f998010)             /* lw t9,0x8010(gp) */         \
    : 0x8f998000)               /* lw t9,0x8000(gp) */
 #define STUB_MOVE 0x03e07825   /* move t7,ra */
 #define STUB_JALR 0x0320f809   /* jal t9 */
@@ -627,9 +646,9 @@ static reloc_howto_type elf_mips_howto_table[] =
 
     /* The remaining relocs are defined on Irix 5, although they are
        not defined by the ABI.  */
-    { 13 },
-    { 14 },
-    { 15 },
+    EMPTY_HOWTO (13),
+    EMPTY_HOWTO (14),
+    EMPTY_HOWTO (15),
 
   /* A 5 bit shift field.  */
   HOWTO (R_MIPS_SHIFT5,                /* type */
@@ -663,22 +682,19 @@ static reloc_howto_type elf_mips_howto_table[] =
         0x000007c4,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* A 64 bit relocation.  This is used in 32 bit ELF when addresses
-     are 64 bits long; the upper 32 bits are simply a sign extension.
-     The fields of the howto should be the same as for R_MIPS_32,
-     other than the type, name, and special_function.  */
+  /* A 64 bit relocation.  */
   HOWTO (R_MIPS_64,            /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         mips32_64bit_reloc,    /* special_function */
         "R_MIPS_64",           /* name */
         true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
+        MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Displacement in the global offset table.  */
@@ -772,14 +788,39 @@ static reloc_howto_type elf_mips_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Used to cause the linker to insert and delete instructions?  */
-  { R_MIPS_INSERT_A },
-  { R_MIPS_INSERT_B },
-  { R_MIPS_DELETE },
+  EMPTY_HOWTO (R_MIPS_INSERT_A),
+  EMPTY_HOWTO (R_MIPS_INSERT_B),
+  EMPTY_HOWTO (R_MIPS_DELETE),
 
-  /* Get the higher values of a 64 bit addend.  Presumably not used in
-     32 bit ELF.  */
-  { R_MIPS_HIGHER },
-  { R_MIPS_HIGHEST },
+  /* Get the higher value of a 64 bit addend.  */
+  HOWTO (R_MIPS_HIGHER,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_HIGHER",       /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Get the highest value of a 64 bit addend.  */
+  HOWTO (R_MIPS_HIGHEST,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_HIGHEST",      /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
 
   /* High 16 bits of displacement in global offset table.  */
   HOWTO (R_MIPS_CALL_HI16,     /* type */
@@ -826,10 +867,10 @@ static reloc_howto_type elf_mips_howto_table[] =
         0xffffffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  { R_MIPS_REL16 },
-  { R_MIPS_ADD_IMMEDIATE },
-  { R_MIPS_PJUMP },
-  { R_MIPS_RELGOT },
+  EMPTY_HOWTO (R_MIPS_REL16),
+  EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
+  EMPTY_HOWTO (R_MIPS_PJUMP),
+  EMPTY_HOWTO (R_MIPS_RELGOT),
 
   /* Protected jump conversion.  This is an optimization hint.  No 
      relocation is required for correctness.  */
@@ -884,10 +925,7 @@ static reloc_howto_type elf_mips16_jump_howto =
         0x3ffffff,             /* dst_mask */
         false);                /* pcrel_offset */
 
-/* The reloc used for the mips16 gprel instruction.  The src_mask and
-   dsk_mask for this howto do not reflect the actual instruction, in
-   which the value is not contiguous; the masks are for the
-   convenience of the relocate_section routine.  */
+/* The reloc used for the mips16 gprel instruction.  */
 static reloc_howto_type elf_mips16_gprel_howto =
   HOWTO (R_MIPS16_GPREL,       /* type */
         0,                     /* rightshift */
@@ -899,8 +937,8 @@ static reloc_howto_type elf_mips16_gprel_howto =
         mips16_gprel_reloc,    /* special_function */
         "R_MIPS16_GPREL",      /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x07ff001f,            /* src_mask */
+        0x07ff001f,            /* dst_mask */
         false);                /* pcrel_offset */
 
 
@@ -964,7 +1002,7 @@ _bfd_mips_elf_hi16_reloc (abfd,
                     input_section,
                     output_bfd,
                     error_message)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *reloc_entry;
      asymbol *symbol;
      PTR data;
@@ -1567,13 +1605,13 @@ mips32_64bit_reloc (abfd, reloc_entry, symbol, data, input_section,
 static bfd_reloc_status_type
 mips16_jump_reloc (abfd, reloc_entry, symbol, data, input_section,
                   output_bfd, error_message)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *reloc_entry;
      asymbol *symbol;
-     PTR data;
+     PTR data ATTRIBUTE_UNUSED;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   if (output_bfd != (bfd *) NULL
       && (symbol->flags & BSF_SECTION_SYM) == 0
@@ -1741,12 +1779,20 @@ elf_mips_mach (flags)
   return 0;
 }
 
-/* Return printable name for ABI from flagword. */
+/* Return printable name for ABI. */
 
 static INLINE char*
-elf_mips_abi_name (flags)
-     flagword flags;
+elf_mips_abi_name (abfd)
+     bfd *abfd;
 {
+  flagword flags;
+
+  if (ABI_N32_P (abfd))
+    return "N32";
+  else if (ABI_64_P (abfd))
+    return "64";
+      
+  flags = elf_elfheader (abfd)->e_flags;
   switch (flags & EF_MIPS_ABI)
     {
     case 0:
@@ -2095,7 +2141,7 @@ bfd_mips_elf_swap_msym_out (abfd, in, ex)
 /*ARGSUSED*/
 static boolean
 mips_elf_sym_is_global (abfd, sym)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      asymbol *sym;
 {
   return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
@@ -2108,23 +2154,14 @@ boolean
 _bfd_mips_elf_object_p (abfd)
      bfd *abfd;
 {
-  bfd_default_set_arch_mach (abfd, bfd_arch_mips,
-                            elf_mips_mach (elf_elfheader (abfd)->e_flags));
-  return true;
-}
-
-/* Set the right machine number for a 32-bit MIPS ELF file.  */
-
-static boolean
-mips_elf32_object_p (abfd)
-     bfd *abfd;
-{
-  /* Irix 5 is broken.  Object file symbol tables are not always
+  /* Irix 5 and 6 is broken.  Object file symbol tables are not always
      sorted correctly such that local symbols precede global symbols,
      and the sh_info field in the symbol table is not always right.  */
   elf_bad_symtab (abfd) = true;
 
-  return _bfd_mips_elf_object_p (abfd);
+  bfd_default_set_arch_mach (abfd, bfd_arch_mips,
+                            elf_mips_mach (elf_elfheader (abfd)->e_flags));
+  return true;
 }
 
 /* The final processing done just before writing out a MIPS ELF object
@@ -2135,7 +2172,7 @@ mips_elf32_object_p (abfd)
 void
 _bfd_mips_elf_final_write_processing (abfd, linker)
      bfd *abfd;
-     boolean linker;
+     boolean linker ATTRIBUTE_UNUSED;
 {
   unsigned long val;
   unsigned int i;
@@ -2333,6 +2370,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
     {
       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)
@@ -2420,18 +2459,22 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
       old_flags &= ~ (EF_MIPS_ARCH | EF_MIPS_MACH);
     }
 
-  /* Compare ABI's */
-  if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI))
+  /* Compare ABI's.  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))
+      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)
            (_("%s: ABI mismatch: linking %s module with previous %s modules"),
             bfd_get_filename (ibfd),
-            elf_mips_abi_name (new_flags),
-            elf_mips_abi_name (old_flags));
+            elf_mips_abi_name (ibfd),
+            elf_mips_abi_name (obfd));
          ok = false;
        }
       new_flags &= ~EF_MIPS_ABI;
@@ -2457,7 +2500,7 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
   return true;
 }
 \f
-static boolean
+boolean
 _bfd_mips_elf_print_private_bfd_data (abfd, ptr)
      bfd *abfd;
      PTR ptr;
@@ -2482,8 +2525,10 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr)
     fprintf (file, _ (" [abi=EABI64]"));
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI))
     fprintf (file, _ (" [abi unknown]"));
-  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2))
+  else if (ABI_N32_P (abfd))
     fprintf (file, _ (" [abi=N32]"));
+  else if (ABI_64_P (abfd))
+    fprintf (file, _ (" [abi=64]"));
   else
     fprintf (file, _ (" [no abi set]"));
 
@@ -2519,7 +2564,7 @@ boolean
 _bfd_mips_elf_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      Elf_Internal_Shdr *hdr;
-     const char *name;
+     char *name;
 {
   flagword flags = 0;
 
@@ -2603,20 +2648,6 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name)
        return false;
     }
 
-  return true;
-}
-
-/* Handle a 32-bit MIPS ELF specific section.  */
-
-static boolean
-mips_elf32_section_from_shdr (abfd, hdr, name)
-     bfd *abfd;
-     Elf_Internal_Shdr *hdr;
-     char *name;
-{
-  if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name))
-    return false;
-
   /* FIXME: We should record sh_info for a .gptab section.  */
 
   /* For a .reginfo section, set the gp value in the tdata information
@@ -2660,7 +2691,18 @@ mips_elf32_section_from_shdr (abfd, hdr, name)
 
          bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
                                        &intopt);
-         if (intopt.kind == ODK_REGINFO)
+         if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO)
+           {
+             Elf64_Internal_RegInfo intreg;
+
+             bfd_mips_elf64_swap_reginfo_in
+               (abfd,
+                ((Elf64_External_RegInfo *)
+                 (l + sizeof (Elf_External_Options))),
+                &intreg);
+             elf_gp (abfd) = intreg.ri_gp_value;
+           }
+         else if (intopt.kind == ODK_REGINFO)
            {
              Elf32_RegInfo intreg;
 
@@ -2699,12 +2741,6 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
       hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib);
       /* The sh_link field is set in final_write_processing.  */
     }
-  else if (strcmp (name, MIPS_ELF_MSYM_SECTION_NAME (abfd)) == 0)
-    {
-      hdr->sh_type = SHT_MIPS_MSYM;
-      hdr->sh_entsize = 8;
-      /* FIXME: Set the sh_info field.  */
-    }
   else if (strcmp (name, ".conflict") == 0)
     hdr->sh_type = SHT_MIPS_CONFLICT;
   else if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0)
@@ -2821,8 +2857,8 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
 
 boolean
 _bfd_mips_elf_section_from_bfd_section (abfd, hdr, sec, retval)
-     bfd *abfd;
-     Elf32_Internal_Shdr *hdr;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     Elf32_Internal_Shdr *hdr ATTRIBUTE_UNUSED;
      asection *sec;
      int *retval;
 {
@@ -2893,57 +2929,6 @@ boolean
 _bfd_mips_elf_section_processing (abfd, hdr)
      bfd *abfd;
      Elf_Internal_Shdr *hdr;
-{
-  if (hdr->bfd_section != NULL)
-    {
-      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
-
-      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;
-       }
-      else if (strcmp (name, MIPS_ELF_SRDATA_SECTION_NAME (abfd)) == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_PROGBITS;
-       }
-      else if (strcmp (name, ".compact_rel") == 0)
-       {
-         hdr->sh_flags = 0;
-         hdr->sh_type = SHT_PROGBITS;
-       }
-      else if (strcmp (name, ".rtproc") == 0)
-       {
-         if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
-           {
-             unsigned int adjust;
-
-             adjust = hdr->sh_size % hdr->sh_addralign;
-             if (adjust != 0)
-               hdr->sh_size += hdr->sh_addralign - adjust;
-           }
-       }
-    }
-
-  return true;
-}
-
-/* Work over a section just before writing it out.  We update the GP
-   value in the SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS sections based
-   on the value we are using.  */
-
-static boolean
-mips_elf32_section_processing (abfd, hdr)
-     bfd *abfd;
-     Elf32_Internal_Shdr *hdr;
 {
   if (hdr->sh_type == SHT_MIPS_REGINFO
       && hdr->sh_size > 0)
@@ -2985,7 +2970,22 @@ mips_elf32_section_processing (abfd, hdr)
 
          bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
                                        &intopt);
-         if (intopt.kind == ODK_REGINFO)
+         if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO)
+           {
+             bfd_byte buf[8];
+
+             if (bfd_seek (abfd,
+                           (hdr->sh_offset
+                            + (l - contents)
+                            + sizeof (Elf_External_Options)
+                            + (sizeof (Elf64_External_RegInfo) - 8)),
+                            SEEK_SET) == -1)
+               return false;
+             bfd_h_put_64 (abfd, elf_gp (abfd), buf);
+             if (bfd_write (buf, 1, 8, abfd) != 8)
+               return false;
+           }
+         else if (intopt.kind == ODK_REGINFO)
            {
              bfd_byte buf[4];
 
@@ -3004,8 +3004,48 @@ mips_elf32_section_processing (abfd, hdr)
        }
     }
 
-  return _bfd_mips_elf_section_processing (abfd, hdr);
+  if (hdr->bfd_section != NULL)
+    {
+      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+
+      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;
+       }
+      else if (strcmp (name, MIPS_ELF_SRDATA_SECTION_NAME (abfd)) == 0)
+       {
+         hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
+         hdr->sh_type = SHT_PROGBITS;
+       }
+      else if (strcmp (name, ".compact_rel") == 0)
+       {
+         hdr->sh_flags = 0;
+         hdr->sh_type = SHT_PROGBITS;
+       }
+      else if (strcmp (name, ".rtproc") == 0)
+       {
+         if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
+           {
+             unsigned int adjust;
+
+             adjust = hdr->sh_size % hdr->sh_addralign;
+             if (adjust != 0)
+               hdr->sh_size += hdr->sh_addralign - adjust;
+           }
+       }
+    }
+
+  return true;
 }
+
 \f
 /* MIPS ELF uses two common sections.  One is the usual one, and the
    other is for small objects.  All the small objects are kept
@@ -3114,8 +3154,8 @@ _bfd_mips_elf_symbol_processing (abfd, asym)
 /* When creating an Irix 5 executable, we need REGINFO and RTPROC
    segments.  */
 
-static int
-mips_elf_additional_program_headers (abfd)
+int
+_bfd_mips_elf_additional_program_headers (abfd)
      bfd *abfd;
 {
   asection *s;
@@ -3146,8 +3186,8 @@ mips_elf_additional_program_headers (abfd)
 
 /* Modify the segment map for an Irix 5 executable.  */
 
-static boolean
-mips_elf_modify_segment_map (abfd)
+boolean
+_bfd_mips_elf_modify_segment_map (abfd)
      bfd *abfd;
 {
   asection *s;
@@ -3724,7 +3764,7 @@ mips_elf_link_hash_newfunc (entry, table, string)
       /* 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->mips_32_relocs = 0;
+      ret->possibly_dynamic_relocs = 0;
       ret->min_dyn_reloc_index = 0;
       ret->fn_stub = NULL;
       ret->need_fn_stub = false;
@@ -3737,8 +3777,8 @@ mips_elf_link_hash_newfunc (entry, table, string)
 
 /* Create a MIPS ELF linker hash table.  */
 
-static struct bfd_link_hash_table *
-mips_elf_link_hash_table_create (abfd)
+struct bfd_link_hash_table *
+_bfd_mips_elf_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct mips_elf_link_hash_table *ret;
@@ -3773,13 +3813,13 @@ mips_elf_link_hash_table_create (abfd)
    file.  We must handle the special MIPS section numbers here.  */
 
 /*ARGSUSED*/
-static boolean
-mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+boolean
+_bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      bfd *abfd;
      struct bfd_link_info *info;
      const Elf_Internal_Sym *sym;
      const char **namep;
-     flagword *flagsp;
+     flagword *flagsp ATTRIBUTE_UNUSED;
      asection **secp;
      bfd_vma *valp;
 {
@@ -4251,8 +4291,8 @@ gptab_compare (p1, p2)
    the .mdebug sections.  We need to merge all instances of these
    sections together, not write them all out sequentially.  */
 
-static boolean
-mips_elf_final_link (abfd, info)
+boolean
+_bfd_mips_elf_final_link (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
@@ -4279,6 +4319,30 @@ mips_elf_final_link (abfd, info)
       elf_elfheader (abfd)->e_flags |= EF_MIPS_CPIC;
     }
 
+  /* We'd carefully arranged the dynamic symbol indices, and then the
+     generic size_dynamic_sections renumbered them out from under us.
+     Rather than trying somehow to prevent the renumbering, just do
+     the sort again.  */
+
+  if (elf_hash_table (info)->dynobj)
+    {
+      bfd *dynobj;
+      asection *got;
+      struct mips_got_info *g;
+
+      if (!mips_elf_sort_hash_table (info, bfd_count_sections (abfd) + 1))
+        return false;
+
+      /* Make sure we didn't grow the global .got region.  */
+      dynobj = elf_hash_table (info)->dynobj;
+      got = bfd_get_section_by_name (dynobj, ".got");
+      g = (struct mips_got_info *) elf_section_data (got)->tdata;
+
+      BFD_ASSERT ((elf_hash_table (info)->dynsymcount
+                  - g->global_gotsym->dynindx)
+                 <= g->global_gotno);
+    }
+
   /* On IRIX5, we omit the .options section.  On IRIX6, however, we
      include it, even though we don't process it quite right.  (Some
      entries are supposed to be merged.)  Empirically, we seem to be
@@ -4854,7 +4918,17 @@ mips_elf_final_link (abfd, info)
     }
 
   /* Invoke the regular ELF backend linker to do all the work.  */
-  if (! bfd_elf32_bfd_final_link (abfd, info))
+  if (ABI_64_P (abfd))
+    {
+#ifdef BFD64
+      if (!bfd_elf64_bfd_final_link (abfd, info))
+       return false;
+#else
+      abort ();
+      return false;
+#endif /* BFD64 */
+    }
+  else if (!bfd_elf32_bfd_final_link (abfd, info))
     return false;
 
   /* Now write out the computed sections.  */
@@ -5113,7 +5187,7 @@ mips_elf_high (value)
 
 static bfd_vma
 mips_elf_higher (value)
-     bfd_vma value;
+     bfd_vma value ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   return ((value + (bfd_vma) 0x80008000) >> 32) & 0xffff;
@@ -5127,7 +5201,7 @@ mips_elf_higher (value)
 
 static bfd_vma 
 mips_elf_highest (value)
-     bfd_vma value;
+     bfd_vma value ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   return ((value + (bfd_vma) 0x800080008000) > 48) & 0xffff;
@@ -5155,7 +5229,8 @@ mips_elf_global_got_index (abfd, h)
      indices into the GOT.  That makes it easy to calculate the GOT
      offset.  */
   BFD_ASSERT (h->dynindx >= g->global_gotsym->dynindx);
-  index = (h->dynindx - g->global_gotsym->dynindx + g->local_gotno) * 4;
+  index = ((h->dynindx - g->global_gotsym->dynindx + g->local_gotno) 
+          * MIPS_ELF_GOT_SIZE (abfd));
   BFD_ASSERT (index < sgot->_raw_size);
 
   return index;
@@ -5172,9 +5247,8 @@ mips_elf_got_offset_from_index (dynobj, output_bfd, index)
 {
   asection *sgot;
   bfd_vma gp;
-  char *error_message;
 
-  sgot = bfd_get_section_by_name (dynobj, ".got");
+  sgot = mips_elf_got_section (dynobj);
   gp = _bfd_get_gp_value (output_bfd);
   return (sgot->output_section->vma + sgot->output_offset + index - 
          gp);
@@ -5188,7 +5262,7 @@ static boolean
 mips_elf_record_global_got_symbol (h, info, g)
      struct elf_link_hash_entry *h;
      struct bfd_link_info *info;
-     struct mips_got_info *g;
+     struct mips_got_info *g ATTRIBUTE_UNUSED;
 {
   /* A global symbol in the GOT must also be in the dynamic symbol
      table.  */
@@ -5254,11 +5328,15 @@ mips_elf_sort_hash_table_f (h, data)
 
 /* Sort the dynamic symbol table so that symbols that need GOT entries
    appear towards the end.  This reduces the amount of GOT space
-   required.  */
+   required.  MAX_LOCAL is used to set the number of local symbols
+   known to be in the dynamic symbol table.  During
+   mips_elf_size_dynamic_sections, this value is 1.  Afterward, the
+   section symbols are added and the count is higher.  */
 
 static boolean
-mips_elf_sort_hash_table (info)
+mips_elf_sort_hash_table (info, max_local)
      struct bfd_link_info *info;
+     unsigned long max_local;
 {
   struct mips_elf_hash_sort_data hsd;
   struct mips_got_info *g;
@@ -5268,7 +5346,7 @@ mips_elf_sort_hash_table (info)
 
   hsd.low = NULL;
   hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount;
-  hsd.max_non_got_dynindx = 1;
+  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, 
@@ -5305,8 +5383,10 @@ mips_elf_create_local_got_entry (abfd, g, sgot, value)
       return (bfd_vma) -1;
     }
 
-  bfd_put_32 (abfd, value, sgot->contents + 4 * g->assigned_gotno);
-  return 4 * g->assigned_gotno++;
+  MIPS_ELF_PUT_WORD (abfd, value,
+                    (sgot->contents 
+                     + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno));
+  return MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
 }
 
 /* Returns the GOT offset at which the indicated address can be found.
@@ -5326,12 +5406,12 @@ mips_elf_local_got_index (abfd, info, value)
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
   /* Look to see if we already have an appropriate entry.  */
-  for (entry = sgot->contents + 4 * MIPS_RESERVED_GOTNO; 
-       entry != sgot->contents + 4 * g->assigned_gotno;
-       entry += 4)
+  for (entry = (sgot->contents 
+               + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO); 
+       entry != sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno;
+       entry += MIPS_ELF_GOT_SIZE (abfd))
     {
-      bfd_vma address = bfd_get_32 (abfd, entry);
-
+      bfd_vma address = MIPS_ELF_GET_WORD (abfd, entry);
       if (address == value)
        return entry - sgot->contents;
     }
@@ -5362,12 +5442,14 @@ mips_elf_got_page (abfd, info, value, offsetp)
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
   /* Look to see if we aleady have an appropriate entry.  */
-  last_entry = sgot->contents + 4 * g->assigned_gotno;
-  for (entry = sgot->contents + 4 * MIPS_RESERVED_GOTNO; 
+  last_entry = sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno;
+  for (entry = (sgot->contents 
+               + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO);
        entry != last_entry;
-       entry += 4)
+       entry += MIPS_ELF_GOT_SIZE (abfd))
     {
-      address = bfd_get_32 (abfd, entry);
+      address = MIPS_ELF_GET_WORD (abfd, entry);
+
       if (!mips_elf_overflow_p (value - address, 16))
        {
          /* This entry will serve as the page pointer.  We can add a
@@ -5383,7 +5465,7 @@ mips_elf_got_page (abfd, info, value, offsetp)
 
   if (offsetp)
     {
-      address = bfd_get_32 (abfd, entry);
+      address = MIPS_ELF_GET_WORD (abfd, entry);
       *offsetp = value - address;
     }
 
@@ -5410,16 +5492,17 @@ mips_elf_got16_entry (abfd, info, value)
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
   /* Look to see if we already have an appropriate entry.  */
-  last_entry = sgot->contents + 4 * g->assigned_gotno;
-  for (entry = sgot->contents + 4 * MIPS_RESERVED_GOTNO; 
+  last_entry = sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno;
+  for (entry = (sgot->contents 
+               + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO);
        entry != last_entry;
-       entry += 4)
+       entry += MIPS_ELF_GOT_SIZE (abfd))
     {
-      address = bfd_get_32 (abfd, entry);
-      if (address & 0xffff0000 == value)
+      address = MIPS_ELF_GET_WORD (abfd, entry);
+      if ((address & 0xffff0000) == value)
        {
          /* This entry has the right high-order 16 bits.  */
-         index = 4 * (entry - sgot->contents);
+         index = MIPS_ELF_GOT_SIZE (abfd) * (entry - sgot->contents);
          break;
        }
     }
@@ -5437,8 +5520,8 @@ mips_elf_got16_entry (abfd, info, value)
 
 static boolean
 mips_elf_next_lo16_addend (relocation, relend, addendp)
-     Elf_Internal_Rela *relocation;
-     Elf_Internal_Rela *relend;
+     const Elf_Internal_Rela *relocation;
+     const Elf_Internal_Rela *relend;
      bfd_vma *addendp;
 {
   /* According to the MIPS ELF ABI, the R_MIPS_LO16 relocation must be
@@ -5472,7 +5555,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
                                    addend, input_section)
      bfd *output_bfd;
      struct bfd_link_info *info;
-     Elf_Internal_Rela *rel;
+     const Elf_Internal_Rela *rel;
      long dynindx;
      bfd_vma addend;
      asection *input_section;
@@ -5485,7 +5568,9 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
 
   r_type = ELF32_R_TYPE (rel->r_info);
   dynobj = elf_hash_table (info)->dynobj;
-  sreloc = bfd_get_section_by_name (dynobj, ".rel.dyn");
+  sreloc 
+    = bfd_get_section_by_name (dynobj,
+                              MIPS_ELF_REL_DYN_SECTION_NAME (output_bfd));
   BFD_ASSERT (sreloc != NULL);
 
   skip = false;
@@ -5520,10 +5605,18 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
   if (skip)
     memset (&outrel, 0, sizeof (outrel));
 
-  bfd_elf32_swap_reloc_out (output_bfd, &outrel,
-                           (((Elf32_External_Rel *)
-                             sreloc->contents)
-                            + sreloc->reloc_count));
+  if (ABI_64_P (output_bfd))
+    {
+      (*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
+       (output_bfd, &outrel,
+        (sreloc->contents 
+         + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+    }
+  else
+    bfd_elf32_swap_reloc_out (output_bfd, &outrel,
+                             (((Elf32_External_Rel *)
+                               sreloc->contents)
+                              + sreloc->reloc_count));
   ++sreloc->reloc_count;
 
   /* Make sure the output section is writable.  The dynamic linker
@@ -5583,7 +5676,6 @@ mips_elf_calculate_relocation (abfd,
                               relocation,
                               addend,
                               howto,
-                              relend,
                               local_syms,
                               local_sections,
                               valuep,
@@ -5592,10 +5684,9 @@ mips_elf_calculate_relocation (abfd,
      bfd *input_bfd;
      asection *input_section;
      struct bfd_link_info *info;
-     Elf_Internal_Rela *relocation;
+     const Elf_Internal_Rela *relocation;
      bfd_vma addend;
      reloc_howto_type *howto;
-     Elf_Internal_Rela *relend;
      Elf_Internal_Sym *local_syms;
      asection **local_sections;
      bfd_vma *valuep;
@@ -5622,12 +5713,17 @@ mips_elf_calculate_relocation (abfd,
      located.  */
   asection *sec = NULL;
   struct mips_elf_link_hash_entry* h = NULL;
-  unsigned long r_symndx;
+  /* True if the symbol referred to by this relocation is a local
+     symbol.  */
   boolean local_p;
+  /* True if the symbol referred to by this relocation is "_gp_disp".  */
   boolean gp_disp_p = false;
   Elf_Internal_Shdr *symtab_hdr;
   size_t extsymoff;
+  unsigned long r_symndx;
   int r_type;
+  /* True if overflow occurred during the calculation of the
+     relocation value.  */
   boolean overflowed_p;
 
   /* Parse the relocation.  */
@@ -5675,7 +5771,7 @@ mips_elf_calculate_relocation (abfd,
       *namep = bfd_elf_string_from_elf_section (input_bfd,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
-      if (*namep = '\0')
+      if (*namep == '\0')
        *namep = bfd_section_name (input_bfd, sec);
     }
   else
@@ -5702,11 +5798,13 @@ mips_elf_calculate_relocation (abfd,
 
          gp_disp_p = true;
        }
-
-      /* If this symbol is defined, calculate its address.  */
-      if ((h->root.root.type == bfd_link_hash_defined
-          || h->root.root.type == bfd_link_hash_defweak)
-         && h->root.root.u.def.section)
+      /* If this symbol is defined, calculate its address.  Note that
+        _gp_disp is a magic symbol, always implicitly defined by the
+        linker, so it's inappropriate to check to see whether or not
+        its defined.  */
+      else if ((h->root.root.type == bfd_link_hash_defined
+               || h->root.root.type == bfd_link_hash_defweak)
+              && h->root.root.u.def.section)
        {
          sec = h->root.root.u.def.section;
          if (sec->output_section)
@@ -5780,6 +5878,7 @@ mips_elf_calculate_relocation (abfd,
 
     case R_MIPS_32:
     case R_MIPS_REL32:
+    case R_MIPS_64:
       /* If we're creating a shared library, or this relocation is
         against a symbol in a shared library, then we can't know
         where the symbol will end up.  So, we create a relocation
@@ -5792,11 +5891,11 @@ mips_elf_calculate_relocation (abfd,
          BFD_ASSERT (h != NULL);
          reloc_index 
            = mips_elf_create_dynamic_relocation (abfd, 
-                                                  info, 
-                                                  relocation,
-                                                  h->root.dynindx,
-                                                  addend,
-                                                  input_section);
+                                                 info, 
+                                                 relocation,
+                                                 h->root.dynindx,
+                                                 addend,
+                                                 input_section);
          if (h->min_dyn_reloc_index == 0
              || reloc_index < h->min_dyn_reloc_index)
            h->min_dyn_reloc_index = reloc_index;
@@ -5804,7 +5903,7 @@ mips_elf_calculate_relocation (abfd,
        }
       else
        {
-         if (r_type == R_MIPS_32)
+         if (r_type != R_MIPS_REL32)
            value = symbol + addend;
          else
            value = addend;
@@ -5812,6 +5911,12 @@ mips_elf_calculate_relocation (abfd,
       value &= howto->dst_mask;
       break;
 
+    case R_MIPS16_26:
+      /* The calculation for R_MIPS_26 is just the same as for an
+        R_MIPS_26.  It's only the storage of the relocated field into
+        the output file that's different.  That's handled in
+        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 << 2) | (p & 0xf0000000)) + symbol) >> 2;
@@ -5839,7 +5944,22 @@ mips_elf_calculate_relocation (abfd,
       else
        {
          value = addend + gp - p + 4;
-         overflowed_p = mips_elf_overflow_p (value, 16);
+         /* The MIPS ABI requires checking the R_MIPS_LO16 relocation
+            for overflow.  But, on, say, Irix 5, relocations against
+            _gp_disp are normally generated from the .cpload
+            pseudo-op.  It generates code that normally looks like
+            this:
+
+              lui    $gp,%hi(_gp_disp)
+              addiu  $gp,$gp,%lo(_gp_disp)
+              addu   $gp,$gp,$t9
+
+            Here $t9 holds the address of the function being called,
+            as required by the MIPS ELF ABI.  The R_MIPS_LO16
+            relocation can easily overflow in this situation, but the
+            R_MIPS_HI16 relocation will handle the overflow.
+            Therefore, we consider this a bug in the MIPS ABI, and do
+            not check for overflow here.  */
        }
       break;
 
@@ -5851,6 +5971,11 @@ mips_elf_calculate_relocation (abfd,
 
       /* Fall through.  */
 
+    case R_MIPS16_GPREL:
+      /* The R_MIPS16_GPREL performs the same calculation as
+        R_MIPS_GPREL16, but stores the relocated bits in a different
+        order.  We don't need to do anything special here; the
+        differences are handled in mips_elf_perform_relocation.  */
     case R_MIPS_GPREL16:
       if (local_p)
        value = mips_elf_sign_extend (addend, 16) + symbol + gp0 - gp;
@@ -5905,10 +6030,6 @@ mips_elf_calculate_relocation (abfd,
       value = g & howto->dst_mask;
       break;
 
-    case R_MIPS_64:
-      value = (symbol + addend) & howto->dst_mask;
-      break;
-
     case R_MIPS_GOT_PAGE:
       value = mips_elf_got_page (abfd, info, symbol + addend, NULL);
       if (value == (bfd_vma) -1)
@@ -5955,12 +6076,6 @@ mips_elf_calculate_relocation (abfd,
       /* We don't do anything with these at present.  */
       return bfd_reloc_continue;
 
-    case R_MIPS16_26:
-    case R_MIPS16_GPREL:
-      /* These relocations, used for MIPS16, are not clearly
-        documented anywhere.  What do they do?  */
-      return bfd_reloc_notsupported;
-
     default:
       /* An unrecognized relocation type.  */
       return bfd_reloc_notsupported;
@@ -5976,43 +6091,22 @@ mips_elf_calculate_relocation (abfd,
 static bfd_vma
 mips_elf_obtain_contents (howto, relocation, input_bfd, contents)
      reloc_howto_type *howto;
-     Elf_Internal_Rela *relocation;
+     const Elf_Internal_Rela *relocation;
      bfd *input_bfd;
      bfd_byte *contents;
 {
   bfd_vma x;
   bfd_byte *location = contents + relocation->r_offset;
 
-  switch (bfd_get_reloc_size (howto))
-    {
-    case 0:
-      x = 0;
-      break;
-
-    case 1:
-      x = bfd_get_8 (input_bfd, location);
-      break;
+  /* Obtain the bytes.  */
+  x = bfd_get (8 * bfd_get_reloc_size (howto), input_bfd, location);
 
-    case 2:
-      x = bfd_get_16 (input_bfd, location);
-      break;
-
-    case 4:
-      x = bfd_get_32 (input_bfd, location);
-      break;
-
-    case 8:
-#ifdef BFD64
-      x = bfd_get_64 (input_bfd, location);
-#else
-      abort ();
-#endif
-      break;
-
-    default:
-      abort ();
-      break;
-    }
+  if ((ELF32_R_TYPE (relocation->r_info) == R_MIPS16_26
+       || ELF32_R_TYPE (relocation->r_info) == R_MIPS16_GPREL)
+      && bfd_little_endian (input_bfd))
+    /* The two 16-bit words will be reversed on a little-endian
+       system.  See mips_elf_perform_relocation for more details.  */
+    x = (((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16));
 
   return x;
 }
@@ -6025,15 +6119,20 @@ mips_elf_obtain_contents (howto, relocation, input_bfd, contents)
    Returns false if anything goes wrong.  */
 
 static void
-mips_elf_perform_relocation (howto, relocation, value, input_bfd, contents)
+mips_elf_perform_relocation (info, howto, relocation, value,
+                            input_bfd, contents)
+     struct bfd_link_info *info;
      reloc_howto_type *howto;
-     Elf_Internal_Rela *relocation;
+     const Elf_Internal_Rela *relocation;
      bfd_vma value;
      bfd *input_bfd;
      bfd_byte *contents;
 {
   bfd_vma x;
-  bfd_byte *location = contents + relocation->r_offset;
+  bfd_byte *location;
+
+  /* Figure out where the relocation is occurring.  */
+  location = contents + relocation->r_offset;
 
   /* Obtain the current value.  */
   x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
@@ -6041,47 +6140,121 @@ mips_elf_perform_relocation (howto, relocation, value, input_bfd, contents)
   /* Clear the field we are setting.  */
   x &= ~howto->dst_mask;
 
-  /* Set the field.  */
-  x |= (value & howto->dst_mask);
-
-  /* Put the value into the output.  */
-  switch (bfd_get_reloc_size (howto))
+  /* If this is the R_MIPS16_26 relocation, we must store the
+     value in a funny way.  */
+  if (ELF32_R_TYPE (relocation->r_info) == R_MIPS16_26)
+    {
+      /* R_MIPS16_26 is used for the mips16 jal and jalx instructions.
+        Most mips16 instructions are 16 bits, but these instructions
+        are 32 bits.
+
+        The format of these instructions is:
+
+        +--------------+--------------------------------+
+        !     JALX     ! X!   Imm 20:16  !   Imm 25:21  !
+        +--------------+--------------------------------+
+        !                Immediate  15:0                   !
+        +-----------------------------------------------+
+        
+        JALX is the 5-bit value 00011.  X is 0 for jal, 1 for jalx.
+        Note that the immediate value in the first word is swapped.
+
+        When producing a relocateable object file, R_MIPS16_26 is
+        handled mostly like R_MIPS_26.  In particular, the addend is
+        stored as a straight 26-bit value in a 32-bit instruction.
+        (gas makes life simpler for itself by never adjusting a
+        R_MIPS16_26 reloc to be against a section, so the addend is
+        always zero).  However, the 32 bit instruction is stored as 2
+        16-bit values, rather than a single 32-bit value.  In a
+        big-endian file, the result is the same; in a little-endian
+        file, the two 16-bit halves of the 32 bit value are swapped.
+        This is so that a disassembler can recognize the jal
+        instruction.
+
+        When doing a final link, R_MIPS16_26 is treated as a 32 bit
+        instruction stored as two 16-bit values.  The addend A is the
+        contents of the targ26 field.  The calculation is the same as
+        R_MIPS_26.  When storing the calculated value, reorder the
+        immediate value as shown above, and don't forget to store the
+        value as two 16-bit values.
+
+        To put it in MIPS ABI terms, the relocation field is T-targ26-16,
+        defined as
+        
+        big-endian:
+        +--------+----------------------+
+        |        |                      |
+        |        |    targ26-16         |
+        |31    26|25                   0|
+        +--------+----------------------+
+        
+        little-endian:
+        +----------+------+-------------+
+        |          |      |             |
+        |  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)).
+        
+        When producing a relocateable object file, the calculation is
+        (((A < 2) | (P & 0xf0000000) + S) >> 2)
+        When producing a fully linked file, the calculation is
+        let R = (((A < 2) | (P & 0xf0000000) + S) >> 2)
+        ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)  */
+
+      if (!info->relocateable)
+       /* Shuffle the bits according to the formula above.  */
+       value = (((value & 0x1f0000) << 5) 
+                | ((value & 0x3e00000) >> 5) 
+                | (value & 0xffff));
+      
+    }
+  else if (ELF32_R_TYPE (relocation->r_info) == R_MIPS16_GPREL)
     {
-    case 0:
-      x = 0;
-      break;
-
-    case 1:
-      bfd_put_8 (input_bfd, x, location);
-      break;
+      /* R_MIPS16_GPREL is used for GP-relative addressing in mips16
+        mode.  A typical instruction will have a format like this:
 
-    case 2:
-      bfd_put_16 (input_bfd, x, location);
-      break;
+        +--------------+--------------------------------+
+        !    EXTEND    !     Imm 10:5    !   Imm 15:11  !
+        +--------------+--------------------------------+
+        !    Major     !   rx   !   ry   !   Imm  4:0   !
+        +--------------+--------------------------------+
+        
+        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.  
 
-    case 4:
-      bfd_put_32 (input_bfd, x, location);
-      break;
+         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.  */
+      value = (((value & 0x7e0) << 16)
+              | ((value & 0xf800) << 5)
+              | (value & 0x1f));
+    }
 
-    case 8:
-#ifdef BFD64
-      bfd_put_64 (input_bfd, x, location);
-#else
-      abort ();
-#endif
-      break;
+  /* Set the field.  */
+  x |= (value & howto->dst_mask);
 
-    default:
-      abort ();
-      break;
-    }
+  /* Swap the high- and low-order 16 bits on little-endian systems
+     when doing a MIPS16 relocation.  */
+  if ((ELF32_R_TYPE (relocation->r_info) == R_MIPS16_GPREL
+       || ELF32_R_TYPE (relocation->r_info) == R_MIPS16_26)
+      && bfd_little_endian (input_bfd))
+    x = (((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16));
+  
+  /* Put the value into the output.  */
+  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
 }
 
 /* Relocate a MIPS ELF section.  */
 
-static boolean
-mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
-                          contents, relocs, local_syms, local_sections)
+boolean
+_bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
+                               contents, relocs, local_syms, local_sections)
      bfd *output_bfd;
      struct bfd_link_info *info;
      bfd *input_bfd;
@@ -6091,55 +6264,34 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
      Elf_Internal_Sym *local_syms;
      asection **local_sections;
 {
-  Elf_Internal_Shdr *symtab_hdr;
-  size_t locsymcount;
-  size_t extsymoff;
-  asection *sgot, *sreloc, *scpt;
-  bfd *dynobj;
-  bfd_vma gp;
-  Elf_Internal_Rela *rel;
-  Elf_Internal_Rela *relend;
-  struct mips_got_info *g;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *relend;
   bfd_vma addend;
   bfd_vma last_hi16_addend;
-  boolean next_relocation_for_same_address_p = false;
   boolean use_saved_addend_p = false;
   boolean last_hi16_addend_valid_p = false;
+  struct elf_backend_data *bed;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-
-  sgot = NULL;
-  sreloc = NULL;
-  if (dynobj == NULL || ! SGI_COMPAT (output_bfd))
-    scpt = NULL;
-  else
-    scpt = bfd_get_section_by_name (dynobj, ".compact_rel");
-  g = NULL;
-
-  if (elf_bad_symtab (input_bfd))
-    {
-      locsymcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
-      extsymoff = 0;
-    }
-  else
-    {
-      locsymcount = symtab_hdr->sh_info;
-      extsymoff = symtab_hdr->sh_info;
-    }
-
-  gp = _bfd_get_gp_value (output_bfd);
-  relend = relocs + input_section->reloc_count;
-  
+  bed = get_elf_backend_data (output_bfd);
+  relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
   for (rel = relocs; rel < relend; ++rel)
     {
       const char *name;
       bfd_vma value;
-      int result;
       reloc_howto_type *howto;
 
       /* Find the relocation howto for this relocation.  */
-      howto = elf_mips_howto_table + ELF32_R_TYPE (rel->r_info);
+      if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
+         && !ABI_64_P (output_bfd))
+       /* Some 32-bit code uses R_MIPS_64.  In particular, people use
+          64-bit code, but make sure all their addresses are in the 
+          lowermost or uppermost 32-bit section of the 64-bit address
+          space.  Thus, when they use an R_MIPS_64 they mean what is
+          usually meant by R_MIPS_32, with the exception that the
+          stored value is sign-extended to 64 bits.  */
+       howto = elf_mips_howto_table + R_MIPS_32;
+      else
+       howto = elf_mips_howto_table + ELF32_R_TYPE (rel->r_info);
 
       if (!use_saved_addend_p)
        {
@@ -6152,9 +6304,11 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             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 (input_section)->rel_hdr;
-         if (rel - relocs >= rel_hdr->sh_size / rel_hdr->sh_entsize)
+         if ((size_t) (rel - relocs)
+             >= (rel_hdr->sh_size / rel_hdr->sh_entsize
+                 * bed->s->int_rels_per_ext_rel))
            rel_hdr = elf_section_data (input_section)->rel_hdr2;
-         if (rel_hdr->sh_entsize == sizeof (Elf32_External_Rel))
+         if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
            {
              int r_type = ELF32_R_TYPE (rel->r_info);
 
@@ -6193,6 +6347,15 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                    return false;
                  addend |= last_hi16_addend;
                }
+             else if (r_type == R_MIPS16_GPREL)
+               {
+                 /* The addend is scrambled in the object file.  See
+                    mips_elf_perform_relocation for details on the
+                    format.  */
+                 addend = (((addend & 0x1f0000) >> 5)
+                           | ((addend & 0x7e00000) >> 16)
+                           | (addend & 0x1f));
+               }
            }
          else
            addend = rel->r_addend;
@@ -6202,7 +6365,9 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
         relocations for the same offset.  In that case we are
         supposed to treat the output of each relocation as the addend
         for the next.  */
-      if (rel + 1 < relend && rel->r_offset == (rel + 1)->r_offset)
+      if (rel + 1 < relend 
+         && rel->r_offset == rel[1].r_offset
+         && ELF32_R_TYPE (rel[1].r_info) != R_MIPS_NONE)
        use_saved_addend_p = true;
       else
        use_saved_addend_p = false;
@@ -6215,7 +6380,6 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                             rel,
                                             addend,
                                             howto,
-                                            relend,
                                             local_syms,
                                             local_sections,
                                             &value,
@@ -6261,8 +6425,58 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
        }
 
+      if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
+         && !ABI_64_P (output_bfd))
+       /* See the comment above about using R_MIPS_64 in the 32-bit
+          ABI.  Until now, we've been using the HOWTO for R_MIPS_32;
+          that calculated the right value.  Now, however, we
+          sign-extend the 32-bit result to 64-bits, and store it as a
+          64-bit value.  We are especially generous here in that we
+          go to extreme lengths to support this usage on systems with
+          only a 32-bit VMA.  */
+       {
+#ifdef BFD64
+         /* Just sign-extend the value, and then fall through to the
+            normal case, using the R_MIPS_64 howto.  That will store
+            the 64-bit value into a 64-bit area.  */
+         value = mips_elf_sign_extend (value, 64);
+         howto = elf_mips_howto_table + R_MIPS_64;
+#else /* !BFD64 */
+         /* In the 32-bit VMA case, we must handle sign-extension and
+            endianness manually.  */
+         bfd_vma sign_bits;
+         bfd_vma low_bits;
+         bfd_vma high_bits;
+
+         if (value & 0x80000000)
+           sign_bits = 0xffffffff;
+         else
+           sign_bits = 0;
+
+         /* If only a 32-bit VMA is available do two separate
+            stores.  */
+         if (bfd_big_endian (input_bfd))
+           {
+             /* Store the sign-bits (which are most significant)
+                first.  */
+             low_bits = sign_bits;
+             high_bits = value;
+           }
+         else
+           {
+             low_bits = value;
+             high_bits = sign_bits;
+           }
+         bfd_put_32 (input_bfd, low_bits, 
+                     contents + rel->r_offset);
+         bfd_put_32 (input_bfd, high_bits, 
+                     contents + rel->r_offset + 4);
+         continue;
+#endif /* !BFD64 */
+       }
+
       /* Actually perform the relocation.  */
-      mips_elf_perform_relocation (howto, rel, value, input_bfd, 
+      mips_elf_perform_relocation (info, howto, rel, value, input_bfd, 
                                   contents);
     }
 
@@ -6274,11 +6488,11 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
    also where we undo the increment of the value for a mips16 symbol.  */
 
 /*ARGSIGNORED*/
-static boolean
-mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     const char *name;
+boolean
+_bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
      Elf_Internal_Sym *sym;
      asection *input_sec;
 {
@@ -6301,13 +6515,15 @@ mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
 /* 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" : "/usr/lib/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")
 
 /* Create dynamic sections when linking against a dynamic object.  */
 
-static boolean
-mips_elf_create_dynamic_sections (abfd, info)
+boolean
+_bfd_mips_elf_create_dynamic_sections (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
@@ -6345,7 +6561,8 @@ mips_elf_create_dynamic_sections (abfd, info)
       s = bfd_make_section (abfd, MIPS_ELF_STUB_SECTION_NAME (abfd));
       if (s == NULL
          || ! bfd_set_section_flags (abfd, s, flags | SEC_CODE)
-         || ! bfd_set_section_alignment (abfd, s, 2))
+         || ! bfd_set_section_alignment (abfd, s,
+                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return false;
     }
 
@@ -6356,7 +6573,8 @@ mips_elf_create_dynamic_sections (abfd, info)
       s = bfd_make_section (abfd, ".rld_map");
       if (s == NULL
          || ! bfd_set_section_flags (abfd, s, flags & ~SEC_READONLY)
-         || ! bfd_set_section_alignment (abfd, s, 2))
+         || ! bfd_set_section_alignment (abfd, s,
+                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return false;
     }
 
@@ -6454,7 +6672,7 @@ mips_elf_create_dynamic_sections (abfd, info)
 static boolean
 mips_elf_create_compact_rel_section (abfd, info)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
 {
   flagword flags;
   register asection *s;
@@ -6467,7 +6685,8 @@ mips_elf_create_compact_rel_section (abfd, info)
       s = bfd_make_section (abfd, ".compact_rel");
       if (s == NULL
          || ! bfd_set_section_flags (abfd, s, flags)
-         || ! bfd_set_section_alignment (abfd, s, 2))
+         || ! bfd_set_section_alignment (abfd, s,
+                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return false;
 
       s->_raw_size = sizeof (Elf32_External_compact_rel);
@@ -6489,7 +6708,7 @@ mips_elf_create_got_section (abfd, info)
   struct mips_got_info *g;
 
   /* This function may be called more than once.  */
-  if (bfd_get_section_by_name (abfd, ".got") != NULL)
+  if (mips_elf_got_section (abfd))
     return true;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -6520,7 +6739,7 @@ mips_elf_create_got_section (abfd, info)
     return false;
 
   /* The first several global offset table entries are reserved.  */
-  s->_raw_size = MIPS_RESERVED_GOTNO * 4;
+  s->_raw_size = MIPS_RESERVED_GOTNO * MIPS_ELF_GOT_SIZE (abfd);
 
   g = (struct mips_got_info *) bfd_alloc (abfd,
                                          sizeof (struct mips_got_info));
@@ -6563,18 +6782,40 @@ mips_elf_create_msym_section (abfd)
                                     | SEC_HAS_CONTENTS
                                     | SEC_LINKER_CREATED 
                                     | SEC_READONLY)
-         || !bfd_set_section_alignment (abfd, s, 2))
+         || !bfd_set_section_alignment (abfd, s,
+                                        MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return NULL;
     }
 
   return s;
 }
 
+/* Add room for N relocations to the .rel.dyn section in ABFD.  */
+
+static void
+mips_elf_allocate_dynamic_relocations (abfd, n)
+     bfd *abfd;
+     unsigned int n;
+{
+  asection *s;
+
+  s = bfd_get_section_by_name (abfd, MIPS_ELF_REL_DYN_SECTION_NAME (abfd));
+  BFD_ASSERT (s != NULL);
+  
+  if (s->_raw_size == 0)
+    {
+      /* Make room for a null element. */
+      s->_raw_size += MIPS_ELF_REL_SIZE (abfd);
+      ++s->reloc_count;
+    }
+  s->_raw_size += n * MIPS_ELF_REL_SIZE (abfd);
+}
+
 /* Look through the relocs for a section during the first phase, and
    allocate space in the global offset table.  */
 
-static boolean
-mips_elf_check_relocs (abfd, info, sec, relocs)
+boolean
+_bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
      bfd *abfd;
      struct bfd_link_info *info;
      asection *sec;
@@ -6590,6 +6831,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
   const Elf_Internal_Rela *rel_end;
   asection *sgot;
   asection *sreloc;
+  struct elf_backend_data *bed;
 
   if (info->relocateable)
     return true;
@@ -6674,7 +6916,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
              asection **n;
 
              if (elf_bad_symtab (abfd))
-               symcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+               symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
              else
                symcount = symtab_hdr->sh_info;
              n = (asection **) bfd_zalloc (abfd,
@@ -6764,7 +7006,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
     }
   else
     {
-      sgot = bfd_get_section_by_name (dynobj, ".got");
+      sgot = mips_elf_got_section (dynobj);
       if (sgot == NULL)
        g = NULL;
       else
@@ -6776,9 +7018,9 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
     }
 
   sreloc = NULL;
-
-  rel_end = relocs + sec->reloc_count;
-  for (rel = relocs; rel < rel_end; rel++)
+  bed = get_elf_backend_data (abfd);
+  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+  for (rel = relocs; rel < rel_end; ++rel)
     {
       unsigned long r_symndx;
       int r_type;
@@ -6821,6 +7063,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
 
            case R_MIPS_32:
            case R_MIPS_REL32:
+           case R_MIPS_64:
              if (dynobj == NULL
                  && (info->shared || h != NULL)
                  && (sec->flags & SEC_ALLOC) != 0)
@@ -6848,7 +7091,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
             conservative, we could actually build the GOT here,
             rather than in relocate_section.  */
          g->local_gotno++;
-         sgot->_raw_size += 4;
+         sgot->_raw_size += MIPS_ELF_GOT_SIZE (dynobj);
        }
 
       switch (r_type)
@@ -6889,12 +7132,13 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
 
        case R_MIPS_32:
        case R_MIPS_REL32:
+       case R_MIPS_64:
          if ((info->shared || h != NULL)
              && (sec->flags & SEC_ALLOC) != 0)
            {
              if (sreloc == NULL)
                {
-                 const char *name = ".rel.dyn";
+                 const char *name = MIPS_ELF_REL_DYN_SECTION_NAME (dynobj);
 
                  sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
@@ -6914,19 +7158,11 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                    }
                }
              if (info->shared)
-               {
-                 /* When creating a shared object, we must copy these
-                    reloc types into the output file as R_MIPS_REL32
-                    relocs.  We make room for this reloc in the
-                    .rel.dyn reloc section */
-                 if (sreloc->_raw_size == 0)
-                   {
-                     /* Add a null element. */
-                     sreloc->_raw_size += sizeof (Elf32_External_Rel);
-                     ++sreloc->reloc_count;
-                   }
-                 sreloc->_raw_size += sizeof (Elf32_External_Rel);
-               }
+               /* When creating a shared object, we must copy these
+                  reloc types into the output file as R_MIPS_REL32
+                  relocs.  We make room for this reloc in the
+                  .rel.dyn reloc section.  */
+               mips_elf_allocate_dynamic_relocations (dynobj, 1);
              else
                {
                  struct mips_elf_link_hash_entry *hmips;
@@ -6934,7 +7170,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                  /* 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->mips_32_relocs;
+                 ++hmips->possibly_dynamic_relocs;
                }
             
              /* Even though we don't directly need a GOT entry for
@@ -6945,17 +7181,16 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                return false;
            }
 
-         if (SGI_COMPAT (abfd))
+         if (SGI_COMPAT (dynobj))
            mips_elf_hash_table (info)->compact_rel_size +=
              sizeof (Elf32_External_crinfo);
-
          break;
 
        case R_MIPS_26:
        case R_MIPS_GPREL16:
        case R_MIPS_LITERAL:
        case R_MIPS_GPREL32:
-         if (SGI_COMPAT (abfd))
+         if (SGI_COMPAT (dynobj))
            mips_elf_hash_table (info)->compact_rel_size +=
              sizeof (Elf32_External_crinfo);
          break;
@@ -7003,10 +7238,10 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
 /* Return the section that should be marked against GC for a given
    relocation.  */
 
-static asection *
-mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
+asection *
+_bfd_mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      Elf_Internal_Rela *rel;
      struct elf_link_hash_entry *h;
      Elf_Internal_Sym *sym;
@@ -7052,12 +7287,12 @@ mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
 
 /* Update the got entry reference counts for the section being removed.  */
 
-static boolean
-mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     asection *sec;
-     const Elf_Internal_Rela *relocs;
+boolean
+_bfd_mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
+     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
 {
 #if 0
   Elf_Internal_Shdr *symtab_hdr;
@@ -7101,8 +7336,8 @@ mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
    change the definition to something the rest of the link can
    understand.  */
 
-static boolean
-mips_elf_adjust_dynamic_symbol (info, h)
+boolean
+_bfd_mips_elf_adjust_dynamic_symbol (info, h)
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
 {
@@ -7128,20 +7363,10 @@ mips_elf_adjust_dynamic_symbol (info, h)
      file.  */
   hmips = (struct mips_elf_link_hash_entry *) h;
   if (! info->relocateable
-      && hmips->mips_32_relocs != 0
+      && hmips->possibly_dynamic_relocs != 0
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-    {
-      s = bfd_get_section_by_name (dynobj, ".rel.dyn");
-      BFD_ASSERT (s != NULL);
-
-      if (s->_raw_size == 0)
-       {
-         /* Make room for a null element. */
-         s->_raw_size += sizeof (Elf32_External_Rel);
-         ++s->reloc_count;
-       }
-      s->_raw_size += hmips->mips_32_relocs * sizeof (Elf32_External_Rel);
-    }
+    mips_elf_allocate_dynamic_relocations (dynobj, 
+                                          hmips->possibly_dynamic_relocs);
 
   /* For a function, create a stub, if needed. */
   if (h->type == STT_FUNC
@@ -7201,8 +7426,8 @@ mips_elf_adjust_dynamic_symbol (info, h)
 static boolean mips_elf_check_mips16_stubs
   PARAMS ((struct mips_elf_link_hash_entry *, PTR));
 
-static boolean
-mips_elf_always_size_sections (output_bfd, info)
+boolean
+_bfd_mips_elf_always_size_sections (output_bfd, info)
      bfd *output_bfd;
      struct bfd_link_info *info;
 {
@@ -7231,7 +7456,7 @@ mips_elf_always_size_sections (output_bfd, info)
 static boolean
 mips_elf_check_mips16_stubs (h, data)
      struct mips_elf_link_hash_entry *h;
-     PTR data;
+     PTR data ATTRIBUTE_UNUSED;
 {
   if (h->fn_stub != NULL
       && ! h->need_fn_stub)
@@ -7277,8 +7502,8 @@ mips_elf_check_mips16_stubs (h, data)
 
 /* Set the sizes of the dynamic sections.  */
 
-static boolean
-mips_elf_size_dynamic_sections (output_bfd, info)
+boolean
+_bfd_mips_elf_size_dynamic_sections (output_bfd, info)
      bfd *output_bfd;
      struct bfd_link_info *info;
 {
@@ -7354,12 +7579,14 @@ mips_elf_size_dynamic_sections (output_bfd, info)
              if ((target != NULL
                   && (target->flags & SEC_READONLY) != 0
                   && (target->flags & SEC_ALLOC) != 0)
-                 || strcmp (outname, ".rel.dyn") == 0)
+                 || strcmp (outname, 
+                            MIPS_ELF_REL_DYN_SECTION_NAME (output_bfd)) == 0)
                reltext = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
-             if (strcmp (name, ".rel.dyn") != 0)
+             if (strcmp (name, 
+                         MIPS_ELF_REL_DYN_SECTION_NAME (output_bfd)) != 0)
                s->reloc_count = 0;
            }
        }
@@ -7396,18 +7623,19 @@ mips_elf_size_dynamic_sections (output_bfd, info)
             contiguous sections.  Is 5 enough? */
          local_gotno = (loadable_size >> 16) + 5;
          g->local_gotno += local_gotno;
-         s->_raw_size += local_gotno * 4;
+         s->_raw_size += local_gotno * MIPS_ELF_GOT_SIZE (dynobj);
 
          /* There has to be a global GOT entry for every symbol with
             a dynamic symbol table index of DT_MIPS_GOTSYM or
             higher.  Therefore, it make sense to put those symbols
             that need GOT entries at the end of the symbol table.  We
             do that here.  */
-         if (!mips_elf_sort_hash_table (info))
+         if (!mips_elf_sort_hash_table (info, 1))
            return false;
 
          i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
-         s->_raw_size += i * 4;
+         g->global_gotno = i;
+         s->_raw_size += i * MIPS_ELF_GOT_SIZE (dynobj);
        }
       else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
        {
@@ -7465,171 +7693,107 @@ mips_elf_size_dynamic_sections (output_bfd, info)
            {
              /* SGI object has the equivalence of DT_DEBUG in the
                 DT_MIPS_RLD_MAP entry.  */
-             if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_RLD_MAP, 0))
+             if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
                return false;
            }
          else
-           if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+           if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
              return false;
        }
 
       if (reltext)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
            return false;
        }
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
        return false;
 
-      if (bfd_get_section_by_name (dynobj, ".rel.dyn"))
+      if (bfd_get_section_by_name (dynobj,
+                                  MIPS_ELF_REL_DYN_SECTION_NAME (dynobj)))
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
            return false;
 
-         if (! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
            return false;
 
-         if (! bfd_elf32_add_dynamic_entry (info, DT_RELENT, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
            return false;
        }
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_CONFLICTNO, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_CONFLICTNO, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LIBLISTNO, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LIBLISTNO, 0))
        return false;
 
       if (bfd_get_section_by_name (dynobj, ".conflict") != NULL)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_CONFLICT, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_CONFLICT, 0))
            return false;
 
          s = bfd_get_section_by_name (dynobj, ".liblist");
          BFD_ASSERT (s != NULL);
 
-         if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LIBLIST, 0))
+         if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LIBLIST, 0))
            return false;
        }
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_RLD_VERSION, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_VERSION, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_FLAGS, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_FLAGS, 0))
        return false;
 
 #if 0
       /* Time stamps in executable files are a bad idea.  */
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_TIME_STAMP, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_TIME_STAMP, 0))
        return false;
 #endif
 
 #if 0 /* FIXME  */
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_ICHECKSUM, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_ICHECKSUM, 0))
        return false;
 #endif
 
 #if 0 /* FIXME  */
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_IVERSION, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_IVERSION, 0))
        return false;
 #endif
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_BASE_ADDRESS, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_BASE_ADDRESS, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LOCAL_GOTNO, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LOCAL_GOTNO, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_SYMTABNO, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_SYMTABNO, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_UNREFEXTNO, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_UNREFEXTNO, 0))
        return false;
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_GOTSYM, 0))
+      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
        return false;
 
       if (IRIX_COMPAT (dynobj) == ict_irix5
-         && ! bfd_elf32_add_dynamic_entry (info, DT_MIPS_HIPAGENO, 0))
+         && ! 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)))
-         && !bfd_elf32_add_dynamic_entry (info, DT_MIPS_OPTIONS, 0))
+         && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
        return false;
 
       if (bfd_get_section_by_name (dynobj, 
                                   MIPS_ELF_MSYM_SECTION_NAME (dynobj))
-         && !bfd_elf32_add_dynamic_entry (info, DT_MIPS_MSYM, 0))
+         && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_MSYM, 0))
        return false;
     }
 
-  /* If we use dynamic linking, we generate a section symbol for each
-     output section.  These are local symbols, which means that they
-     must come first in the dynamic symbol table.
-     That means we must increment the dynamic symbol index of every
-     other dynamic symbol.  */
-  {
-    unsigned int c, i;
-    struct mips_got_info *g;
-
-    c = 0;
-    if (elf_hash_table (info)->dynamic_sections_created)
-      {
-#if 0
-       /* We no longer try to restrict the set of sections which get
-           dynamic symbol table entries, since it fails if we have
-           other random sections which need dynamic relocations.  */
-       const char * const *namep;
-       bfd_size_type strindex;
-       struct bfd_strtab_hash *dynstr;
-
-       if (SGI_COMPAT (output_bfd))
-         {
-           c = SIZEOF_MIPS_DYNSYM_SECNAMES - 1;
-           elf_link_hash_traverse (elf_hash_table (info),
-                                   mips_elf_adjust_dynindx,
-                                   (PTR) &c);
-           elf_hash_table (info)->dynsymcount += c;
-
-           dynstr = elf_hash_table (info)->dynstr;
-           BFD_ASSERT (dynstr != NULL);
-
-           for (i = 1, namep = mips_elf_dynsym_sec_names;
-                *namep != NULL;
-                i++, namep++)
-             {
-               s = bfd_get_section_by_name (output_bfd, *namep);
-               if (s != NULL)
-                 elf_section_data (s)->dynindx = i;
-
-               strindex = _bfd_stringtab_add (dynstr, *namep, true, false);
-               if (strindex == (bfd_size_type) -1)
-                 return false;
-
-               mips_elf_hash_table (info)->dynsym_sec_strindex[i] = strindex;
-             }
-         }
-       else
-#endif /* 0 */
-         {
-           c = bfd_count_sections (output_bfd);
-           elf_link_hash_traverse (elf_hash_table (info),
-                                   _bfd_elf_link_adjust_dynindx,
-                                   (PTR) &c);
-           elf_hash_table (info)->dynsymcount += c;
-
-           for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++)
-             {
-               elf_section_data (s)->dynindx = i;
-               /* These symbols will have no names, so we don't need to
-                  fiddle with dynstr_index.  */
-             }
-         }
-      }
-  }
-
   return true;
 }
 
@@ -7638,7 +7802,7 @@ mips_elf_size_dynamic_sections (output_bfd, info)
 
 static void
 mips_elf_irix6_finish_dynamic_symbol (abfd, name, sym)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      const char *name;
      Elf_Internal_Sym *sym;
 {
@@ -7687,8 +7851,8 @@ mips_elf_irix6_finish_dynamic_symbol (abfd, name, sym)
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
-static boolean
-mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
+boolean
+_bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
      bfd *output_bfd;
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
@@ -7751,7 +7915,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   BFD_ASSERT (h->dynindx != -1);
 
-  sgot = bfd_get_section_by_name (dynobj, ".got");
+  sgot = mips_elf_got_section (dynobj);
   BFD_ASSERT (sgot != NULL);
   BFD_ASSERT (elf_section_data (sgot) != NULL);
   g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
@@ -7775,7 +7939,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
        value = h->root.u.def.value;
 
       offset = mips_elf_global_got_index (dynobj, h);
-      bfd_put_32 (output_bfd, value, sgot->contents + offset);
+      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
     }
 
   /* Create a .msym entry, if appropriate.  */
@@ -7875,8 +8039,8 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
 /* Finish up the dynamic sections.  */
 
-static boolean
-mips_elf_finish_dynamic_sections (output_bfd, info)
+boolean
+_bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
      bfd *output_bfd;
      struct bfd_link_info *info;
 {
@@ -7889,7 +8053,7 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
 
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
-  sgot = bfd_get_section_by_name (dynobj, ".got");
+  sgot = mips_elf_got_section (dynobj);
   if (sgot == NULL)
     g = NULL;
   else
@@ -7901,39 +8065,41 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      Elf32_External_Dyn *dyncon, *dynconend;
+      bfd_byte *b;
 
       BFD_ASSERT (sdyn != NULL);
       BFD_ASSERT (g != NULL);
 
-      dyncon = (Elf32_External_Dyn *) sdyn->contents;
-      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
-      for (; dyncon < dynconend; dyncon++)
+      for (b = sdyn->contents;
+          b < sdyn->contents + sdyn->_raw_size;
+          b += MIPS_ELF_DYN_SIZE (dynobj))
        {
          Elf_Internal_Dyn dyn;
          const char *name;
          size_t elemsize;
          asection *s;
+         boolean swap_out_p;
 
-         bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+         /* Read in the current dynamic entry.  */
+         (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
+         
+         /* Assume that we're going to modify it and write it out.  */
+         swap_out_p = true;
 
          switch (dyn.d_tag)
            {
-           default:
-             break;
-
            case DT_RELENT:
-             s = bfd_get_section_by_name (dynobj, ".rel.dyn");
+             s = (bfd_get_section_by_name 
+                  (dynobj,
+                   MIPS_ELF_REL_DYN_SECTION_NAME (dynobj)));
              BFD_ASSERT (s != NULL);
-             dyn.d_un.d_val = sizeof (Elf32_External_Rel);
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             dyn.d_un.d_val = MIPS_ELF_REL_SIZE (dynobj);
              break;
 
            case DT_STRSZ:
              /* Rewrite DT_STRSZ.  */
              dyn.d_un.d_val =
                _bfd_stringtab_size (elf_hash_table (info)->dynstr);
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_PLTGOT:
@@ -7948,17 +8114,14 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
              s = bfd_get_section_by_name (output_bfd, name);
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_ptr = s->vma;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_RLD_VERSION:
              dyn.d_un.d_val = 1; /* XXX */
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_FLAGS:
              dyn.d_un.d_val = RHF_NOTPOT; /* XXX */
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_CONFLICTNO:
@@ -7980,38 +8143,35 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
                }
              else
                    dyn.d_un.d_val = 0;
-
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_TIME_STAMP:
              time ((time_t *) &dyn.d_un.d_val);
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_ICHECKSUM:
              /* XXX FIXME: */
+             swap_out_p = false;
              break;
 
            case DT_MIPS_IVERSION:
              /* XXX FIXME: */
+             swap_out_p = false;
              break;
 
            case DT_MIPS_BASE_ADDRESS:
              s = output_bfd->sections;
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_ptr = s->vma & ~(0xffff);
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_LOCAL_GOTNO:
              dyn.d_un.d_val = g->local_gotno;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_SYMTABNO:
              name = ".dynsym";
-             elemsize = sizeof (Elf32_External_Sym);
+             elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
              s = bfd_get_section_by_name (output_bfd, name);
              BFD_ASSERT (s != NULL);
 
@@ -8019,7 +8179,6 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
                dyn.d_un.d_val = s->_cooked_size / elemsize;
              else
                dyn.d_un.d_val = s->_raw_size / elemsize;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_UNREFEXTNO:
@@ -8027,38 +8186,40 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
                 entry of the first external symbol that is not
                 referenced within the same object.  */
              dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_GOTSYM:
              dyn.d_un.d_val = g->global_gotsym->dynindx;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_HIPAGENO:
              dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_RLD_MAP:
              dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_OPTIONS:
              s = (bfd_get_section_by_name 
                   (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (output_bfd)));
              dyn.d_un.d_ptr = s->vma;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_MIPS_MSYM:
              s = (bfd_get_section_by_name 
                   (output_bfd, MIPS_ELF_MSYM_SECTION_NAME (output_bfd)));
              dyn.d_un.d_ptr = s->vma;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           default:
+             swap_out_p = false;
              break;
            }
+
+         if (swap_out_p)
+           (*get_elf_backend_data (dynobj)->s->swap_dyn_out) 
+             (dynobj, &dyn, b);
        }
     }
 
@@ -8067,123 +8228,41 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
      This isn't the case of Irix rld. */
   if (sgot != NULL && sgot->_raw_size > 0)
     {
-      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
-      bfd_put_32 (output_bfd, (bfd_vma) 0x80000000, sgot->contents + 4);
+      MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents);
+      MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000, 
+                        sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd));
     }
 
   if (sgot != NULL)
-    elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+    elf_section_data (sgot->output_section)->this_hdr.sh_entsize
+      = MIPS_ELF_GOT_SIZE (output_bfd);
 
   {
-    asection *sdynsym;
     asection *smsym;
     asection *s;
-    Elf_Internal_Sym sym;
     Elf32_compact_rel cpt;
 
-    /* Set up the section symbols for the output sections. SGI sets
-       the STT_NOTYPE attribute for these symbols.  Should we do so?  */
+    /* ??? The section symbols for the output sections were set up in
+       _bfd_elf_final_link.  SGI sets the STT_NOTYPE attribute for these
+       symbols.  Should we do so?  */
 
-    sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
     smsym = bfd_get_section_by_name (dynobj, 
                                     MIPS_ELF_MSYM_SECTION_NAME (dynobj));
-    if (sdynsym != NULL)
+    if (smsym != NULL)
       {
-#if 0
-       const char *name;
-       const char * const * namep = mips_elf_dynsym_sec_names;
-       unsigned int i;
-       bfd_vma last;
-       long dindx;
-
-       /* We no longer try to restrict the set of sections which get
-           dynamic symbol table entries, since it fails if we have
-           other random sections which need dynamic relocations.  */
-       if (SGI_COMPAT (output_bfd))
-         {
-           sym.st_size = 0;
-           sym.st_name = 0;
-           sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
-           sym.st_other = 0;
-
-           i = 0;
-           last = 0;
-           dindx = 0;
-           while ((name = *namep++) != NULL)
-             {
-               s = bfd_get_section_by_name (output_bfd, name);
-               if (s != NULL)
-                 {
-                   sym.st_value = s->vma;
-                   dindx = elf_section_data (s)->dynindx;
-                   last = s->vma + s->_raw_size;
-                 }
-               else
-                 {
-                   sym.st_value = last;
-                   dindx++;
-                 }
-
-               sym.st_shndx = (i < MIPS_TEXT_DYNSYM_SECNO
-                               ? SHN_MIPS_TEXT
-                               : SHN_MIPS_DATA);
-               ++i;
-               sym.st_name =
-                 mips_elf_hash_table (info)->dynsym_sec_strindex[dindx];
-
-               bfd_elf32_swap_symbol_out (output_bfd, &sym,
-                                          (((Elf32_External_Sym *)
-                                            sdynsym->contents)
-                                           + dindx));
-             }
-
-           /* Set the sh_info field of the output .dynsym section to
-              the index of the first global symbol.  */
-           elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
-             SIZEOF_MIPS_DYNSYM_SECNAMES;
-         }
-       else
-#endif /* 0 */
-         {
-           Elf32_Internal_Msym msym;
-
-           sym.st_size = 0;
-           sym.st_name = 0;
-           sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
-           sym.st_other = 0;
+       Elf32_Internal_Msym msym;
 
-           msym.ms_hash_value = 0;
-           msym.ms_info = ELF32_MS_INFO (0, 1);
+       msym.ms_hash_value = 0;
+       msym.ms_info = ELF32_MS_INFO (0, 1);
 
-           for (s = output_bfd->sections; s != NULL; s = s->next)
-             {
-               int indx;
-               long dynindx;
-
-               sym.st_value = s->vma;
-
-               indx = elf_section_data (s)->this_idx;
-               BFD_ASSERT (indx > 0);
-               sym.st_shndx = indx;
-               
-               dynindx  = elf_section_data (s)->dynindx;
-
-               bfd_elf32_swap_symbol_out 
-                 (output_bfd, &sym,
-                  (((Elf32_External_Sym *) sdynsym->contents)
-                   + dynindx));
-               
-               if (smsym)
-                 bfd_mips_elf_swap_msym_out 
-                   (output_bfd, &msym,
-                    (((Elf32_External_Msym *) smsym->contents)
-                     + dynindx));
-             }
+       for (s = output_bfd->sections; s != NULL; s = s->next)
+         {
+           long dynindx = elf_section_data (s)->dynindx;
 
-           /* Set the sh_info field of the output .dynsym section to
-              the index of the first global symbol.  */
-           elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
-             bfd_count_sections (output_bfd) + 1;
+           bfd_mips_elf_swap_msym_out 
+             (output_bfd, &msym,
+              (((Elf32_External_Msym *) smsym->contents)
+               + dynindx));
          }
       }
 
@@ -8220,9 +8299,10 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
       }
 
     /* Clean up a first relocation in .rel.dyn.  */
-    s = bfd_get_section_by_name (dynobj, ".rel.dyn");
+    s = bfd_get_section_by_name (dynobj, 
+                                MIPS_ELF_REL_DYN_SECTION_NAME (dynobj));
     if (s != NULL && s->_raw_size > 0)
-      memset (s->contents, 0, sizeof (Elf32_External_Rel));
+      memset (s->contents, 0, MIPS_ELF_REL_SIZE (dynobj));
   }
 
   return true;
@@ -8473,27 +8553,49 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 #define elf_info_to_howto              mips_info_to_howto_rela
 #define elf_info_to_howto_rel          mips_info_to_howto_rel
 #define elf_backend_sym_is_global      mips_elf_sym_is_global
-#define elf_backend_object_p           mips_elf32_object_p
-#define elf_backend_section_from_shdr  mips_elf32_section_from_shdr
+#define elf_backend_object_p           _bfd_mips_elf_object_p
+#define elf_backend_section_from_shdr  _bfd_mips_elf_section_from_shdr
 #define elf_backend_fake_sections      _bfd_mips_elf_fake_sections
 #define elf_backend_section_from_bfd_section \
                                        _bfd_mips_elf_section_from_bfd_section
-#define elf_backend_section_processing mips_elf32_section_processing
+#define elf_backend_section_processing _bfd_mips_elf_section_processing
 #define elf_backend_symbol_processing  _bfd_mips_elf_symbol_processing
 #define elf_backend_additional_program_headers \
-                                       mips_elf_additional_program_headers
-#define elf_backend_modify_segment_map mips_elf_modify_segment_map
+                                       _bfd_mips_elf_additional_program_headers
+#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map
 #define elf_backend_final_write_processing \
                                        _bfd_mips_elf_final_write_processing
 #define elf_backend_ecoff_debug_swap   &mips_elf32_ecoff_debug_swap
+#define elf_backend_add_symbol_hook    _bfd_mips_elf_add_symbol_hook
+#define elf_backend_create_dynamic_sections \
+                                       _bfd_mips_elf_create_dynamic_sections
+#define elf_backend_check_relocs       _bfd_mips_elf_check_relocs
+#define elf_backend_adjust_dynamic_symbol \
+                                       _bfd_mips_elf_adjust_dynamic_symbol
+#define elf_backend_always_size_sections \
+                                       _bfd_mips_elf_always_size_sections
+#define elf_backend_size_dynamic_sections \
+                                       _bfd_mips_elf_size_dynamic_sections
+#define elf_backend_relocate_section   _bfd_mips_elf_relocate_section
+#define elf_backend_link_output_symbol_hook \
+                                       _bfd_mips_elf_link_output_symbol_hook
+#define elf_backend_finish_dynamic_symbol \
+                                       _bfd_mips_elf_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+                                       _bfd_mips_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook       _bfd_mips_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook      _bfd_mips_elf_gc_sweep_hook
+
+#define elf_backend_got_header_size    (4*MIPS_RESERVED_GOTNO)
+#define elf_backend_plt_header_size    0
 
 #define bfd_elf32_bfd_is_local_label_name \
                                        mips_elf_is_local_label_name
 #define bfd_elf32_find_nearest_line    _bfd_mips_elf_find_nearest_line
 #define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents
 #define bfd_elf32_bfd_link_hash_table_create \
-                                       mips_elf_link_hash_table_create
-#define bfd_elf32_bfd_final_link       mips_elf_final_link
+                                       _bfd_mips_elf_link_hash_table_create
+#define bfd_elf32_bfd_final_link       _bfd_mips_elf_final_link
 #define bfd_elf32_bfd_copy_private_bfd_data \
                                        _bfd_mips_elf_copy_private_bfd_data
 #define bfd_elf32_bfd_merge_private_bfd_data \
@@ -8501,27 +8603,4 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 #define bfd_elf32_bfd_set_private_flags        _bfd_mips_elf_set_private_flags
 #define bfd_elf32_bfd_print_private_bfd_data \
                                        _bfd_mips_elf_print_private_bfd_data
-#define elf_backend_add_symbol_hook    mips_elf_add_symbol_hook
-#define elf_backend_create_dynamic_sections \
-                                       mips_elf_create_dynamic_sections
-#define elf_backend_check_relocs       mips_elf_check_relocs
-#define elf_backend_adjust_dynamic_symbol \
-                                       mips_elf_adjust_dynamic_symbol
-#define elf_backend_always_size_sections \
-                                       mips_elf_always_size_sections
-#define elf_backend_size_dynamic_sections \
-                                       mips_elf_size_dynamic_sections
-#define elf_backend_relocate_section   mips_elf_relocate_section
-#define elf_backend_link_output_symbol_hook \
-                                       mips_elf_link_output_symbol_hook
-#define elf_backend_finish_dynamic_symbol \
-                                       mips_elf_finish_dynamic_symbol
-#define elf_backend_finish_dynamic_sections \
-                                       mips_elf_finish_dynamic_sections
-#define elf_backend_gc_mark_hook       mips_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook      mips_elf_gc_sweep_hook
-
-#define elf_backend_got_header_size    (4*MIPS_RESERVED_GOTNO)
-#define elf_backend_plt_header_size    0
-
 #include "elf32-target.h"
This page took 0.059364 seconds and 4 git commands to generate.