* elf32-mips.c (_bfd_mips_elf_relocate_section): Formatting.
[binutils-gdb.git] / bfd / elf32-mips.c
index fd79bbaec62c8aac23e304aca0de7c81e510da88..9e8e0d3dfb3512f0620299431b21c663a90c495a 100644 (file)
@@ -219,6 +219,12 @@ static boolean _bfd_elf32_mips_grok_prstatus
   PARAMS ((bfd *, Elf_Internal_Note *));
 static boolean _bfd_elf32_mips_grok_psinfo
   PARAMS ((bfd *, Elf_Internal_Note *));
+static boolean _bfd_elf32_mips_discard_info
+  PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *));
+static boolean _bfd_elf32_mips_ignore_discarded_relocs
+  PARAMS ((asection *));
+static boolean _bfd_elf32_mips_write_section
+  PARAMS ((bfd *, asection *, bfd_byte *));
 
 extern const bfd_target bfd_elf32_tradbigmips_vec;
 extern const bfd_target bfd_elf32_tradlittlemips_vec;
@@ -263,6 +269,8 @@ static bfd *reldyn_sorting_bfd;
   ((ABI_N32_P (abfd) || ABI_64_P (abfd)) ? ict_irix6 : ict_irix5))
 #endif
 
+#define NEWABI_P(abfd) (ABI_N32_P(abfd) || ABI_64_P(abfd))
+
 /* Whether we are trying to be compatible with IRIX at all.  */
 #define SGI_COMPAT(abfd) \
   (IRIX_COMPAT (abfd) != ict_none)
@@ -484,13 +492,13 @@ static void bfd_elf32_swap_compact_rel_out
 static void bfd_elf32_swap_crinfo_out
   PARAMS ((bfd *, const Elf32_crinfo *, Elf32_External_crinfo *));
 
-#define USE_REL        1               /* MIPS uses REL relocations instead of RELA */
-
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 
-static reloc_howto_type elf_mips_howto_table[] =
+/* The relocation table used for SHT_REL sections.  */
+
+static reloc_howto_type elf_mips_howto_table_rel[] =
 {
   /* No relocation.  */
   HOWTO (R_MIPS_NONE,          /* type */
@@ -510,16 +518,16 @@ static reloc_howto_type elf_mips_howto_table[] =
   /* 16 bit relocation.  */
   HOWTO (R_MIPS_16,            /* type */
         0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_16",           /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* 32 bit relocation.  */
@@ -529,7 +537,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_32",           /* name */
         true,                  /* partial_inplace */
@@ -544,7 +552,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_REL32",        /* name */
         true,                  /* partial_inplace */
@@ -566,8 +574,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_26",           /* name */
         true,                  /* partial_inplace */
-        0x3ffffff,             /* src_mask */
-        0x3ffffff,             /* dst_mask */
+        0x03ffffff,            /* src_mask */
+        0x03ffffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* High 16 bits of symbol value.  */
@@ -581,8 +589,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         _bfd_mips_elf_hi16_reloc,      /* special_function */
         "R_MIPS_HI16",         /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Low 16 bits of symbol value.  */
@@ -596,8 +604,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         _bfd_mips_elf_lo16_reloc,      /* special_function */
         "R_MIPS_LO16",         /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* GP relative reference.  */
@@ -611,8 +619,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_GPREL16",      /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Reference to literal section.  */
@@ -626,8 +634,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_LITERAL",      /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Reference to global offset table.  */
@@ -640,9 +648,9 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_signed, /* complain_on_overflow */
         _bfd_mips_elf_got16_reloc,     /* special_function */
         "R_MIPS_GOT16",        /* name */
-        false,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* 16 bit PC relative reference.  */
@@ -656,8 +664,8 @@ static reloc_howto_type elf_mips_howto_table[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_PC16",         /* name */
         true,                  /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         true),                 /* pcrel_offset */
 
   /* 16 bit call through global offset table.  */
@@ -670,9 +678,9 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_CALL16",       /* name */
-        false,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* 32 bit GP relative reference.  */
@@ -682,19 +690,467 @@ static reloc_howto_type elf_mips_howto_table[] =
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        _bfd_mips_elf_gprel32_reloc, /* special_function */
+        "R_MIPS_GPREL32",      /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* The remaining relocs are defined on Irix 5, although they are
+     not defined by the ABI.  */
+  EMPTY_HOWTO (13),
+  EMPTY_HOWTO (14),
+  EMPTY_HOWTO (15),
+
+  /* A 5 bit shift field.  */
+  HOWTO (R_MIPS_SHIFT5,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        5,                     /* bitsize */
+        false,                 /* pc_relative */
+        6,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_SHIFT5",       /* name */
+        true,                  /* partial_inplace */
+        0x000007c0,            /* src_mask */
+        0x000007c0,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* A 6 bit shift field.  */
+  /* FIXME: This is not handled correctly; a special function is
+     needed to put the most significant bit in the right place.  */
+  HOWTO (R_MIPS_SHIFT6,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        false,                 /* pc_relative */
+        6,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_SHIFT6",       /* name */
+        true,                  /* partial_inplace */
+        0x000007c4,            /* src_mask */
+        0x000007c4,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* A 64 bit relocation.  */
+  HOWTO (R_MIPS_64,            /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        mips32_64bit_reloc,    /* special_function */
+        "R_MIPS_64",           /* name */
+        true,                  /* partial_inplace */
+        MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Displacement in the global offset table.  */
+  HOWTO (R_MIPS_GOT_DISP,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_GOT_DISP",     /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Displacement to page pointer in the global offset table.  */
+  HOWTO (R_MIPS_GOT_PAGE,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_GOT_PAGE",     /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Offset from page pointer in the global offset table.  */
+  HOWTO (R_MIPS_GOT_OFST,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_GOT_OFST",     /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* High 16 bits of displacement in global offset table.  */
+  HOWTO (R_MIPS_GOT_HI16,      /* 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_GOT_HI16",     /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Low 16 bits of displacement in global offset table.  */
+  HOWTO (R_MIPS_GOT_LO16,      /* 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_GOT_LO16",     /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 64 bit subtraction.  Used in the N32 ABI.  */
+  HOWTO (R_MIPS_SUB,           /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_SUB",          /* name */
+        true,                  /* partial_inplace */
+        MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used to cause the linker to insert and delete instructions?  */
+  EMPTY_HOWTO (R_MIPS_INSERT_A),
+  EMPTY_HOWTO (R_MIPS_INSERT_B),
+  EMPTY_HOWTO (R_MIPS_DELETE),
+
+  /* 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 */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* 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 */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* High 16 bits of displacement in global offset table.  */
+  HOWTO (R_MIPS_CALL_HI16,     /* 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_CALL_HI16",    /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Low 16 bits of displacement in global offset table.  */
+  HOWTO (R_MIPS_CALL_LO16,     /* 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_CALL_LO16",    /* name */
+        true,                  /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Section displacement.  */
+  HOWTO (R_MIPS_SCN_DISP,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_SCN_DISP",     /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  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.  */
+  HOWTO (R_MIPS_JALR,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_JALR",         /* name */
+        false,                 /* partial_inplace */
+        0x00000000,            /* src_mask */
+        0x00000000,            /* dst_mask */
+        false),                /* pcrel_offset */
+};
+
+/* The relocation table used for SHT_RELA sections.  */
+
+static reloc_howto_type elf_mips_howto_table_rela[] =
+{
+  /* No relocation.  */
+  HOWTO (R_MIPS_NONE,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_NONE",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 16 bit relocation.  */
+  HOWTO (R_MIPS_16,            /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_16",           /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 32 bit relocation.  */
+  HOWTO (R_MIPS_32,            /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_32",           /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 32 bit symbol relative relocation.  */
+  HOWTO (R_MIPS_REL32,         /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_REL32",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 26 bit jump address.  */
+  HOWTO (R_MIPS_26,            /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        26,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+                               /* This needs complex overflow
+                                  detection, because the upper 36
+                                  bits must match the PC + 4.  */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_26",           /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x03ffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* R_MIPS_HI16 and R_MIPS_LO16 are unsupported for 64 bit REL.  */
+  /* High 16 bits of symbol value.  */
+  HOWTO (R_MIPS_HI16,          /* 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_HI16",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Low 16 bits of symbol value.  */
+  HOWTO (R_MIPS_LO16,          /* 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_LO16",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_MIPS_GPREL16,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
+        "R_MIPS_GPREL16",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Reference to literal section.  */
+  HOWTO (R_MIPS_LITERAL,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
+        "R_MIPS_LITERAL",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Reference to global offset table.  */
+  /* FIXME: This is not handled correctly.  */
+  HOWTO (R_MIPS_GOT16,         /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_GOT16",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 16 bit PC relative reference.  */
+  HOWTO (R_MIPS_PC16,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_PC16",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* 16 bit call through global offset table.  */
+  /* FIXME: This is not handled correctly.  */
+  HOWTO (R_MIPS_CALL16,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_CALL16",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* 32 bit GP relative reference.  */
+  HOWTO (R_MIPS_GPREL32,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
         _bfd_mips_elf_gprel32_reloc, /* special_function */
         "R_MIPS_GPREL32",      /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
-    /* The remaining relocs are defined on Irix 5, although they are
-       not defined by the ABI.  */
-    EMPTY_HOWTO (13),
-    EMPTY_HOWTO (14),
-    EMPTY_HOWTO (15),
+  EMPTY_HOWTO (13),
+  EMPTY_HOWTO (14),
+  EMPTY_HOWTO (15),
 
   /* A 5 bit shift field.  */
   HOWTO (R_MIPS_SHIFT5,                /* type */
@@ -706,14 +1162,13 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_SHIFT5",       /* name */
-        true,                  /* partial_inplace */
-        0x000007c0,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x000007c0,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* A 6 bit shift field.  */
-  /* FIXME: This is not handled correctly; a special function is
-     needed to put the most significant bit in the right place.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_SHIFT6,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -721,74 +1176,78 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         6,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_SHIFT6",       /* name */
-        true,                  /* partial_inplace */
-        0x000007c4,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x000007c4,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* 64 bit relocation.  */
+  /* 64 bit relocation.  */
   HOWTO (R_MIPS_64,            /* type */
         0,                     /* rightshift */
         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 */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_64",           /* name */
-        true,                  /* partial_inplace */
-        MINUS_ONE,             /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         MINUS_ONE,             /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Displacement in the global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_GOT_DISP,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT_DISP",     /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Displacement to page pointer in the global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_GOT_PAGE,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT_PAGE",     /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Offset from page pointer in the global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_GOT_OFST,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT_OFST",     /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* High 16 bits of displacement in global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_GOT_HI16,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -798,12 +1257,13 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT_HI16",     /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Low 16 bits of displacement in global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_GOT_LO16,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -813,30 +1273,75 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT_LO16",     /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* 64 bit subtraction.  Used in the N32 ABI.  */
+  /* 64 bit substraction.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_SUB,           /* type */
         0,                     /* rightshift */
         4,                     /* size (0 = byte, 1 = short, 2 = long) */
         64,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_SUB",          /* name */
-        true,                  /* partial_inplace */
-        MINUS_ONE,             /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         MINUS_ONE,             /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* Used to cause the linker to insert and delete instructions?  */
-  EMPTY_HOWTO (R_MIPS_INSERT_A),
-  EMPTY_HOWTO (R_MIPS_INSERT_B),
-  EMPTY_HOWTO (R_MIPS_DELETE),
+  /* Insert the addend as an instruction.  */
+  /* FIXME: Not handled correctly.  */
+  HOWTO (R_MIPS_INSERT_A,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_INSERT_A",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Insert the addend as an instruction, and change all relocations
+     to refer to the old instruction at the address.  */
+  /* FIXME: Not handled correctly.  */
+  HOWTO (R_MIPS_INSERT_B,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_INSERT_B",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Delete a 32 bit instruction.  */
+  /* FIXME: Not handled correctly.  */
+  HOWTO (R_MIPS_DELETE,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_DELETE",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
 
   /* Get the higher value of a 64 bit addend.  */
   HOWTO (R_MIPS_HIGHER,                /* type */
@@ -846,11 +1351,11 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_HIGHER",       /* name */
-        true,                  /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Get the highest value of a 64 bit addend.  */
@@ -861,14 +1366,15 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_HIGHEST",      /* name */
-        true,                  /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffff,                /* dst_mask */
+        0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* High 16 bits of displacement in global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_CALL_HI16,     /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -878,12 +1384,13 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_CALL_HI16",    /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Low 16 bits of displacement in global offset table.  */
+  /* FIXME: Not handled correctly.  */
   HOWTO (R_MIPS_CALL_LO16,     /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -893,13 +1400,14 @@ static reloc_howto_type elf_mips_howto_table[] =
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_CALL_LO16",    /* name */
-        true,                  /* partial_inplace */
-        0x0000ffff,            /* src_mask */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* Section displacement.  */
-  HOWTO (R_MIPS_SCN_DISP,       /* type */
+  /* Section displacement, used by an associated event location section.  */
+  /* FIXME: Not handled correctly.  */
+  HOWTO (R_MIPS_SCN_DISP,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -907,31 +1415,60 @@ static reloc_howto_type elf_mips_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_MIPS_SCN_DISP",     /* name */
+        "R_MIPS_SCN_DISP",     /* name */
         false,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
+        0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
         false),                /* pcrel_offset */
 
-  EMPTY_HOWTO (R_MIPS_REL16),
+  HOWTO (R_MIPS_REL16,         /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_REL16",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* These two are obsolete.  */
   EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
   EMPTY_HOWTO (R_MIPS_PJUMP),
-  EMPTY_HOWTO (R_MIPS_RELGOT),
+
+  /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section.
+     It must be used for multigot GOT's (and only there).  */
+  HOWTO (R_MIPS_RELGOT,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_RELGOT",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
 
   /* Protected jump conversion.  This is an optimization hint.  No
      relocation is required for correctness.  */
   HOWTO (R_MIPS_JALR,          /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_JALR",         /* name */
         false,                 /* partial_inplace */
-        0x00000000,            /* src_mask */
-        0x00000000,            /* dst_mask */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
         false),                /* pcrel_offset */
 };
 
@@ -1190,6 +1727,8 @@ _bfd_mips_elf_hi16_reloc (abfd,
   relocation += symbol->section->output_section->vma;
   relocation += symbol->section->output_offset;
   relocation += reloc_entry->addend;
+  if (reloc_entry->howto->pc_relative)
+    relocation -= reloc_entry->address;
 
   if (reloc_entry->address > input_section->_cooked_size)
     return bfd_reloc_outofrange;
@@ -1555,8 +2094,8 @@ gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
       || (symbol->flags & BSF_SECTION_SYM) != 0)
     val += relocation - gp;
 
-  insn = (insn &~ (bfd_vma) 0xffff) | (val & 0xffff);
-  bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);
+  insn = (insn & ~0xffff) | (val & 0xffff);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
 
   if (relocateable)
     reloc_entry->address += input_section->output_offset;
@@ -1708,7 +2247,7 @@ mips32_64bit_reloc (abfd, reloc_entry, symbol, data, input_section,
   reloc32 = *reloc_entry;
   if (bfd_big_endian (abfd))
     reloc32.address += 4;
-  reloc32.howto = &elf_mips_howto_table[R_MIPS_32];
+  reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32];
   r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
                              output_bfd, error_message);
 
@@ -1973,12 +2512,12 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
   { BFD_RELOC_HI16_S, R_MIPS_HI16 },
   { BFD_RELOC_LO16, R_MIPS_LO16 },
-  { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 },
+  { BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
   { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
   { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
   { BFD_RELOC_16_PCREL, R_MIPS_PC16 },
   { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
-  { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 },
+  { BFD_RELOC_GPREL32, R_MIPS_GPREL32 },
   { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
   { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
   { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
@@ -2001,7 +2540,7 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
   for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++)
     {
       if (mips_reloc_map[i].bfd_reloc_val == code)
-       return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
+       return &elf_mips_howto_table_rel[(int) mips_reloc_map[i].elf_reloc_val];
     }
 
   switch (code)
@@ -2015,7 +2554,7 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
         Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
         size of addresses on this architecture.  */
       if (bfd_arch_bits_per_address (abfd) == 32)
-       return &elf_mips_howto_table[(int) R_MIPS_32];
+       return &elf_mips_howto_table_rel[(int) R_MIPS_32];
       else
        return &elf_mips_ctor64_howto;
 
@@ -2078,7 +2617,7 @@ mips_rtype_to_howto (r_type)
 
     default:
       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
-      return &elf_mips_howto_table[r_type];
+      return &elf_mips_howto_table_rel[r_type];
       break;
     }
 }
@@ -2323,7 +2862,7 @@ boolean
 _bfd_mips_elf_object_p (abfd)
      bfd *abfd;
 {
-  /* Irix 5 and 6 is broken.  Object file symbol tables are not always
+  /* Irix 5 and 6 are 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.  */
   if (SGI_COMPAT(abfd))
@@ -2416,7 +2955,7 @@ _bfd_mips_elf_final_write_processing (abfd, linker)
   /* Set the sh_info field for .gptab sections and other appropriate
      info for each special section.  */
   for (i = 1, hdrpp = elf_elfsections (abfd) + 1;
-       i < elf_elfheader (abfd)->e_shnum;
+       i < elf_numsections (abfd);
        i++, hdrpp++)
     {
       switch ((*hdrpp)->sh_type)
@@ -3510,7 +4049,7 @@ _bfd_mips_elf_modify_segment_map (abfd)
        if ((*pm)->p_type == PT_DYNAMIC)
          break;
       m = *pm;
-      if (IRIX_COMPAT (abfd) == ict_none)
+      if (m != NULL && IRIX_COMPAT (abfd) == ict_none)
        {
          /* For a normal mips executable the permissions for the PT_DYNAMIC
             segment are read, write and execute. We do that here since
@@ -5585,7 +6124,7 @@ mips_elf_sort_hash_table (info, max_local)
                               mips_elf_sort_hash_table_f,
                               &hsd);
 
-  /* There shoud have been enough room in the symbol table to
+  /* There should have been enough room in the symbol table to
      accomodate both the GOT and non-GOT symbols.  */
   BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
 
@@ -5819,29 +6358,10 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
              < sreloc->_raw_size);
 
   skip = false;
-
-  /* We begin by assuming that the offset for the dynamic relocation
-     is the same as for the original relocation.  We'll adjust this
-     later to reflect the correct output offsets.  */
-  if (elf_section_data (input_section)->stab_info == NULL)
-    outrel.r_offset = rel->r_offset;
-  else
-    {
-      /* Except that in a stab section things are more complex.
-        Because we compress stab information, the offset given in the
-        relocation may not be the one we want; we must let the stabs
-        machinery tell us the offset.  */
-      outrel.r_offset
-       = (_bfd_stab_section_offset
-          (output_bfd, &elf_hash_table (info)->stab_info,
-           input_section,
-           &elf_section_data (input_section)->stab_info,
-           rel->r_offset));
-      /* If we didn't need the relocation at all, this value will be
-        -1.  */
-      if (outrel.r_offset == (bfd_vma) -1)
-       skip = true;
-    }
+  outrel.r_offset =
+    _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset);
+  if (outrel.r_offset == (bfd_vma) -1)
+    skip = true;
 
   /* If we've decided to skip this relocation, just output an empty
      record.  Note that R_MIPS_NONE == 0, so that this call to memset
@@ -6319,8 +6839,11 @@ mips_elf_calculate_relocation (abfd,
       if ((info->shared
           || (elf_hash_table (info)->dynamic_sections_created
               && h != NULL
-              && ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
-                  != 0)))
+              && ((h->root.elf_link_hash_flags
+                   & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+              && ((h->root.elf_link_hash_flags
+                   & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+         && r_symndx != 0
          && (input_section->flags & SEC_ALLOC) != 0)
        {
          /* If we're creating a shared library, or this relocation is
@@ -6811,7 +7334,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             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;
+         howto = elf_mips_howto_table_rel + R_MIPS_32;
 
          /* On big-endian systems, we need to lie about the position
             of the reloc.  */
@@ -7012,7 +7535,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                }
 
              if (!mips_elf_perform_relocation (info, howto, rel, addend,
-                                               input_bfd,  input_section,
+                                               input_bfd, input_section,
                                                contents, false))
                return false;
            }
@@ -8016,13 +8539,7 @@ _bfd_mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
     }
   else
     {
-      if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
-               && sym->st_shndx != SHN_COMMON))
-       {
-         return bfd_section_from_elf_index (abfd, sym->st_shndx);
-       }
+      return bfd_section_from_elf_index (abfd, sym->st_shndx);
     }
 
   return NULL;
@@ -8074,7 +8591,8 @@ _bfd_mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
 
 /* Copy data from a MIPS ELF indirect symbol to its direct symbol,
    hiding the old indirect symbol.  Process additional relocation
-   information.  */
+   information.  Also called for weakdefs, in which case we just let
+   _bfd_elf_link_hash_copy_indirect copy the flags for us.  */
 
 static void
 _bfd_mips_elf_copy_indirect_symbol (dir, ind)
@@ -8084,6 +8602,9 @@ _bfd_mips_elf_copy_indirect_symbol (dir, ind)
 
   _bfd_elf_link_hash_copy_indirect (dir, ind);
 
+  if (ind->root.type != bfd_link_hash_indirect)
+    return;
+
   dirmips = (struct mips_elf_link_hash_entry *) dir;
   indmips = (struct mips_elf_link_hash_entry *) ind;
   dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
@@ -8920,7 +9441,7 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
            case DT_STRSZ:
              /* Rewrite DT_STRSZ.  */
              dyn.d_un.d_val =
-               _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+               _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
              break;
 
            case DT_PLTGOT:
@@ -9217,6 +9738,114 @@ _bfd_elf32_mips_grok_psinfo (abfd, note)
   return true;
 }
 \f
+#define PDR_SIZE 32
+
+static boolean
+_bfd_elf32_mips_discard_info (abfd, cookie, info)
+     bfd *abfd;
+     struct elf_reloc_cookie *cookie;
+     struct bfd_link_info *info;
+{
+  asection *o;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  boolean ret = false;
+  unsigned char *tdata;
+  size_t i, skip;
+
+  o = bfd_get_section_by_name (abfd, ".pdr");
+  if (! o)
+    return false;
+  if (o->_raw_size == 0)
+    return false;
+  if (o->_raw_size % PDR_SIZE != 0)
+    return false;
+  if (o->output_section != NULL
+      && bfd_is_abs_section (o->output_section))
+    return false;
+
+  tdata = bfd_zmalloc (o->_raw_size / PDR_SIZE);
+  if (! tdata)
+    return false;
+
+  cookie->rels = _bfd_elf32_link_read_relocs (abfd, o, (PTR) NULL,
+                                            (Elf_Internal_Rela *) NULL,
+                                             info->keep_memory);
+  if (!cookie->rels)
+    {
+      free (tdata);
+      return false;
+    }
+
+  cookie->rel = cookie->rels;
+  cookie->relend =
+    cookie->rels + o->reloc_count * bed->s->int_rels_per_ext_rel;
+      
+  for (i = 0, skip = 0; i < o->_raw_size; i ++)
+    {
+      if (_bfd_elf32_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
+       {
+         tdata[i] = 1;
+         skip ++;
+       }
+    }
+
+  if (skip != 0)
+    {
+      elf_section_data (o)->tdata = tdata;
+      o->_cooked_size = o->_raw_size - skip * PDR_SIZE;
+      ret = true;
+    }
+  else
+    free (tdata);
+
+  if (! info->keep_memory)
+    free (cookie->rels);
+
+  return ret;
+}
+
+static boolean
+_bfd_elf32_mips_ignore_discarded_relocs (sec)
+     asection *sec;
+{
+  if (strcmp (sec->name, ".pdr") == 0)
+    return true;
+  return false;
+}
+
+static boolean
+_bfd_elf32_mips_write_section (output_bfd, sec, contents)
+     bfd *output_bfd;
+     asection *sec;
+     bfd_byte *contents;
+{
+  bfd_byte *to, *from, *end;
+  int i;
+
+  if (strcmp (sec->name, ".pdr") != 0)
+    return false;
+
+  if (elf_section_data (sec)->tdata == NULL)
+    return false;
+
+  to = contents;
+  end = contents + sec->_raw_size;
+  for (from = contents, i = 0;
+       from < end;
+       from += PDR_SIZE, i++)
+    {
+      if (((unsigned char *)elf_section_data (sec)->tdata)[i] == 1)
+       continue;
+      if (to != from)
+       memcpy (to, from, PDR_SIZE);
+      to += PDR_SIZE;
+    }
+  bfd_set_section_contents (output_bfd, sec->output_section, contents,
+                           (file_ptr) sec->output_offset,
+                           sec->_cooked_size);
+  return true;
+}
+\f
 /* This is almost identical to bfd_generic_get_... except that some
    MIPS relocations need to be handled specially.  Sigh.  */
 
@@ -9446,10 +10075,6 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
   _bfd_mips_elf_read_ecoff_info
 };
 \f
-#define TARGET_LITTLE_SYM              bfd_elf32_littlemips_vec
-#define TARGET_LITTLE_NAME             "elf32-littlemips"
-#define TARGET_BIG_SYM                 bfd_elf32_bigmips_vec
-#define TARGET_BIG_NAME                        "elf32-bigmips"
 #define ELF_ARCH                       bfd_arch_mips
 #define ELF_MACHINE_CODE               EM_MIPS
 
@@ -9460,24 +10085,19 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
 #define elf_backend_collect            true
 #define elf_backend_type_change_ok     true
 #define elf_backend_can_gc_sections    true
-#define elf_backend_sign_extend_vma    true
 #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           _bfd_mips_elf_object_p
+#define elf_backend_symbol_processing  _bfd_mips_elf_symbol_processing
+#define elf_backend_section_processing _bfd_mips_elf_section_processing
 #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 _bfd_mips_elf_section_processing
-#define elf_backend_symbol_processing  _bfd_mips_elf_symbol_processing
-#define elf_backend_additional_program_headers \
-                                       _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_link_output_symbol_hook \
+                                       _bfd_mips_elf_link_output_symbol_hook
 #define elf_backend_create_dynamic_sections \
                                        _bfd_mips_elf_create_dynamic_sections
 #define elf_backend_check_relocs       _bfd_mips_elf_check_relocs
@@ -9488,24 +10108,35 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
 #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_final_write_processing \
+                                       _bfd_mips_elf_final_write_processing
+#define elf_backend_additional_program_headers \
+                                       _bfd_mips_elf_additional_program_headers
+#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map
 #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 elf_backend_copy_indirect_symbol \
                                        _bfd_mips_elf_copy_indirect_symbol
-
 #define elf_backend_hide_symbol                _bfd_mips_elf_hide_symbol
 #define elf_backend_grok_prstatus      _bfd_elf32_mips_grok_prstatus
 #define elf_backend_grok_psinfo                _bfd_elf32_mips_grok_psinfo
+#define elf_backend_ecoff_debug_swap   &mips_elf32_ecoff_debug_swap
+
+#define elf_backend_got_header_size    (4 * MIPS_RESERVED_GOTNO)
+#define elf_backend_plt_header_size    0
+#define elf_backend_may_use_rel_p      1
+#define elf_backend_may_use_rela_p     0
+#define elf_backend_default_use_rela_p 0
+#define elf_backend_sign_extend_vma    true
+
+#define elf_backend_discard_info       _bfd_elf32_mips_discard_info
+#define elf_backend_ignore_discarded_relocs \
+                                       _bfd_elf32_mips_ignore_discarded_relocs
+#define elf_backend_write_section      _bfd_elf32_mips_write_section
 
 #define bfd_elf32_bfd_is_local_label_name \
                                        mips_elf_is_local_label_name
@@ -9521,11 +10152,17 @@ 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
-#include "elf32-target.h"
 
-/* Support for traditional mips targets */
+/* Support for SGI-ish mips targets.  */
+#define TARGET_LITTLE_SYM              bfd_elf32_littlemips_vec
+#define TARGET_LITTLE_NAME             "elf32-littlemips"
+#define TARGET_BIG_SYM                 bfd_elf32_bigmips_vec
+#define TARGET_BIG_NAME                        "elf32-bigmips"
+
+#include "elf32-target.h"
 
-#define INCLUDED_TARGET_FILE            /* More a type of flag */
+/* Support for traditional mips targets.  */
+#define INCLUDED_TARGET_FILE            /* More a type of flag.  */
 
 #undef TARGET_LITTLE_SYM
 #undef TARGET_LITTLE_NAME