include/
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index 9ec9c86dcb0547b1425d48546685e0dc1f4ed479..4d73239b3a1a4169dab13ce9cf500f989c03438b 100644 (file)
@@ -1,6 +1,6 @@
 /* MIPS-specific support for ELF
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004 Free Software Foundation, Inc.
+   2003, 2004, 2005 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -369,132 +369,20 @@ typedef struct runtime_pdr {
 #define cbRPDR sizeof (RPDR)
 #define rpdNil ((pRPDR) 0)
 \f
-static struct bfd_hash_entry *mips_elf_link_hash_newfunc
-  (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
-static void ecoff_swap_rpdr_out
-  (bfd *, const RPDR *, struct rpdr_ext *);
-static bfd_boolean mips_elf_create_procedure_table
-  (void *, bfd *, struct bfd_link_info *, asection *,
-   struct ecoff_debug_info *);
-static bfd_boolean mips_elf_check_mips16_stubs
-  (struct mips_elf_link_hash_entry *, void *);
-static void bfd_mips_elf32_swap_gptab_in
-  (bfd *, const Elf32_External_gptab *, Elf32_gptab *);
-static void bfd_mips_elf32_swap_gptab_out
-  (bfd *, const Elf32_gptab *, Elf32_External_gptab *);
-static void bfd_elf32_swap_compact_rel_out
-  (bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *);
-static void bfd_elf32_swap_crinfo_out
-  (bfd *, const Elf32_crinfo *, Elf32_External_crinfo *);
-static int sort_dynamic_relocs
-  (const void *, const void *);
-static int sort_dynamic_relocs_64
-  (const void *, const void *);
-static bfd_boolean mips_elf_output_extsym
-  (struct mips_elf_link_hash_entry *, void *);
-static int gptab_compare
-  (const void *, const void *);
-static asection *mips_elf_rel_dyn_section
-  (bfd *, bfd_boolean);
-static asection *mips_elf_got_section
-  (bfd *, bfd_boolean);
-static struct mips_got_info *mips_elf_got_info
-  (bfd *, asection **);
-static bfd_vma mips_elf_local_got_index
-  (bfd *, bfd *, struct bfd_link_info *, bfd_vma);
-static bfd_vma mips_elf_global_got_index
-  (bfd *, bfd *, struct elf_link_hash_entry *);
-static bfd_vma mips_elf_got_page
-  (bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *);
-static bfd_vma mips_elf_got16_entry
-  (bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean);
-static bfd_vma mips_elf_got_offset_from_index
-  (bfd *, bfd *, bfd *, bfd_vma);
 static struct mips_got_entry *mips_elf_create_local_got_entry
   (bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma);
-static bfd_boolean mips_elf_sort_hash_table
-  (struct bfd_link_info *, unsigned long);
 static bfd_boolean mips_elf_sort_hash_table_f
   (struct mips_elf_link_hash_entry *, void *);
-static bfd_boolean mips_elf_record_local_got_symbol
-  (bfd *, long, bfd_vma, struct mips_got_info *);
-static bfd_boolean mips_elf_record_global_got_symbol
-  (struct elf_link_hash_entry *, bfd *, struct bfd_link_info *,
-   struct mips_got_info *);
-static const Elf_Internal_Rela *mips_elf_next_relocation
-  (bfd *, unsigned int, const Elf_Internal_Rela *, const Elf_Internal_Rela *);
-static bfd_boolean mips_elf_local_relocation_p
-  (bfd *, const Elf_Internal_Rela *, asection **, bfd_boolean);
-static bfd_boolean mips_elf_overflow_p
-  (bfd_vma, int);
 static bfd_vma mips_elf_high
   (bfd_vma);
-static bfd_vma mips_elf_higher
-  (bfd_vma);
-static bfd_vma mips_elf_highest
-  (bfd_vma);
-static bfd_boolean mips_elf_create_compact_rel_section
-  (bfd *, struct bfd_link_info *);
-static bfd_boolean mips_elf_create_got_section
-  (bfd *, struct bfd_link_info *, bfd_boolean);
-static bfd_reloc_status_type mips_elf_calculate_relocation
-  (bfd *, bfd *, asection *, struct bfd_link_info *,
-   const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
-   Elf_Internal_Sym *, asection **, bfd_vma *, const char **,
-   bfd_boolean *, bfd_boolean);
-static bfd_vma mips_elf_obtain_contents
-  (reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *);
-static bfd_boolean mips_elf_perform_relocation
-  (struct bfd_link_info *, reloc_howto_type *, const Elf_Internal_Rela *,
-   bfd_vma, bfd *, asection *, bfd_byte *, bfd_boolean);
 static bfd_boolean mips_elf_stub_section_p
   (bfd *, asection *);
-static void mips_elf_allocate_dynamic_relocations
-  (bfd *, unsigned int);
 static bfd_boolean mips_elf_create_dynamic_relocation
   (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
    struct mips_elf_link_hash_entry *, asection *, bfd_vma,
    bfd_vma *, asection *);
-static void mips_set_isa_flags
-  (bfd *);
-static INLINE char *elf_mips_abi_name
-  (bfd *);
-static void mips_elf_irix6_finish_dynamic_symbol
-  (bfd *, const char *, Elf_Internal_Sym *);
-static bfd_boolean mips_mach_extends_p
-  (unsigned long, unsigned long);
-static bfd_boolean mips_32bit_flags_p
-  (flagword);
-static INLINE hashval_t mips_elf_hash_bfd_vma
-  (bfd_vma);
 static hashval_t mips_elf_got_entry_hash
   (const void *);
-static int mips_elf_got_entry_eq
-  (const void *, const void *);
-
-static bfd_boolean mips_elf_multi_got
-  (bfd *, struct bfd_link_info *, struct mips_got_info *,
-   asection *, bfd_size_type);
-static hashval_t mips_elf_multi_got_entry_hash
-  (const void *);
-static int mips_elf_multi_got_entry_eq
-  (const void *, const void *);
-static hashval_t mips_elf_bfd2got_entry_hash
-  (const void *);
-static int mips_elf_bfd2got_entry_eq
-  (const void *, const void *);
-static int mips_elf_make_got_per_bfd
-  (void **, void *);
-static int mips_elf_merge_gots
-  (void **, void *);
-static int mips_elf_set_global_got_offset
-  (void **, void *);
-static int mips_elf_set_no_stub
-  (void **, void *);
-static int mips_elf_resolve_final_got_entry
-  (void **, void *);
-static void mips_elf_resolve_final_got_entries
-  (struct mips_got_info *);
 static bfd_vma mips_elf_adjust_gp
   (bfd *, struct mips_got_info *, bfd *);
 static struct mips_got_info *mips_elf_got_for_ibfd
@@ -930,7 +818,7 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd,
       ss = bfd_malloc (count);
       if (ss == NULL)
        goto error_return;
-      if (! _bfd_ecoff_get_accumulated_ss (handle, ss))
+      if (! _bfd_ecoff_get_accumulated_ss (handle, (bfd_byte *) ss))
        goto error_return;
 
       count = hdr->ipdMax;
@@ -1061,6 +949,152 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
   return TRUE;
 }
 \f
+/* 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 relocatable object file, R_MIPS16_26 is
+   handled mostly like R_MIPS_26.  In particular, the addend is
+   stored as a straight 26-bit value in a 32-bit instruction.
+   (gas makes life simpler for itself by never adjusting a
+   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 relocatable object file, the calculation is
+   (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
+   When producing a fully linked file, the calculation is
+   let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
+   ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
+
+   R_MIPS16_GPREL is used for GP-relative addressing in mips16
+   mode.  A typical instruction will have a format like this:
+
+   +--------------+--------------------------------+
+   |    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.
+
+   All we need to do here is shuffle the bits appropriately.  As
+   above, the two 16-bit halves must be swapped on a
+   little-endian system.
+
+   R_MIPS16_HI16 and R_MIPS16_LO16 are used in mips16 mode to
+   access data when neither GP-relative nor PC-relative addressing
+   can be used.  They are handled like R_MIPS_HI16 and R_MIPS_LO16,
+   except that the addend is retrieved and stored as shown above
+   for R_MIPS16_GPREL.
+  */
+void
+_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
+                                bfd_boolean jal_shuffle, bfd_byte *data)
+{
+  bfd_vma extend, insn, val;
+
+  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
+      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+    return;
+
+  /* Pick up the mips16 extend instruction and the real instruction.  */
+  extend = bfd_get_16 (abfd, data);
+  insn = bfd_get_16 (abfd, data + 2);
+  if (r_type == R_MIPS16_26)
+    {
+      if (jal_shuffle)
+       val = ((extend & 0xfc00) << 16) | ((extend & 0x3e0) << 11)
+             | ((extend & 0x1f) << 21) | insn;
+      else
+       val = extend << 16 | insn;
+    }
+  else
+    val = ((extend & 0xf800) << 16) | ((insn & 0xffe0) << 11)
+         | ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+  bfd_put_32 (abfd, val, data);
+}
+
+void
+_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
+                              bfd_boolean jal_shuffle, bfd_byte *data)
+{
+  bfd_vma extend, insn, val;
+
+  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
+      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
+    return;
+
+  val = bfd_get_32 (abfd, data);
+  if (r_type == R_MIPS16_26)
+    {
+      if (jal_shuffle)
+       {
+         insn = val & 0xffff;
+         extend = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
+                  | ((val >> 21) & 0x1f);
+       }
+      else
+       {
+         insn = val & 0xffff;
+         extend = val >> 16;
+       }
+    }
+  else
+    {
+      insn = ((val >> 11) & 0xffe0) | (val & 0x1f);
+      extend = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
+    }
+  bfd_put_16 (abfd, insn, data + 2);
+  bfd_put_16 (abfd, extend, data);
+}
+
 bfd_reloc_status_type
 _bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
                               arelent *reloc_entry, asection *input_section,
@@ -1194,11 +1228,17 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                          bfd *output_bfd, char **error_message)
 {
   bfd_vma vallo;
+  bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
 
   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
     return bfd_reloc_outofrange;
 
-  vallo = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+  _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+                                  location);
+  vallo = bfd_get_32 (abfd, location);
+  _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+                                location);
+
   while (mips_hi16_list != NULL)
     {
       bfd_reloc_status_type ret;
@@ -1284,13 +1324,19 @@ _bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
     reloc_entry->addend += val;
   else
     {
+      bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
+
       /* Add in the separate addend, if any.  */
       val += reloc_entry->addend;
 
       /* Add VAL to the relocation field.  */
+      _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+                                      location);
       status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
-                                      (bfd_byte *) data
-                                      + reloc_entry->address);
+                                      location);
+      _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+                                    location);
+
       if (status != bfd_reloc_ok)
        return status;
     }
@@ -1449,8 +1495,10 @@ sort_dynamic_relocs (const void *arg1, const void *arg2)
 /* Like sort_dynamic_relocs, but used for elf64 relocations.  */
 
 static int
-sort_dynamic_relocs_64 (const void *arg1, const void *arg2)
+sort_dynamic_relocs_64 (const void *arg1 ATTRIBUTE_UNUSED,
+                       const void *arg2 ATTRIBUTE_UNUSED)
 {
+#ifdef BFD64
   Elf_Internal_Rela int_reloc1[3];
   Elf_Internal_Rela int_reloc2[3];
 
@@ -1461,6 +1509,9 @@ sort_dynamic_relocs_64 (const void *arg1, const void *arg2)
 
   return (ELF64_R_SYM (int_reloc1[0].r_info)
          - ELF64_R_SYM (int_reloc2[0].r_info));
+#else
+  abort ();
+#endif
 }
 
 
@@ -1491,7 +1542,8 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
   if (h->root.indx == -2)
     strip = FALSE;
   else if ((h->root.def_dynamic
-           || h->root.ref_dynamic)
+           || h->root.ref_dynamic
+           || h->root.type == bfd_link_hash_new)
           && !h->root.def_regular
           && !h->root.ref_regular)
     strip = TRUE;
@@ -3077,7 +3129,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        {
          /* Relocations against _gp_disp are permitted only with
             R_MIPS_HI16 and R_MIPS_LO16 relocations.  */
-         if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16)
+         if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16
+             && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
            return bfd_reloc_notsupported;
 
          gp_disp_p = TRUE;
@@ -3264,10 +3317,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
     case R_MIPS_HI16:
     case R_MIPS_LO16:
-    case R_MIPS16_GPREL:
     case R_MIPS_GPREL16:
     case R_MIPS_GPREL32:
     case R_MIPS_LITERAL:
+    case R_MIPS16_HI16:
+    case R_MIPS16_LO16:
+    case R_MIPS16_GPREL:
       gp0 = _bfd_get_gp_value (input_bfd);
       gp = _bfd_get_gp_value (abfd);
       if (elf_hash_table (info)->dynobj)
@@ -3359,6 +3414,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       break;
 
     case R_MIPS_HI16:
+    case R_MIPS16_HI16:
       if (!gp_disp_p)
        {
          value = mips_elf_high (addend + symbol);
@@ -3366,17 +3422,35 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        }
       else
        {
-         value = mips_elf_high (addend + gp - p);
+         /* For MIPS16 ABI code we generate this sequence
+               0: li      $v0,%hi(_gp_disp)
+               4: addiupc $v1,%lo(_gp_disp)
+               8: sll     $v0,16
+              12: addu    $v0,$v1
+              14: move    $gp,$v0
+            So the offsets of hi and lo relocs are the same, but the
+            $pc is four higher than $t9 would be, so reduce
+            both reloc addends by 4. */
+         if (r_type == R_MIPS16_HI16)
+           value = mips_elf_high (addend + gp - p - 4);
+         else
+           value = mips_elf_high (addend + gp - p);
          overflowed_p = mips_elf_overflow_p (value, 16);
        }
       break;
 
     case R_MIPS_LO16:
+    case R_MIPS16_LO16:
       if (!gp_disp_p)
        value = (symbol + addend) & howto->dst_mask;
       else
        {
-         value = addend + gp - p + 4;
+         /* See the comment for R_MIPS16_HI16 above for the reason
+            for this conditional.  */
+         if (r_type == R_MIPS16_LO16)
+           value = addend + gp - p;
+         else
+           value = addend + gp - p + 4;
          /* The MIPS ABI requires checking the R_MIPS_LO16 relocation
             for overflow.  But, on, say, IRIX5, relocations against
             _gp_disp are normally generated from the .cpload
@@ -3562,13 +3636,6 @@ mips_elf_obtain_contents (reloc_howto_type *howto,
   /* Obtain the bytes.  */
   x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location);
 
-  if ((ELF_R_TYPE (input_bfd, relocation->r_info) == R_MIPS16_26
-       || ELF_R_TYPE (input_bfd, 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;
 }
 
@@ -3596,107 +3663,14 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   /* Figure out where the relocation is occurring.  */
   location = contents + relocation->r_offset;
 
+  _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+
   /* Obtain the current value.  */
   x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
 
   /* Clear the field we are setting.  */
   x &= ~howto->dst_mask;
 
-  /* If this is the R_MIPS16_26 relocation, we must store the
-     value in a funny way.  */
-  if (r_type == 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 relocatable object file, R_MIPS16_26 is
-        handled mostly like R_MIPS_26.  In particular, the addend is
-        stored as a straight 26-bit value in a 32-bit instruction.
-        (gas makes life simpler for itself by never adjusting a
-        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 relocatable object file, the calculation is
-        (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
-        When producing a fully linked file, the calculation is
-        let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
-        ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)  */
-
-      if (!info->relocatable)
-       /* Shuffle the bits according to the formula above.  */
-       value = (((value & 0x1f0000) << 5)
-                | ((value & 0x3e00000) >> 5)
-                | (value & 0xffff));
-    }
-  else if (r_type == R_MIPS16_GPREL)
-    {
-      /* R_MIPS16_GPREL is used for GP-relative addressing in mips16
-        mode.  A typical instruction will have a format like this:
-
-        +--------------+--------------------------------+
-        !    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.
-
-         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));
-    }
-
   /* Set the field.  */
   x |= (value & howto->dst_mask);
 
@@ -3762,14 +3736,12 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
        x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff);   /* bal addr */
     }
 
-  /* Swap the high- and low-order 16 bits on little-endian systems
-     when doing a MIPS16 relocation.  */
-  if ((r_type == R_MIPS16_GPREL || r_type == 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);
+
+  _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
+                               location);
+
   return TRUE;
 }
 
@@ -4248,6 +4220,72 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
     }
 }
 \f
+/* Implement elf_backend_eh_frame_address_size.  This differs from
+   the default in the way it handles EABI64.
+
+   EABI64 was originally specified as an LP64 ABI, and that is what
+   -mabi=eabi normally gives on a 64-bit target.  However, gcc has
+   historically accepted the combination of -mabi=eabi and -mlong32,
+   and this ILP32 variation has become semi-official over time.
+   Both forms use elf32 and have pointer-sized FDE addresses.
+
+   If an EABI object was generated by GCC 4.0 or above, it will have
+   an empty .gcc_compiled_longXX section, where XX is the size of longs
+   in bits.  Unfortunately, ILP32 objects generated by earlier compilers
+   have no special marking to distinguish them from LP64 objects.
+
+   We don't want users of the official LP64 ABI to be punished for the
+   existence of the ILP32 variant, but at the same time, we don't want
+   to mistakenly interpret pre-4.0 ILP32 objects as being LP64 objects.
+   We therefore take the following approach:
+
+      - If ABFD contains a .gcc_compiled_longXX section, use it to
+        determine the pointer size.
+
+      - Otherwise check the type of the first relocation.  Assume that
+        the LP64 ABI is being used if the relocation is of type R_MIPS_64.
+
+      - Otherwise punt.
+
+   The second check is enough to detect LP64 objects generated by pre-4.0
+   compilers because, in the kind of output generated by those compilers,
+   the first relocation will be associated with either a CIE personality
+   routine or an FDE start address.  Furthermore, the compilers never
+   used a special (non-pointer) encoding for this ABI.
+
+   Checking the relocation type should also be safe because there is no
+   reason to use R_MIPS_64 in an ILP32 object.  Pre-4.0 compilers never
+   did so.  */
+
+unsigned int
+_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec)
+{
+  if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+    return 8;
+  if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64)
+    {
+      bfd_boolean long32_p, long64_p;
+
+      long32_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long32") != 0;
+      long64_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long64") != 0;
+      if (long32_p && long64_p)
+       return 0;
+      if (long32_p)
+       return 4;
+      if (long64_p)
+       return 8;
+
+      if (sec->reloc_count > 0
+         && elf_section_data (sec)->relocs != NULL
+         && (ELF32_R_TYPE (elf_section_data (sec)->relocs[0].r_info)
+             == R_MIPS_64))
+       return 8;
+
+      return 0;
+    }
+  return 4;
+}
+\f
 /* There appears to be a bug in the MIPSpro linker that causes GOT_DISP
    relocations against two unnamed section symbols to resolve to the
    same address.  For example, if we have code like:
@@ -6223,18 +6261,25 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            rel_hdr = elf_section_data (input_section)->rel_hdr2;
          if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
            {
+             bfd_byte *location = contents + rel->r_offset;
+
              /* Note that this is a REL relocation.  */
              rela_relocation_p = FALSE;
 
              /* Get the addend, which is stored in the input file.  */
+             _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE,
+                                              location);
              addend = mips_elf_obtain_contents (howto, rel, input_bfd,
                                                 contents);
+             _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, FALSE,
+                                           location);
+
              addend &= howto->src_mask;
 
              /* For some kinds of relocations, the ADDEND is a
                 combination of the addend stored in two different
                 relocations.   */
-             if (r_type == R_MIPS_HI16
+             if (r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16
                  || (r_type == R_MIPS_GOT16
                      && mips_elf_local_relocation_p (input_bfd, rel,
                                                      local_sections, FALSE)))
@@ -6242,6 +6287,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  bfd_vma l;
                  const Elf_Internal_Rela *lo16_relocation;
                  reloc_howto_type *lo16_howto;
+                 bfd_byte *lo16_location;
+                 int lo16_type;
+
+                 if (r_type == R_MIPS16_HI16)
+                   lo16_type = R_MIPS16_LO16;
+                 else
+                   lo16_type = R_MIPS_LO16;
 
                  /* The combined value is the sum of the HI16 addend,
                     left-shifted by sixteen bits, and the LO16
@@ -6260,16 +6312,22 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                     as one of these.  We permit a similar extension
                     in general, as that is useful for GCC.  */
                  lo16_relocation = mips_elf_next_relocation (input_bfd,
-                                                             R_MIPS_LO16,
+                                                             lo16_type,
                                                              rel, relend);
                  if (lo16_relocation == NULL)
                    return FALSE;
 
+                 lo16_location = contents + lo16_relocation->r_offset;
+
                  /* Obtain the addend kept there.  */
                  lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd,
-                                                       R_MIPS_LO16, FALSE);
+                                                       lo16_type, FALSE);
+                 _bfd_mips16_elf_reloc_unshuffle (input_bfd, lo16_type, FALSE,
+                                                  lo16_location);
                  l = mips_elf_obtain_contents (lo16_howto, lo16_relocation,
                                                input_bfd, contents);
+                 _bfd_mips16_elf_reloc_shuffle (input_bfd, lo16_type, FALSE,
+                                                lo16_location);
                  l &= lo16_howto->src_mask;
                  l <<= lo16_howto->rightshift;
                  l = _bfd_mips_elf_sign_extend (l, 16);
@@ -6279,15 +6337,6 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  /* Compute the combined addend.  */
                  addend += l;
                }
-             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 <<= howto->rightshift;
            }
This page took 0.031375 seconds and 4 git commands to generate.