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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [lto-plugin/] [lto-plugin.c] - Diff between revs 816 and 826

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* LTO plugin for gold.
/* LTO plugin for gold.
   Copyright (C) 2009 Free Software Foundation, Inc.
   Copyright (C) 2009 Free Software Foundation, Inc.
   Contributed by Rafael Avila de Espindola (espindola@google.com).
   Contributed by Rafael Avila de Espindola (espindola@google.com).
 
 
This program is free software; you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
the Free Software Foundation; either version 3, or (at your option)
any later version.
any later version.
 
 
This program is distributed in the hope that it will be useful, but
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
General Public License 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 this program; see the file COPYING3.  If not see
along with this program; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
/* The plugin has only one external function: onload. Gold passes it an array of
/* The plugin has only one external function: onload. Gold passes it an array of
   function that the plugin uses to communicate back to gold.
   function that the plugin uses to communicate back to gold.
 
 
   With the functions provided by gold, the plugin can be notified when
   With the functions provided by gold, the plugin can be notified when
   gold first analyzes a file and pass a symbol table back to gold. The plugin
   gold first analyzes a file and pass a symbol table back to gold. The plugin
   is also notified when all symbols have been read and it is time to generate
   is also notified when all symbols have been read and it is time to generate
   machine code for the necessary symbols.
   machine code for the necessary symbols.
 
 
   More information at http://gcc.gnu.org/wiki/whopr/driver.
   More information at http://gcc.gnu.org/wiki/whopr/driver.
 
 
   This plugin should be passed the lto-wrapper options and will forward them.
   This plugin should be passed the lto-wrapper options and will forward them.
   It also has 2 options of its own:
   It also has 2 options of its own:
   -debug: Print the command line used to run lto-wrapper.
   -debug: Print the command line used to run lto-wrapper.
   -nop: Instead of running lto-wrapper, pass the original to the plugin. This
   -nop: Instead of running lto-wrapper, pass the original to the plugin. This
   only works if the input files are hybrid.  */
   only works if the input files are hybrid.  */
 
 
#include <assert.h>
#include <assert.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <inttypes.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <unistd.h>
#include <unistd.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <stdbool.h>
#include <libiberty.h>
#include <libiberty.h>
 
 
/* The presence of gelf.h is checked by the toplevel configure script.  */
/* The presence of gelf.h is checked by the toplevel configure script.  */
#include <gelf.h>
#include <gelf.h>
 
 
#include "plugin-api.h"
#include "plugin-api.h"
#include "../gcc/lto/common.h"
#include "../gcc/lto/common.h"
 
 
/* The part of the symbol table the plugin has to keep track of. Note that we
/* The part of the symbol table the plugin has to keep track of. Note that we
   must keep SYMS until all_symbols_read is called to give the linker time to
   must keep SYMS until all_symbols_read is called to give the linker time to
   copy the symbol information. */
   copy the symbol information. */
 
 
struct plugin_symtab
struct plugin_symtab
{
{
  int nsyms;
  int nsyms;
  uint32_t *slots;
  uint32_t *slots;
  struct ld_plugin_symbol *syms;
  struct ld_plugin_symbol *syms;
};
};
 
 
/* All that we have to remember about a file. */
/* All that we have to remember about a file. */
 
 
struct plugin_file_info
struct plugin_file_info
{
{
  char *name;
  char *name;
  void *handle;
  void *handle;
  struct plugin_symtab symtab;
  struct plugin_symtab symtab;
};
};
 
 
 
 
static char *arguments_file_name;
static char *arguments_file_name;
static ld_plugin_register_claim_file register_claim_file;
static ld_plugin_register_claim_file register_claim_file;
static ld_plugin_add_symbols add_symbols;
static ld_plugin_add_symbols add_symbols;
static ld_plugin_register_all_symbols_read register_all_symbols_read;
static ld_plugin_register_all_symbols_read register_all_symbols_read;
static ld_plugin_get_symbols get_symbols;
static ld_plugin_get_symbols get_symbols;
static ld_plugin_register_cleanup register_cleanup;
static ld_plugin_register_cleanup register_cleanup;
static ld_plugin_add_input_file add_input_file;
static ld_plugin_add_input_file add_input_file;
static ld_plugin_add_input_library add_input_library;
static ld_plugin_add_input_library add_input_library;
static ld_plugin_message message;
static ld_plugin_message message;
 
 
static struct plugin_file_info *claimed_files = NULL;
static struct plugin_file_info *claimed_files = NULL;
static unsigned int num_claimed_files = 0;
static unsigned int num_claimed_files = 0;
 
 
static char **output_files = NULL;
static char **output_files = NULL;
static unsigned int num_output_files = 0;
static unsigned int num_output_files = 0;
 
 
static char **lto_wrapper_argv;
static char **lto_wrapper_argv;
static int lto_wrapper_num_args;
static int lto_wrapper_num_args;
 
 
static char **pass_through_items = NULL;
static char **pass_through_items = NULL;
static unsigned int num_pass_through_items;
static unsigned int num_pass_through_items;
 
 
static bool debug;
static bool debug;
static bool nop;
static bool nop;
static char *resolution_file = NULL;
static char *resolution_file = NULL;
 
 
static void
static void
check (bool gate, enum ld_plugin_level level, const char *text)
check (bool gate, enum ld_plugin_level level, const char *text)
{
{
  if (gate)
  if (gate)
    return;
    return;
 
 
  if (message)
  if (message)
    message (level, text);
    message (level, text);
  else
  else
    {
    {
      /* If there is no nicer way to inform the user, fallback to stderr. */
      /* If there is no nicer way to inform the user, fallback to stderr. */
      fprintf (stderr, "%s\n", text);
      fprintf (stderr, "%s\n", text);
      if (level == LDPL_FATAL)
      if (level == LDPL_FATAL)
        abort ();
        abort ();
    }
    }
}
}
 
 
/* Parse an entry of the IL symbol table. The data to be parsed is pointed
/* Parse an entry of the IL symbol table. The data to be parsed is pointed
   by P and the result is written in ENTRY. The slot number is stored in SLOT.
   by P and the result is written in ENTRY. The slot number is stored in SLOT.
   Returns the address of the next entry. */
   Returns the address of the next entry. */
 
 
static char *
static char *
parse_table_entry (char *p, struct ld_plugin_symbol *entry, uint32_t *slot)
parse_table_entry (char *p, struct ld_plugin_symbol *entry, uint32_t *slot)
{
{
  unsigned char t;
  unsigned char t;
  enum ld_plugin_symbol_kind translate_kind[] =
  enum ld_plugin_symbol_kind translate_kind[] =
    {
    {
      LDPK_DEF,
      LDPK_DEF,
      LDPK_WEAKDEF,
      LDPK_WEAKDEF,
      LDPK_UNDEF,
      LDPK_UNDEF,
      LDPK_WEAKUNDEF,
      LDPK_WEAKUNDEF,
      LDPK_COMMON
      LDPK_COMMON
    };
    };
 
 
  enum ld_plugin_symbol_visibility translate_visibility[] =
  enum ld_plugin_symbol_visibility translate_visibility[] =
    {
    {
      LDPV_DEFAULT,
      LDPV_DEFAULT,
      LDPV_PROTECTED,
      LDPV_PROTECTED,
      LDPV_INTERNAL,
      LDPV_INTERNAL,
      LDPV_HIDDEN
      LDPV_HIDDEN
    };
    };
 
 
  entry->name = strdup (p);
  entry->name = strdup (p);
  while (*p)
  while (*p)
    p++;
    p++;
  p++;
  p++;
 
 
  entry->version = NULL;
  entry->version = NULL;
 
 
  entry->comdat_key = p;
  entry->comdat_key = p;
  while (*p)
  while (*p)
    p++;
    p++;
  p++;
  p++;
 
 
  if (strlen (entry->comdat_key) == 0)
  if (strlen (entry->comdat_key) == 0)
    entry->comdat_key = NULL;
    entry->comdat_key = NULL;
  else
  else
    entry->comdat_key = strdup (entry->comdat_key);
    entry->comdat_key = strdup (entry->comdat_key);
 
 
  t = *p;
  t = *p;
  check (t <= 4, LDPL_FATAL, "invalid symbol kind found");
  check (t <= 4, LDPL_FATAL, "invalid symbol kind found");
  entry->def = translate_kind[t];
  entry->def = translate_kind[t];
  p++;
  p++;
 
 
  t = *p;
  t = *p;
  check (t <= 3, LDPL_FATAL, "invalid symbol visibility found");
  check (t <= 3, LDPL_FATAL, "invalid symbol visibility found");
  entry->visibility = translate_visibility[t];
  entry->visibility = translate_visibility[t];
  p++;
  p++;
 
 
  entry->size = *(uint64_t *) p;
  entry->size = *(uint64_t *) p;
  p += 8;
  p += 8;
 
 
  *slot = *(uint32_t *) p;
  *slot = *(uint32_t *) p;
  p += 4;
  p += 4;
 
 
  entry->resolution = LDPR_UNKNOWN;
  entry->resolution = LDPR_UNKNOWN;
 
 
  return p;
  return p;
}
}
 
 
/* Return the section in ELF that is named NAME. */
/* Return the section in ELF that is named NAME. */
 
 
static Elf_Scn *
static Elf_Scn *
get_section (Elf *elf, const char *name)
get_section (Elf *elf, const char *name)
{
{
  Elf_Scn *section = 0;
  Elf_Scn *section = 0;
  GElf_Ehdr header;
  GElf_Ehdr header;
  GElf_Ehdr *t = gelf_getehdr (elf, &header);
  GElf_Ehdr *t = gelf_getehdr (elf, &header);
  if (t == NULL)
  if (t == NULL)
    return NULL;
    return NULL;
  assert (t == &header);
  assert (t == &header);
 
 
  while ((section = elf_nextscn(elf, section)) != 0)
  while ((section = elf_nextscn(elf, section)) != 0)
    {
    {
      GElf_Shdr shdr;
      GElf_Shdr shdr;
      GElf_Shdr *tshdr = gelf_getshdr (section, &shdr);
      GElf_Shdr *tshdr = gelf_getshdr (section, &shdr);
      const char *t;
      const char *t;
      assert (tshdr == &shdr);
      assert (tshdr == &shdr);
      t = elf_strptr (elf, header.e_shstrndx, shdr.sh_name);
      t = elf_strptr (elf, header.e_shstrndx, shdr.sh_name);
      assert (t != NULL);
      assert (t != NULL);
      if (strcmp (t, name) == 0)
      if (strcmp (t, name) == 0)
        return section;
        return section;
    }
    }
  return NULL;
  return NULL;
}
}
 
 
/* Returns the IL symbol table of file ELF. */
/* Returns the IL symbol table of file ELF. */
 
 
static Elf_Data *
static Elf_Data *
get_symtab (Elf *elf)
get_symtab (Elf *elf)
{
{
  Elf_Data *data = 0;
  Elf_Data *data = 0;
  Elf_Scn *section = get_section (elf, ".gnu.lto_.symtab");
  Elf_Scn *section = get_section (elf, ".gnu.lto_.symtab");
  if (!section)
  if (!section)
    return NULL;
    return NULL;
 
 
  data = elf_getdata (section, data);
  data = elf_getdata (section, data);
  assert (data);
  assert (data);
  return data;
  return data;
}
}
 
 
/* Translate the IL symbol table SYMTAB. Write the slots and symbols in OUT. */
/* Translate the IL symbol table SYMTAB. Write the slots and symbols in OUT. */
 
 
static void
static void
translate (Elf_Data *symtab, struct plugin_symtab *out)
translate (Elf_Data *symtab, struct plugin_symtab *out)
{
{
  uint32_t *slots = NULL;
  uint32_t *slots = NULL;
  char *data = symtab->d_buf;
  char *data = symtab->d_buf;
  char *end = data + symtab->d_size;
  char *end = data + symtab->d_size;
  struct ld_plugin_symbol *syms = NULL;
  struct ld_plugin_symbol *syms = NULL;
  int n = 0;
  int n = 0;
 
 
  while (data < end)
  while (data < end)
    {
    {
      n++;
      n++;
      syms = realloc (syms, n * sizeof (struct ld_plugin_symbol));
      syms = realloc (syms, n * sizeof (struct ld_plugin_symbol));
      check (syms, LDPL_FATAL, "could not allocate memory");
      check (syms, LDPL_FATAL, "could not allocate memory");
      slots = realloc (slots, n * sizeof (uint32_t));
      slots = realloc (slots, n * sizeof (uint32_t));
      check (slots, LDPL_FATAL, "could not allocate memory");
      check (slots, LDPL_FATAL, "could not allocate memory");
      data = parse_table_entry (data, &syms[n - 1], &slots[n - 1]);
      data = parse_table_entry (data, &syms[n - 1], &slots[n - 1]);
    }
    }
 
 
  out->nsyms = n;
  out->nsyms = n;
  out->syms = syms;
  out->syms = syms;
  out->slots = slots;
  out->slots = slots;
}
}
 
 
/* Free all memory that is no longer needed after writing the symbol
/* Free all memory that is no longer needed after writing the symbol
   resolution. */
   resolution. */
 
 
static void
static void
free_1 (void)
free_1 (void)
{
{
  unsigned int i;
  unsigned int i;
  for (i = 0; i < num_claimed_files; i++)
  for (i = 0; i < num_claimed_files; i++)
    {
    {
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_symtab *symtab = &info->symtab;
      struct plugin_symtab *symtab = &info->symtab;
      unsigned int j;
      unsigned int j;
      for (j = 0; j < symtab->nsyms; j++)
      for (j = 0; j < symtab->nsyms; j++)
        {
        {
          struct ld_plugin_symbol *s = &symtab->syms[j];
          struct ld_plugin_symbol *s = &symtab->syms[j];
          free (s->name);
          free (s->name);
          if (s->comdat_key)
          if (s->comdat_key)
            free (s->comdat_key);
            free (s->comdat_key);
        }
        }
      free (symtab->syms);
      free (symtab->syms);
      symtab->syms = NULL;
      symtab->syms = NULL;
    }
    }
}
}
 
 
/* Free all remaining memory. */
/* Free all remaining memory. */
 
 
static void
static void
free_2 (void)
free_2 (void)
{
{
  unsigned int i;
  unsigned int i;
  for (i = 0; i < num_claimed_files; i++)
  for (i = 0; i < num_claimed_files; i++)
    {
    {
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_symtab *symtab = &info->symtab;
      struct plugin_symtab *symtab = &info->symtab;
      free (symtab->slots);
      free (symtab->slots);
      free (info->name);
      free (info->name);
    }
    }
 
 
  for (i = 0; i < num_output_files; i++)
  for (i = 0; i < num_output_files; i++)
    free (output_files[i]);
    free (output_files[i]);
  free (output_files);
  free (output_files);
 
 
  free (claimed_files);
  free (claimed_files);
  claimed_files = NULL;
  claimed_files = NULL;
  num_claimed_files = 0;
  num_claimed_files = 0;
 
 
  if (arguments_file_name)
  if (arguments_file_name)
    free (arguments_file_name);
    free (arguments_file_name);
  arguments_file_name = NULL;
  arguments_file_name = NULL;
 
 
  if (resolution_file)
  if (resolution_file)
    {
    {
      free (resolution_file);
      free (resolution_file);
      resolution_file = NULL;
      resolution_file = NULL;
    }
    }
}
}
 
 
/*  Writes the relocations to disk. */
/*  Writes the relocations to disk. */
 
 
static void
static void
write_resolution (void)
write_resolution (void)
{
{
  unsigned int i;
  unsigned int i;
  FILE *f;
  FILE *f;
 
 
  f = fopen (resolution_file, "w");
  f = fopen (resolution_file, "w");
  check (f, LDPL_FATAL, "could not open file");
  check (f, LDPL_FATAL, "could not open file");
 
 
  fprintf (f, "%d\n", num_claimed_files);
  fprintf (f, "%d\n", num_claimed_files);
 
 
  for (i = 0; i < num_claimed_files; i++)
  for (i = 0; i < num_claimed_files; i++)
    {
    {
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_symtab *symtab = &info->symtab;
      struct plugin_symtab *symtab = &info->symtab;
      struct ld_plugin_symbol *syms = symtab->syms;
      struct ld_plugin_symbol *syms = symtab->syms;
      unsigned j;
      unsigned j;
 
 
      get_symbols (info->handle, symtab->nsyms, syms);
      get_symbols (info->handle, symtab->nsyms, syms);
 
 
      fprintf (f, "%s %d\n", info->name, info->symtab.nsyms);
      fprintf (f, "%s %d\n", info->name, info->symtab.nsyms);
 
 
      for (j = 0; j < info->symtab.nsyms; j++)
      for (j = 0; j < info->symtab.nsyms; j++)
        {
        {
          uint32_t slot = symtab->slots[j];
          uint32_t slot = symtab->slots[j];
          unsigned int resolution = syms[j].resolution;
          unsigned int resolution = syms[j].resolution;
          fprintf (f, "%d %s %s\n", slot, lto_resolution_str[resolution], syms[j].name);
          fprintf (f, "%d %s %s\n", slot, lto_resolution_str[resolution], syms[j].name);
        }
        }
    }
    }
  fclose (f);
  fclose (f);
}
}
 
 
/* Pass files generated by the lto-wrapper to the linker. FD is lto-wrapper's
/* Pass files generated by the lto-wrapper to the linker. FD is lto-wrapper's
   stdout. */
   stdout. */
 
 
static void
static void
add_output_files (FILE *f)
add_output_files (FILE *f)
{
{
  char fname[1000]; /* FIXME: Remove this restriction. */
  char fname[1000]; /* FIXME: Remove this restriction. */
 
 
  for (;;)
  for (;;)
    {
    {
      size_t len;
      size_t len;
      char *s = fgets (fname, sizeof (fname), f);
      char *s = fgets (fname, sizeof (fname), f);
      if (!s)
      if (!s)
        break;
        break;
 
 
      len = strlen (s);
      len = strlen (s);
      check (s[len - 1] == '\n', LDPL_FATAL, "file name too long");
      check (s[len - 1] == '\n', LDPL_FATAL, "file name too long");
      s[len - 1] = '\0';
      s[len - 1] = '\0';
 
 
      num_output_files++;
      num_output_files++;
      output_files = realloc (output_files, num_output_files * sizeof (char *));
      output_files = realloc (output_files, num_output_files * sizeof (char *));
      output_files[num_output_files - 1] = strdup (s);
      output_files[num_output_files - 1] = strdup (s);
      add_input_file (output_files[num_output_files - 1]);
      add_input_file (output_files[num_output_files - 1]);
    }
    }
}
}
 
 
/* Execute the lto-wrapper. ARGV[0] is the binary. The rest of ARGV is the
/* Execute the lto-wrapper. ARGV[0] is the binary. The rest of ARGV is the
   argument list. */
   argument list. */
 
 
static void
static void
exec_lto_wrapper (char *argv[])
exec_lto_wrapper (char *argv[])
{
{
  int t, i;
  int t, i;
  int status;
  int status;
  char *at_args;
  char *at_args;
  FILE *args;
  FILE *args;
  FILE *wrapper_output;
  FILE *wrapper_output;
  char *new_argv[3];
  char *new_argv[3];
  struct pex_obj *pex;
  struct pex_obj *pex;
  const char *errmsg;
  const char *errmsg;
 
 
  /* Write argv to a file to avoid a command line that is too long. */
  /* Write argv to a file to avoid a command line that is too long. */
  arguments_file_name = make_temp_file ("");
  arguments_file_name = make_temp_file ("");
  check (arguments_file_name, LDPL_FATAL,
  check (arguments_file_name, LDPL_FATAL,
         "Failed to generate a temorary file name");
         "Failed to generate a temorary file name");
 
 
  args = fopen (arguments_file_name, "w");
  args = fopen (arguments_file_name, "w");
  check (args, LDPL_FATAL, "could not open arguments file");
  check (args, LDPL_FATAL, "could not open arguments file");
 
 
  t = writeargv (&argv[1], args);
  t = writeargv (&argv[1], args);
  check (t == 0, LDPL_FATAL, "could not write arguments");
  check (t == 0, LDPL_FATAL, "could not write arguments");
  t = fclose (args);
  t = fclose (args);
  check (t == 0, LDPL_FATAL, "could not close arguments file");
  check (t == 0, LDPL_FATAL, "could not close arguments file");
 
 
  at_args = concat ("@", arguments_file_name, NULL);
  at_args = concat ("@", arguments_file_name, NULL);
  check (at_args, LDPL_FATAL, "could not allocate");
  check (at_args, LDPL_FATAL, "could not allocate");
 
 
  for (i = 1; argv[i]; i++)
  for (i = 1; argv[i]; i++)
    {
    {
      char *a = argv[i];
      char *a = argv[i];
      if (a[0] == '-' && a[1] == 'v' && a[2] == '\0')
      if (a[0] == '-' && a[1] == 'v' && a[2] == '\0')
        {
        {
          for (i = 0; argv[i]; i++)
          for (i = 0; argv[i]; i++)
            fprintf (stderr, "%s ", argv[i]);
            fprintf (stderr, "%s ", argv[i]);
          fprintf (stderr, "\n");
          fprintf (stderr, "\n");
          break;
          break;
        }
        }
    }
    }
 
 
  new_argv[0] = argv[0];
  new_argv[0] = argv[0];
  new_argv[1] = at_args;
  new_argv[1] = at_args;
  new_argv[2] = NULL;
  new_argv[2] = NULL;
 
 
  if (debug)
  if (debug)
    {
    {
      for (i = 0; new_argv[i]; i++)
      for (i = 0; new_argv[i]; i++)
        fprintf (stderr, "%s ", new_argv[i]);
        fprintf (stderr, "%s ", new_argv[i]);
      fprintf (stderr, "\n");
      fprintf (stderr, "\n");
    }
    }
 
 
 
 
  pex = pex_init (PEX_USE_PIPES, "lto-wrapper", NULL);
  pex = pex_init (PEX_USE_PIPES, "lto-wrapper", NULL);
  check (pex != NULL, LDPL_FATAL, "could not pex_init lto-wrapper");
  check (pex != NULL, LDPL_FATAL, "could not pex_init lto-wrapper");
 
 
  errmsg = pex_run (pex, 0, new_argv[0], new_argv, NULL, NULL, &t);
  errmsg = pex_run (pex, 0, new_argv[0], new_argv, NULL, NULL, &t);
  check (errmsg == NULL, LDPL_FATAL, "could not run lto-wrapper");
  check (errmsg == NULL, LDPL_FATAL, "could not run lto-wrapper");
  check (t == 0, LDPL_FATAL, "could not run lto-wrapper");
  check (t == 0, LDPL_FATAL, "could not run lto-wrapper");
 
 
  wrapper_output = pex_read_output (pex, 0);
  wrapper_output = pex_read_output (pex, 0);
  check (wrapper_output, LDPL_FATAL, "could not read lto-wrapper output");
  check (wrapper_output, LDPL_FATAL, "could not read lto-wrapper output");
 
 
  add_output_files (wrapper_output);
  add_output_files (wrapper_output);
 
 
  t = pex_get_status (pex, 1, &status);
  t = pex_get_status (pex, 1, &status);
  check (t == 1, LDPL_FATAL, "could not get lto-wrapper exit status");
  check (t == 1, LDPL_FATAL, "could not get lto-wrapper exit status");
  check (WIFEXITED (status) && WEXITSTATUS (status) == 0, LDPL_FATAL,
  check (WIFEXITED (status) && WEXITSTATUS (status) == 0, LDPL_FATAL,
         "lto-wrapper failed");
         "lto-wrapper failed");
 
 
  pex_free (pex);
  pex_free (pex);
 
 
  free (at_args);
  free (at_args);
}
}
 
 
/* Pass the original files back to the linker. */
/* Pass the original files back to the linker. */
 
 
static void
static void
use_original_files (void)
use_original_files (void)
{
{
  unsigned i;
  unsigned i;
  for (i = 0; i < num_claimed_files; i++)
  for (i = 0; i < num_claimed_files; i++)
    {
    {
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_file_info *info = &claimed_files[i];
      add_input_file (info->name);
      add_input_file (info->name);
    }
    }
}
}
 
 
 
 
/* Called by the linker once all symbols have been read. */
/* Called by the linker once all symbols have been read. */
 
 
static enum ld_plugin_status
static enum ld_plugin_status
all_symbols_read_handler (void)
all_symbols_read_handler (void)
{
{
  unsigned i;
  unsigned i;
  unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 2 + 1;
  unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 2 + 1;
  char **lto_argv;
  char **lto_argv;
  const char **lto_arg_ptr;
  const char **lto_arg_ptr;
  if (num_claimed_files == 0)
  if (num_claimed_files == 0)
    return LDPS_OK;
    return LDPS_OK;
 
 
  if (nop)
  if (nop)
    {
    {
      use_original_files ();
      use_original_files ();
      return LDPS_OK;
      return LDPS_OK;
    }
    }
 
 
  lto_argv = (char **) calloc (sizeof (char *), num_lto_args);
  lto_argv = (char **) calloc (sizeof (char *), num_lto_args);
  lto_arg_ptr = (const char **) lto_argv;
  lto_arg_ptr = (const char **) lto_argv;
  assert (lto_wrapper_argv);
  assert (lto_wrapper_argv);
 
 
  resolution_file = make_temp_file ("");
  resolution_file = make_temp_file ("");
 
 
  write_resolution ();
  write_resolution ();
 
 
  free_1 ();
  free_1 ();
 
 
  for (i = 0; i < lto_wrapper_num_args; i++)
  for (i = 0; i < lto_wrapper_num_args; i++)
    *lto_arg_ptr++ = lto_wrapper_argv[i];
    *lto_arg_ptr++ = lto_wrapper_argv[i];
 
 
  *lto_arg_ptr++ = "-fresolution";
  *lto_arg_ptr++ = "-fresolution";
  *lto_arg_ptr++ = resolution_file;
  *lto_arg_ptr++ = resolution_file;
 
 
  for (i = 0; i < num_claimed_files; i++)
  for (i = 0; i < num_claimed_files; i++)
    {
    {
      struct plugin_file_info *info = &claimed_files[i];
      struct plugin_file_info *info = &claimed_files[i];
 
 
      *lto_arg_ptr++ = info->name;
      *lto_arg_ptr++ = info->name;
    }
    }
 
 
  *lto_arg_ptr++ = NULL;
  *lto_arg_ptr++ = NULL;
  exec_lto_wrapper (lto_argv);
  exec_lto_wrapper (lto_argv);
 
 
  free (lto_argv);
  free (lto_argv);
 
 
  if (pass_through_items)
  if (pass_through_items)
    {
    {
      unsigned int i;
      unsigned int i;
      for (i = 0; i < num_pass_through_items; i++)
      for (i = 0; i < num_pass_through_items; i++)
        {
        {
          if (strncmp (pass_through_items[i], "-l", 2) == 0)
          if (strncmp (pass_through_items[i], "-l", 2) == 0)
            add_input_library (pass_through_items[i] + 2);
            add_input_library (pass_through_items[i] + 2);
          else
          else
            add_input_file (pass_through_items[i]);
            add_input_file (pass_through_items[i]);
          free (pass_through_items[i]);
          free (pass_through_items[i]);
          pass_through_items[i] = NULL;
          pass_through_items[i] = NULL;
        }
        }
      free (pass_through_items);
      free (pass_through_items);
      pass_through_items = NULL;
      pass_through_items = NULL;
    }
    }
 
 
  return LDPS_OK;
  return LDPS_OK;
}
}
 
 
/* Remove temporary files at the end of the link. */
/* Remove temporary files at the end of the link. */
 
 
static enum ld_plugin_status
static enum ld_plugin_status
cleanup_handler (void)
cleanup_handler (void)
{
{
  unsigned int i;
  unsigned int i;
  int t;
  int t;
 
 
  if (debug)
  if (debug)
    return LDPS_OK;
    return LDPS_OK;
 
 
  if (arguments_file_name)
  if (arguments_file_name)
    {
    {
      t = unlink (arguments_file_name);
      t = unlink (arguments_file_name);
      check (t == 0, LDPL_FATAL, "could not unlink arguments file");
      check (t == 0, LDPL_FATAL, "could not unlink arguments file");
    }
    }
 
 
  if (resolution_file)
  if (resolution_file)
    {
    {
      t = unlink (resolution_file);
      t = unlink (resolution_file);
      check (t == 0, LDPL_FATAL, "could not unlink resolution file");
      check (t == 0, LDPL_FATAL, "could not unlink resolution file");
    }
    }
 
 
  for (i = 0; i < num_output_files; i++)
  for (i = 0; i < num_output_files; i++)
    {
    {
      t = unlink (output_files[i]);
      t = unlink (output_files[i]);
      check (t == 0, LDPL_FATAL, "could not unlink output file");
      check (t == 0, LDPL_FATAL, "could not unlink output file");
    }
    }
 
 
  free_2 ();
  free_2 ();
  return LDPS_OK;
  return LDPS_OK;
}
}
 
 
/* Callback used by gold to check if the plugin will claim FILE. Writes
/* Callback used by gold to check if the plugin will claim FILE. Writes
   the result in CLAIMED. */
   the result in CLAIMED. */
 
 
static enum ld_plugin_status
static enum ld_plugin_status
claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
{
{
  enum ld_plugin_status status;
  enum ld_plugin_status status;
  Elf *elf;
  Elf *elf;
  struct plugin_file_info lto_file;
  struct plugin_file_info lto_file;
  Elf_Data *symtab;
  Elf_Data *symtab;
 
 
  if (file->offset != 0)
  if (file->offset != 0)
    {
    {
      char *objname;
      char *objname;
      Elf *archive;
      Elf *archive;
      off_t offset;
      off_t offset;
      /* We pass the offset of the actual file, not the archive header. */
      /* We pass the offset of the actual file, not the archive header. */
      int t = asprintf (&objname, "%s@0x%" PRIx64, file->name,
      int t = asprintf (&objname, "%s@0x%" PRIx64, file->name,
                        (int64_t) file->offset);
                        (int64_t) file->offset);
      check (t >= 0, LDPL_FATAL, "asprintf failed");
      check (t >= 0, LDPL_FATAL, "asprintf failed");
      lto_file.name = objname;
      lto_file.name = objname;
 
 
      archive = elf_begin (file->fd, ELF_C_READ, NULL);
      archive = elf_begin (file->fd, ELF_C_READ, NULL);
      check (elf_kind (archive) == ELF_K_AR, LDPL_FATAL,
      check (elf_kind (archive) == ELF_K_AR, LDPL_FATAL,
             "Not an archive and offset not 0");
             "Not an archive and offset not 0");
 
 
      /* 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 */
 
 
      offset = file->offset - 60;
      offset = file->offset - 60;
      check (offset == elf_rand (archive, offset), LDPL_FATAL,
      check (offset == elf_rand (archive, offset), LDPL_FATAL,
             "could not seek in archive");
             "could not seek in archive");
      elf = elf_begin (file->fd, ELF_C_READ, archive);
      elf = elf_begin (file->fd, ELF_C_READ, archive);
      check (elf != NULL, LDPL_FATAL, "could not find archive member");
      check (elf != NULL, LDPL_FATAL, "could not find archive member");
      elf_end (archive);
      elf_end (archive);
    }
    }
  else
  else
    {
    {
      lto_file.name = strdup (file->name);
      lto_file.name = strdup (file->name);
      elf = elf_begin (file->fd, ELF_C_READ, NULL);
      elf = elf_begin (file->fd, ELF_C_READ, NULL);
    }
    }
  lto_file.handle = file->handle;
  lto_file.handle = file->handle;
 
 
  *claimed = 0;
  *claimed = 0;
 
 
  if (!elf)
  if (!elf)
    goto err;
    goto err;
 
 
  symtab = get_symtab (elf);
  symtab = get_symtab (elf);
  if (!symtab)
  if (!symtab)
    goto err;
    goto err;
 
 
  translate (symtab, &lto_file.symtab);
  translate (symtab, &lto_file.symtab);
 
 
  status = add_symbols (file->handle, lto_file.symtab.nsyms,
  status = add_symbols (file->handle, lto_file.symtab.nsyms,
                        lto_file.symtab.syms);
                        lto_file.symtab.syms);
  check (status == LDPS_OK, LDPL_FATAL, "could not add symbols");
  check (status == LDPS_OK, LDPL_FATAL, "could not add symbols");
 
 
  *claimed = 1;
  *claimed = 1;
  num_claimed_files++;
  num_claimed_files++;
  claimed_files =
  claimed_files =
    realloc (claimed_files,
    realloc (claimed_files,
             num_claimed_files * sizeof (struct plugin_file_info));
             num_claimed_files * sizeof (struct plugin_file_info));
  claimed_files[num_claimed_files - 1] = lto_file;
  claimed_files[num_claimed_files - 1] = lto_file;
 
 
  goto cleanup;
  goto cleanup;
 
 
 err:
 err:
  free (lto_file.name);
  free (lto_file.name);
 
 
 cleanup:
 cleanup:
  if (elf)
  if (elf)
    elf_end (elf);
    elf_end (elf);
 
 
  return LDPS_OK;
  return LDPS_OK;
}
}
 
 
/* Parse the plugin options. */
/* Parse the plugin options. */
 
 
static void
static void
process_option (const char *option)
process_option (const char *option)
{
{
  if (strcmp (option, "-debug") == 0)
  if (strcmp (option, "-debug") == 0)
    debug = 1;
    debug = 1;
  else if (strcmp (option, "-nop") == 0)
  else if (strcmp (option, "-nop") == 0)
    nop = 1;
    nop = 1;
  else if (!strncmp (option, "-pass-through=", strlen("-pass-through=")))
  else if (!strncmp (option, "-pass-through=", strlen("-pass-through=")))
    {
    {
      num_pass_through_items++;
      num_pass_through_items++;
      pass_through_items = realloc (pass_through_items,
      pass_through_items = realloc (pass_through_items,
                                    num_pass_through_items * sizeof (char *));
                                    num_pass_through_items * sizeof (char *));
      pass_through_items[num_pass_through_items - 1] =
      pass_through_items[num_pass_through_items - 1] =
          strdup (option + strlen ("-pass-through="));
          strdup (option + strlen ("-pass-through="));
    }
    }
  else
  else
    {
    {
      int size;
      int size;
      lto_wrapper_num_args += 1;
      lto_wrapper_num_args += 1;
      size = lto_wrapper_num_args * sizeof (char *);
      size = lto_wrapper_num_args * sizeof (char *);
      lto_wrapper_argv = (char **) realloc (lto_wrapper_argv, size);
      lto_wrapper_argv = (char **) realloc (lto_wrapper_argv, size);
      lto_wrapper_argv[lto_wrapper_num_args - 1] = strdup(option);
      lto_wrapper_argv[lto_wrapper_num_args - 1] = strdup(option);
    }
    }
}
}
 
 
/* Called by gold after loading the plugin. TV is the transfer vector. */
/* Called by gold after loading the plugin. TV is the transfer vector. */
 
 
enum ld_plugin_status
enum ld_plugin_status
onload (struct ld_plugin_tv *tv)
onload (struct ld_plugin_tv *tv)
{
{
  struct ld_plugin_tv *p;
  struct ld_plugin_tv *p;
  enum ld_plugin_status status;
  enum ld_plugin_status status;
 
 
  unsigned version = elf_version (EV_CURRENT);
  unsigned version = elf_version (EV_CURRENT);
  check (version != EV_NONE, LDPL_FATAL, "invalid ELF version");
  check (version != EV_NONE, LDPL_FATAL, "invalid ELF version");
 
 
  p = tv;
  p = tv;
  while (p->tv_tag)
  while (p->tv_tag)
    {
    {
      switch (p->tv_tag)
      switch (p->tv_tag)
        {
        {
        case LDPT_MESSAGE:
        case LDPT_MESSAGE:
          message = p->tv_u.tv_message;
          message = p->tv_u.tv_message;
          break;
          break;
        case LDPT_REGISTER_CLAIM_FILE_HOOK:
        case LDPT_REGISTER_CLAIM_FILE_HOOK:
          register_claim_file = p->tv_u.tv_register_claim_file;
          register_claim_file = p->tv_u.tv_register_claim_file;
          break;
          break;
        case LDPT_ADD_SYMBOLS:
        case LDPT_ADD_SYMBOLS:
          add_symbols = p->tv_u.tv_add_symbols;
          add_symbols = p->tv_u.tv_add_symbols;
          break;
          break;
        case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
        case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
          register_all_symbols_read = p->tv_u.tv_register_all_symbols_read;
          register_all_symbols_read = p->tv_u.tv_register_all_symbols_read;
          break;
          break;
        case LDPT_GET_SYMBOLS:
        case LDPT_GET_SYMBOLS:
          get_symbols = p->tv_u.tv_get_symbols;
          get_symbols = p->tv_u.tv_get_symbols;
          break;
          break;
        case LDPT_REGISTER_CLEANUP_HOOK:
        case LDPT_REGISTER_CLEANUP_HOOK:
          register_cleanup = p->tv_u.tv_register_cleanup;
          register_cleanup = p->tv_u.tv_register_cleanup;
          break;
          break;
        case LDPT_ADD_INPUT_FILE:
        case LDPT_ADD_INPUT_FILE:
          add_input_file = p->tv_u.tv_add_input_file;
          add_input_file = p->tv_u.tv_add_input_file;
          break;
          break;
        case LDPT_ADD_INPUT_LIBRARY:
        case LDPT_ADD_INPUT_LIBRARY:
          add_input_library = p->tv_u.tv_add_input_library;
          add_input_library = p->tv_u.tv_add_input_library;
          break;
          break;
        case LDPT_OPTION:
        case LDPT_OPTION:
          process_option (p->tv_u.tv_string);
          process_option (p->tv_u.tv_string);
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
      p++;
      p++;
    }
    }
 
 
  check (register_claim_file, LDPL_FATAL, "register_claim_file not found");
  check (register_claim_file, LDPL_FATAL, "register_claim_file not found");
  check (add_symbols, LDPL_FATAL, "add_symbols not found");
  check (add_symbols, LDPL_FATAL, "add_symbols not found");
  status = register_claim_file (claim_file_handler);
  status = register_claim_file (claim_file_handler);
  check (status == LDPS_OK, LDPL_FATAL,
  check (status == LDPS_OK, LDPL_FATAL,
         "could not register the claim_file callback");
         "could not register the claim_file callback");
 
 
  if (register_cleanup)
  if (register_cleanup)
    {
    {
      status = register_cleanup (cleanup_handler);
      status = register_cleanup (cleanup_handler);
      check (status == LDPS_OK, LDPL_FATAL,
      check (status == LDPS_OK, LDPL_FATAL,
             "could not register the cleanup callback");
             "could not register the cleanup callback");
    }
    }
 
 
  if (register_all_symbols_read)
  if (register_all_symbols_read)
    {
    {
      check (get_symbols, LDPL_FATAL, "get_symbols not found");
      check (get_symbols, LDPL_FATAL, "get_symbols not found");
      status = register_all_symbols_read (all_symbols_read_handler);
      status = register_all_symbols_read (all_symbols_read_handler);
      check (status == LDPS_OK, LDPL_FATAL,
      check (status == LDPS_OK, LDPL_FATAL,
             "could not register the all_symbols_read callback");
             "could not register the all_symbols_read callback");
    }
    }
 
 
  return LDPS_OK;
  return LDPS_OK;
}
}
 
 

powered by: WebSVN 2.1.0

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