OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc1/] [gcc/] [lto/] [lto-elf.c] - Diff between revs 288 and 338

Only display areas with differences | Details | Blame | View Log

Rev 288 Rev 338
/* LTO routines for ELF object files.
/* LTO routines for ELF object files.
   Copyright 2009, 2010 Free Software Foundation, Inc.
   Copyright 2009, 2010 Free Software Foundation, Inc.
   Contributed by CodeSourcery, Inc.
   Contributed by CodeSourcery, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "toplev.h"
#include "toplev.h"
#include <gelf.h>
#include <gelf.h>
#include "lto.h"
#include "lto.h"
#include "tm.h"
#include "tm.h"
#include "libiberty.h"
#include "libiberty.h"
#include "ggc.h"
#include "ggc.h"
#include "lto-streamer.h"
#include "lto-streamer.h"
 
 
/* Cater to hosts with half-backed <elf.h> file like HP-UX.  */
/* Cater to hosts with half-backed <elf.h> file like HP-UX.  */
#ifndef EM_SPARC
#ifndef EM_SPARC
# define EM_SPARC 2
# define EM_SPARC 2
#endif
#endif
 
 
#ifndef EM_SPARC32PLUS
#ifndef EM_SPARC32PLUS
# define EM_SPARC32PLUS 18
# define EM_SPARC32PLUS 18
#endif
#endif
 
 
 
 
/* Handle opening elf files on hosts, such as Windows, that may use
/* Handle opening elf files on hosts, such as Windows, that may use
   text file handling that will break binary access.  */
   text file handling that will break binary access.  */
#ifndef O_BINARY
#ifndef O_BINARY
# define O_BINARY 0
# define O_BINARY 0
#endif
#endif
 
 
 
 
/* Initialize FILE, an LTO file object for FILENAME.  */
/* Initialize FILE, an LTO file object for FILENAME.  */
static void
static void
lto_file_init (lto_file *file, const char *filename, off_t offset)
lto_file_init (lto_file *file, const char *filename, off_t offset)
{
{
  file->filename = filename;
  file->filename = filename;
  file->offset = offset;
  file->offset = offset;
}
}
 
 
/* An ELF file.  */
/* An ELF file.  */
struct lto_elf_file
struct lto_elf_file
{
{
  /* The base information.  */
  /* The base information.  */
  lto_file base;
  lto_file base;
 
 
  /* The system file descriptor for the file.  */
  /* The system file descriptor for the file.  */
  int fd;
  int fd;
 
 
  /* The libelf descriptor for the file.  */
  /* The libelf descriptor for the file.  */
  Elf *elf;
  Elf *elf;
 
 
  /* Section number of string table used for section names.  */
  /* Section number of string table used for section names.  */
  size_t sec_strtab;
  size_t sec_strtab;
 
 
  /* Writable file members.  */
  /* Writable file members.  */
 
 
  /* The currently active section.  */
  /* The currently active section.  */
  Elf_Scn *scn;
  Elf_Scn *scn;
 
 
  /* The output stream for section header names.  */
  /* The output stream for section header names.  */
  struct lto_output_stream *shstrtab_stream;
  struct lto_output_stream *shstrtab_stream;
 
 
  /* Linked list of data which must be freed *after* the file has been
  /* Linked list of data which must be freed *after* the file has been
     closed.  This is an annoying limitation of libelf.  */
     closed.  This is an annoying limitation of libelf.  */
  struct lto_char_ptr_base *data;
  struct lto_char_ptr_base *data;
};
};
typedef struct lto_elf_file lto_elf_file;
typedef struct lto_elf_file lto_elf_file;
 
 
/* Stores executable header attributes which must be shared by all ELF files.
/* Stores executable header attributes which must be shared by all ELF files.
   This is used for validating input files and populating output files.  */
   This is used for validating input files and populating output files.  */
static struct {
static struct {
  bool initialized;
  bool initialized;
  /* 32 or 64 bits?  */
  /* 32 or 64 bits?  */
  size_t bits;
  size_t bits;
  unsigned char elf_ident[EI_NIDENT];
  unsigned char elf_ident[EI_NIDENT];
  Elf64_Half elf_machine;
  Elf64_Half elf_machine;
} cached_file_attrs;
} cached_file_attrs;
 
 
 
 
/* Return the section header for SECTION.  The return value is never
/* Return the section header for SECTION.  The return value is never
   NULL.  Call lto_elf_free_shdr to release the memory allocated.  */
   NULL.  Call lto_elf_free_shdr to release the memory allocated.  */
 
 
static Elf64_Shdr *
static Elf64_Shdr *
lto_elf_get_shdr (Elf_Scn *section)
lto_elf_get_shdr (Elf_Scn *section)
{
{
  Elf64_Shdr *shdr;
  Elf64_Shdr *shdr;
 
 
  switch (cached_file_attrs.bits)
  switch (cached_file_attrs.bits)
    {
    {
    case 32:
    case 32:
      {
      {
        Elf32_Shdr *shdr32;
        Elf32_Shdr *shdr32;
 
 
        /* Read the 32-bit section header.  */
        /* Read the 32-bit section header.  */
        shdr32 = elf32_getshdr (section);
        shdr32 = elf32_getshdr (section);
        if (!shdr32)
        if (!shdr32)
          fatal_error ("could not read section header: %s", elf_errmsg (0));
          fatal_error ("could not read section header: %s", elf_errmsg (0));
 
 
        /* Transform it into a 64-bit section header.  */
        /* Transform it into a 64-bit section header.  */
        shdr = XNEW (Elf64_Shdr);
        shdr = XNEW (Elf64_Shdr);
        shdr->sh_name = shdr32->sh_name;
        shdr->sh_name = shdr32->sh_name;
        shdr->sh_type = shdr32->sh_type;
        shdr->sh_type = shdr32->sh_type;
        shdr->sh_flags = shdr32->sh_flags;
        shdr->sh_flags = shdr32->sh_flags;
        shdr->sh_addr = shdr32->sh_addr;
        shdr->sh_addr = shdr32->sh_addr;
        shdr->sh_offset = shdr32->sh_offset;
        shdr->sh_offset = shdr32->sh_offset;
        shdr->sh_size = shdr32->sh_size;
        shdr->sh_size = shdr32->sh_size;
        shdr->sh_link = shdr32->sh_link;
        shdr->sh_link = shdr32->sh_link;
        shdr->sh_info = shdr32->sh_info;
        shdr->sh_info = shdr32->sh_info;
        shdr->sh_addralign = shdr32->sh_addralign;
        shdr->sh_addralign = shdr32->sh_addralign;
        shdr->sh_entsize  = shdr32->sh_entsize;
        shdr->sh_entsize  = shdr32->sh_entsize;
        break;
        break;
      }
      }
      break;
      break;
 
 
    case 64:
    case 64:
      shdr = elf64_getshdr (section);
      shdr = elf64_getshdr (section);
      if (!shdr)
      if (!shdr)
        fatal_error ("could not read section header: %s", elf_errmsg (0));
        fatal_error ("could not read section header: %s", elf_errmsg (0));
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  return shdr;
  return shdr;
}
}
 
 
/* Free SHDR, previously allocated by lto_elf_get_shdr.  */
/* Free SHDR, previously allocated by lto_elf_get_shdr.  */
static void
static void
lto_elf_free_shdr (Elf64_Shdr *shdr)
lto_elf_free_shdr (Elf64_Shdr *shdr)
{
{
  if (cached_file_attrs.bits != 64)
  if (cached_file_attrs.bits != 64)
    free (shdr);
    free (shdr);
}
}
 
 
 
 
/* Returns a hash code for P.  */
/* Returns a hash code for P.  */
 
 
static hashval_t
static hashval_t
hash_name (const void *p)
hash_name (const void *p)
{
{
  const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
  const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
  return (hashval_t) htab_hash_string (ds->name);
  return (hashval_t) htab_hash_string (ds->name);
}
}
 
 
 
 
/* Returns nonzero if P1 and P2 are equal.  */
/* Returns nonzero if P1 and P2 are equal.  */
 
 
static int
static int
eq_name (const void *p1, const void *p2)
eq_name (const void *p1, const void *p2)
{
{
  const struct lto_section_slot *s1 =
  const struct lto_section_slot *s1 =
    (const struct lto_section_slot *) p1;
    (const struct lto_section_slot *) p1;
  const struct lto_section_slot *s2 =
  const struct lto_section_slot *s2 =
    (const struct lto_section_slot *) p2;
    (const struct lto_section_slot *) p2;
 
 
  return strcmp (s1->name, s2->name) == 0;
  return strcmp (s1->name, s2->name) == 0;
}
}
 
 
 
 
/* Build a hash table whose key is the section names and whose data is
/* 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.  */
   the start and size of each section in the .o file.  */
 
 
htab_t
htab_t
lto_obj_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;
  lto_elf_file *elf_file = (lto_elf_file *)lto_file;
  htab_t section_hash_table;
  htab_t section_hash_table;
  Elf_Scn *section;
  Elf_Scn *section;
  size_t base_offset;
  size_t base_offset;
 
 
  section_hash_table = htab_create (37, hash_name, eq_name, free);
  section_hash_table = htab_create (37, hash_name, eq_name, free);
 
 
  base_offset = elf_getbase (elf_file->elf);
  base_offset = elf_getbase (elf_file->elf);
  /* We are reasonably sure that elf_getbase does not fail at this
  /* We are reasonably sure that elf_getbase does not fail at this
     point.  So assume that we run into the incompatibility with
     point.  So assume that we run into the incompatibility with
     the FreeBSD libelf implementation that has a non-working
     the FreeBSD libelf implementation that has a non-working
     elf_getbase for non-archive members in which case the offset
     elf_getbase for non-archive members in which case the offset
     should be zero.  */
     should be zero.  */
  if (base_offset == (size_t)-1)
  if (base_offset == (size_t)-1)
    base_offset = 0;
    base_offset = 0;
  for (section = elf_getscn (elf_file->elf, 0);
  for (section = elf_getscn (elf_file->elf, 0);
       section;
       section;
       section = elf_nextscn (elf_file->elf, section))
       section = elf_nextscn (elf_file->elf, section))
    {
    {
      Elf64_Shdr *shdr;
      Elf64_Shdr *shdr;
      const char *name;
      const char *name;
      size_t offset;
      size_t offset;
      char *new_name;
      char *new_name;
      void **slot;
      void **slot;
      struct lto_section_slot s_slot;
      struct lto_section_slot s_slot;
 
 
      /* Get the name of this section.  */
      /* Get the name of this section.  */
      shdr = lto_elf_get_shdr (section);
      shdr = lto_elf_get_shdr (section);
      offset = shdr->sh_name;
      offset = shdr->sh_name;
      name = elf_strptr (elf_file->elf,
      name = elf_strptr (elf_file->elf,
                         elf_file->sec_strtab,
                         elf_file->sec_strtab,
                         offset);
                         offset);
 
 
      /* Only put lto stuff into the symtab.  */
      /* Only put lto stuff into the symtab.  */
      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
                   strlen (LTO_SECTION_NAME_PREFIX)) != 0)
                   strlen (LTO_SECTION_NAME_PREFIX)) != 0)
        {
        {
          lto_elf_free_shdr (shdr);
          lto_elf_free_shdr (shdr);
          continue;
          continue;
        }
        }
 
 
      new_name = XNEWVEC (char, strlen (name) + 1);
      new_name = XNEWVEC (char, strlen (name) + 1);
      strcpy (new_name, name);
      strcpy (new_name, name);
      s_slot.name = new_name;
      s_slot.name = new_name;
      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
      if (*slot == NULL)
      if (*slot == NULL)
        {
        {
          struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
          struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
 
 
          new_slot->name = new_name;
          new_slot->name = new_name;
          /* The offset into the file for this section.  */
          /* The offset into the file for this section.  */
          new_slot->start = base_offset + shdr->sh_offset;
          new_slot->start = base_offset + shdr->sh_offset;
          new_slot->len = shdr->sh_size;
          new_slot->len = shdr->sh_size;
          *slot = new_slot;
          *slot = new_slot;
        }
        }
      else
      else
        {
        {
          error ("two or more sections for %s:", new_name);
          error ("two or more sections for %s:", new_name);
          return NULL;
          return NULL;
        }
        }
 
 
      lto_elf_free_shdr (shdr);
      lto_elf_free_shdr (shdr);
    }
    }
 
 
  return section_hash_table;
  return section_hash_table;
}
}
 
 
 
 
/* Initialize the section header of section SCN.  SH_NAME is the section name
/* Initialize the section header of section SCN.  SH_NAME is the section name
   as an index into the section header string table.  SH_TYPE is the section
   as an index into the section header string table.  SH_TYPE is the section
   type, an SHT_* macro from libelf headers.  */
   type, an SHT_* macro from libelf headers.  */
 
 
#define DEFINE_INIT_SHDR(BITS)                                        \
#define DEFINE_INIT_SHDR(BITS)                                        \
static void                                                           \
static void                                                           \
init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type)        \
init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type)        \
{                                                                     \
{                                                                     \
  Elf##BITS##_Shdr *shdr;                                             \
  Elf##BITS##_Shdr *shdr;                                             \
                                                                      \
                                                                      \
  shdr = elf##BITS##_getshdr (scn);                                   \
  shdr = elf##BITS##_getshdr (scn);                                   \
  if (!shdr)                                                          \
  if (!shdr)                                                          \
    {                                                                 \
    {                                                                 \
      if (BITS == 32)                                                 \
      if (BITS == 32)                                                 \
        fatal_error ("elf32_getshdr() failed: %s", elf_errmsg (-1));  \
        fatal_error ("elf32_getshdr() failed: %s", elf_errmsg (-1));  \
      else                                                            \
      else                                                            \
        fatal_error ("elf64_getshdr() failed: %s", elf_errmsg (-1));  \
        fatal_error ("elf64_getshdr() failed: %s", elf_errmsg (-1));  \
    }                                                                 \
    }                                                                 \
                                                                      \
                                                                      \
  shdr->sh_name = sh_name;                                            \
  shdr->sh_name = sh_name;                                            \
  shdr->sh_type = sh_type;                                            \
  shdr->sh_type = sh_type;                                            \
  shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT;                  \
  shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT;                  \
  shdr->sh_flags = 0;                                                  \
  shdr->sh_flags = 0;                                                  \
  shdr->sh_entsize = 0;                                                \
  shdr->sh_entsize = 0;                                                \
}
}
 
 
DEFINE_INIT_SHDR (32)
DEFINE_INIT_SHDR (32)
DEFINE_INIT_SHDR (64)
DEFINE_INIT_SHDR (64)
 
 
static bool first_data_block;
static bool first_data_block;
 
 
/* Begin a new ELF section named NAME with type TYPE in the current output
/* Begin a new ELF section named NAME with type TYPE in the current output
   file.  TYPE is an SHT_* macro from the libelf headers.  */
   file.  TYPE is an SHT_* macro from the libelf headers.  */
 
 
static void
static void
lto_elf_begin_section_with_type (const char *name, size_t type)
lto_elf_begin_section_with_type (const char *name, size_t type)
{
{
  lto_elf_file *file;
  lto_elf_file *file;
  Elf_Scn *scn;
  Elf_Scn *scn;
  size_t sh_name;
  size_t sh_name;
 
 
  /* Grab the current output file and do some basic assertion checking.  */
  /* Grab the current output file and do some basic assertion checking.  */
  file = (lto_elf_file *) lto_get_current_out_file (),
  file = (lto_elf_file *) lto_get_current_out_file (),
  gcc_assert (file);
  gcc_assert (file);
  gcc_assert (file->elf);
  gcc_assert (file->elf);
  gcc_assert (!file->scn);
  gcc_assert (!file->scn);
 
 
  /* Create a new section.  */
  /* Create a new section.  */
  scn = elf_newscn (file->elf);
  scn = elf_newscn (file->elf);
  if (!scn)
  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;
  file->scn = scn;
 
 
  /* Add a string table entry and record the offset.  */
  /* Add a string table entry and record the offset.  */
  gcc_assert (file->shstrtab_stream);
  gcc_assert (file->shstrtab_stream);
  sh_name = file->shstrtab_stream->total_size;
  sh_name = file->shstrtab_stream->total_size;
  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
 
 
  /* Initialize the section header.  */
  /* Initialize the section header.  */
  switch (cached_file_attrs.bits)
  switch (cached_file_attrs.bits)
    {
    {
    case 32:
    case 32:
      init_shdr32 (scn, sh_name, type);
      init_shdr32 (scn, sh_name, type);
      break;
      break;
 
 
    case 64:
    case 64:
      init_shdr64 (scn, sh_name, type);
      init_shdr64 (scn, sh_name, type);
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  first_data_block = true;
  first_data_block = true;
}
}
 
 
 
 
/* Begin a new ELF section named NAME in the current output file.  */
/* Begin a new ELF section named NAME in the current output file.  */
 
 
void
void
lto_obj_begin_section (const char *name)
lto_obj_begin_section (const char *name)
{
{
  lto_elf_begin_section_with_type (name, SHT_PROGBITS);
  lto_elf_begin_section_with_type (name, SHT_PROGBITS);
}
}
 
 
 
 
/* Append DATA of length LEN to the current output section.  BASE is a pointer
/* Append DATA of length LEN to the current output section.  BASE is a pointer
   to the output page containing DATA.  It is freed once the output file has
   to the output page containing DATA.  It is freed once the output file has
   been written.  */
   been written.  */
 
 
void
void
lto_obj_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;
  lto_elf_file *file;
  Elf_Data *elf_data;
  Elf_Data *elf_data;
  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
 
 
  /* Grab the current output file and do some basic assertion checking.  */
  /* Grab the current output file and do some basic assertion checking.  */
  file = (lto_elf_file *) lto_get_current_out_file ();
  file = (lto_elf_file *) lto_get_current_out_file ();
  gcc_assert (file);
  gcc_assert (file);
  gcc_assert (file->scn);
  gcc_assert (file->scn);
 
 
  elf_data = elf_newdata (file->scn);
  elf_data = elf_newdata (file->scn);
  if (!elf_data)
  if (!elf_data)
    fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1));
    fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1));
 
 
  if (first_data_block)
  if (first_data_block)
    {
    {
      elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT;
      elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT;
      first_data_block = false;
      first_data_block = false;
    }
    }
  else
  else
    elf_data->d_align = 1;
    elf_data->d_align = 1;
  elf_data->d_buf = CONST_CAST (void *, data);
  elf_data->d_buf = CONST_CAST (void *, data);
  elf_data->d_off = 0LL;
  elf_data->d_off = 0LL;
  elf_data->d_size = len;
  elf_data->d_size = len;
  elf_data->d_type = ELF_T_BYTE;
  elf_data->d_type = ELF_T_BYTE;
  elf_data->d_version = EV_CURRENT;
  elf_data->d_version = EV_CURRENT;
 
 
  base->ptr = (char *)file->data;
  base->ptr = (char *)file->data;
  file->data = base;
  file->data = base;
}
}
 
 
 
 
/* End the current output section.  This just does some assertion checking
/* End the current output section.  This just does some assertion checking
   and sets the current output file's scn member to NULL.  */
   and sets the current output file's scn member to NULL.  */
 
 
void
void
lto_obj_end_section (void)
lto_obj_end_section (void)
{
{
  lto_elf_file *file;
  lto_elf_file *file;
 
 
  /* Grab the current output file and validate some basic assertions.  */
  /* Grab the current output file and validate some basic assertions.  */
  file = (lto_elf_file *) lto_get_current_out_file ();
  file = (lto_elf_file *) lto_get_current_out_file ();
  gcc_assert (file);
  gcc_assert (file);
  gcc_assert (file->scn);
  gcc_assert (file->scn);
 
 
  file->scn = NULL;
  file->scn = NULL;
}
}
 
 
 
 
/* Return true if ELF_MACHINE is compatible with the cached value of the
/* 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
   Note: if you want to add more EM_* cases, you'll need to provide the
   corresponding definitions at the beginning of the file.  */
   corresponding definitions at the beginning of the file.  */
 
 
static bool
static bool
is_compatible_architecture (Elf64_Half elf_machine)
is_compatible_architecture (Elf64_Half elf_machine)
{
{
  if (cached_file_attrs.elf_machine == elf_machine)
  if (cached_file_attrs.elf_machine == elf_machine)
    return true;
    return true;
 
 
  switch (cached_file_attrs.elf_machine)
  switch (cached_file_attrs.elf_machine)
    {
    {
    case EM_SPARC:
    case EM_SPARC:
      if (elf_machine == EM_SPARC32PLUS)
      if (elf_machine == EM_SPARC32PLUS)
        {
        {
          cached_file_attrs.elf_machine = elf_machine;
          cached_file_attrs.elf_machine = elf_machine;
          return true;
          return true;
        }
        }
      break;
      break;
 
 
    case EM_SPARC32PLUS:
    case EM_SPARC32PLUS:
      if (elf_machine == EM_SPARC)
      if (elf_machine == EM_SPARC)
        return true;
        return true;
      break;
      break;
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  return false;
  return false;
}
}
 
 
 
 
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
   uninitialized, caches the architecture.  */
   uninitialized, caches the architecture.  */
 
 
#define DEFINE_VALIDATE_EHDR(BITS)                              \
#define DEFINE_VALIDATE_EHDR(BITS)                              \
static bool                                                     \
static bool                                                     \
validate_ehdr##BITS (lto_elf_file *elf_file)                    \
validate_ehdr##BITS (lto_elf_file *elf_file)                    \
{                                                               \
{                                                               \
  Elf##BITS##_Ehdr *elf_header;                                 \
  Elf##BITS##_Ehdr *elf_header;                                 \
                                                                \
                                                                \
  elf_header = elf##BITS##_getehdr (elf_file->elf);             \
  elf_header = elf##BITS##_getehdr (elf_file->elf);             \
  if (!elf_header)                                              \
  if (!elf_header)                                              \
    {                                                           \
    {                                                           \
      error ("could not read ELF header: %s", elf_errmsg (0));   \
      error ("could not read ELF header: %s", elf_errmsg (0));   \
      return false;                                             \
      return false;                                             \
    }                                                           \
    }                                                           \
                                                                \
                                                                \
  if (elf_header->e_type != ET_REL)                             \
  if (elf_header->e_type != ET_REL)                             \
    {                                                           \
    {                                                           \
      error ("not a relocatable ELF object file");              \
      error ("not a relocatable ELF object file");              \
      return false;                                             \
      return false;                                             \
    }                                                           \
    }                                                           \
                                                                \
                                                                \
  if (!cached_file_attrs.initialized)                           \
  if (!cached_file_attrs.initialized)                           \
    cached_file_attrs.elf_machine = elf_header->e_machine;      \
    cached_file_attrs.elf_machine = elf_header->e_machine;      \
  else if (!is_compatible_architecture (elf_header->e_machine)) \
  else if (!is_compatible_architecture (elf_header->e_machine)) \
    {                                                           \
    {                                                           \
      error ("inconsistent file architecture detected");        \
      error ("inconsistent file architecture detected");        \
      return false;                                             \
      return false;                                             \
    }                                                           \
    }                                                           \
                                                                \
                                                                \
  return true;                                                  \
  return true;                                                  \
}
}
 
 
DEFINE_VALIDATE_EHDR (32)
DEFINE_VALIDATE_EHDR (32)
DEFINE_VALIDATE_EHDR (64)
DEFINE_VALIDATE_EHDR (64)
 
 
 
 
#ifndef HAVE_ELF_GETSHDRSTRNDX
#ifndef HAVE_ELF_GETSHDRSTRNDX
/* elf_getshdrstrndx replacement for systems that lack it, but provide
/* elf_getshdrstrndx replacement for systems that lack it, but provide
   either the gABI conformant or Solaris 2 variant of elf_getshstrndx
   either the gABI conformant or Solaris 2 variant of elf_getshstrndx
   instead.  */
   instead.  */
 
 
static int
static int
elf_getshdrstrndx (Elf *elf, size_t *dst)
elf_getshdrstrndx (Elf *elf, size_t *dst)
{
{
#ifdef HAVE_ELF_GETSHSTRNDX_GABI
#ifdef HAVE_ELF_GETSHSTRNDX_GABI
  return elf_getshstrndx (elf, dst);
  return elf_getshstrndx (elf, dst);
#else
#else
  return elf_getshstrndx (elf, dst) ? 0 : -1;
  return elf_getshstrndx (elf, dst) ? 0 : -1;
#endif
#endif
}
}
#endif
#endif
 
 
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
   uninitialized, caches the results.  Also records the section header string
   uninitialized, caches the results.  Also records the section header string
   table's section index.  Returns true on success or false on failure.  */
   table's section index.  Returns true on success or false on failure.  */
 
 
static bool
static bool
validate_file (lto_elf_file *elf_file)
validate_file (lto_elf_file *elf_file)
{
{
  const char *elf_ident;
  const char *elf_ident;
 
 
  /* Some aspects of the libelf API are dependent on whether the
  /* Some aspects of the libelf API are dependent on whether the
     object file is a 32-bit or 64-bit file.  Determine which kind of
     object file is a 32-bit or 64-bit file.  Determine which kind of
     file this is now.  */
     file this is now.  */
  elf_ident = elf_getident (elf_file->elf, NULL);
  elf_ident = elf_getident (elf_file->elf, NULL);
  if (!elf_ident)
  if (!elf_ident)
    {
    {
      error ("could not read ELF identification information: %s",
      error ("could not read ELF identification information: %s",
              elf_errmsg (0));
              elf_errmsg (0));
      return false;
      return false;
 
 
    }
    }
 
 
  if (!cached_file_attrs.initialized)
  if (!cached_file_attrs.initialized)
    {
    {
      switch (elf_ident[EI_CLASS])
      switch (elf_ident[EI_CLASS])
        {
        {
        case ELFCLASS32:
        case ELFCLASS32:
          cached_file_attrs.bits = 32;
          cached_file_attrs.bits = 32;
          break;
          break;
 
 
        case ELFCLASS64:
        case ELFCLASS64:
          cached_file_attrs.bits = 64;
          cached_file_attrs.bits = 64;
          break;
          break;
 
 
        default:
        default:
          error ("unsupported ELF file class");
          error ("unsupported ELF file class");
          return false;
          return false;
        }
        }
 
 
      memcpy (cached_file_attrs.elf_ident, elf_ident,
      memcpy (cached_file_attrs.elf_ident, elf_ident,
              sizeof cached_file_attrs.elf_ident);
              sizeof cached_file_attrs.elf_ident);
    }
    }
 
 
  if (memcmp (elf_ident, cached_file_attrs.elf_ident,
  if (memcmp (elf_ident, cached_file_attrs.elf_ident,
              sizeof cached_file_attrs.elf_ident))
              sizeof cached_file_attrs.elf_ident))
    return false;
    return false;
 
 
  /* Check that the input file is a relocatable object file with the correct
  /* Check that the input file is a relocatable object file with the correct
     architecture.  */
     architecture.  */
  switch (cached_file_attrs.bits)
  switch (cached_file_attrs.bits)
    {
    {
    case 32:
    case 32:
      if (!validate_ehdr32 (elf_file))
      if (!validate_ehdr32 (elf_file))
        return false;
        return false;
      break;
      break;
 
 
    case 64:
    case 64:
      if (!validate_ehdr64 (elf_file))
      if (!validate_ehdr64 (elf_file))
        return false;
        return false;
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  /* Read the string table used for section header names.  */
  /* Read the string table used for section header names.  */
  if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
  if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
    {
    {
      error ("could not locate ELF string table: %s", elf_errmsg (0));
      error ("could not locate ELF string table: %s", elf_errmsg (0));
      return false;
      return false;
    }
    }
 
 
  cached_file_attrs.initialized = true;
  cached_file_attrs.initialized = true;
  return true;
  return true;
}
}
 
 
 
 
/* Helper functions used by init_ehdr.  Initialize ELF_FILE's executable
/* Helper functions used by init_ehdr.  Initialize ELF_FILE's executable
   header using cached data from previously read files.  */
   header using cached data from previously read files.  */
 
 
#define DEFINE_INIT_EHDR(BITS)                                        \
#define DEFINE_INIT_EHDR(BITS)                                        \
static void                                                           \
static void                                                           \
init_ehdr##BITS (lto_elf_file *elf_file)                              \
init_ehdr##BITS (lto_elf_file *elf_file)                              \
{                                                                     \
{                                                                     \
  Elf##BITS##_Ehdr *ehdr;                                             \
  Elf##BITS##_Ehdr *ehdr;                                             \
                                                                      \
                                                                      \
  gcc_assert (cached_file_attrs.bits);                                \
  gcc_assert (cached_file_attrs.bits);                                \
                                                                      \
                                                                      \
  ehdr = elf##BITS##_newehdr (elf_file->elf);                         \
  ehdr = elf##BITS##_newehdr (elf_file->elf);                         \
  if (!ehdr)                                                          \
  if (!ehdr)                                                          \
    {                                                                 \
    {                                                                 \
      if (BITS == 32)                                                 \
      if (BITS == 32)                                                 \
        fatal_error ("elf32_newehdr() failed: %s", elf_errmsg (-1));  \
        fatal_error ("elf32_newehdr() failed: %s", elf_errmsg (-1));  \
      else                                                            \
      else                                                            \
        fatal_error ("elf64_newehdr() failed: %s", elf_errmsg (-1));  \
        fatal_error ("elf64_newehdr() failed: %s", elf_errmsg (-1));  \
    }                                                                 \
    }                                                                 \
                                                                      \
                                                                      \
  memcpy (ehdr->e_ident, cached_file_attrs.elf_ident,                 \
  memcpy (ehdr->e_ident, cached_file_attrs.elf_ident,                 \
          sizeof cached_file_attrs.elf_ident);                        \
          sizeof cached_file_attrs.elf_ident);                        \
  ehdr->e_type = ET_REL;                                              \
  ehdr->e_type = ET_REL;                                              \
  ehdr->e_version = EV_CURRENT;                                       \
  ehdr->e_version = EV_CURRENT;                                       \
  ehdr->e_machine = cached_file_attrs.elf_machine;                    \
  ehdr->e_machine = cached_file_attrs.elf_machine;                    \
}
}
 
 
DEFINE_INIT_EHDR (32)
DEFINE_INIT_EHDR (32)
DEFINE_INIT_EHDR (64)
DEFINE_INIT_EHDR (64)
 
 
 
 
/* Initialize ELF_FILE's executable header using cached data from previously
/* Initialize ELF_FILE's executable header using cached data from previously
   read files.  */
   read files.  */
 
 
static void
static void
init_ehdr (lto_elf_file *elf_file)
init_ehdr (lto_elf_file *elf_file)
{
{
  switch (cached_file_attrs.bits)
  switch (cached_file_attrs.bits)
    {
    {
    case 32:
    case 32:
      init_ehdr32 (elf_file);
      init_ehdr32 (elf_file);
      break;
      break;
 
 
    case 64:
    case 64:
      init_ehdr64 (elf_file);
      init_ehdr64 (elf_file);
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
}
}
 
 
/* Open ELF file FILENAME.  If WRITABLE is true, the file is opened for write
/* 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.
   and, if necessary, created.  Otherwise, the file is opened for reading.
   Returns the opened file.  */
   Returns the opened file.  */
 
 
lto_file *
lto_file *
lto_obj_file_open (const char *filename, bool writable)
lto_obj_file_open (const char *filename, bool writable)
{
{
  lto_elf_file *elf_file;
  lto_elf_file *elf_file;
  lto_file *result = NULL;
  lto_file *result = NULL;
  off_t offset;
  off_t offset;
  long loffset;
  long loffset;
  off_t header_offset;
  off_t header_offset;
  const char *offset_p;
  const char *offset_p;
  char *fname;
  char *fname;
  int consumed;
  int consumed;
 
 
  offset_p = strrchr (filename, '@');
  offset_p = strrchr (filename, '@');
  if (offset_p
  if (offset_p
      && offset_p != filename
      && offset_p != filename
      && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
      && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
      && strlen (offset_p) == (unsigned int)consumed)
      && strlen (offset_p) == (unsigned int)consumed)
    {
    {
      fname = (char *) xmalloc (offset_p - filename + 1);
      fname = (char *) xmalloc (offset_p - filename + 1);
      memcpy (fname, filename, offset_p - filename);
      memcpy (fname, filename, offset_p - filename);
      fname[offset_p - filename] = '\0';
      fname[offset_p - filename] = '\0';
      offset = (off_t)loffset;
      offset = (off_t)loffset;
      /* elf_rand expects the offset to point to the ar header, not the
      /* elf_rand expects the offset to point to the ar header, not the
         object itself. Subtract the size of the ar header (60 bytes).
         object itself. Subtract the size of the ar header (60 bytes).
         We don't uses sizeof (struct ar_hd) to avoid including ar.h */
         We don't uses sizeof (struct ar_hd) to avoid including ar.h */
      header_offset = offset - 60;
      header_offset = offset - 60;
    }
    }
  else
  else
    {
    {
      fname = xstrdup (filename);
      fname = xstrdup (filename);
      offset = 0;
      offset = 0;
      header_offset = 0;
      header_offset = 0;
    }
    }
 
 
  /* Set up.  */
  /* Set up.  */
  elf_file = XCNEW (lto_elf_file);
  elf_file = XCNEW (lto_elf_file);
  result = (lto_file *) elf_file;
  result = (lto_file *) elf_file;
  lto_file_init (result, fname, offset);
  lto_file_init (result, fname, offset);
  elf_file->fd = -1;
  elf_file->fd = -1;
 
 
  /* Open the file.  */
  /* Open the file.  */
  elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT|O_BINARY
  elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT|O_BINARY
                                       : O_RDONLY|O_BINARY, 0666);
                                       : O_RDONLY|O_BINARY, 0666);
  if (elf_file->fd == -1)
  if (elf_file->fd == -1)
    {
    {
      error ("could not open file %s", fname);
      error ("could not open file %s", fname);
      goto fail;
      goto fail;
    }
    }
 
 
  /* Initialize the ELF library.  */
  /* Initialize the ELF library.  */
  if (elf_version (EV_CURRENT) == EV_NONE)
  if (elf_version (EV_CURRENT) == EV_NONE)
    {
    {
      error ("ELF library is older than that used when building GCC");
      error ("ELF library is older than that used when building GCC");
      goto fail;
      goto fail;
    }
    }
 
 
  /* Open the ELF file descriptor.  */
  /* Open the ELF file descriptor.  */
  elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ,
  elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ,
                             NULL);
                             NULL);
  if (!elf_file->elf)
  if (!elf_file->elf)
    {
    {
      error ("could not open ELF file: %s", elf_errmsg (0));
      error ("could not open ELF file: %s", elf_errmsg (0));
      goto fail;
      goto fail;
    }
    }
 
 
  if (offset != 0)
  if (offset != 0)
    {
    {
      Elf *e;
      Elf *e;
      off_t t = elf_rand (elf_file->elf, header_offset);
      off_t t = elf_rand (elf_file->elf, header_offset);
      if (t != header_offset)
      if (t != header_offset)
        {
        {
          error ("could not seek in archive");
          error ("could not seek in archive");
          goto fail;
          goto fail;
        }
        }
 
 
      e = elf_begin (elf_file->fd, ELF_C_READ, elf_file->elf);
      e = elf_begin (elf_file->fd, ELF_C_READ, elf_file->elf);
      if (e == NULL)
      if (e == NULL)
        {
        {
          error("could not find archive member");
          error("could not find archive member");
          goto fail;
          goto fail;
        }
        }
      elf_end (elf_file->elf);
      elf_end (elf_file->elf);
      elf_file->elf = e;
      elf_file->elf = e;
    }
    }
 
 
  if (writable)
  if (writable)
    {
    {
      init_ehdr (elf_file);
      init_ehdr (elf_file);
      elf_file->shstrtab_stream = XCNEW (struct lto_output_stream);
      elf_file->shstrtab_stream = XCNEW (struct lto_output_stream);
      /* Output an empty string to the section header table.  This becomes the
      /* Output an empty string to the section header table.  This becomes the
         name of the initial NULL section.  */
         name of the initial NULL section.  */
      lto_output_1_stream (elf_file->shstrtab_stream, '\0');
      lto_output_1_stream (elf_file->shstrtab_stream, '\0');
    }
    }
  else
  else
    if (!validate_file (elf_file))
    if (!validate_file (elf_file))
      goto fail;
      goto fail;
 
 
  return result;
  return result;
 
 
 fail:
 fail:
  if (result)
  if (result)
    lto_obj_file_close (result);
    lto_obj_file_close (result);
  return NULL;
  return NULL;
}
}
 
 
 
 
/* Close ELF file FILE and clean up any associated data structures.  If FILE
/* Close ELF file FILE and clean up any associated data structures.  If FILE
   was opened for writing, the file's ELF data is written at this time, and
   was opened for writing, the file's ELF data is written at this time, and
   any cached data buffers are freed.  */
   any cached data buffers are freed.  */
 
 
void
void
lto_obj_file_close (lto_file *file)
lto_obj_file_close (lto_file *file)
{
{
  lto_elf_file *elf_file = (lto_elf_file *) file;
  lto_elf_file *elf_file = (lto_elf_file *) file;
  struct lto_char_ptr_base *cur, *tmp;
  struct lto_char_ptr_base *cur, *tmp;
 
 
  /* Write the ELF section header string table.  */
  /* Write the ELF section header string table.  */
  if (elf_file->shstrtab_stream)
  if (elf_file->shstrtab_stream)
    {
    {
      size_t strtab;
      size_t strtab;
      GElf_Ehdr *ehdr_p, ehdr_buf;
      GElf_Ehdr *ehdr_p, ehdr_buf;
      lto_file *old_file = lto_set_current_out_file (file);
      lto_file *old_file = lto_set_current_out_file (file);
 
 
      lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
      lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
      ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf);
      ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf);
      if (ehdr_p == NULL)
      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);
      strtab = elf_ndxscn (elf_file->scn);
      if (strtab < SHN_LORESERVE)
      if (strtab < SHN_LORESERVE)
        ehdr_p->e_shstrndx = strtab;
        ehdr_p->e_shstrndx = strtab;
      else
      else
        {
        {
          GElf_Shdr *shdr_p, shdr_buf;
          GElf_Shdr *shdr_p, shdr_buf;
          Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0);
          Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0);
          if (scn_p == NULL)
          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);
          shdr_p = gelf_getshdr (scn_p, &shdr_buf);
          if (shdr_p == NULL)
          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;
          shdr_p->sh_link = strtab;
          if (gelf_update_shdr (scn_p, shdr_p) == 0)
          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;
          ehdr_p->e_shstrndx = SHN_XINDEX;
        }
        }
      if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0)
      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_write_stream (elf_file->shstrtab_stream);
      lto_obj_end_section ();
      lto_obj_end_section ();
 
 
      lto_set_current_out_file (old_file);
      lto_set_current_out_file (old_file);
      free (elf_file->shstrtab_stream);
      free (elf_file->shstrtab_stream);
 
 
      if (elf_update (elf_file->elf, ELF_C_WRITE) < 0)
      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)
  if (elf_file->elf)
    elf_end (elf_file->elf);
    elf_end (elf_file->elf);
  if (elf_file->fd != -1)
  if (elf_file->fd != -1)
    close (elf_file->fd);
    close (elf_file->fd);
 
 
  /* Free any ELF data buffers.  */
  /* Free any ELF data buffers.  */
  cur = elf_file->data;
  cur = elf_file->data;
  while (cur)
  while (cur)
    {
    {
      tmp = cur;
      tmp = cur;
      cur = (struct lto_char_ptr_base *) cur->ptr;
      cur = (struct lto_char_ptr_base *) cur->ptr;
      free (tmp);
      free (tmp);
    }
    }
 
 
  free (file);
  free (file);
}
}
 
 
 
 
/* The current output file.  */
/* The current output file.  */
static lto_file *current_out_file;
static lto_file *current_out_file;
 
 
 
 
/* Sets the current output file to FILE.  Returns the old output file or
/* Sets the current output file to FILE.  Returns the old output file or
   NULL.  */
   NULL.  */
 
 
lto_file *
lto_file *
lto_set_current_out_file (lto_file *file)
lto_set_current_out_file (lto_file *file)
{
{
  lto_file *old_file = current_out_file;
  lto_file *old_file = current_out_file;
  current_out_file = file;
  current_out_file = file;
  return old_file;
  return old_file;
}
}
 
 
 
 
/* Returns the current output file.  */
/* Returns the current output file.  */
 
 
lto_file *
lto_file *
lto_get_current_out_file (void)
lto_get_current_out_file (void)
{
{
  return current_out_file;
  return current_out_file;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.