* elf64-mips.c: Improve reloc special_functions and handling of
authorIan Lance Taylor <ian@airs.com>
Fri, 31 May 1996 21:43:35 +0000 (21:43 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 31 May 1996 21:43:35 +0000 (21:43 +0000)
SHT_MIPS_OPTIONS section.
* elf32-mips.c (_bfd_mips_elf_hi16_reloc): Rename from
mips_elf_hi16_reloc and make globally visible.
(_bfd_mips_elf_lo16_reloc): Rename from mips_elf_lo16_reloc and
make globally visible.
(_bfd_mips_elf_got16_reloc): Rename from mips_elf_got16_reloc and
make globally visible.
(_bfd_mips_elf_gprel16_reloc): Rename from mips_elf_gprel16_reloc
and make globally visible.
(gprel16_with_gp): Check howto->src_mask before using value in
insn.
(_bfd_mips_elf_gprel32_reloc): Rename from mips_elf_gprel32_reloc
and make globally visible.
(gprel32_with_gp): Check howto->src_mask before fetching value.
(bfd_mips_elf_swap_options_in): New function.
(bfd_mips_elf_swap_options_out): New function.
(_bfd_mips_elf_set_private_flags): Rename from
mips_elf_set_private_flags and make globally visible.
(_bfd_mips_elf_copy_private_bfd_data): Rename from
mips_elf_copy_private_bfd_data and make globally visible.
(_bfd_mips_elf_merge_private_bfd_data): Rename from
mips_elf_merge_private_bfd_data and make globally visible.
(_bfd_mips_elf_section_from_shdr): Accept .MIPS.options as a name
for a SHT_MIPS_OPTIONS section.
(mips_elf32_section_from_shdr): Handle SHT_MIPS_OPTIONS section.
(_bfd_mips_elf_fake_sections): Consider .MIPS.options to be the
name of a SHT_MIPS_OPTIONS section.
(_bfd_mips_elf_set_section_contents): New function.
(mips_elf32_section_processing): Set the GP value in a
SHT_MIPS_OPTIONS section.
(_bfd_mips_elf_find_nearest_line): Rename from
mips_elf_find_nearest_line and make globally visible.
(bfd_elf32_set_section_contents): Define.
* elf-bfd.h (_bfd_mips_elf_hi16_reloc): Declare.
(_bfd_mips_elf_lo16_reloc): Declare.
(_bfd_mips_elf_gprel16_reloc): Declare.
(_bfd_mips_elf_got16_reloc): Declare.
(_bfd_mips_elf_gprel32_reloc): Declare.
(_bfd_mips_elf_set_private_flags): Declare.
(_bfd_mips_elf_copy_private_bfd_data): Declare.
(_bfd_mips_elf_merge_private_bfd_data): Declare.
(_bfd_mips_elf_find_nearest_line): Declare.
(_bfd_mips_elf_set_section_contents): Declare.

bfd/ChangeLog
bfd/elf32-mips.c
bfd/elf64-mips.c

index 2dae47a..3e8fc46 100644 (file)
@@ -1,5 +1,50 @@
 Fri May 31 13:51:28 1996  Ian Lance Taylor  <ian@cygnus.com>
 
+       * elf64-mips.c: Improve reloc special_functions and handling of
+       SHT_MIPS_OPTIONS section.
+       * elf32-mips.c (_bfd_mips_elf_hi16_reloc): Rename from
+       mips_elf_hi16_reloc and make globally visible.
+       (_bfd_mips_elf_lo16_reloc): Rename from mips_elf_lo16_reloc and
+       make globally visible.
+       (_bfd_mips_elf_got16_reloc): Rename from mips_elf_got16_reloc and
+       make globally visible.
+       (_bfd_mips_elf_gprel16_reloc): Rename from mips_elf_gprel16_reloc
+       and make globally visible.
+       (gprel16_with_gp): Check howto->src_mask before using value in
+       insn.
+       (_bfd_mips_elf_gprel32_reloc): Rename from mips_elf_gprel32_reloc
+       and make globally visible.
+       (gprel32_with_gp): Check howto->src_mask before fetching value.
+       (bfd_mips_elf_swap_options_in): New function.
+       (bfd_mips_elf_swap_options_out): New function.
+       (_bfd_mips_elf_set_private_flags): Rename from
+       mips_elf_set_private_flags and make globally visible.
+       (_bfd_mips_elf_copy_private_bfd_data): Rename from
+       mips_elf_copy_private_bfd_data and make globally visible.
+       (_bfd_mips_elf_merge_private_bfd_data): Rename from
+       mips_elf_merge_private_bfd_data and make globally visible.
+       (_bfd_mips_elf_section_from_shdr): Accept .MIPS.options as a name
+       for a SHT_MIPS_OPTIONS section.
+       (mips_elf32_section_from_shdr): Handle SHT_MIPS_OPTIONS section.
+       (_bfd_mips_elf_fake_sections): Consider .MIPS.options to be the
+       name of a SHT_MIPS_OPTIONS section.
+       (_bfd_mips_elf_set_section_contents): New function.
+       (mips_elf32_section_processing): Set the GP value in a
+       SHT_MIPS_OPTIONS section.
+       (_bfd_mips_elf_find_nearest_line): Rename from
+       mips_elf_find_nearest_line and make globally visible.
+       (bfd_elf32_set_section_contents): Define.
+       * elf-bfd.h (_bfd_mips_elf_hi16_reloc): Declare.
+       (_bfd_mips_elf_lo16_reloc): Declare.
+       (_bfd_mips_elf_gprel16_reloc): Declare.
+       (_bfd_mips_elf_got16_reloc): Declare.
+       (_bfd_mips_elf_gprel32_reloc): Declare.
+       (_bfd_mips_elf_set_private_flags): Declare.
+       (_bfd_mips_elf_copy_private_bfd_data): Declare.
+       (_bfd_mips_elf_merge_private_bfd_data): Declare.
+       (_bfd_mips_elf_find_nearest_line): Declare.
+       (_bfd_mips_elf_set_section_contents): Declare.
+
        * elf32-hppa.c (elf32_hppa_info_to_howto): Rename from
        elf_info_to_howto.
        (elf_info_to_howto): Define.
index 2beb720..94eb015 100644 (file)
@@ -41,41 +41,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define ECOFF_32
 #include "ecoffswap.h"
 
-static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd,
-                                                         arelent *reloc,
-                                                         asymbol *symbol,
-                                                         PTR data,
-                                                         asection *section,
-                                                         bfd *output_bfd,
-                                                         char **error));
-static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *abfd,
-                                                          arelent *reloc,
-                                                          asymbol *symbol,
-                                                          PTR data,
-                                                          asection *section,
-                                                          bfd *output_bfd,
-                                                          char **error));
-static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd,
-                                                         arelent *reloc,
-                                                         asymbol *symbol,
-                                                         PTR data,
-                                                         asection *section,
-                                                         bfd *output_bfd,
-                                                         char **error));
-static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd,
-                                                            arelent *reloc,
-                                                            asymbol *symbol,
-                                                            PTR data,
-                                                            asection *section,
-                                                            bfd *output_bfd,
-                                                            char **error));
-static bfd_reloc_status_type mips_elf_gprel32_reloc PARAMS ((bfd *abfd,
-                                                            arelent *reloc,
-                                                            asymbol *symbol,
-                                                            PTR data,
-                                                            asection *section,
-                                                            bfd *output_bfd,
-                                                            char **error));
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void mips_info_to_howto_rel
@@ -91,18 +56,12 @@ static boolean mips_elf_create_procedure_table
           struct ecoff_debug_info *));
 static int mips_elf_additional_program_headers PARAMS ((bfd *));
 static boolean mips_elf_modify_segment_map PARAMS ((bfd *));
-static boolean mips_elf_set_private_flags PARAMS ((bfd *, flagword));
-static boolean mips_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
-static boolean mips_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
 static boolean mips_elf32_section_from_shdr
   PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
 static boolean mips_elf32_section_processing
   PARAMS ((bfd *, Elf32_Internal_Shdr *));
 static boolean mips_elf_is_local_label
   PARAMS ((bfd *, asymbol *));
-static boolean mips_elf_find_nearest_line
-  PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **,
-          const char **, unsigned int *));
 static struct bfd_hash_entry *mips_elf_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static struct bfd_link_hash_table *mips_elf_link_hash_table_create
@@ -427,7 +386,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        mips_elf_hi16_reloc,   /* special_function */
+        _bfd_mips_elf_hi16_reloc,      /* special_function */
         "R_MIPS_HI16",         /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -442,7 +401,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        mips_elf_lo16_reloc,   /* special_function */
+        _bfd_mips_elf_lo16_reloc,      /* special_function */
         "R_MIPS_LO16",         /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -457,7 +416,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_GPREL16",      /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -472,7 +431,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_LITERAL",      /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -487,7 +446,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_got16_reloc,  /* special_function */
+        _bfd_mips_elf_got16_reloc,     /* special_function */
         "R_MIPS_GOT16",        /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -533,7 +492,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        mips_elf_gprel32_reloc, /* special_function */
+        _bfd_mips_elf_gprel32_reloc, /* special_function */
         "R_MIPS_GPREL32",      /* name */
         true,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -727,8 +686,8 @@ struct mips_hi16
 
 static struct mips_hi16 *mips_hi16_list;
 
-static bfd_reloc_status_type
-mips_elf_hi16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_hi16_reloc (abfd,
                     reloc_entry,
                     symbol,
                     data,
@@ -820,8 +779,8 @@ mips_elf_hi16_reloc (abfd,
    inplace relocation; this function exists in order to do the
    R_MIPS_HI16 relocation described above.  */
 
-static bfd_reloc_status_type
-mips_elf_lo16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_lo16_reloc (abfd,
                     reloc_entry,
                     symbol,
                     data,
@@ -930,8 +889,8 @@ mips_elf_lo16_reloc (abfd,
    This implementation suffices for the assembler, but the linker does
    not yet know how to create global offset tables.  */
 
-static bfd_reloc_status_type
-mips_elf_got16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_got16_reloc (abfd,
                      reloc_entry,
                      symbol,
                      data,
@@ -960,8 +919,8 @@ mips_elf_got16_reloc (abfd,
      just like HI16.  */
   if (output_bfd != (bfd *) NULL
       && (symbol->flags & BSF_SECTION_SYM) != 0)
-    return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
-                               input_section, output_bfd, error_message);
+    return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+                                    input_section, output_bfd, error_message);
 
   abort ();
 }
@@ -1050,14 +1009,9 @@ static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *,
                                                      arelent *, asection *,
                                                      boolean, PTR, bfd_vma));
 
-static bfd_reloc_status_type
-mips_elf_gprel16_reloc (abfd,
-                       reloc_entry,
-                       symbol,
-                       data,
-                       input_section,
-                       output_bfd,
-                       error_message)
+bfd_reloc_status_type
+_bfd_mips_elf_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section,
+                            output_bfd, error_message)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol;
@@ -1128,9 +1082,17 @@ gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
   insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
 
   /* Set val to the offset into the section or symbol.  */
-  val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
-  if (val & 0x8000)
-    val -= 0x10000;
+  if (reloc_entry->howto->src_mask == 0)
+    {
+      /* This case occurs with the 64-bit MIPS ELF ABI.  */
+      val = reloc_entry->addend;
+    }
+  else
+    {
+      val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
+      if (val & 0x8000)
+       val -= 0x10000;
+    }
 
   /* Adjust val for the final section location and GP value.  If we
      are producing relocateable output, we don't want to do this for
@@ -1159,8 +1121,8 @@ static bfd_reloc_status_type gprel32_with_gp PARAMS ((bfd *, asymbol *,
                                                      arelent *, asection *,
                                                      boolean, PTR, bfd_vma));
 
-static bfd_reloc_status_type
-mips_elf_gprel32_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_gprel32_reloc (abfd,
                        reloc_entry,
                        symbol,
                        data,
@@ -1237,7 +1199,13 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
   if (reloc_entry->address > input_section->_cooked_size)
     return bfd_reloc_outofrange;
 
-  val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+  if (reloc_entry->howto->src_mask == 0)
+    {
+      /* This case arises with the 64-bit MIPS ELF ABI.  */
+      val = 0;
+    }
+  else
+    val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
 
   /* Set val to the offset into the section or symbol.  */
   val += reloc_entry->addend;
@@ -1420,6 +1388,34 @@ bfd_elf32_swap_crinfo_out (abfd, in, ex)
   bfd_h_put_32 (abfd, (bfd_vma) in->konst, ex->konst);
   bfd_h_put_32 (abfd, (bfd_vma) in->vaddr, ex->vaddr);
 }
+
+/* Swap in an options header.  */
+
+void
+bfd_mips_elf_swap_options_in (abfd, ex, in)
+     bfd *abfd;
+     const Elf_External_Options *ex;
+     Elf_Internal_Options *in;
+{
+  in->kind = bfd_h_get_8 (abfd, ex->kind);
+  in->size = bfd_h_get_8 (abfd, ex->size);
+  in->section = bfd_h_get_16 (abfd, ex->section);
+  in->info = bfd_h_get_32 (abfd, ex->info);
+}
+
+/* Swap out an options header.  */
+
+void
+bfd_mips_elf_swap_options_out (abfd, in, ex)
+     bfd *abfd;
+     const Elf_Internal_Options *in;
+     Elf_External_Options *ex;
+{
+  bfd_h_put_8 (abfd, in->kind, ex->kind);
+  bfd_h_put_8 (abfd, in->size, ex->size);
+  bfd_h_put_16 (abfd, in->section, ex->section);
+  bfd_h_put_32 (abfd, in->info, ex->info);
+}
 \f
 /* Determine whether a symbol is global for the purposes of splitting
    the symbol table into global symbols and local symbols.  At least
@@ -1543,8 +1539,8 @@ _bfd_mips_elf_final_write_processing (abfd, linker)
 \f
 /* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */
 
-static boolean
-mips_elf_set_private_flags (abfd, flags)
+boolean
+_bfd_mips_elf_set_private_flags (abfd, flags)
      bfd *abfd;
      flagword flags;
 {
@@ -1558,8 +1554,8 @@ mips_elf_set_private_flags (abfd, flags)
 
 /* Copy backend specific data from one object module to another */
 
-static boolean
-mips_elf_copy_private_bfd_data (ibfd, obfd)
+boolean
+_bfd_mips_elf_copy_private_bfd_data (ibfd, obfd)
      bfd *ibfd;
      bfd *obfd;
 {
@@ -1582,8 +1578,8 @@ mips_elf_copy_private_bfd_data (ibfd, obfd)
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-static boolean
-mips_elf_merge_private_bfd_data (ibfd, obfd)
+boolean
+_bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
      bfd *ibfd;
      bfd *obfd;
 {
@@ -1705,7 +1701,8 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name)
        return false;
       break;
     case SHT_MIPS_OPTIONS:
-      if (strcmp (name, ".options") != 0)
+      if (strcmp (name, ".options") != 0
+         && strcmp (name, ".MIPS.options") != 0)
        return false;
       break;
     case SHT_MIPS_DWARF:
@@ -1764,6 +1761,47 @@ mips_elf32_section_from_shdr (abfd, hdr, name)
       elf_gp (abfd) = s.ri_gp_value;
     }
 
+  /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and
+     set the gp value based on what we find.  We may see both
+     SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case,
+     they should agree.  */
+  if (hdr->sh_type == SHT_MIPS_OPTIONS)
+    {
+      bfd_byte *contents, *l, *lend;
+
+      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+      if (contents == NULL)
+       return false;
+      if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents,
+                                     (file_ptr) 0, hdr->sh_size))
+       {
+         free (contents);
+         return false;
+       }
+      l = contents;
+      lend = contents + hdr->sh_size;
+      while (l + sizeof (Elf_External_Options) <= lend)
+       {
+         Elf_Internal_Options intopt;
+
+         bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+                                       &intopt);
+         if (intopt.kind == ODK_REGINFO)
+           {
+             Elf32_RegInfo intreg;
+
+             bfd_mips_elf32_swap_reginfo_in
+               (abfd,
+                ((Elf32_External_RegInfo *)
+                 (l + sizeof (Elf_External_Options))),
+                &intreg);
+             elf_gp (abfd) = intreg.ri_gp_value;
+           }
+         l += intopt.size;
+       }
+      free (contents);
+    }
+
   return true;
 }
 
@@ -1842,7 +1880,8 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
           || strcmp (name, ".lit4") == 0
           || strcmp (name, ".lit8") == 0)
     hdr->sh_flags |= SHF_MIPS_GPREL;
-  else if (strcmp (name, ".options") == 0)
+  else if (strcmp (name, ".options") == 0
+          || strcmp (name, ".MIPS.options") == 0)
     {
       hdr->sh_type = SHT_MIPS_OPTIONS;
       hdr->sh_entsize = 1;
@@ -1881,11 +1920,56 @@ _bfd_mips_elf_section_from_bfd_section (abfd, hdr, sec, retval)
   return false;
 }
 
-/* Work over a section just before writing it out.  We update the GP
-   value in the .reginfo section based on the value we are using.
-   This routine is used by both the 32-bit and the 64-bit ABI.  FIXME:
-   We recognize sections that need the SHF_MIPS_GPREL flag by name;
-   there has to be a better way.  */
+/* When are writing out the .options or .MIPS.options section,
+   remember the bytes we are writing out, so that we can install the
+   GP value in the section_processing routine.  */
+
+boolean
+_bfd_mips_elf_set_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
+{
+  if (strcmp (section->name, ".options") == 0
+      || strcmp (section->name, ".MIPS.options") == 0)
+    {
+      bfd_byte *c;
+
+      if (elf_section_data (section) == NULL)
+       {
+         section->used_by_bfd =
+           (PTR) bfd_zalloc (abfd, sizeof (struct bfd_elf_section_data));
+         if (elf_section_data (section) == NULL)
+           return false;
+       }
+      c = (bfd_byte *) elf_section_data (section)->tdata;
+      if (c == NULL)
+       {
+         bfd_size_type size;
+
+         if (section->_cooked_size != 0)
+           size = section->_cooked_size;
+         else
+           size = section->_raw_size;
+         c = (PTR) bfd_zalloc (abfd, size);
+         if (c == NULL)
+           return false;
+         elf_section_data (section)->tdata = (PTR) c;
+       }
+
+      memcpy (c + offset, location, count);
+    }
+
+  return _bfd_elf_set_section_contents (abfd, section, location, offset,
+                                       count);
+}
+
+/* Work over a section just before writing it out.  This routine is
+   used by both the 32-bit and the 64-bit ABI.  FIXME: We recognize
+   sections that need the SHF_MIPS_GPREL flag by name; there has to be
+   a better way.  */
 
 boolean
 _bfd_mips_elf_section_processing (abfd, hdr)
@@ -1934,8 +2018,8 @@ _bfd_mips_elf_section_processing (abfd, hdr)
 }
 
 /* Work over a section just before writing it out.  We update the GP
-   value in the .reginfo section based on the value we are using.  The
-   64 bit ABI does not use the .reginfo section.  */
+   value in the SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS sections based
+   on the value we are using.  */
 
 static boolean
 mips_elf32_section_processing (abfd, hdr)
@@ -1958,6 +2042,48 @@ mips_elf32_section_processing (abfd, hdr)
        return false;
     }
 
+  if (hdr->sh_type == SHT_MIPS_OPTIONS
+      && hdr->bfd_section != NULL
+      && elf_section_data (hdr->bfd_section) != NULL
+      && elf_section_data (hdr->bfd_section)->tdata != NULL)
+    {
+      bfd_byte *contents, *l, *lend;
+
+      /* We stored the section contents in the elf_section_data tdata
+        field in the set_section_contents routine.  We save the
+        section contents so that we don't have to read them again.
+        At this point we know that elf_gp is set, so we can look
+        through the section contents to see if there is an
+        ODK_REGINFO structure.  */
+
+      contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata;
+      l = contents;
+      lend = contents + hdr->sh_size;
+      while (l + sizeof (Elf_External_Options) <= lend)
+       {
+         Elf_Internal_Options intopt;
+
+         bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+                                       &intopt);
+         if (intopt.kind == ODK_REGINFO)
+           {
+             bfd_byte buf[4];
+
+             if (bfd_seek (abfd,
+                           (hdr->sh_offset
+                            + (l - contents)
+                            + sizeof (Elf_External_Options)
+                            + (sizeof (Elf32_External_RegInfo) - 4)),
+                            SEEK_SET) == -1)
+               return false;
+             bfd_h_put_32 (abfd, elf_gp (abfd), buf);
+             if (bfd_write (buf, 1, 4, abfd) != 4)
+               return false;
+           }
+         l += intopt.size;
+       }
+    }
+
   return _bfd_mips_elf_section_processing (abfd, hdr);
 }
 \f
@@ -2408,9 +2534,9 @@ struct mips_elf_find_line
   struct ecoff_find_line i;
 };
 
-static boolean
-mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
-                           functionname_ptr, line_ptr)
+boolean
+_bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+                                functionname_ptr, line_ptr)
      bfd *abfd;
      asection *section;
      asymbol **symbols;
@@ -5839,7 +5965,7 @@ elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data,
                 fall over on its own.  */
            }
          else if ((*parent)->howto->special_function
-                  == mips_elf_gprel16_reloc)
+                  == _bfd_mips_elf_gprel16_reloc)
            {
              /* bypass special_function call */
              r = gprel16_with_gp (input_bfd, sym, *parent, input_section,
@@ -5980,16 +6106,16 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 #define elf_backend_ecoff_debug_swap   &mips_elf32_ecoff_debug_swap
 
 #define bfd_elf32_bfd_is_local_label   mips_elf_is_local_label
-#define bfd_elf32_find_nearest_line    mips_elf_find_nearest_line
-
+#define bfd_elf32_find_nearest_line    _bfd_mips_elf_find_nearest_line
+#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents
 #define bfd_elf32_bfd_link_hash_table_create \
                                        mips_elf_link_hash_table_create
 #define bfd_elf32_bfd_final_link       mips_elf_final_link
 #define bfd_elf32_bfd_copy_private_bfd_data \
-                                       mips_elf_copy_private_bfd_data
+                                       _bfd_mips_elf_copy_private_bfd_data
 #define bfd_elf32_bfd_merge_private_bfd_data \
-                                       mips_elf_merge_private_bfd_data
-#define bfd_elf32_bfd_set_private_flags        mips_elf_set_private_flags
+                                       _bfd_mips_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags        _bfd_mips_elf_set_private_flags
 #define elf_backend_add_symbol_hook    mips_elf_add_symbol_hook
 #define elf_backend_create_dynamic_sections \
                                        mips_elf_create_dynamic_sections
index 2f89b48..ff0b0f2 100644 (file)
@@ -67,6 +67,8 @@ static boolean mips_elf64_slurp_reloc_table
 static void mips_elf64_write_relocs PARAMS ((bfd *, asection *, PTR));
 static boolean mips_elf64_section_from_shdr
   PARAMS ((bfd *, Elf_Internal_Shdr *, char *));
+static boolean mips_elf64_section_processing
+  PARAMS ((bfd *, Elf_Internal_Shdr *));
 
 /* The relocation types.  */
 
@@ -117,14 +119,6 @@ enum mips_elf64_reloc_type
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 
-/* FIXME: These need to be rewritten, or we need to use the versions
-   in elf32-mips.c.  */
-#define mips_elf_hi16_reloc bfd_elf_generic_reloc
-#define mips_elf_lo16_reloc bfd_elf_generic_reloc
-#define mips_elf_gprel16_reloc bfd_elf_generic_reloc
-#define mips_elf_got16_reloc bfd_elf_generic_reloc
-#define mips_elf_gprel32_reloc bfd_elf_generic_reloc
-
 /* The relocation table used for SHT_REL sections.  */
 
 static reloc_howto_type mips_elf64_howto_table_rel[] =
@@ -215,7 +209,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        mips_elf_hi16_reloc,   /* special_function */
+        _bfd_mips_elf_hi16_reloc,      /* special_function */
         "R_MIPS_HI16",         /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -230,7 +224,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        mips_elf_lo16_reloc,   /* special_function */
+        _bfd_mips_elf_lo16_reloc,      /* special_function */
         "R_MIPS_LO16",         /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -245,7 +239,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_GPREL16",      /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -260,7 +254,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_LITERAL",      /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -275,7 +269,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_got16_reloc,  /* special_function */
+        _bfd_mips_elf_got16_reloc,     /* special_function */
         "R_MIPS_GOT16",        /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -321,7 +315,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        mips_elf_gprel32_reloc, /* special_function */
+        _bfd_mips_elf_gprel32_reloc, /* special_function */
         "R_MIPS_GPREL32",      /* name */
         true,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -782,7 +776,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_GPREL16",      /* name */
         true,                  /* partial_inplace */
         0,                     /* src_mask */
@@ -797,7 +791,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_gprel16_reloc, /* special_function */
+        _bfd_mips_elf_gprel16_reloc, /* special_function */
         "R_MIPS_LITERAL",      /* name */
         true,                  /* partial_inplace */
         0,                     /* src_mask */
@@ -805,6 +799,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
         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) */
@@ -812,7 +807,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        mips_elf_got16_reloc,  /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_GOT16",        /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -858,7 +853,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        mips_elf_gprel32_reloc, /* special_function */
+        _bfd_mips_elf_gprel32_reloc, /* special_function */
         "R_MIPS_GPREL32",      /* name */
         true,                  /* partial_inplace */
         0,                     /* src_mask */
@@ -1725,6 +1720,47 @@ mips_elf64_write_relocs (abfd, sec, data)
              == count);
 }
 \f
+/* The .MIPS.options section holds register information in an
+   Elf64_Reginfo structure.  These routines swap them in and out.
+   They are globally visible because they are used outside of BFD.  */
+
+void
+bfd_mips_elf64_swap_reginfo_in (abfd, ex, in)
+     bfd *abfd;
+     const Elf64_External_RegInfo *ex;
+     Elf64_Internal_RegInfo *in;
+{
+  in->ri_gprmask = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gprmask);
+  in->ri_pad = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_pad);
+  in->ri_cprmask[0] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[0]);
+  in->ri_cprmask[1] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[1]);
+  in->ri_cprmask[2] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[2]);
+  in->ri_cprmask[3] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[3]);
+  in->ri_gp_value = bfd_h_get_64 (abfd, (bfd_byte *) ex->ri_gp_value);
+}
+
+void
+bfd_mips_elf64_swap_reginfo_out (abfd, in, ex)
+     bfd *abfd;
+     const Elf64_Internal_RegInfo *in;
+     Elf64_External_RegInfo *ex;
+{
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_gprmask,
+               (bfd_byte *) ex->ri_gprmask);
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_pad,
+               (bfd_byte *) ex->ri_pad);
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[0],
+               (bfd_byte *) ex->ri_cprmask[0]);
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[1],
+               (bfd_byte *) ex->ri_cprmask[1]);
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[2],
+               (bfd_byte *) ex->ri_cprmask[2]);
+  bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[3],
+               (bfd_byte *) ex->ri_cprmask[3]);
+  bfd_h_put_64 (abfd, (bfd_vma) in->ri_gp_value,
+               (bfd_byte *) ex->ri_gp_value);
+}
+
 /* Handle a 64-bit MIPS ELF specific section.  */
 
 static boolean
@@ -1736,8 +1772,103 @@ mips_elf64_section_from_shdr (abfd, hdr, name)
   if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name))
     return false;
 
+  /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and
+     set the gp value based on what we find.  We may see both
+     SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case,
+     they should agree.  */
+  if (hdr->sh_type == SHT_MIPS_OPTIONS)
+    {
+      bfd_byte *contents, *l, *lend;
+
+      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+      if (contents == NULL)
+       return false;
+      if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents,
+                                     (file_ptr) 0, hdr->sh_size))
+       {
+         free (contents);
+         return false;
+       }
+      l = contents;
+      lend = contents + hdr->sh_size;
+      while (l + sizeof (Elf_External_Options) <= lend)
+       {
+         Elf_Internal_Options intopt;
+
+         bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+                                       &intopt);
+         if (intopt.kind == ODK_REGINFO)
+           {
+             Elf64_Internal_RegInfo intreg;
+
+             bfd_mips_elf64_swap_reginfo_in
+               (abfd,
+                ((Elf64_External_RegInfo *)
+                 (l + sizeof (Elf_External_Options))),
+                &intreg);
+             elf_gp (abfd) = intreg.ri_gp_value;
+           }
+         l += intopt.size;
+       }
+      free (contents);
+    }
+
   return true;
 }
+
+/* Work over a section just before writing it out.  We update the GP
+   value in the SHT_MIPS_OPTIONS section based on the value we are
+   using.  */
+
+static boolean
+mips_elf64_section_processing (abfd, hdr)
+     bfd *abfd;
+     Elf_Internal_Shdr *hdr;
+{
+  if (hdr->sh_type == SHT_MIPS_OPTIONS
+      && hdr->bfd_section != NULL
+      && elf_section_data (hdr->bfd_section) != NULL
+      && elf_section_data (hdr->bfd_section)->tdata != NULL)
+    {
+      bfd_byte *contents, *l, *lend;
+
+      /* We stored the section contents in the elf_section_data tdata
+        field in the set_section_contents routine.  We save the
+        section contents so that we don't have to read them again.
+        At this point we know that elf_gp is set, so we can look
+        through the section contents to see if there is an
+        ODK_REGINFO structure.  */
+
+      contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata;
+      l = contents;
+      lend = contents + hdr->sh_size;
+      while (l + sizeof (Elf_External_Options) <= lend)
+       {
+         Elf_Internal_Options intopt;
+
+         bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+                                       &intopt);
+         if (intopt.kind == ODK_REGINFO)
+           {
+             bfd_byte buf[8];
+
+             if (bfd_seek (abfd,
+                           (hdr->sh_offset
+                            + (l - contents)
+                            + sizeof (Elf_External_Options)
+                            + (sizeof (Elf64_External_RegInfo) - 8)),
+                            SEEK_SET) == -1)
+               return false;
+             bfd_h_put_64 (abfd, elf_gp (abfd), buf);
+             if (bfd_write (buf, 1, 8, abfd) != 8)
+               return false;
+           }
+         l += intopt.size;
+       }
+    }
+
+  return _bfd_mips_elf_section_processing (abfd, hdr);
+}
 \f
 /* ECOFF swapping routines.  These are used when dealing with the
    .mdebug section, which is in the ECOFF debugging format.  */
@@ -1822,13 +1953,20 @@ const struct elf_size_info mips_elf64_size_info =
 #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_section_processing mips_elf64_section_processing
 #define elf_backend_symbol_processing  _bfd_mips_elf_symbol_processing
 #define elf_backend_final_write_processing \
                                        _bfd_mips_elf_final_write_processing
 #define elf_backend_ecoff_debug_swap   &mips_elf64_ecoff_debug_swap
 
+#define bfd_elf64_find_nearest_line    _bfd_mips_elf_find_nearest_line
 #define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
 #define bfd_elf64_bfd_reloc_type_lookup        mips_elf64_reloc_type_lookup
+#define bfd_elf64_set_section_contents _bfd_mips_elf_set_section_contents
+#define bfd_elf64_bfd_copy_private_bfd_data \
+                                       _bfd_mips_elf_copy_private_bfd_data
+#define bfd_elf64_bfd_merge_private_bfd_data \
+                                       _bfd_mips_elf_merge_private_bfd_data
+#define bfd_elf64_bfd_set_private_flags        _bfd_mips_elf_set_private_flags
 
 #include "elf64-target.h"