/* 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.
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include <gelf.h>
#include "lto.h"
#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
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))
/* 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);
}
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;
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;
/* 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)
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. */
error ("could not read ELF identification information: %s",
elf_errmsg (0));
return false;
-
}
if (!cached_file_attrs.initialized)
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. */
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;
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;
}
fail:
if (result)
- lto_elf_file_close (result);
+ lto_obj_file_close (result);
return NULL;
}
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;
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);