OSDN Git Service

* lto.c (add_cgraph_node_to_partition,
[pf3gnuchains/gcc-fork.git] / gcc / lto / lto-elf.c
index 0135284..6268a9c 100644 (file)
@@ -1,5 +1,5 @@
 /* LTO routines for ELF object files.
-   Copyright 2009 Free Software Foundation, Inc.
+   Copyright 2009, 2010 Free Software Foundation, Inc.
    Contributed by CodeSourcery, Inc.
 
 This file is part of GCC.
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include <gelf.h>
 #include "lto.h"
@@ -29,9 +30,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "lto-streamer.h"
 
+/* Cater to hosts with half-backed <elf.h> file like HP-UX.  */
+#ifndef EM_SPARC
+# define EM_SPARC 2
+#endif
+
+#ifndef EM_SPARC32PLUS
+# define EM_SPARC32PLUS 18
+#endif
+
+#ifndef ELFOSABI_NONE
+# define ELFOSABI_NONE 0
+#endif
+
+#ifndef ELFOSABI_LINUX
+# define ELFOSABI_LINUX 3
+#endif
+
+#ifndef SHN_XINDEX
+# define SHN_XINDEX 0xffff
+#endif
+
+
 /* Handle opening elf files on hosts, such as Windows, that may use 
    text file handling that will break binary access.  */
-
 #ifndef O_BINARY
 # define O_BINARY 0
 #endif
@@ -141,45 +163,27 @@ lto_elf_free_shdr (Elf64_Shdr *shdr)
     free (shdr);
 }
 
-
-/* Returns a hash code for P.  */
-
-static hashval_t
-hash_name (const void *p)
-{
-  const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
-  return (hashval_t) htab_hash_string (ds->name);
-}
-
-
-/* Returns nonzero if P1 and P2 are equal.  */
-
-static int
-eq_name (const void *p1, const void *p2)
-{
-  const struct lto_section_slot *s1 =
-    (const struct lto_section_slot *) p1;
-  const struct lto_section_slot *s2 =
-    (const struct lto_section_slot *) p2;
-
-  return strcmp (s1->name, s2->name) == 0;
-}
-
-
 /* Build a hash table whose key is the section names and whose data is
    the start and size of each section in the .o file.  */
 
 htab_t
-lto_elf_build_section_table (lto_file *lto_file) 
+lto_obj_build_section_table (lto_file *lto_file) 
 {
   lto_elf_file *elf_file = (lto_elf_file *)lto_file;
   htab_t section_hash_table;
   Elf_Scn *section;
   size_t base_offset;
 
-  section_hash_table = htab_create (37, hash_name, eq_name, free);
+  section_hash_table = lto_obj_create_section_hash_table ();
 
   base_offset = elf_getbase (elf_file->elf);
+  /* We are reasonably sure that elf_getbase does not fail at this
+     point.  So assume that we run into the incompatibility with
+     the FreeBSD libelf implementation that has a non-working
+     elf_getbase for non-archive members in which case the offset
+     should be zero.  */
+  if (base_offset == (size_t)-1)
+    base_offset = 0;
   for (section = elf_getscn (elf_file->elf, 0);
        section;
        section = elf_nextscn (elf_file->elf, section)) 
@@ -313,7 +317,7 @@ lto_elf_begin_section_with_type (const char *name, size_t type)
 /* Begin a new ELF section named NAME in the current output file.  */
 
 void
-lto_elf_begin_section (const char *name)
+lto_obj_begin_section (const char *name)
 {
   lto_elf_begin_section_with_type (name, SHT_PROGBITS);
 }
@@ -324,7 +328,7 @@ lto_elf_begin_section (const char *name)
    been written.  */
 
 void
-lto_elf_append_data (const void *data, size_t len, void *block)
+lto_obj_append_data (const void *data, size_t len, void *block)
 {
   lto_elf_file *file;
   Elf_Data *elf_data;
@@ -361,7 +365,7 @@ lto_elf_append_data (const void *data, size_t len, void *block)
    and sets the current output file's scn member to NULL.  */
 
 void
-lto_elf_end_section (void)
+lto_obj_end_section (void)
 {
   lto_elf_file *file;
 
@@ -375,7 +379,10 @@ lto_elf_end_section (void)
 
 
 /* Return true if ELF_MACHINE is compatible with the cached value of the
-   architecture and possibly update the latter.  Return false otherwise.  */
+   architecture and possibly update the latter.  Return false otherwise.
+
+   Note: if you want to add more EM_* cases, you'll need to provide the
+   corresponding definitions at the beginning of the file.  */
 
 static bool
 is_compatible_architecture (Elf64_Half elf_machine)
@@ -443,6 +450,22 @@ DEFINE_VALIDATE_EHDR (32)
 DEFINE_VALIDATE_EHDR (64)
 
 
+#ifndef HAVE_ELF_GETSHDRSTRNDX
+/* elf_getshdrstrndx replacement for systems that lack it, but provide
+   either the gABI conformant or Solaris 2 variant of elf_getshstrndx
+   instead.  */
+
+static int
+elf_getshdrstrndx (Elf *elf, size_t *dst)
+{
+#ifdef HAVE_ELF_GETSHSTRNDX_GABI
+  return elf_getshstrndx (elf, dst);
+#else
+  return elf_getshstrndx (elf, dst) ? 0 : -1;
+#endif
+}
+#endif
+
 /* Validate's ELF_FILE's executable header and, if cached_file_attrs is
    uninitialized, caches the results.  Also records the section header string
    table's section index.  Returns true on success or false on failure.  */
@@ -461,7 +484,6 @@ validate_file (lto_elf_file *elf_file)
       error ("could not read ELF identification information: %s",
              elf_errmsg (0));
       return false;
-            
     }
 
   if (!cached_file_attrs.initialized)
@@ -484,10 +506,31 @@ validate_file (lto_elf_file *elf_file)
       memcpy (cached_file_attrs.elf_ident, elf_ident,
              sizeof cached_file_attrs.elf_ident);
     }
+  else
+    {
+      char elf_ident_buf[EI_NIDENT];
+
+      memcpy (elf_ident_buf, elf_ident, sizeof elf_ident_buf);
+
+      if (elf_ident_buf[EI_OSABI] != cached_file_attrs.elf_ident[EI_OSABI])
+       {
+         /* Allow mixing ELFOSABI_NONE with ELFOSABI_LINUX, with the result
+            ELFOSABI_LINUX.  */
+         if (elf_ident_buf[EI_OSABI] == ELFOSABI_NONE
+             && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_LINUX)
+           elf_ident_buf[EI_OSABI] = cached_file_attrs.elf_ident[EI_OSABI];
+         else if (elf_ident_buf[EI_OSABI] == ELFOSABI_LINUX
+                  && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_NONE)
+           cached_file_attrs.elf_ident[EI_OSABI] = elf_ident_buf[EI_OSABI];
+       }
 
-  if (memcmp (elf_ident, cached_file_attrs.elf_ident,
-             sizeof cached_file_attrs.elf_ident))
-    return false;
+      if (memcmp (elf_ident_buf, cached_file_attrs.elf_ident,
+                 sizeof cached_file_attrs.elf_ident))
+       {
+         error ("incompatible ELF identification");
+         return false;
+       }
+    }
 
   /* Check that the input file is a relocatable object file with the correct
      architecture.  */
@@ -576,7 +619,7 @@ init_ehdr (lto_elf_file *elf_file)
    Returns the opened file.  */
 
 lto_file *
-lto_elf_file_open (const char *filename, bool writable)
+lto_obj_file_open (const char *filename, bool writable)
 {
   lto_elf_file *elf_file;
   lto_file *result = NULL;
@@ -636,7 +679,7 @@ lto_elf_file_open (const char *filename, bool writable)
                             NULL);
   if (!elf_file->elf)
     {
-      error ("could not open ELF file: %s", elf_errmsg (0));
+      error ("could not open %s as an ELF file: %s", fname, elf_errmsg (0));
       goto fail;
     }
 
@@ -676,7 +719,7 @@ lto_elf_file_open (const char *filename, bool writable)
 
  fail:
   if (result)
-    lto_elf_file_close (result);
+    lto_obj_file_close (result);
   return NULL;
 }
 
@@ -686,7 +729,7 @@ lto_elf_file_open (const char *filename, bool writable)
    any cached data buffers are freed.  */
 
 void
-lto_elf_file_close (lto_file *file)
+lto_obj_file_close (lto_file *file)
 {
   lto_elf_file *elf_file = (lto_elf_file *) file;
   struct lto_char_ptr_base *cur, *tmp;
@@ -722,7 +765,7 @@ lto_elf_file_close (lto_file *file)
       if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0)
        fatal_error ("gelf_update_ehdr() failed: %s", elf_errmsg (-1));
       lto_write_stream (elf_file->shstrtab_stream);
-      lto_elf_end_section ();
+      lto_obj_end_section ();
 
       lto_set_current_out_file (old_file);
       free (elf_file->shstrtab_stream);