Fix building with --enable-targets=all
[deliverable/binutils-gdb.git] / bfd / elf32-mips.c
index 9ae6e6d33509b582622ce4514facdc93286fb2a9..05c83ac56ae48329b3d038fd12b3620ef30dd607 100644 (file)
@@ -98,6 +98,8 @@ static bfd_reloc_status_type mips32_64bit_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
+static reloc_howto_type *mips_rtype_to_howto
+  PARAMS ((unsigned int));
 static void mips_info_to_howto_rel
   PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
 static void mips_info_to_howto_rela
@@ -106,8 +108,10 @@ static void bfd_mips_elf32_swap_gptab_in
   PARAMS ((bfd *, const Elf32_External_gptab *, Elf32_gptab *));
 static void bfd_mips_elf32_swap_gptab_out
   PARAMS ((bfd *, const Elf32_gptab *, Elf32_External_gptab *));
+#if 0
 static void bfd_mips_elf_swap_msym_in 
   PARAMS ((bfd *, const Elf32_External_Msym *, Elf32_Internal_Msym *));
+#endif
 static void bfd_mips_elf_swap_msym_out
   PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
 static boolean mips_elf_sym_is_global PARAMS ((bfd *, asymbol *));
@@ -122,14 +126,6 @@ static boolean mips_elf_is_local_label_name
 static struct bfd_hash_entry *mips_elf_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static int gptab_compare PARAMS ((const void *, const void *));
-static void mips_elf_relocate_hi16
-  PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *,
-          bfd_vma));
-static boolean mips_elf_relocate_got_local
-  PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *,
-          Elf_Internal_Rela *, bfd_byte *, bfd_vma));
-static void mips_elf_relocate_global_got
-   PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma));
 static bfd_reloc_status_type mips16_jump_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type mips16_gprel_reloc
@@ -163,8 +159,8 @@ static boolean mips_elf_record_global_got_symbol
           struct mips_got_info *));
 static bfd_vma mips_elf_got_page
   PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *));
-static boolean mips_elf_next_lo16_addend
-  PARAMS ((const Elf_Internal_Rela *, const Elf_Internal_Rela *, bfd_vma *));
+static const Elf_Internal_Rela *mips_elf_next_lo16_relocation
+  PARAMS ((const Elf_Internal_Rela *, const Elf_Internal_Rela *));
 static bfd_reloc_status_type mips_elf_calculate_relocation
   PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
           const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
@@ -190,9 +186,10 @@ static bfd_vma mips_elf_create_local_got_entry
   PARAMS ((bfd *, struct mips_got_info *, asection *, bfd_vma));
 static bfd_vma mips_elf_got16_entry 
   PARAMS ((bfd *, struct bfd_link_info *, bfd_vma));
-static unsigned int mips_elf_create_dynamic_relocation 
+static boolean mips_elf_create_dynamic_relocation 
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
-          long, bfd_vma, asection *));
+          struct mips_elf_link_hash_entry *, asection *,
+          bfd_vma, bfd_vma *, asection *));
 static void mips_elf_allocate_dynamic_relocations 
   PARAMS ((bfd *, unsigned int));
 static boolean mips_elf_stub_section_p 
@@ -600,7 +597,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         _bfd_mips_elf_got16_reloc,     /* special_function */
         "R_MIPS_GOT16",        /* name */
         false,                 /* partial_inplace */
-        0,                     /* src_mask */
+        0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -630,7 +627,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_CALL16",       /* name */
         false,                 /* partial_inplace */
-        0,                     /* src_mask */
+        0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -1890,35 +1887,44 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
 
 /* Given a MIPS Elf32_Internal_Rel, fill in an arelent structure.  */
 
-static void
-mips_info_to_howto_rel (abfd, cache_ptr, dst)
-     bfd *abfd;
-     arelent *cache_ptr;
-     Elf32_Internal_Rel *dst;
+static reloc_howto_type *
+mips_rtype_to_howto (r_type)
+     unsigned int r_type;
 {
-  unsigned int r_type;
-
-  r_type = ELF32_R_TYPE (dst->r_info);
   switch (r_type)
     {
     case R_MIPS16_26:
-      cache_ptr->howto = &elf_mips16_jump_howto;
+      return &elf_mips16_jump_howto;
       break;
     case R_MIPS16_GPREL:
-      cache_ptr->howto = &elf_mips16_gprel_howto;
+      return &elf_mips16_gprel_howto;
       break;
     case R_MIPS_GNU_VTINHERIT:
-      cache_ptr->howto = &elf_mips_gnu_vtinherit_howto;
+      return &elf_mips_gnu_vtinherit_howto;
       break;
     case R_MIPS_GNU_VTENTRY:
-      cache_ptr->howto = &elf_mips_gnu_vtentry_howto;
+      return &elf_mips_gnu_vtentry_howto;
       break;
 
     default:
       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
-      cache_ptr->howto = &elf_mips_howto_table[r_type];
+      return &elf_mips_howto_table[r_type];
       break;
     }
+}
+
+/* Given a MIPS Elf32_Internal_Rel, fill in an arelent structure.  */
+
+static void
+mips_info_to_howto_rel (abfd, cache_ptr, dst)
+     bfd *abfd;
+     arelent *cache_ptr;
+     Elf32_Internal_Rel *dst;
+{
+  unsigned int r_type;
+
+  r_type = ELF32_R_TYPE (dst->r_info);
+  cache_ptr->howto = mips_rtype_to_howto (r_type);
 
   /* The addend for a GPREL16 or LITERAL relocation comes from the GP
      value for the object file.  We get the addend now, rather than
@@ -2111,7 +2117,7 @@ bfd_mips_elf_swap_options_out (abfd, in, ex)
   bfd_h_put_16 (abfd, in->section, ex->section);
   bfd_h_put_32 (abfd, in->info, ex->info);
 }
-
+#if 0
 /* Swap in an MSYM entry.  */
 
 static void
@@ -2123,7 +2129,7 @@ bfd_mips_elf_swap_msym_in (abfd, ex, in)
   in->ms_hash_value = bfd_h_get_32 (abfd, ex->ms_hash_value);
   in->ms_info = bfd_h_get_32 (abfd, ex->ms_info);
 }
-
+#endif
 /* Swap out an MSYM entry.  */
 
 static void
@@ -3865,7 +3871,7 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
          mips_elf_text_section.symbol = &mips_elf_text_symbol;
          mips_elf_text_section.symbol_ptr_ptr = &mips_elf_text_symbol_ptr;
          mips_elf_text_symbol.name = ".text";
-         mips_elf_text_symbol.flags = BSF_SECTION_SYM;
+         mips_elf_text_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
          mips_elf_text_symbol.section = &mips_elf_text_section;
          mips_elf_text_symbol_ptr = &mips_elf_text_symbol;
          mips_elf_text_section_ptr = &mips_elf_text_section;
@@ -3889,7 +3895,7 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
          mips_elf_data_section.symbol = &mips_elf_data_symbol;
          mips_elf_data_section.symbol_ptr_ptr = &mips_elf_data_symbol_ptr;
          mips_elf_data_symbol.name = ".data";
-         mips_elf_data_symbol.flags = BSF_SECTION_SYM;
+         mips_elf_data_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
          mips_elf_data_symbol.section = &mips_elf_data_section;
          mips_elf_data_symbol_ptr = &mips_elf_data_symbol;
          mips_elf_data_section_ptr = &mips_elf_data_section;
@@ -4330,7 +4336,7 @@ _bfd_mips_elf_final_link (abfd, info)
      generic size_dynamic_sections renumbered them out from under us.
      Rather than trying somehow to prevent the renumbering, just do
      the sort again.  */
-  if (elf_hash_table (info)->dynobj)
+  if (elf_hash_table (info)->dynamic_sections_created)
     {
       bfd *dynobj;
       asection *got;
@@ -4352,9 +4358,10 @@ _bfd_mips_elf_final_link (abfd, info)
       got = bfd_get_section_by_name (dynobj, ".got");
       g = (struct mips_got_info *) elf_section_data (got)->tdata;
 
-      BFD_ASSERT ((elf_hash_table (info)->dynsymcount
-                  - g->global_gotsym->dynindx)
-                 <= g->global_gotno);
+      if (g->global_gotsym != NULL)
+       BFD_ASSERT ((elf_hash_table (info)->dynsymcount
+                    - g->global_gotsym->dynindx)
+                   <= g->global_gotno);
     }
 
   /* On IRIX5, we omit the .options section.  On IRIX6, however, we
@@ -5002,124 +5009,6 @@ _bfd_mips_elf_final_link (abfd, info)
   return true;
 }
 
-/* Handle a MIPS ELF HI16 reloc.  */
-
-static void
-mips_elf_relocate_hi16 (input_bfd, relhi, rello, contents, addend)
-     bfd *input_bfd;
-     Elf_Internal_Rela *relhi;
-     Elf_Internal_Rela *rello;
-     bfd_byte *contents;
-     bfd_vma addend;
-{
-  bfd_vma insn;
-  bfd_vma addlo;
-
-  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
-
-  addlo = bfd_get_32 (input_bfd, contents + rello->r_offset);
-  addlo &= 0xffff;
-
-  addend += ((insn & 0xffff) << 16) + addlo;
-
-  if ((addlo & 0x8000) != 0)
-    addend -= 0x10000;
-  if ((addend & 0x8000) != 0)
-    addend += 0x10000;
-
-  bfd_put_32 (input_bfd,
-             (insn & 0xffff0000) | ((addend >> 16) & 0xffff),
-             contents + relhi->r_offset);
-}
-
-/* Handle a MIPS ELF local GOT16 reloc.  */
-
-static boolean
-mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
-                            contents, addend)
-     bfd *output_bfd;
-     bfd *input_bfd;
-     asection *sgot;
-     Elf_Internal_Rela *relhi;
-     Elf_Internal_Rela *rello;
-     bfd_byte *contents;
-     bfd_vma addend;
-{
-  unsigned int assigned_gotno;
-  unsigned int i;
-  bfd_vma insn;
-  bfd_vma addlo;
-  bfd_vma address;
-  bfd_vma hipage;
-  bfd_byte *got_contents;
-  struct mips_got_info *g;
-
-  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
-
-  addlo = bfd_get_32 (input_bfd, contents + rello->r_offset);
-  addlo &= 0xffff;
-
-  addend += ((insn & 0xffff) << 16) + addlo;
-
-  if ((addlo & 0x8000) != 0)
-    addend -= 0x10000;
-  if ((addend & 0x8000) != 0)
-    addend += 0x10000;
-
-  /* Get a got entry representing requested hipage.  */
-  BFD_ASSERT (elf_section_data (sgot) != NULL);
-  g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
-  BFD_ASSERT (g != NULL);
-
-  assigned_gotno = g->assigned_gotno;
-  got_contents = sgot->contents;
-  hipage = addend & 0xffff0000;
-
-  for (i = MIPS_RESERVED_GOTNO; i < assigned_gotno; i++)
-    {
-      address = bfd_get_32 (input_bfd, got_contents + i * 4);
-      if (hipage == (address & 0xffff0000))
-       break;
-    }
-
-  if (i == assigned_gotno)
-    {
-      if (assigned_gotno >= g->local_gotno)
-       {
-         (*_bfd_error_handler)
-           (_("more got entries are needed for hipage relocations"));
-         bfd_set_error (bfd_error_bad_value);
-         return false;
-       }
-
-      bfd_put_32 (input_bfd, hipage, got_contents + assigned_gotno * 4);
-      ++g->assigned_gotno;
-    }
-
-  i = - ELF_MIPS_GP_OFFSET (output_bfd) + i * 4;
-  bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff),
-             contents + relhi->r_offset);
-
-  return true;
-}
-
-/* Handle MIPS ELF CALL16 reloc and global GOT16 reloc.  */
-
-static void
-mips_elf_relocate_global_got (input_bfd, rel, contents, offset)
-     bfd *input_bfd;
-     Elf_Internal_Rela *rel;
-     bfd_byte *contents;
-     bfd_vma offset;
-{
-  bfd_vma insn;
-
-  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
-  bfd_put_32 (input_bfd,
-             (insn & 0xffff0000) | (offset & 0xffff),
-             contents + rel->r_offset);
-}
-
 /* Returns the GOT section for ABFD.  */
 
 static asection *
@@ -5182,7 +5071,7 @@ mips_elf_sign_extend (value, bits)
      bfd_vma value;
      int bits;
 {
-  if (value & (1 << (bits - 1)))
+  if (value & ((bfd_vma)1 << (bits - 1)))
     /* VALUE is negative.  */
     value |= ((bfd_vma) - 1) << bits;      
   
@@ -5241,7 +5130,7 @@ mips_elf_highest (value)
      bfd_vma value ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
-  return ((value + (bfd_vma) 0x800080008000) > 48) & 0xffff;
+  return ((value + (bfd_vma) 0x800080008000) >> 48) & 0xffff;
 #else
   abort ();
   return (bfd_vma) -1;
@@ -5473,7 +5362,7 @@ mips_elf_got_page (abfd, info, value, offsetp)
   struct mips_got_info *g;
   bfd_byte *entry;
   bfd_byte *last_entry;
-  bfd_vma index;
+  bfd_vma index = 0;
   bfd_vma address;
 
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
@@ -5522,10 +5411,14 @@ mips_elf_got16_entry (abfd, info, value)
   struct mips_got_info *g;
   bfd_byte *entry;
   bfd_byte *last_entry;
-  bfd_vma index;
+  bfd_vma index = 0;
   bfd_vma address;
 
-  value &= 0xffff0000;
+  /* Although the ABI says that it is "the high-order 16 bits" that we
+     want, it is really the %high value.  The complete value is
+     calculated with a `addiu' of a LO16 relocation, just as with a
+     HI16/LO16 pair.  */
+  value = mips_elf_high (value) << 16;
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
   /* Look to see if we already have an appropriate entry.  */
@@ -5539,7 +5432,7 @@ mips_elf_got16_entry (abfd, info, value)
       if ((address & 0xffff0000) == value)
        {
          /* This entry has the right high-order 16 bits.  */
-         index = MIPS_ELF_GOT_SIZE (abfd) * (entry - sgot->contents);
+         index = entry - sgot->contents;
          break;
        }
     }
@@ -5551,15 +5444,13 @@ mips_elf_got16_entry (abfd, info, value)
   return index;
 }
 
-/* Sets *ADDENDP to the addend for the first R_MIPS_LO16 relocation
-   found, beginning with RELOCATION.  RELEND is one-past-the-end of
-   the relocation table.  */
+/* Returns the first R_MIPS_LO16 relocation found, beginning with
+   RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
 
-static boolean
-mips_elf_next_lo16_addend (relocation, relend, addendp)
+static const Elf_Internal_Rela *
+mips_elf_next_lo16_relocation (relocation, relend)
      const Elf_Internal_Rela *relocation;
      const Elf_Internal_Rela *relend;
-     bfd_vma *addendp;
 {
   /* According to the MIPS ELF ABI, the R_MIPS_LO16 relocation must be
      immediately following.  However, for the IRIX6 ABI, the next
@@ -5570,32 +5461,31 @@ mips_elf_next_lo16_addend (relocation, relend, addendp)
   while (relocation < relend)
     {
       if (ELF32_R_TYPE (relocation->r_info) == R_MIPS_LO16)
-       {
-         *addendp = relocation->r_addend;
-         return true;
-       }
+       return relocation;
 
       ++relocation;
     }
 
   /* We didn't find it.  */
   bfd_set_error (bfd_error_bad_value);
-  return false;
+  return NULL;
 }
 
-/* Create a rel.dyn relocation for the dynamic linker to resolve.  The
-   relocatin is against the symbol with the dynamic symbol table index
-   DYNINDX.  REL is the original relocation, which is now being made
-   dynamic.  */
+/* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
+   is the original relocation, which is now being transformed into a
+   dyanmic relocation.  The ADDENDP is adjusted if necessary; the
+   caller should store the result in place of the original addend.  */
 
-static unsigned int
-mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
-                                   addend, input_section)
+static boolean
+mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
+                                   symbol, addendp, input_section)
      bfd *output_bfd;
      struct bfd_link_info *info;
      const Elf_Internal_Rela *rel;
-     long dynindx;
-     bfd_vma addend;
+     struct mips_elf_link_hash_entry *h;
+     asection *sec;
+     bfd_vma symbol;
+     bfd_vma *addendp;
      asection *input_section;
 {
   Elf_Internal_Rel outrel;
@@ -5613,36 +5503,94 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
 
   skip = false;
 
-  /* The symbol for the relocation is the same as it was for the
-     original relocation.  */
-  outrel.r_info = ELF32_R_INFO (dynindx, R_MIPS_REL32);
-
-  /* The offset for the dynamic relocation is the same as for the
-     original relocation, adjusted by the offset at which the original
-     section is output.  */
+  /* 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
     {
-      bfd_vma off;
-
-      off = (_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 (off == (bfd_vma) -1)
+      /* 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 = off;
     }
-  outrel.r_offset += (input_section->output_section->vma
-                     + input_section->output_offset);
 
   /* If we've decided to skip this relocation, just output an emtpy
-     record.  */
+     record.  Note that R_MIPS_NONE == 0, so that this call to memset
+     is a way of setting R_TYPE to R_MIPS_NONE.  */
   if (skip)
     memset (&outrel, 0, sizeof (outrel));
+  else
+    {
+      long indx;
+      bfd_vma section_offset;
 
+      /* We must now calculate the dynamic symbol table index to use
+        in the relocation.  */
+      if (h != NULL
+         && (! info->symbolic || (h->root.elf_link_hash_flags
+                                  & ELF_LINK_HASH_DEF_REGULAR) == 0))
+       {
+         indx = h->root.dynindx;
+         BFD_ASSERT (indx != -1);
+       }
+      else
+       {
+         if (sec != NULL && bfd_is_abs_section (sec))
+           indx = 0;
+         else if (sec == NULL || sec->owner == NULL)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+         else
+           {
+             indx = elf_section_data (sec->output_section)->dynindx;
+             if (indx == 0)
+               abort ();
+           }
+
+         /* Figure out how far the target of the relocation is from
+            the beginning of its section.  */
+         section_offset = symbol - sec->output_section->vma;
+         /* The relocation we're building is section-relative.
+            Therefore, the original addend must be adjusted by the
+            section offset.  */
+         *addendp += symbol - sec->output_section->vma;
+         /* Now, the relocation is just against the section.  */
+         symbol = sec->output_section->vma;
+       }
+      
+      /* If the relocation was previously an absolute relocation, we
+        must adjust it by the value we give it in the dynamic symbol
+        table.  */
+      if (r_type != R_MIPS_REL32)
+       *addendp += symbol;
+
+      /* The relocation is always an REL32 relocation because we don't
+        know where the shared library will wind up at load-time.  */
+      outrel.r_info = ELF32_R_INFO (indx, R_MIPS_REL32);
+
+      /* Adjust the output offset of the relocation to reference the
+        correct location in the output file.  */
+      outrel.r_offset += (input_section->output_section->vma
+                         + input_section->output_offset);
+    }
+
+  /* Put the relocation back out.  We have to use the special
+     relocation outputter in the 64-bit case since the 64-bit
+     relocation format is non-standard.  */
   if (ABI_64_P (output_bfd))
     {
       (*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
@@ -5655,6 +5603,15 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
                              (((Elf32_External_Rel *)
                                sreloc->contents)
                               + sreloc->reloc_count));
+
+  /* Record the index of the first relocation referencing H.  This
+     information is later emitted in the .msym section.  */
+  if (h != NULL
+      && (h->min_dyn_reloc_index == 0 
+         || sreloc->reloc_count < h->min_dyn_reloc_index))
+    h->min_dyn_reloc_index = sreloc->reloc_count;
+
+  /* We've now added another relocation.  */
   ++sreloc->reloc_count;
 
   /* Make sure the output section is writable.  The dynamic linker
@@ -5681,7 +5638,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
          else
            mips_elf_set_cr_type (cptrel, CRT_MIPS_WORD);
          mips_elf_set_cr_dist2to (cptrel, 0);
-         cptrel.konst = addend;
+         cptrel.konst = *addendp;
 
          cr = (scpt->contents
                + sizeof (Elf32_External_compact_rel));
@@ -5692,7 +5649,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
        }
     }
 
-  return sreloc->reloc_count - 1;
+  return true;
 }
 
 /* Calculate the value produced by the RELOCATION (which comes from
@@ -5859,12 +5816,33 @@ mips_elf_calculate_relocation (abfd,
          else
            symbol = h->root.root.u.def.value;
        }
+      else if (h->root.root.type == bfd_link_hash_undefweak)
+       /* We allow relocations against undefined weak symbols, giving
+          it the value zero, so that you can undefined weak functions
+          and check to see if they exist by looking at their
+          addresses.  */
+       symbol = 0;
+      else if (info->shared && !info->symbolic && !info->no_undefined)
+       symbol = 0;
+      else if (strcmp (h->root.root.root.string, "_DYNAMIC_LINK") == 0)
+       {
+         /* If this is a dynamic link, we should have created a
+            _DYNAMIC_LINK symbol in mips_elf_create_dynamic_sections.
+            Otherwise, we should define the symbol with a value of 0.
+            FIXME: It should probably get into the symbol table
+            somehow as well.  */
+         BFD_ASSERT (! info->shared);
+         BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL);
+         symbol = 0;
+       }
       else
        {
-         (*info->callbacks->undefined_symbol)
-           (info, h->root.root.root.string, input_bfd,
-            input_section, relocation->r_offset);
-         return bfd_reloc_undefined;
+         if (! ((*info->callbacks->undefined_symbol)
+                (info, h->root.root.root.string, input_bfd,
+                 input_section, relocation->r_offset,
+                 (!info->shared || info->no_undefined))))
+           return bfd_reloc_undefined;
+         symbol = 0;
        }
 
       target_is_16_bit_code_p = (h->root.other == STO_MIPS16);
@@ -5938,19 +5916,24 @@ mips_elf_calculate_relocation (abfd,
   switch (r_type)
     {
     case R_MIPS_CALL16:
+    case R_MIPS_GOT16:
     case R_MIPS_GOT_DISP:
     case R_MIPS_GOT_HI16:
     case R_MIPS_CALL_HI16:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
       /* Find the index into the GOT where this value is located.  */
-      if (h)
+      if (!local_p)
        {
          BFD_ASSERT (addend == 0);
          g = mips_elf_global_got_index 
            (elf_hash_table (info)->dynobj,
             (struct elf_link_hash_entry*) h);
        }
+      else if (r_type == R_MIPS_GOT16)
+       /* There's no need to create a local GOT entry here; the
+          calculation for a local GOT16 entry does not involve G.  */
+       break;
       else
        {
          g = mips_elf_local_got_index (abfd, info, symbol + addend);
@@ -5967,6 +5950,7 @@ mips_elf_calculate_relocation (abfd,
     case R_MIPS_LO16:
     case R_MIPS_GPREL16:
     case R_MIPS_GPREL32:
+    case R_MIPS_LITERAL:
       gp0 = _bfd_get_gp_value (input_bfd);
       gp = _bfd_get_gp_value (abfd);
       break;
@@ -5989,27 +5973,28 @@ mips_elf_calculate_relocation (abfd,
     case R_MIPS_32:
     case R_MIPS_REL32:
     case R_MIPS_64:
-      /* If we're creating a shared library, or this relocation is
-        against a symbol in a shared library, then we can't know
-        where the symbol will end up.  So, we create a relocation
-        record in the output, and leave the job up to the dynamic
-        linker.  */
-      if (info->shared || !sec->output_section)
+      if ((info->shared
+          || (elf_hash_table (info)->dynamic_sections_created
+              && h != NULL
+              && ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+                  == 0)))
+         && (input_section->flags & SEC_ALLOC) != 0)
        {
-         unsigned int reloc_index;
-
-         BFD_ASSERT (h != NULL);
-         reloc_index 
-           = mips_elf_create_dynamic_relocation (abfd, 
-                                                 info, 
-                                                 relocation,
-                                                 h->root.dynindx,
-                                                 addend,
-                                                 input_section);
-         if (h->min_dyn_reloc_index == 0
-             || reloc_index < h->min_dyn_reloc_index)
-           h->min_dyn_reloc_index = reloc_index;
-         value = symbol + addend;
+         /* If we're creating a shared library, or this relocation is
+            against a symbol in a shared library, then we can't know
+            where the symbol will end up.  So, we create a relocation
+            record in the output, and leave the job up to the dynamic
+            linker.  */
+         value = addend;
+         if (!mips_elf_create_dynamic_relocation (abfd, 
+                                                  info, 
+                                                  relocation,
+                                                  h,
+                                                  sec,
+                                                  symbol,
+                                                  &value,
+                                                  input_section))
+           return false;
        }
       else
        {
@@ -6122,6 +6107,7 @@ mips_elf_calculate_relocation (abfd,
 
     case R_MIPS_PC16:
       value = mips_elf_sign_extend (addend, 16) + symbol - p;
+      value = (bfd_vma) ((bfd_signed_vma) value / 4);
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -6431,10 +6417,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 {
   Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *relend;
-  bfd_vma addend;
-  bfd_vma last_hi16_addend;
+  bfd_vma addend = 0;
   boolean use_saved_addend_p = false;
-  boolean last_hi16_addend_valid_p = false;
   struct elf_backend_data *bed;
 
   bed = get_elf_backend_data (output_bfd);
@@ -6452,15 +6436,22 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
       /* Find the relocation howto for this relocation.  */
       if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
-       /* Some 32-bit code uses R_MIPS_64.  In particular, people use
-          64-bit code, but make sure all their addresses are in the 
-          lowermost or uppermost 32-bit section of the 64-bit address
-          space.  Thus, when they use an R_MIPS_64 they mean what is
-          usually meant by R_MIPS_32, with the exception that the
-          stored value is sign-extended to 64 bits.  */
-       howto = elf_mips_howto_table + R_MIPS_32;
+       {
+         /* Some 32-bit code uses R_MIPS_64.  In particular, people use
+            64-bit code, but make sure all their addresses are in the 
+            lowermost or uppermost 32-bit section of the 64-bit address
+            space.  Thus, when they use an R_MIPS_64 they mean what is
+            usually meant by R_MIPS_32, with the exception that the
+            stored value is sign-extended to 64 bits.  */
+         howto = elf_mips_howto_table + R_MIPS_32;
+
+         /* On big-endian systems, we need to lie about the position
+            of the reloc.  */
+         if (bfd_big_endian (input_bfd))
+             rel->r_offset += 4;
+       }
       else
-       howto = elf_mips_howto_table + r_type;
+       howto = mips_rtype_to_howto (r_type);
 
       if (!use_saved_addend_p)
        {
@@ -6497,32 +6488,35 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      && mips_elf_local_relocation_p (input_bfd, rel,
                                                      local_sections)))
                {
-                 /* Scan ahead to find a matching R_MIPS_LO16
-                    relocation.  */
                  bfd_vma l;
-                 
-                 if (!mips_elf_next_lo16_addend (rel, relend, &l))
+                 const Elf_Internal_Rela *lo16_relocation;
+                 reloc_howto_type *lo16_howto;
+
+                 /* The combined value is the sum of the HI16 addend,
+                    left-shifted by sixteen bits, and the LO16
+                    addend, sign extended.  (Usually, the code does
+                    a `lui' of the HI16 value, and then an `addiu' of
+                    the LO16 value.)  
+
+                    Scan ahead to find a matching R_MIPS_LO16
+                    relocation.  */
+                 lo16_relocation 
+                   = mips_elf_next_lo16_relocation (rel, relend); 
+                 if (lo16_relocation == NULL)
                    return false;
 
-                 /* Save the high-order bit for later.  When we
-                    encounter the R_MIPS_LO16 relocation we will need
-                    them again.  */
+                 /* Obtain the addend kept there.  */
+                 lo16_howto = mips_rtype_to_howto (R_MIPS_LO16);
+                 l = mips_elf_obtain_contents (lo16_howto,
+                                               lo16_relocation,
+                                               input_bfd, contents);
+                 l &= lo16_howto->src_mask;
+                 l = mips_elf_sign_extend (l, 16);
+
                  addend <<= 16;
-                 last_hi16_addend = addend;
-                 last_hi16_addend_valid_p = true;
 
                  /* Compute the combined addend.  */
-                 addend |= l;
-               }
-             else if (r_type == R_MIPS_LO16) 
-               {
-                 /* Used the saved HI16 addend.  */
-                 if (!last_hi16_addend_valid_p)
-                   {
-                     bfd_set_error (bfd_error_bad_value);
-                     return false;
-                   }
-                 addend |= last_hi16_addend;
+                 addend += l;
                }
              else if (r_type == R_MIPS16_GPREL)
                {
@@ -6551,28 +6545,38 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             that we're adjusting GP in this relocateable object.  */
 
          if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections))
-           /* A non-local relocation is never against a section.  */
+           /* There's nothing to do for non-local relocations.  */
            continue;
 
+         if (r_type == R_MIPS16_GPREL 
+             || r_type == R_MIPS_GPREL16
+             || r_type == R_MIPS_GPREL32
+             || r_type == R_MIPS_LITERAL)
+           addend -= (_bfd_get_gp_value (output_bfd)
+                      - _bfd_get_gp_value (input_bfd));
+         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26)
+           /* The addend is stored without its two least
+              significant bits (which are always zero.)  In a
+              non-relocateable link, calculate_relocation will do
+              this shift; here, we must do it ourselves.  */
+           addend <<= 2;
+
          r_symndx = ELF32_R_SYM (rel->r_info);
          sym = local_syms + r_symndx;
          if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-           {
-             /* Adjust the addend appropriately.  */
-             addend += local_sections[r_symndx]->output_offset;
-
-             /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
+           /* Adjust the addend appropriately.  */
+           addend += local_sections[r_symndx]->output_offset;
+         
+         /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
             then we only want to write out the high-order 16 bits.
             The subsequent R_MIPS_LO16 will handle the low-order bits.  */
-             if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
-               addend >>= 16;
-           }
-         
-         if (r_type == R_MIPS16_GPREL 
-             || r_type == R_MIPS_GPREL16
-             || r_type == R_MIPS_GPREL32)
-           addend -= (_bfd_get_gp_value (output_bfd)
-                      - _bfd_get_gp_value (input_bfd));
+         if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
+           addend = mips_elf_high (addend);
+         /* If the relocation is for an R_MIPS_26 relocation, then
+            the two low-order bits are not stored in the object file;
+            they are implicitly zero.  */
+         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26)
+           addend >>= 2;
 
          if (rela_relocation_p)
            /* If this is a RELA relocation, just update the addend.
@@ -6602,7 +6606,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
         for the next.  */
       if (rel + 1 < relend 
          && rel->r_offset == rel[1].r_offset
-         && r_type != R_MIPS_NONE)
+         && ELF32_R_TYPE (rel[1].r_info) != R_MIPS_NONE)
        use_saved_addend_p = true;
       else
        use_saved_addend_p = false;
@@ -6627,8 +6631,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
        case bfd_reloc_undefined:
          /* mips_elf_calculate_relocation already called the
-             undefined_symbol callback.  */
-         break;
+             undefined_symbol callback.  There's no real point in
+            trying to perform the relocation at this point, so we
+            just skip ahead to the next relocation.  */
+         continue;
 
        case bfd_reloc_notsupported:
          abort ();
@@ -6674,15 +6680,6 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
           go to extreme lengths to support this usage on systems with
           only a 32-bit VMA.  */
        {
-#ifdef BFD64
-         /* Just sign-extend the value, and then fall through to the
-            normal case, using the R_MIPS_64 howto.  That will store
-            the 64-bit value into a 64-bit area.  */
-         value = mips_elf_sign_extend (value, 64);
-         howto = elf_mips_howto_table + R_MIPS_64;
-#else /* !BFD64 */
-         /* In the 32-bit VMA case, we must handle sign-extension and
-            endianness manually.  */
          bfd_vma sign_bits;
          bfd_vma low_bits;
          bfd_vma high_bits;
@@ -6696,6 +6693,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             stores.  */
          if (bfd_big_endian (input_bfd))
            {
+             /* Undo what we did above.  */
+             rel->r_offset -= 4;
              /* Store the sign-bits (which are most significant)
                 first.  */
              low_bits = sign_bits;
@@ -6711,7 +6710,6 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          bfd_put_32 (input_bfd, high_bits, 
                      contents + rel->r_offset + 4);
          continue;
-#endif /* !BFD64 */
        }
 
       /* Actually perform the relocation.  */
@@ -7324,11 +7322,12 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
                 || r_type == R_MIPS_GOT_DISP))
        {
          /* We may need a local GOT entry for this relocation.  We
-            don't count R_MIPS_HI16 or R_MIPS_GOT16 relocations
-            because they are always followed by a R_MIPS_LO16
-            relocation for the value.  We don't R_MIPS_GOT_PAGE
-            because we can estimate the maximum number of pages
-            needed by looking at the size of the segment.
+            don't count R_MIPS_GOT_PAGE because we can estimate the
+            maximum number of pages needed by looking at the size of
+            the segment.  Similar comments apply to R_MIPS_GOT16.  We
+            don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because
+            these are always followed by an R_MIPS_GOT_LO16 or
+            R_MIPS_CALL_LO16.
 
             This estimation is very conservative since we can merge
             duplicate entries in the GOT.  In order to be less
@@ -7353,16 +7352,18 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
 
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_LO16:
-         /* This symbol requires a global offset table entry.  */
-         if (!mips_elf_record_global_got_symbol (h, info, g))
-           return false;
-
-         /* We need a stub, not a plt entry for the undefined
-            function.  But we record it as if it needs plt.  See
-            elf_adjust_dynamic_symbol in elflink.h.  */
-         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-         h->type = STT_FUNC;
+         if (h != NULL)
+           {
+             /* This symbol requires a global offset table entry.  */
+             if (!mips_elf_record_global_got_symbol (h, info, g))
+               return false;
 
+             /* We need a stub, not a plt entry for the undefined
+                function.  But we record it as if it needs plt.  See
+                elf_adjust_dynamic_symbol in elflink.h.  */
+             h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+             h->type = STT_FUNC;
+           }
          break;
 
        case R_MIPS_GOT16:
@@ -7419,9 +7420,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
             
              /* Even though we don't directly need a GOT entry for
                 this symbol, a symbol must have a dynamic symbol
-                table index greater that DT_GOTSYM if there are
+                table index greater that DT_MIPS_GOTSYM if there are
                 dynamic relocations against it.  */
-             if (!mips_elf_record_global_got_symbol (h, info, g))
+             if (h != NULL
+                 && !mips_elf_record_global_got_symbol (h, info, g))
                return false;
            }
 
@@ -7754,7 +7756,7 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
   bfd *dynobj;
   asection *s;
   boolean reltext;
-  struct mips_got_info *g;
+  struct mips_got_info *g = NULL;
 
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -7864,8 +7866,14 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
          loadable_size += MIPS_FUNCTION_STUB_SIZE;
 
          /* Assume there are two loadable segments consisting of
-            contiguous sections.  Is 5 enough? */
+            contiguous sections.  Is 5 enough?  */
          local_gotno = (loadable_size >> 16) + 5;
+         if (IRIX_COMPAT (output_bfd) == ict_irix6)
+           /* It's possible we will need GOT_PAGE entries as well as
+              GOT16 entries.  Often, these will be able to share GOT
+              entries, but not always.  */
+           local_gotno *= 2;
+
          g->local_gotno += local_gotno;
          s->_raw_size += local_gotno * MIPS_ELF_GOT_SIZE (dynobj);
 
@@ -7877,7 +7885,12 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
          if (!mips_elf_sort_hash_table (info, 1))
            return false;
 
-         i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
+         if (g->global_gotsym != NULL)
+           i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
+         else
+           /* If there are no global symbols, or none requiring
+              relocations, then GLOBAL_GOTSYM will be NULL.  */
+           i = 0;
          g->global_gotno = i;
          s->_raw_size += i * MIPS_ELF_GOT_SIZE (dynobj);
        }
@@ -7911,7 +7924,7 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
 
       if (strip)
        {
-         _bfd_strip_section_from_output (s);
+         _bfd_strip_section_from_output (info, s);
          continue;
        }
 
@@ -8167,7 +8180,8 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   /* Run through the global symbol table, creating GOT entries for all
      the symbols that need them.  */
-  if (h->dynindx >= g->global_gotsym->dynindx)
+  if (g->global_gotsym != NULL
+      && h->dynindx >= g->global_gotsym->dynindx)
     {
       bfd_vma offset;
       bfd_vma value;
@@ -8413,6 +8427,23 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
              dyn.d_un.d_val = g->local_gotno;
              break;
 
+           case DT_MIPS_UNREFEXTNO:
+             /* The index into the dynamic symbol table which is the
+                entry of the first external symbol that is not
+                referenced within the same object.  */
+             dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
+             break;
+
+           case DT_MIPS_GOTSYM:
+             if (g->global_gotsym)
+               {
+                 dyn.d_un.d_val = g->global_gotsym->dynindx;
+                 break;
+               }
+             /* In case if we don't have global got symbols we default
+                to setting DT_MIPS_GOTSYM to the same value as
+                DT_MIPS_SYMTABNO, so we just fall through.  */
+
            case DT_MIPS_SYMTABNO:
              name = ".dynsym";
              elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
@@ -8425,17 +8456,6 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
                dyn.d_un.d_val = s->_raw_size / elemsize;
              break;
 
-           case DT_MIPS_UNREFEXTNO:
-             /* The index into the dynamic symbol table which is the
-                entry of the first external symbol that is not
-                referenced within the same object.  */
-             dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
-             break;
-
-           case DT_MIPS_GOTSYM:
-             dyn.d_un.d_val = g->global_gotsym->dynindx;
-             break;
-
            case DT_MIPS_HIPAGENO:
              dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO;
              break;
@@ -8699,7 +8719,8 @@ elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data,
                case bfd_reloc_undefined:
                  if (!((*link_info->callbacks->undefined_symbol)
                        (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        input_bfd, input_section, (*parent)->address)))
+                        input_bfd, input_section, (*parent)->address,
+                        true)))
                    goto error_return;
                  break;
                case bfd_reloc_dangerous:
@@ -8794,6 +8815,7 @@ 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
This page took 0.047474 seconds and 4 git commands to generate.