Fixed xgettext invocation in .Sanitize files
[binutils-gdb.git] / bfd / elf64-mips.c
index ff0b0f242ff78be2d1ecc5f0e2b65a225188b8d2..30ea6a767379e94fe49337d3f8fd5caf79afde6d 100644 (file)
@@ -22,11 +22,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
    The MIPS 64-bit ELF ABI uses an unusual reloc format.  This file
    overrides the usual ELF reloc handling, and handles reading and
-   writing the relocations here.  */
+   writing the relocations here.
+
+   The MIPS 64-bit ELF ABI also uses an unusual archive map format.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
+#include "aout/ar.h"
 #include "bfdlink.h"
 #include "genlink.h"
 #include "elf-bfd.h"
@@ -69,6 +72,9 @@ static boolean mips_elf64_section_from_shdr
   PARAMS ((bfd *, Elf_Internal_Shdr *, char *));
 static boolean mips_elf64_section_processing
   PARAMS ((bfd *, Elf_Internal_Shdr *));
+static boolean mips_elf64_slurp_armap PARAMS ((bfd *));
+static boolean mips_elf64_write_armap
+  PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
 
 /* The relocation types.  */
 
@@ -1537,13 +1543,20 @@ mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, rel_hdr)
    associated with a single data section.  */
 
 static boolean
-mips_elf64_slurp_reloc_table (abfd, asect, symbols)
+mips_elf64_slurp_reloc_table (abfd, asect, symbols, dynamic)
      bfd *abfd;
      asection *asect;
      asymbol **symbols;
+     boolean dynamic;
 {
   struct bfd_elf_section_data * const d = elf_section_data (asect);
 
+  if (dynamic)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
   if (asect->relocation != NULL
       || (asect->flags & SEC_RELOC) == 0
       || asect->reloc_count == 0)
@@ -1720,47 +1733,6 @@ 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
@@ -1870,6 +1842,215 @@ mips_elf64_section_processing (abfd, hdr)
   return _bfd_mips_elf_section_processing (abfd, hdr);
 }
 \f
+/* Irix 6 defines a brand new archive map format, so that they can
+   have archives more than 4 GB in size.  */
+
+/* Read an Irix 6 armap.  */
+
+static boolean
+mips_elf64_slurp_armap (abfd)
+     bfd *abfd;
+{
+  struct artdata *ardata = bfd_ardata (abfd);
+  char nextname[17];
+  file_ptr arhdrpos;
+  bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
+  struct areltdata *mapdata;
+  bfd_byte int_buf[8];
+  char *stringbase;
+  bfd_byte *raw_armap = NULL;
+  carsym *carsyms;
+
+  ardata->symdefs = NULL;
+
+  /* Get the name of the first element.  */
+  arhdrpos = bfd_tell (abfd);
+  i = bfd_read ((PTR) nextname, 1, 16, abfd);
+  if (i == 0)
+    return true;
+  if (i != 16)
+    return false;
+
+  if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
+    return false;
+
+  /* Archives with traditional armaps are still permitted.  */
+  if (strncmp (nextname, "/               ", 16) == 0)
+    return bfd_slurp_armap (abfd);
+
+  if (strncmp (nextname, "/SYM64/         ", 16) != 0)
+    {
+      bfd_has_map (abfd) = false;
+      return true;
+    }
+
+  mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
+  if (mapdata == NULL)
+    return false;
+  parsed_size = mapdata->parsed_size;
+  bfd_release (abfd, (PTR) mapdata);
+
+  if (bfd_read (int_buf, 1, 8, abfd) != 8)
+    {
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_malformed_archive);
+      return false;
+    }
+
+  nsymz = bfd_getb64 (int_buf);
+  stringsize = parsed_size - 8 * nsymz - 8;
+
+  carsym_size = nsymz * sizeof (carsym);
+  ptrsize = 8 * nsymz;
+
+  ardata->symdefs = (carsym *) bfd_zalloc (abfd, carsym_size + stringsize + 1);
+  if (ardata->symdefs == NULL)
+    return false;
+  carsyms = ardata->symdefs;
+  stringbase = ((char *) ardata->symdefs) + carsym_size;
+
+  raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize);
+  if (raw_armap == NULL)
+    goto error_return;
+
+  if (bfd_read (raw_armap, 1, ptrsize, abfd) != ptrsize
+      || bfd_read (stringbase, 1, stringsize, abfd) != stringsize)
+    {
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_malformed_archive);
+      goto error_return;
+    }
+
+  for (i = 0; i < nsymz; i++)
+    {
+      carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
+      carsyms->name = stringbase;
+      stringbase += strlen (stringbase) + 1;
+      ++carsyms;
+    }
+  *stringbase = '\0';
+
+  ardata->symdef_count = nsymz;
+  ardata->first_file_filepos = arhdrpos + sizeof (struct ar_hdr) + parsed_size;
+
+  bfd_has_map (abfd) = true;
+  bfd_release (abfd, raw_armap);
+
+  return true;
+
+ error_return:
+  if (raw_armap != NULL)
+    bfd_release (abfd, raw_armap);
+  if (ardata->symdefs != NULL)
+    bfd_release (abfd, ardata->symdefs);
+  return false;
+}
+
+/* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
+   able to handle ordinary ELF armaps, but at least on Irix 6.2 the
+   linker crashes.  */
+
+static boolean
+mips_elf64_write_armap (arch, elength, map, symbol_count, stridx)
+     bfd *arch;
+     unsigned int elength;
+     struct orl *map;
+     unsigned int symbol_count;
+     int stridx;
+{
+  unsigned int ranlibsize = (symbol_count * 8) + 8;
+  unsigned int stringsize = stridx;
+  unsigned int mapsize = stringsize + ranlibsize;
+  file_ptr archive_member_file_ptr;
+  bfd *current = arch->archive_head;
+  unsigned int count;
+  struct ar_hdr hdr;
+  unsigned int i;
+  int padding;
+  bfd_byte buf[8];
+
+  padding = BFD_ALIGN (mapsize, 8) - mapsize;
+  mapsize += padding;
+
+  /* work out where the first object file will go in the archive */
+  archive_member_file_ptr = (mapsize
+                            + elength
+                            + sizeof (struct ar_hdr)
+                            + SARMAG);
+
+  memset ((char *) (&hdr), 0, sizeof (struct ar_hdr));
+  strcpy (hdr.ar_name, "/SYM64/");
+  sprintf (hdr.ar_size, "%-10d", (int) mapsize);
+  sprintf (hdr.ar_date, "%ld", (long) time (NULL));
+  /* This, at least, is what Intel coff sets the values to.: */
+  sprintf ((hdr.ar_uid), "%d", 0);
+  sprintf ((hdr.ar_gid), "%d", 0);
+  sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0);
+  strncpy (hdr.ar_fmag, ARFMAG, 2);
+
+  for (i = 0; i < sizeof (struct ar_hdr); i++)
+    if (((char *) (&hdr))[i] == '\0')
+      (((char *) (&hdr))[i]) = ' ';
+
+  /* Write the ar header for this item and the number of symbols */
+
+  if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), arch)
+      != sizeof (struct ar_hdr))
+    return false;
+
+  bfd_putb64 (symbol_count, buf);
+  if (bfd_write (buf, 1, 8, arch) != 8)
+    return false;
+
+  /* Two passes, first write the file offsets for each symbol -
+     remembering that each offset is on a two byte boundary.  */
+
+  /* Write out the file offset for the file associated with each
+     symbol, and remember to keep the offsets padded out.  */
+
+  current = arch->archive_head;
+  count = 0;
+  while (current != (bfd *) NULL && count < symbol_count)
+    {
+      /* For each symbol which is used defined in this object, write out
+        the object file's address in the archive */
+
+      while (((bfd *) (map[count]).pos) == current)
+       {
+         bfd_putb64 (archive_member_file_ptr, buf);
+         if (bfd_write (buf, 1, 8, arch) != 8)
+           return false;
+         count++;
+       }
+      /* Add size of this archive entry */
+      archive_member_file_ptr += (arelt_size (current)
+                                 + sizeof (struct ar_hdr));
+      /* remember about the even alignment */
+      archive_member_file_ptr += archive_member_file_ptr % 2;
+      current = current->next;
+    }
+
+  /* now write the strings themselves */
+  for (count = 0; count < symbol_count; count++)
+    {
+      size_t len = strlen (*map[count].name) + 1;
+
+      if (bfd_write (*map[count].name, 1, len, arch) != len)
+       return false;
+    }
+
+  /* The spec says that this should be padded to an 8 byte boundary.
+     However, the Irix 6.2 tools do not appear to do this.  */
+  while (padding != 0)
+    {
+      if (bfd_write ("", 1, 1, arch) != 1)
+       return false;
+      --padding;
+    }
+
+  return true;
+}
+\f
 /* ECOFF swapping routines.  These are used when dealing with the
    .mdebug section, which is in the ECOFF debugging format.  */
 static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap =
@@ -1969,4 +2150,23 @@ const struct elf_size_info mips_elf64_size_info =
                                        _bfd_mips_elf_merge_private_bfd_data
 #define bfd_elf64_bfd_set_private_flags        _bfd_mips_elf_set_private_flags
 
+#define bfd_elf64_archive_functions
+#define bfd_elf64_archive_slurp_armap  mips_elf64_slurp_armap
+#define bfd_elf64_archive_slurp_extended_name_table \
+                               _bfd_archive_coff_slurp_extended_name_table
+#define bfd_elf64_archive_construct_extended_name_table \
+                               _bfd_archive_coff_construct_extended_name_table
+#define bfd_elf64_archive_truncate_arname \
+                                       _bfd_archive_coff_truncate_arname
+#define bfd_elf64_archive_write_armap  mips_elf64_write_armap
+#define bfd_elf64_archive_read_ar_hdr  _bfd_archive_coff_read_ar_hdr
+#define bfd_elf64_archive_openr_next_archived_file \
+                               _bfd_archive_coff_openr_next_archived_file
+#define bfd_elf64_archive_get_elt_at_index \
+                                       _bfd_archive_coff_get_elt_at_index
+#define bfd_elf64_archive_generic_stat_arch_elt \
+                                       _bfd_archive_coff_generic_stat_arch_elt
+#define bfd_elf64_archive_update_armap_timestamp \
+                               _bfd_archive_coff_update_armap_timestamp
+
 #include "elf64-target.h"