/* 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 "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
+
+
+/* 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
+
/* Initialize FILE, an LTO file object for FILENAME. */
static void
-lto_file_init (lto_file *file, const char *filename)
+lto_file_init (lto_file *file, const char *filename, off_t offset)
{
file->filename = filename;
+ file->offset = offset;
}
/* An ELF 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);
+ base_offset = elf_getbase (elf_file->elf);
for (section = elf_getscn (elf_file->elf, 0);
section;
section = elf_nextscn (elf_file->elf, section))
new_slot->name = new_name;
/* The offset into the file for this section. */
- new_slot->start = shdr->sh_offset;
+ new_slot->start = base_offset + shdr->sh_offset;
new_slot->len = shdr->sh_size;
*slot = new_slot;
}
\
shdr = elf##BITS##_getshdr (scn); \
if (!shdr) \
- fatal_error ("elf"#BITS"_getshdr() failed: %s.", elf_errmsg (-1));\
+ { \
+ if (BITS == 32) \
+ fatal_error ("elf32_getshdr() failed: %s", elf_errmsg (-1)); \
+ else \
+ fatal_error ("elf64_getshdr() failed: %s", elf_errmsg (-1)); \
+ } \
\
shdr->sh_name = sh_name; \
shdr->sh_type = sh_type; \
/* Create a new section. */
scn = elf_newscn (file->elf);
if (!scn)
- fatal_error ("could not create a new ELF section: %s.", elf_errmsg (-1));
+ fatal_error ("could not create a new ELF section: %s", elf_errmsg (-1));
file->scn = scn;
/* Add a string table entry and record the offset. */
}
+/* Return true if ELF_MACHINE is compatible with the cached value of the
+ 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)
+{
+ if (cached_file_attrs.elf_machine == elf_machine)
+ return true;
+
+ switch (cached_file_attrs.elf_machine)
+ {
+ case EM_SPARC:
+ if (elf_machine == EM_SPARC32PLUS)
+ {
+ cached_file_attrs.elf_machine = elf_machine;
+ return true;
+ }
+ break;
+
+ case EM_SPARC32PLUS:
+ if (elf_machine == EM_SPARC)
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
uninitialized, caches the architecture. */
\
if (!cached_file_attrs.initialized) \
cached_file_attrs.elf_machine = elf_header->e_machine; \
- \
- if (cached_file_attrs.elf_machine != elf_header->e_machine) \
+ else if (!is_compatible_architecture (elf_header->e_machine)) \
{ \
error ("inconsistent file architecture detected"); \
return false; \
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. */
\
ehdr = elf##BITS##_newehdr (elf_file->elf); \
if (!ehdr) \
- fatal_error ("elf"#BITS"_newehdr() failed: %s.", elf_errmsg (-1));\
+ { \
+ if (BITS == 32) \
+ fatal_error ("elf32_newehdr() failed: %s", elf_errmsg (-1)); \
+ else \
+ fatal_error ("elf64_newehdr() failed: %s", elf_errmsg (-1)); \
+ } \
\
memcpy (ehdr->e_ident, cached_file_attrs.elf_ident, \
sizeof cached_file_attrs.elf_ident); \
}
}
-
/* Open ELF file FILENAME. If WRITABLE is true, the file is opened for write
and, if necessary, created. Otherwise, the file is opened for reading.
Returns the opened file. */
lto_elf_file_open (const char *filename, bool writable)
{
lto_elf_file *elf_file;
- lto_file *result;
+ lto_file *result = NULL;
+ off_t offset;
+ long loffset;
+ off_t header_offset;
+ const char *offset_p;
+ char *fname;
+ int consumed;
+
+ offset_p = strrchr (filename, '@');
+ if (offset_p
+ && offset_p != filename
+ && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (offset_p) == (unsigned int)consumed)
+ {
+ fname = (char *) xmalloc (offset_p - filename + 1);
+ memcpy (fname, filename, offset_p - filename);
+ fname[offset_p - filename] = '\0';
+ offset = (off_t)loffset;
+ /* elf_rand expects the offset to point to the ar header, not the
+ object itself. Subtract the size of the ar header (60 bytes).
+ We don't uses sizeof (struct ar_hd) to avoid including ar.h */
+ header_offset = offset - 60;
+ }
+ else
+ {
+ fname = xstrdup (filename);
+ offset = 0;
+ header_offset = 0;
+ }
/* Set up. */
elf_file = XCNEW (lto_elf_file);
result = (lto_file *) elf_file;
- lto_file_init (result, filename);
+ lto_file_init (result, fname, offset);
elf_file->fd = -1;
/* Open the file. */
- elf_file->fd = open (filename, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666);
+ elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT|O_BINARY
+ : O_RDONLY|O_BINARY, 0666);
if (elf_file->fd == -1)
{
- error ("could not open file %s", filename);
+ error ("could not open file %s", fname);
goto fail;
}
goto fail;
}
+ if (offset != 0)
+ {
+ Elf *e;
+ off_t t = elf_rand (elf_file->elf, header_offset);
+ if (t != header_offset)
+ {
+ error ("could not seek in archive");
+ goto fail;
+ }
+
+ e = elf_begin (elf_file->fd, ELF_C_READ, elf_file->elf);
+ if (e == NULL)
+ {
+ error("could not find archive member");
+ goto fail;
+ }
+ elf_end (elf_file->elf);
+ elf_file->elf = e;
+ }
+
if (writable)
{
init_ehdr (elf_file);
return result;
fail:
- lto_elf_file_close (result);
+ if (result)
+ lto_elf_file_close (result);
return NULL;
}
lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf);
if (ehdr_p == NULL)
- fatal_error ("gelf_getehdr() failed: %s.", elf_errmsg (-1));
+ fatal_error ("gelf_getehdr() failed: %s", elf_errmsg (-1));
strtab = elf_ndxscn (elf_file->scn);
if (strtab < SHN_LORESERVE)
ehdr_p->e_shstrndx = strtab;
GElf_Shdr *shdr_p, shdr_buf;
Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0);
if (scn_p == NULL)
- fatal_error ("elf_getscn() failed: %s.", elf_errmsg (-1));
+ fatal_error ("elf_getscn() failed: %s", elf_errmsg (-1));
shdr_p = gelf_getshdr (scn_p, &shdr_buf);
if (shdr_p == NULL)
- fatal_error ("gelf_getshdr() failed: %s.", elf_errmsg (-1));
+ fatal_error ("gelf_getshdr() failed: %s", elf_errmsg (-1));
shdr_p->sh_link = strtab;
if (gelf_update_shdr (scn_p, shdr_p) == 0)
- fatal_error ("gelf_update_shdr() failed: %s.", elf_errmsg (-1));
+ fatal_error ("gelf_update_shdr() failed: %s", elf_errmsg (-1));
ehdr_p->e_shstrndx = SHN_XINDEX;
}
if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0)
- fatal_error ("gelf_update_ehdr() failed: %s.", elf_errmsg (-1));
+ fatal_error ("gelf_update_ehdr() failed: %s", elf_errmsg (-1));
lto_write_stream (elf_file->shstrtab_stream);
lto_elf_end_section ();
free (elf_file->shstrtab_stream);
if (elf_update (elf_file->elf, ELF_C_WRITE) < 0)
- fatal_error ("elf_update() failed: %s.", elf_errmsg (-1));
+ fatal_error ("elf_update() failed: %s", elf_errmsg (-1));
}
if (elf_file->elf)