OSDN Git Service

* lto-object.c: New file.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Nov 2010 14:48:34 +0000 (14:48 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Nov 2010 14:48:34 +0000 (14:48 +0000)
* lto-elf.c: Remove file.
* lto-macho.c: Remove file.
* lto-macho.h: Remove file.
* lto-coff.c: Remove file.
* lto-coff.h: Remove file.
* Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to
lto/lto-object.o.
($(LTO_EXE)): Remove $(LTO_USE_LIBELF)
(lto/lto-objfile.o): New target.
(lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets.
(lto/lto.o): Remove $(LIBIBERTY_H).

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166187 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/lto/ChangeLog
gcc/lto/Make-lang.in
gcc/lto/lto-coff.c [deleted file]
gcc/lto/lto-coff.h [deleted file]
gcc/lto/lto-elf.c [deleted file]
gcc/lto/lto-macho.c [deleted file]
gcc/lto/lto-macho.h [deleted file]
gcc/lto/lto-object.c [new file with mode: 0644]

index e718fdb..c963d6f 100644 (file)
@@ -1,3 +1,18 @@
+2010-11-02  Ian Lance Taylor  <iant@google.com>
+
+       * lto-object.c: New file.
+       * lto-elf.c: Remove file.
+       * lto-macho.c: Remove file.
+       * lto-macho.h: Remove file.
+       * lto-coff.c: Remove file.
+       * lto-coff.h: Remove file.
+       * Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to
+       lto/lto-object.o.
+       ($(LTO_EXE)): Remove $(LTO_USE_LIBELF)
+       (lto/lto-objfile.o): New target.
+       (lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets.
+       (lto/lto.o): Remove $(LIBIBERTY_H).
+
 2010-10-22  Jan Hubicka  <jh@suse.cz>
 
        * lto.c (add_cgraph_node_to_partition,
index 2dc6409..0c63865 100644 (file)
@@ -23,7 +23,7 @@
 # The name of the LTO compiler.
 LTO_EXE = lto1$(exeext)
 # The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o lto/lto.o lto/$(LTO_BINARY_READER).o attribs.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-object.o attribs.o
 LTO_H = lto/lto.h $(HASHTAB_H)
 LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
 LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H)
@@ -73,7 +73,7 @@ lto-warn = $(STRICT_WARN)
 
 $(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS)
        +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
-               $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) $(LTO_USE_LIBELF)
+               $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS)
 
 # Dependencies
 lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
@@ -81,19 +81,14 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
        $(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
        $(EXPR_H)
 lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \
-       toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) $(LIBIBERTY_H) \
+       toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
        $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \
        langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
        $(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
        $(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H)
-lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-       toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H)
-lto/lto-coff.o: lto/lto-coff.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-       toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
-       lto/lto-coff.h
-lto/lto-macho.o: lto/lto-macho.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-       toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
-       lto/lto-macho.h lto/lto-endian.h
+lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+       $(DIAGNOSTIC_CORE_H) $(TOPLEV_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
+       ../include/simple-object.h
 
 # LTO testing is done as part of C/C++/Fortran etc. testing.
 check-lto:
diff --git a/gcc/lto/lto-coff.c b/gcc/lto/lto-coff.c
deleted file mode 100644 (file)
index f5aaff8..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/* LTO routines for COFF object files.
-   Copyright 2009, 2010 Free Software Foundation, Inc.
-   Contributed by Dave Korn.
-
-This file is part of GCC.
-
-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
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "ggc.h"
-#include "lto-streamer.h"
-#include "lto/lto-coff.h"
-
-
-/* Rather than implementing a libcoff to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) COFF format object file reader/writer.  The generated files
-   will contain a COFF header, a number of COFF section headers, the 
-   section data itself, and a trailing string table for section names.  */
-
-/* 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
-
-/* Known header magics for validation, as an array.  */
-
-static const unsigned int coff_machine_array[] = COFF_KNOWN_MACHINES;
-
-/* Number of valid entries (no sentinel) in array.  */
-
-#define NUM_COFF_KNOWN_MACHINES        \
-       (sizeof (coff_machine_array) / sizeof (coff_machine_array[0]))
-
-/* Cached object file header.  */
-
-static Coff_header cached_coff_hdr;
-
-/* Flag to indicate if we have read and cached any header yet.  */
-
-static bool cached_coff_hdr_valid = false;
-
-/* The current output file.  */
-
-static lto_file *current_out_file;
-
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
-
-
-/* COFF section structure constructor.  */
-
-static lto_coff_section *
-coff_newsection (lto_coff_file *file, const char *name, size_t type)
-{
-  lto_coff_section *ptr, **chain_ptr_ptr;
-
-  ptr = XCNEW (lto_coff_section);
-  ptr->name = name;
-  ptr->type = type;
-
-  chain_ptr_ptr = &file->section_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-
-/* COFF section data block structure constructor.  */
-
-static lto_coff_data *
-coff_newdata (lto_coff_section *sec)
-{
-  lto_coff_data *ptr, **chain_ptr_ptr;
-
-  ptr = XCNEW (lto_coff_data);
-
-  chain_ptr_ptr = &sec->data_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-
-/* Initialize FILE, an LTO file object for FILENAME.  */
-
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_coff_file *coff_file = (lto_coff_file *)lto_file;
-  lto_coff_section *sec;
-  htab_t section_hash_table;
-  ssize_t strtab_size;
-  char *strtab;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  /* Seek to start of string table.  */
-  if (coff_file->strtab_offs != lseek (coff_file->fd,
-               coff_file->base.offset + coff_file->strtab_offs, SEEK_SET))
-    {
-      error ("altered or invalid COFF object file");
-      return section_hash_table;
-    }
-
-  strtab_size = coff_file->file_size - coff_file->strtab_offs;
-  strtab = XNEWVEC (char, strtab_size);
-  if (read (coff_file->fd, strtab, strtab_size) != strtab_size)
-    {
-      error ("invalid COFF object file string table");
-      return section_hash_table;
-    }
-
-  /* Scan sections looking at names.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, sec)
-    {
-      struct lto_section_slot s_slot;
-      void **slot;
-      char *new_name;
-      int stringoffset;
-      char *name = (char *) &sec->coffsec.Name[0];
-
-      /* Skip dummy string section if by any chance we see it.  */
-      if (sec->type == 1)
-       continue;
-
-      if (name[0] == '/')
-       {
-         if (1 != sscanf (&name[1], "%d", &stringoffset)
-               || stringoffset < 0 || stringoffset >= strtab_size)
-           {
-             error ("invalid COFF section name string");
-             continue;
-           }
-         name = strtab + stringoffset;
-       }
-      else
-       {
-         /* If we cared about the VirtualSize field, we couldn't
-            crudely trash it like this to guarantee nul-termination
-            of the Name field.  But we don't, so we do.  */
-         name[8] = 0;
-       }
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-                       strlen (LTO_SECTION_NAME_PREFIX)) != 0)
-         continue;
-
-      new_name = XNEWVEC (char, strlen (name) + 1);
-      strcpy (new_name, name);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-       {
-         struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-         new_slot->name = new_name;
-         /* The offset into the file for this section.  */
-         new_slot->start = coff_file->base.offset
-                       + COFF_GET(&sec->coffsec,PointerToRawData);
-         new_slot->len = COFF_GET(&sec->coffsec,SizeOfRawData);
-         *slot = new_slot;
-       }
-      else
-       {
-         error ("two or more sections for %s:", new_name);
-         return NULL;
-       }
-    }
-
-  free (strtab);
-  return section_hash_table;
-}
-
-
-/* Begin a new COFF section named NAME with type TYPE in the current output
-   file.  TYPE is an SHT_* macro from the libelf headers.  */
-
-static void
-lto_coff_begin_section_with_type (const char *name, size_t type)
-{
-  lto_coff_file *file;
-  size_t sh_name;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_coff_file *) lto_get_current_out_file (),
-  gcc_assert (file);
-  gcc_assert (!file->scn);
-
-  /* Create a new section.  */
-  file->scn = coff_newsection (file, name, type);
-  if (!file->scn)
-    fatal_error ("could not create a new COFF section: %m");
-
-  /* Add a string table entry and record the offset.  */
-  gcc_assert (file->shstrtab_stream);
-  sh_name = file->shstrtab_stream->total_size;
-  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
-
-  /* Initialize the section header.  */
-  file->scn->strtab_offs = sh_name;
-}
-
-
-/* Begin a new COFF section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_coff_begin_section_with_type (name, 0);
-}
-
-
-/* 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
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_coff_file *file;
-  lto_coff_data *coff_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_coff_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  coff_data = coff_newdata (file->scn);
-  if (!coff_data)
-    fatal_error ("could not append data to COFF section: %m");
-
-  coff_data->d_buf = CONST_CAST (void *, data);
-  coff_data->d_size = len;
-
-  /* Chain all data blocks (from all sections) on one singly-linked
-     list for freeing en masse after the file is closed.  */
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_coff_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_coff_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* Validate's COFF_FILE's executable header and, if cached_coff_hdr is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success or false on failure.  */
-
-static bool
-validate_file (lto_coff_file *coff_file)
-{
-  size_t n, secnum;
-  unsigned int numsections, secheaderssize, numsyms;
-  off_t sectionsstart, symbolsstart, stringsstart;
-  unsigned int mach, charact;
-
-  /* Read and sanity check the raw header.  */
-  n = read (coff_file->fd, &coff_file->coffhdr, sizeof (coff_file->coffhdr));
-  if (n != sizeof (coff_file->coffhdr))
-    {
-      error ("not a COFF object file");
-      return false;
-    }
-
-  mach = COFF_GET(&coff_file->coffhdr, Machine);
-  for (n = 0; n < NUM_COFF_KNOWN_MACHINES; n++)
-    if (mach == coff_machine_array[n])
-      break;
-  if (n == NUM_COFF_KNOWN_MACHINES)
-    {
-      error ("not a recognized COFF object file");
-      return false;
-    }
-
-  charact = COFF_GET(&coff_file->coffhdr, Characteristics);
-  if (COFF_NOT_CHARACTERISTICS & charact)
-    {
-      /* DLL, EXE or SYS file.  */
-      error ("not a relocatable COFF object file");
-      return false;
-    }
-
-  if (mach != IMAGE_FILE_MACHINE_AMD64
-      && COFF_CHARACTERISTICS != (COFF_CHARACTERISTICS & charact))
-    {
-      /* ECOFF/XCOFF support not implemented.  */
-      error ("not a 32-bit COFF object file");
-      return false;
-    }
-
-  /* It validated OK, so cached it if we don't already have one.  */
-  if (!cached_coff_hdr_valid)
-    {
-      cached_coff_hdr_valid = true;
-      memcpy (&cached_coff_hdr, &coff_file->coffhdr, sizeof (cached_coff_hdr));
-    }
-
-  if (mach != COFF_GET(&cached_coff_hdr, Machine))
-    {
-      error ("inconsistent file architecture detected");
-      return false;
-    }
-
-  /* Read section headers and string table? */
-
-  numsections = COFF_GET(&coff_file->coffhdr, NumberOfSections);
-  secheaderssize = numsections * sizeof (Coff_section);
-  sectionsstart = sizeof (Coff_header) + secheaderssize;
-  symbolsstart = COFF_GET(&coff_file->coffhdr, PointerToSymbolTable);
-  numsyms = COFF_GET(&coff_file->coffhdr, NumberOfSymbols);
-  stringsstart = (symbolsstart + COFF_SYMBOL_SIZE * numsyms);
-
-#define CVOFFSETTTED(x) (coff_file->base.offset + (x))
-
-  if (numsections <= 0 || symbolsstart <= 0 || numsyms <= 0
-       || (CVOFFSETTTED(sectionsstart) >= coff_file->file_size)
-       || (CVOFFSETTTED(symbolsstart) >= coff_file->file_size)
-       || (CVOFFSETTTED(stringsstart) >= coff_file->file_size))
-    {
-      error ("not a valid COFF object file");
-      return false;
-    }
-
-#undef CVOFFSETTTED
-
-  /* Record start of string table.  */
-  coff_file->strtab_offs = stringsstart;
-
-  /* Validate section table entries.  */
-  for (secnum = 0; secnum < numsections; secnum++)
-    {
-      Coff_section coffsec;
-      lto_coff_section *ltosec;
-      off_t size_raw, offs_raw, offs_relocs, offs_lines;
-      off_t num_relocs, num_lines;
-
-      n = read (coff_file->fd, &coffsec, sizeof (coffsec));
-      if (n != sizeof (coffsec))
-       {
-         error ("short/missing COFF section table");
-         return false;
-       }
-
-      size_raw = COFF_GET(&coffsec, SizeOfRawData);
-      offs_raw = COFF_GET(&coffsec, PointerToRawData);
-      offs_relocs = COFF_GET(&coffsec, PointerToRelocations);
-      offs_lines = COFF_GET(&coffsec, PointerToLinenumbers);
-      num_relocs = COFF_GET(&coffsec, NumberOfRelocations);
-      num_lines = COFF_GET(&coffsec, NumberOfLinenumbers);
-
-      if (size_raw < 0 || num_relocs < 0 || num_lines < 0
-       || (size_raw
-         && ((COFF_GET(&coffsec, Characteristics)
-             & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
-           ? (offs_raw != 0)
-           : (offs_raw < sectionsstart || offs_raw >= coff_file->file_size)))
-       || (num_relocs
-         && (offs_relocs < sectionsstart
-           || offs_relocs >= coff_file->file_size))
-       || (num_lines
-         && (offs_lines < sectionsstart
-           || offs_lines >= coff_file->file_size)))
-       {
-         error ("invalid COFF section table");
-         return false;
-       }
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-        we build the hash table.  */
-      ltosec = coff_newsection (coff_file, NULL, 0);
-      memcpy (&ltosec->coffsec, &coffsec, sizeof (ltosec->coffsec));
-    }
-
-  return true;
-}
-
-/* Initialize COFF_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_coffhdr (lto_coff_file *coff_file)
-{
-  gcc_assert (cached_coff_hdr_valid);
-  memset (&coff_file->coffhdr, 0, sizeof (coff_file->coffhdr));
-  COFF_PUT(&coff_file->coffhdr, Machine, COFF_GET(&cached_coff_hdr, Machine));
-  COFF_PUT(&coff_file->coffhdr, Characteristics, COFF_GET(&cached_coff_hdr, Characteristics));
-}
-
-/* Open COFF 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_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_coff_file *coff_file;
-  lto_file *result = NULL;
-  off_t offset;
-  const char *offset_p;
-  char *fname;
-  struct stat statbuf;
-
-  offset_p = strchr (filename, '@');
-  if (!offset_p)
-    {
-      fname = xstrdup (filename);
-      offset = 0;
-    }
-  else
-    {
-      /* The file started with '@' is a file containing command line
-        options.  Stop if it doesn't exist.  */
-      if (offset_p == filename)
-       fatal_error ("command line option file '%s' does not exist",
-                    filename);
-
-      fname = (char *) xmalloc (offset_p - filename + 1);
-      memcpy (fname, filename, offset_p - filename);
-      fname[offset_p - filename] = '\0';
-      offset_p += 3; /* skip the @0x */
-      offset = lto_parse_hex (offset_p);
-    }
-
-  /* Set up.  */
-  coff_file = XCNEW (lto_coff_file);
-  result = (lto_file *) coff_file;
-  lto_file_init (result, fname, offset);
-  coff_file->fd = -1;
-
-  /* Open the file.  */
-  coff_file->fd = open (fname,
-    O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
-  if (coff_file->fd == -1)
-    {
-      error ("could not open file %s", fname);
-      goto fail;
-    }
-
-  if (stat (fname, &statbuf) < 0)
-    {
-      error ("could not stat file %s", fname);
-      goto fail;
-    }
-
-  coff_file->file_size = statbuf.st_size;
-
-  if (offset != 0)
-    {
-      char ar_tail[12];
-      int size;
-
-      /* Surely not?  */
-      gcc_assert (!writable);
-
-      /* Seek to offset, or error.  */
-      if (lseek (coff_file->fd, offset, SEEK_SET) != (ssize_t) offset)
-       {
-         error ("could not find archive member @0x%lx", (long) offset);
-         goto fail;
-       }
-
-      /* Now seek back 12 chars and read the tail of the AR header to
-         find the length of the member file.  */
-      if (lseek (coff_file->fd, -12, SEEK_CUR) < 0
-         || read (coff_file->fd, ar_tail, 12) != 12
-         || lseek (coff_file->fd, 0, SEEK_CUR) != (ssize_t) offset
-         || ar_tail[10] != '`' || ar_tail[11] != '\n')
-       {
-         error ("could not find archive header @0x%lx", (long) offset);
-         goto fail;
-       }
-
-      ar_tail[11] = 0;
-      if (sscanf (ar_tail, "%d", &size) != 1)
-       {
-         error ("invalid archive header @0x%lx", (long) offset);
-         goto fail;
-       }
-      coff_file->file_size = size;
-    }
-
-  if (writable)
-    {
-      init_coffhdr (coff_file);
-      coff_file->shstrtab_stream = XCNEW (struct lto_output_stream);
-    }
-  else
-    if (!validate_file (coff_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* Close COFF file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's COFF data is written at this time, and
-   any cached data buffers are freed.  Return TRUE if there was an error.  */
-
-static bool
-coff_write_object_file (lto_coff_file *coff_file)
-{
-  lto_coff_section *cursec, *stringsec;
-  lto_coff_data *data;
-  size_t fileoffset, numsections, totalsecsize, numsyms, stringssize;
-  bool write_err = false;
-  int secnum;
-
-  /* Infer whether this file was opened for reading or writing from the
-     presence or absense of an initialised stream for the string table;
-     do nothing if it was opened for reading.  */
-  if (!coff_file->shstrtab_stream)
-    return false;
-  else
-    {
-      /* Write the COFF string table into a dummy new section that
-        we will not write a header for.  */
-      lto_file *old_file = lto_set_current_out_file (&coff_file->base);
-      /* This recursively feeds in the data to a new section.  */
-      lto_coff_begin_section_with_type (".strtab", 1);
-      lto_write_stream (coff_file->shstrtab_stream);
-      lto_obj_end_section ();
-      lto_set_current_out_file (old_file);
-      free (coff_file->shstrtab_stream);
-    }
-
-  /* Layout the file.  Count sections (not dummy string section) and calculate
-     data size for all of them.  */
-  numsections = 0;
-  totalsecsize = 0;
-  stringssize = 0;
-  stringsec = NULL;
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-      lto_coff_data *data;
-      size_t cursecsize;
-      cursecsize = 0;
-      COFF_FOR_ALL_DATA(cursec,data)
-       cursecsize += data->d_size;
-      if (cursec->type == 0)
-       {
-         ++numsections;
-         totalsecsize += COFF_ALIGN(cursecsize);
-#if COFF_ALIGNMENT > 1
-         cursec->pad_needed = COFF_ALIGN(cursecsize) - cursecsize;
-#endif
-       }
-      else
-        {
-         stringssize = cursecsize;
-         stringsec = cursec;
-       }
-      COFF_PUT(&cursec->coffsec, SizeOfRawData, cursecsize);
-    }
-
-  /* There is a file symbol and a section symbol per section,
-     and each of these has a single auxiliary symbol following.  */
-  numsyms = 2 * (1 + numsections);
-
-  /* Great!  Now we have enough info to fill out the file header.  */
-  COFF_PUT(&coff_file->coffhdr, NumberOfSections, numsections);
-  COFF_PUT(&coff_file->coffhdr, NumberOfSymbols, numsyms);
-  COFF_PUT(&coff_file->coffhdr, PointerToSymbolTable, sizeof (Coff_header)
-               + numsections * sizeof (Coff_section) + totalsecsize);
-  /* The remaining members were initialised to zero or copied from
-     a cached header, so we leave them alone here.  */
-
-  /* Now position all the sections, and fill out their headers.  */
-  fileoffset = sizeof (Coff_header) + numsections * sizeof (Coff_section);
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-      /* Skip dummy string section.  */
-      if (cursec->type == 1)
-       continue;
-      COFF_PUT(&cursec->coffsec, PointerToRawData, fileoffset);
-      fileoffset += COFF_ALIGN (COFF_GET(&cursec->coffsec, SizeOfRawData));
-      COFF_PUT(&cursec->coffsec, Characteristics, COFF_SECTION_CHARACTERISTICS);
-      snprintf ((char *)&cursec->coffsec.Name[0], 8, "/%d", cursec->strtab_offs + 4);
-    }
-
-  /* We can write the data now.  As there's no way to indicate an error return
-     from this hook, error handling is limited to not wasting our time doing
-     any more writes in the event that any one fails.  */
-
-  /* Write the COFF header.  */
-  write_err = (write (coff_file->fd, &coff_file->coffhdr,
-               sizeof (coff_file->coffhdr)) != sizeof (coff_file->coffhdr));
-
-  /* Write the COFF section headers.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    if (cursec->type == 1)     /* Skip dummy string section.  */
-       continue;
-    else if (!write_err)
-      write_err = (write (coff_file->fd, &cursec->coffsec,
-               sizeof (cursec->coffsec)) != sizeof (cursec->coffsec));
-    else
-      break;
-
-  /* Write the COFF sections.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-#if COFF_ALIGNMENT > 1
-      static const char padzeros[COFF_ALIGNMENT] = { 0 };
-#endif
-      /* Skip dummy string section.  */
-      if (cursec->type == 1)
-       continue;
-      COFF_FOR_ALL_DATA(cursec, data)
-       if (!write_err)
-         write_err = (write (coff_file->fd, data->d_buf, data->d_size)
-               != data->d_size);
-       else
-         break;
-#if COFF_ALIGNMENT > 1
-      if (!write_err && cursec->pad_needed)
-       write_err = (write (coff_file->fd, padzeros, cursec->pad_needed)
-               != cursec->pad_needed);
-#endif
-    }
-
-  /* Write the COFF symbol table.  */
-  if (!write_err)
-    {
-      union
-       {
-         Coff_symbol sym;
-         Coff_aux_sym_file file;
-         Coff_aux_sym_section sec;
-       } symbols[2];
-      memset (&symbols[0], 0, sizeof (symbols));
-      strcpy ((char *) &symbols[0].sym.Name[0], ".file");
-      COFF_PUT(&symbols[0].sym, SectionNumber, IMAGE_SYM_DEBUG);
-      COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
-      symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_FILE;
-      symbols[0].sym.NumberOfAuxSymbols[0] = 1;
-      snprintf ((char *)symbols[1].file.FileName,
-               sizeof (symbols[1].file.FileName),
-               "%s", lbasename (coff_file->base.filename));
-      write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
-               != (2 * COFF_SYMBOL_SIZE));
-
-      /* Set up constant parts for section sym loop.  */
-      memset (&symbols[0], 0, sizeof (symbols));
-      COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
-      symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_STATIC;
-      symbols[0].sym.NumberOfAuxSymbols[0] = 1;
-
-      secnum = 1;
-      if (!write_err)
-       COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-         {
-           /* Skip dummy string section.  */
-           if (cursec->type == 1)
-             continue;
-           /* Reuse section name string for section symbol name.  */
-           COFF_PUT_NDXSZ(&symbols[0].sym, Name, 0, 0, 4);
-           COFF_PUT_NDXSZ(&symbols[0].sym, Name, cursec->strtab_offs + 4, 4, 4);
-           COFF_PUT(&symbols[0].sym, SectionNumber, secnum++);
-           COFF_PUT(&symbols[1].sec, Length,
-                       COFF_GET(&cursec->coffsec, SizeOfRawData));
-           if (!write_err)
-             write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
-                       != (2 * COFF_SYMBOL_SIZE));
-           else
-             break;
-         }
-    }
-
-  /* Write the COFF string table.  */
-  if (!write_err)
-    {
-      unsigned char outlen[4];
-      COFF_PUT4(outlen, stringssize + 4);
-      if (!write_err)
-       write_err = (write (coff_file->fd, outlen, 4) != 4);
-      if (stringsec)
-       {
-         COFF_FOR_ALL_DATA(stringsec, data)
-           if (!write_err)
-             write_err = (write (coff_file->fd, data->d_buf, data->d_size)
-                          != data->d_size);
-           else
-             break;
-       }
-    }
-
-  return write_err;
-}
-
-/* Close COFF file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's COFF data is written at this time, and
-   any cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_coff_file *coff_file = (lto_coff_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-  lto_coff_section *cursec, *nextsec;
-  bool write_err = false;
-
-  /* Write the COFF string table into a dummy new section that
-     we will not write a header for.  */
-  if (coff_file->shstrtab_stream)
-    coff_write_object_file (coff_file);
-
-  /* Close the file, we're done.  */
-  if (coff_file->fd != -1)
-    close (coff_file->fd);
-
-  /* Free any data buffers.  */
-  cur = coff_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  /* Free any sections and their data chains.  */
-  cursec = coff_file->section_chain;
-  while (cursec)
-    {
-      lto_coff_data *curdata, *nextdata;
-      nextsec = cursec->next;
-      curdata = cursec->data_chain;
-      while (curdata)
-       {
-         nextdata = curdata->next;
-         free (curdata);
-         curdata = nextdata;
-       }
-      free (cursec);
-      cursec = nextsec;
-    }
-
-  free (file);
-
-  /* If there was an error, mention it.  */
-  if (write_err)
-    error ("I/O error writing COFF output file");
-}
-
diff --git a/gcc/lto/lto-coff.h b/gcc/lto/lto-coff.h
deleted file mode 100644 (file)
index bdc9fa5..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/* LTO routines for COFF object files.
-   Copyright 2009 Free Software Foundation, Inc.
-   Contributed by Dave Korn.
-
-This file is part of GCC.
-
-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
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#ifndef LTO_COFF_H
-#define LTO_COFF_H
-
-/* Rather than implementing a libcoff to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) COFF format object file reader/writer.  The generated files
-   will contain a COFF header, a number of COFF section headers, the 
-   section data itself, and a trailing string table for section names.  */
-
-/* Alignment of sections in a COFF object file.
-
-   The LTO writer uses zlib compression on the data that it streams into
-   LTO sections in the output object file.  Because these streams don't
-   have any embedded size information, the section in the object file must
-   be exactly sized to the data emitted; any trailing padding bytes will
-   be interpreted as partial and/or corrupt compressed data.
-
-   This is easy enough to do on COFF targets (with binutils 2.20.1 or
-   above) because we can specify 1-byte alignment for the LTO sections.
-   They are then emitted precisely-sized and byte-packed into the object
-   and the reader is happy when it parses them later.  This is currently
-   implemented in the x86/windows backed in i386_pe_asm_named_section()
-   in config/i386/winnt.c by detecting the LTO section name prefix, 
-
-   That would be sufficient, but for one thing.  At the start of the LTO
-   data is a header struct with (currently) a couple of version numbers and
-   some type info; see struct lto_header in lto-streamer.h.  If the sections
-   are byte-packed, this header will not necessarily be correctly-aligned
-   when it is read back into memory.
-
-   On x86 targets, which are currently the only LTO-COFF targets, misaligned
-   memory accesses aren't problematic (okay, inefficient, but not worth
-   worrying about two half-word memory reads per section in the context of
-   everything else the compiler has to do at the time!), but RISC targets may
-   fail on trying to access the header struct.  In this case, it will be
-   necessary to enable (preferably in a target-dependent fashion, but a few
-   bytes of padding are hardly an important issue if it comes down to it) the
-   COFF_ALIGNMENT macros below.
-
-   As currently implemented, this will emit padding to the necessary number
-   of bytes after each LTO section.  These bytes will constitute 'gaps' in
-   the object file structure, as they won't be covered by any section header.
-   This hasn't yet been tested, because no such RISC LTO-COFF target yet
-   exists.  If it causes problems further down the toolchain, it will be
-   necessary to adapt the code to emit additional section headers for these
-   padding bytes, but the odds are that it will "just work".
-
-  */
-
-#if 0
-#define COFF_ALIGNMENT  (4)
-#define COFF_ALIGNMENTM1 (COFF_ALIGNMENT - 1)
-#define COFF_ALIGN(x)   (((x) + COFF_ALIGNMENTM1) & ~COFF_ALIGNMENTM1)
-#else
-#define COFF_ALIGNMENT  (1)
-#define COFF_ALIGN(x)   (x)
-#endif
-
-/* COFF header machine codes.  */
-
-#define IMAGE_FILE_MACHINE_I386        (0x014c)
-#define IMAGE_FILE_MACHINE_AMD64 (0x8664)
-
-/* Known header magics for validation, as an array initialiser.  */
-
-#define COFF_KNOWN_MACHINES \
-  { IMAGE_FILE_MACHINE_I386, \
-    IMAGE_FILE_MACHINE_AMD64/*, ... add more here when working.  */ }
-
-/* COFF object file header, section and symbol flags and types.  These are
-   currently specific to PE-COFF, which is the only LTO-COFF format at the
-   time of writing.  Maintainers adding support for new COFF formats will
-   need to make these into target macros of some kind.  */
-
-/* COFF header characteristics.  */
-
-#define IMAGE_FILE_EXECUTABLE_IMAGE    (1 << 1)
-#define IMAGE_FILE_32BIT_MACHINE       (1 << 8)
-#define IMAGE_FILE_SYSTEM              (1 << 12)
-#define IMAGE_FILE_DLL                 (1 << 13)
-
-/* Desired characteristics (for validation).  */
-
-#define COFF_CHARACTERISTICS \
-  (IMAGE_FILE_32BIT_MACHINE)
-
-/* Unwanted characteristics (for validation).  */
-
-#define COFF_NOT_CHARACTERISTICS \
-  (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL)
-
-/* Section flags.  LTO emits byte-aligned read-only loadable data sections.  */
-
-#define IMAGE_SCN_CNT_INITIALIZED_DATA  (1 << 6)
-#define IMAGE_SCN_CNT_UNINITIALIZED_DATA (1 << 7)
-#define IMAGE_SCN_ALIGN_1BYTES          (0x1 << 20)
-#define IMAGE_SCN_MEM_DISCARDABLE       (1 << 25)
-#define        IMAGE_SCN_MEM_SHARED             (1 << 28)
-#define IMAGE_SCN_MEM_READ              (1 << 30)
-
-#define COFF_SECTION_CHARACTERISTICS \
-  (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | \
-  IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ)
-
-/* Symbol-related constants.  */
-
-#define IMAGE_SYM_DEBUG                (-2)
-#define IMAGE_SYM_TYPE_NULL    (0)
-#define IMAGE_SYM_DTYPE_NULL   (0)
-#define IMAGE_SYM_CLASS_STATIC (3)
-#define IMAGE_SYM_CLASS_FILE   (103)
-
-#define IMAGE_SYM_TYPE \
-  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
-
-/* Size of a COFF symbol in bytes.  */
-
-#define COFF_SYMBOL_SIZE       (18)
-
-/* On-disk file structures.  */
-
-struct Coff_header
-{
-  unsigned char Machine[2];
-  unsigned char NumberOfSections[2];
-  unsigned char TimeDateStamp[4];
-  unsigned char PointerToSymbolTable[4];
-  unsigned char NumberOfSymbols[4];
-  unsigned char SizeOfOptionalHeader[2];
-  unsigned char Characteristics[2];
-};
-typedef struct Coff_header Coff_header;
-
-struct Coff_section
-{
-  unsigned char Name[8];
-  unsigned char VirtualSize[4];
-  unsigned char VirtualAddress[4];
-  unsigned char SizeOfRawData[4];
-  unsigned char PointerToRawData[4];
-  unsigned char PointerToRelocations[4];
-  unsigned char PointerToLinenumbers[4];
-  unsigned char NumberOfRelocations[2];
-  unsigned char NumberOfLinenumbers[2];
-  unsigned char Characteristics[4];
-};
-typedef struct Coff_section Coff_section;
-
-struct Coff_symbol
-{
-  unsigned char Name[8];
-  unsigned char Value[4];
-  unsigned char SectionNumber[2];
-  unsigned char Type[2];
-  unsigned char StorageClass[1];
-  unsigned char NumberOfAuxSymbols[1];
-};
-typedef struct Coff_symbol Coff_symbol;
-
-struct Coff_aux_sym_file
-{
-  unsigned char FileName[18];
-};
-typedef struct Coff_aux_sym_file Coff_aux_sym_file;
-
-struct Coff_aux_sym_section
-{
-  unsigned char Length[4];
-  unsigned char NumberOfRelocations[2];
-  unsigned char NumberOfLineNumbers[2];
-  unsigned char Checksum[4];
-  unsigned char Number[2];
-  unsigned char Selection[1];
-  unsigned char Unused[3];
-};
-typedef struct Coff_aux_sym_section Coff_aux_sym_section;
-
-/* Accessor macros for the above structures.  */
-
-#define COFF_GET(struc,memb) \
-  ((COFFENDIAN ? get_be : get_le) (&(struc)->memb[0], sizeof ((struc)->memb)))
-
-#define COFF_PUT(struc,memb,val) \
-  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[0], sizeof ((struc)->memb), val))
-
-#define COFF_PUT_NDXSZ(struc,memb,val,ndx,sz) \
-  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[ndx], sz, val))
-
-/* In-memory file structures.  */
-
-/* Forward declared structs.  */
-
-struct lto_coff_data;
-struct lto_coff_section;
-struct lto_coff_file;
-
-/* Section data in output files is made of these.  */
-
-struct lto_coff_data
-{
-  /* Pointer to data block.  */
-  void *d_buf;
-
-  /* Size of data block.  */
-  ssize_t d_size;
-
-  /* Next data block for this section.  */
-  struct lto_coff_data *next;
-};
-typedef struct lto_coff_data lto_coff_data;
-
-/* This struct tracks the data for a section.  */
-
-struct lto_coff_section
-{
-  /* Singly-linked list of section's data blocks.  */
-  lto_coff_data *data_chain;
-
-  /* Offset in string table of name.  */
-  size_t strtab_offs;
-
-  /* Section type: 0 = real, 1 = dummy.  */
-  size_t type;
-
-  /* Section name.  */
-  const char *name;
-
-#if COFF_ALIGNMENT > 1
-  /* Number of trailing padding bytes needed.  */
-  ssize_t pad_needed;
-#endif
-
-  /* Raw section header data.  */
-  Coff_section coffsec;
-
-  /* Next section for this file.  */
-  struct lto_coff_section *next;
-};
-typedef struct lto_coff_section lto_coff_section;
-
-/* A COFF file.  */
-
-struct lto_coff_file 
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* Common file members:  */
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The file's overall header.  */
-  Coff_header coffhdr;
-
-  /* All sections in a singly-linked list.  */
-  lto_coff_section *section_chain;
-
-  /* Readable file members:  */
-
-  /* File total size.  */
-  off_t file_size;
-
-  /* String table file offset, relative to base.offset.  */
-  off_t strtab_offs;
-
-  /* Writable file members:  */
-
-  /* The currently active section.  */
-  lto_coff_section *scn;
-
-  /* The output stream for section header names.  */
-  struct lto_output_stream *shstrtab_stream;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  Which has been
-     faithfully reproduced here.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_coff_file lto_coff_file;
-
-/* Data hunk iterator.  */
-
-#define COFF_FOR_ALL_DATA(sec,var) \
-  for (var = sec->data_chain; var; var = var->next)
-
-/* Section list iterator.  */
-
-#define COFF_FOR_ALL_SECTIONS(file,var) \
-  for (var = file->section_chain; var; var = var->next)
-
-/* Very simple endian-ness layer.  */
-
-#ifndef COFFENDIAN
-#define COFFENDIAN (BYTES_BIG_ENDIAN)
-#endif
-
-static inline unsigned int
-get_2_le (const unsigned char *ptr)
-{
-  return ptr[0] | (ptr[1] << 8);
-}
-
-static inline unsigned int
-get_4_le (const unsigned char *ptr)
-{
-  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-}
-
-static inline unsigned int
-get_2_be (const unsigned char *ptr)
-{
-  return ptr[1] | (ptr[0] << 8);
-}
-
-static inline unsigned int
-get_4_be (const unsigned char *ptr)
-{
-  return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
-}
-
-static inline unsigned int
-get_be (const unsigned char *ptr, size_t size)
-{
-  gcc_assert (size == 4 || size == 2);
-  return (size == 2) ? get_2_be (ptr) : get_4_be (ptr);
-}
-
-static inline unsigned int
-get_le (const unsigned char *ptr, size_t size)
-{
-  gcc_assert (size == 4 || size == 2);
-  return (size == 2) ? get_2_le (ptr) : get_4_le (ptr);
-}
-
-static inline void
-put_2_le (unsigned char *ptr, unsigned int data)
-{
-  ptr[0] = data & 0xff;
-  ptr[1] = (data >> 8) & 0xff;
-}
-
-static inline void
-put_4_le (unsigned char *ptr, unsigned int data)
-{
-  ptr[0] = data & 0xff;
-  ptr[1] = (data >> 8) & 0xff;
-  ptr[2] = (data >> 16) & 0xff;
-  ptr[3] = (data >> 24) & 0xff;
-}
-
-static inline void
-put_2_be (unsigned char *ptr, unsigned int data)
-{
-  ptr[1] = data & 0xff;
-  ptr[0] = (data >> 8) & 0xff;
-}
-
-static inline void
-put_4_be (unsigned char *ptr, unsigned int data)
-{
-  ptr[3] = data & 0xff;
-  ptr[2] = (data >> 8) & 0xff;
-  ptr[1] = (data >> 16) & 0xff;
-  ptr[0] = (data >> 24) & 0xff;
-}
-
-static inline void
-put_le (unsigned char *ptr, size_t size, unsigned int data)
-{
-  gcc_assert (size == 4 || size == 2);
-  (void) (size == 2 ? put_2_le : put_4_le) (ptr, data);
-}
-
-static inline void
-put_be (unsigned char *ptr, size_t size, unsigned int data)
-{
-  gcc_assert (size == 4 || size == 2);
-  (void) (size == 2 ? put_2_be : put_4_be) (ptr, data);
-}
-
-/* We use this for putting the string table size.  */
-
-#define COFF_PUT4(ptr, data) \
-  ((COFFENDIAN ? put_4_be : put_4_le) (ptr, data))
-
-
-#endif /* LTO_COFF_H */
diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c
deleted file mode 100644 (file)
index 6268a9c..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/* LTO routines for ELF object files.
-   Copyright 2009, 2010 Free Software Foundation, Inc.
-   Contributed by CodeSourcery, Inc.
-
-This file is part of GCC.
-
-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
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include <gelf.h>
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "ggc.h"
-#include "lto-streamer.h"
-
-/* Cater to hosts with half-backed <elf.h> file like HP-UX.  */
-#ifndef EM_SPARC
-# define EM_SPARC 2
-#endif
-
-#ifndef EM_SPARC32PLUS
-# define EM_SPARC32PLUS 18
-#endif
-
-#ifndef ELFOSABI_NONE
-# define ELFOSABI_NONE 0
-#endif
-
-#ifndef ELFOSABI_LINUX
-# define ELFOSABI_LINUX 3
-#endif
-
-#ifndef SHN_XINDEX
-# define SHN_XINDEX 0xffff
-#endif
-
-
-/* Handle opening elf files on hosts, such as Windows, that may use 
-   text file handling that will break binary access.  */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-
-/* Initialize FILE, an LTO file object for FILENAME.  */
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* An ELF file.  */
-struct lto_elf_file 
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The libelf descriptor for the file.  */
-  Elf *elf;
-
-  /* Section number of string table used for section names.  */
-  size_t sec_strtab;
-
-  /* Writable file members.  */
-
-  /* The currently active section.  */
-  Elf_Scn *scn;
-
-  /* The output stream for section header names.  */
-  struct lto_output_stream *shstrtab_stream;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_elf_file lto_elf_file;
-
-/* Stores executable header attributes which must be shared by all ELF files.
-   This is used for validating input files and populating output files.  */
-static struct {
-  bool initialized;
-  /* 32 or 64 bits?  */
-  size_t bits;
-  unsigned char elf_ident[EI_NIDENT];
-  Elf64_Half elf_machine;
-} cached_file_attrs;
-
-
-/* Return the section header for SECTION.  The return value is never
-   NULL.  Call lto_elf_free_shdr to release the memory allocated.  */
-
-static Elf64_Shdr *
-lto_elf_get_shdr (Elf_Scn *section)
-{
-  Elf64_Shdr *shdr;
-
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      {
-       Elf32_Shdr *shdr32;
-
-       /* Read the 32-bit section header.  */
-       shdr32 = elf32_getshdr (section);
-       if (!shdr32)
-         fatal_error ("could not read section header: %s", elf_errmsg (0));
-
-       /* Transform it into a 64-bit section header.  */
-       shdr = XNEW (Elf64_Shdr);
-       shdr->sh_name = shdr32->sh_name;
-       shdr->sh_type = shdr32->sh_type;
-       shdr->sh_flags = shdr32->sh_flags;
-       shdr->sh_addr = shdr32->sh_addr;
-       shdr->sh_offset = shdr32->sh_offset;
-       shdr->sh_size = shdr32->sh_size;
-       shdr->sh_link = shdr32->sh_link;
-       shdr->sh_info = shdr32->sh_info;
-       shdr->sh_addralign = shdr32->sh_addralign;
-       shdr->sh_entsize  = shdr32->sh_entsize;
-       break;
-      }
-      break;
-
-    case 64:
-      shdr = elf64_getshdr (section);
-      if (!shdr)
-       fatal_error ("could not read section header: %s", elf_errmsg (0));
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  return shdr;
-}
-
-/* Free SHDR, previously allocated by lto_elf_get_shdr.  */
-static void
-lto_elf_free_shdr (Elf64_Shdr *shdr)
-{
-  if (cached_file_attrs.bits != 64)
-    free (shdr);
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_elf_file *elf_file = (lto_elf_file *)lto_file;
-  htab_t section_hash_table;
-  Elf_Scn *section;
-  size_t base_offset;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  base_offset = elf_getbase (elf_file->elf);
-  /* We are reasonably sure that elf_getbase does not fail at this
-     point.  So assume that we run into the incompatibility with
-     the FreeBSD libelf implementation that has a non-working
-     elf_getbase for non-archive members in which case the offset
-     should be zero.  */
-  if (base_offset == (size_t)-1)
-    base_offset = 0;
-  for (section = elf_getscn (elf_file->elf, 0);
-       section;
-       section = elf_nextscn (elf_file->elf, section)) 
-    {
-      Elf64_Shdr *shdr;
-      const char *name;
-      size_t offset;
-      char *new_name;
-      void **slot;
-      struct lto_section_slot s_slot;
-
-      /* Get the name of this section.  */
-      shdr = lto_elf_get_shdr (section);
-      offset = shdr->sh_name;
-      name = elf_strptr (elf_file->elf, 
-                        elf_file->sec_strtab,
-                        offset);
-
-      /* Only put lto stuff into the symtab.  */
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX, 
-                  strlen (LTO_SECTION_NAME_PREFIX)) != 0)
-       {
-         lto_elf_free_shdr (shdr);
-         continue;
-       }
-
-      new_name = XNEWVEC (char, strlen (name) + 1);
-      strcpy (new_name, name);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-       {
-         struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-         new_slot->name = new_name;
-         /* The offset into the file for this section.  */
-         new_slot->start = base_offset + shdr->sh_offset;
-         new_slot->len = shdr->sh_size;
-         *slot = new_slot;
-       }
-      else
-       {
-         error ("two or more sections for %s:", new_name);
-         return NULL;
-       }
-
-      lto_elf_free_shdr (shdr);
-    }
-
-  return section_hash_table;
-}
-
-
-/* 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
-   type, an SHT_* macro from libelf headers.  */
-
-#define DEFINE_INIT_SHDR(BITS)                                       \
-static void                                                          \
-init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type)       \
-{                                                                    \
-  Elf##BITS##_Shdr *shdr;                                            \
-                                                                     \
-  shdr = elf##BITS##_getshdr (scn);                                  \
-  if (!shdr)                                                         \
-    {                                                                \
-      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;                                           \
-  shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT;                 \
-  shdr->sh_flags = 0;                                                \
-  shdr->sh_entsize = 0;                                                      \
-}
-
-DEFINE_INIT_SHDR (32)
-DEFINE_INIT_SHDR (64)
-
-static bool first_data_block;
-
-/* Begin a new ELF section named NAME with type TYPE in the current output
-   file.  TYPE is an SHT_* macro from the libelf headers.  */
-
-static void
-lto_elf_begin_section_with_type (const char *name, size_t type)
-{
-  lto_elf_file *file;
-  Elf_Scn *scn;
-  size_t sh_name;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_elf_file *) lto_get_current_out_file (),
-  gcc_assert (file);
-  gcc_assert (file->elf);
-  gcc_assert (!file->scn);
-
-  /* Create a new section.  */
-  scn = elf_newscn (file->elf);
-  if (!scn)
-    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.  */
-  gcc_assert (file->shstrtab_stream);
-  sh_name = file->shstrtab_stream->total_size;
-  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
-
-  /* Initialize the section header.  */
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      init_shdr32 (scn, sh_name, type);
-      break;
-
-    case 64:
-      init_shdr64 (scn, sh_name, type);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  first_data_block = true;
-}
-
-
-/* Begin a new ELF section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_elf_begin_section_with_type (name, SHT_PROGBITS);
-}
-
-
-/* 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
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_elf_file *file;
-  Elf_Data *elf_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_elf_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  elf_data = elf_newdata (file->scn);
-  if (!elf_data)
-    fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1));
-
-  if (first_data_block)
-    {
-      elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT;
-      first_data_block = false;
-    }
-  else
-    elf_data->d_align = 1;
-  elf_data->d_buf = CONST_CAST (void *, data);
-  elf_data->d_off = 0LL;
-  elf_data->d_size = len;
-  elf_data->d_type = ELF_T_BYTE;
-  elf_data->d_version = EV_CURRENT;
-
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_elf_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_elf_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* 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.  */
-
-#define DEFINE_VALIDATE_EHDR(BITS)                             \
-static bool                                                    \
-validate_ehdr##BITS (lto_elf_file *elf_file)                   \
-{                                                              \
-  Elf##BITS##_Ehdr *elf_header;                                        \
-                                                               \
-  elf_header = elf##BITS##_getehdr (elf_file->elf);            \
-  if (!elf_header)                                             \
-    {                                                          \
-      error ("could not read ELF header: %s", elf_errmsg (0)); \
-      return false;                                            \
-    }                                                          \
-                                                               \
-  if (elf_header->e_type != ET_REL)                            \
-    {                                                          \
-      error ("not a relocatable ELF object file");             \
-      return false;                                            \
-    }                                                          \
-                                                               \
-  if (!cached_file_attrs.initialized)                          \
-    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;                                            \
-    }                                                          \
-                                                               \
-  return true;                                                 \
-}
-
-DEFINE_VALIDATE_EHDR (32)
-DEFINE_VALIDATE_EHDR (64)
-
-
-#ifndef HAVE_ELF_GETSHDRSTRNDX
-/* elf_getshdrstrndx replacement for systems that lack it, but provide
-   either the gABI conformant or Solaris 2 variant of elf_getshstrndx
-   instead.  */
-
-static int
-elf_getshdrstrndx (Elf *elf, size_t *dst)
-{
-#ifdef HAVE_ELF_GETSHSTRNDX_GABI
-  return elf_getshstrndx (elf, dst);
-#else
-  return elf_getshstrndx (elf, dst) ? 0 : -1;
-#endif
-}
-#endif
-
-/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success or false on failure.  */
-
-static bool
-validate_file (lto_elf_file *elf_file)
-{
-  const char *elf_ident;
-
-  /* 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
-     file this is now.  */
-  elf_ident = elf_getident (elf_file->elf, NULL);
-  if (!elf_ident)
-    {
-      error ("could not read ELF identification information: %s",
-             elf_errmsg (0));
-      return false;
-    }
-
-  if (!cached_file_attrs.initialized)
-    {
-      switch (elf_ident[EI_CLASS])
-       {
-       case ELFCLASS32:
-         cached_file_attrs.bits = 32;
-         break;
-
-       case ELFCLASS64:
-         cached_file_attrs.bits = 64;
-         break;
-
-       default:
-         error ("unsupported ELF file class");
-         return false;
-       }
-
-      memcpy (cached_file_attrs.elf_ident, elf_ident,
-             sizeof cached_file_attrs.elf_ident);
-    }
-  else
-    {
-      char elf_ident_buf[EI_NIDENT];
-
-      memcpy (elf_ident_buf, elf_ident, sizeof elf_ident_buf);
-
-      if (elf_ident_buf[EI_OSABI] != cached_file_attrs.elf_ident[EI_OSABI])
-       {
-         /* Allow mixing ELFOSABI_NONE with ELFOSABI_LINUX, with the result
-            ELFOSABI_LINUX.  */
-         if (elf_ident_buf[EI_OSABI] == ELFOSABI_NONE
-             && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_LINUX)
-           elf_ident_buf[EI_OSABI] = cached_file_attrs.elf_ident[EI_OSABI];
-         else if (elf_ident_buf[EI_OSABI] == ELFOSABI_LINUX
-                  && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_NONE)
-           cached_file_attrs.elf_ident[EI_OSABI] = elf_ident_buf[EI_OSABI];
-       }
-
-      if (memcmp (elf_ident_buf, cached_file_attrs.elf_ident,
-                 sizeof cached_file_attrs.elf_ident))
-       {
-         error ("incompatible ELF identification");
-         return false;
-       }
-    }
-
-  /* Check that the input file is a relocatable object file with the correct
-     architecture.  */
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      if (!validate_ehdr32 (elf_file))
-       return false;
-      break;
-
-    case 64:
-      if (!validate_ehdr64 (elf_file))
-       return false;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  /* Read the string table used for section header names.  */
-  if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
-    {
-      error ("could not locate ELF string table: %s", elf_errmsg (0));
-      return false;
-    }
-
-  cached_file_attrs.initialized = true;
-  return true;
-}
-
-
-/* Helper functions used by init_ehdr.  Initialize ELF_FILE's executable
-   header using cached data from previously read files.  */
-
-#define DEFINE_INIT_EHDR(BITS)                                       \
-static void                                                          \
-init_ehdr##BITS (lto_elf_file *elf_file)                             \
-{                                                                    \
-  Elf##BITS##_Ehdr *ehdr;                                            \
-                                                                     \
-  gcc_assert (cached_file_attrs.bits);                               \
-                                                                     \
-  ehdr = elf##BITS##_newehdr (elf_file->elf);                        \
-  if (!ehdr)                                                         \
-    {                                                                \
-      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);                        \
-  ehdr->e_type = ET_REL;                                             \
-  ehdr->e_version = EV_CURRENT;                                              \
-  ehdr->e_machine = cached_file_attrs.elf_machine;                   \
-}
-
-DEFINE_INIT_EHDR (32)
-DEFINE_INIT_EHDR (64)
-
-
-/* Initialize ELF_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_ehdr (lto_elf_file *elf_file)
-{
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      init_ehdr32 (elf_file);
-      break;
-
-    case 64:
-      init_ehdr64 (elf_file);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* 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_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_elf_file *elf_file;
-  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, fname, offset);
-  elf_file->fd = -1;
-
-  /* Open the file.  */
-  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", fname);
-      goto fail;
-    }
-
-  /* Initialize the ELF library.  */
-  if (elf_version (EV_CURRENT) == EV_NONE)
-    {
-      error ("ELF library is older than that used when building GCC");
-      goto fail;
-    }
-
-  /* Open the ELF file descriptor.  */
-  elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ,
-                            NULL);
-  if (!elf_file->elf)
-    {
-      error ("could not open %s as an ELF file: %s", fname, elf_errmsg (0));
-      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);
-      elf_file->shstrtab_stream = XCNEW (struct lto_output_stream);
-      /* Output an empty string to the section header table.  This becomes the
-        name of the initial NULL section.  */
-      lto_output_1_stream (elf_file->shstrtab_stream, '\0');
-    }
-  else
-    if (!validate_file (elf_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* 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
-   any cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_elf_file *elf_file = (lto_elf_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-
-  /* Write the ELF section header string table.  */
-  if (elf_file->shstrtab_stream)
-    {
-      size_t strtab;
-      GElf_Ehdr *ehdr_p, ehdr_buf;
-      lto_file *old_file = lto_set_current_out_file (file);
-
-      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));
-      strtab = elf_ndxscn (elf_file->scn);
-      if (strtab < SHN_LORESERVE)
-       ehdr_p->e_shstrndx = strtab;
-      else
-       {
-         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));
-         shdr_p = gelf_getshdr (scn_p, &shdr_buf);
-         if (shdr_p == NULL)
-           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));
-         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));
-      lto_write_stream (elf_file->shstrtab_stream);
-      lto_obj_end_section ();
-
-      lto_set_current_out_file (old_file);
-      free (elf_file->shstrtab_stream);
-
-      if (elf_update (elf_file->elf, ELF_C_WRITE) < 0)
-       fatal_error ("elf_update() failed: %s", elf_errmsg (-1));
-    }
-
-  if (elf_file->elf)
-    elf_end (elf_file->elf);
-  if (elf_file->fd != -1)
-    close (elf_file->fd);
-
-  /* Free any ELF data buffers.  */
-  cur = elf_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  free (file);
-}
-
-
-/* The current output file.  */
-static lto_file *current_out_file;
-
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
diff --git a/gcc/lto/lto-macho.c b/gcc/lto/lto-macho.c
deleted file mode 100644 (file)
index 9f89e8e..0000000
+++ /dev/null
@@ -1,948 +0,0 @@
-/* LTO routines for Mach-O object files.
-   Copyright 2010 Free Software Foundation, Inc.
-   Contributed by Steven Bosscher.
-
-This file is part of GCC.
-
-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
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "lto-streamer.h"
-#include "lto/lto-endian.h"
-#include "lto/lto-macho.h"
-
-/* Rather than implementing a libmacho to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) Mach-O format object file reader/writer.  The generated files
-   will contain a Mach-O header, a number of Mach-O load commands an
-   section headers, the  section data itself, and a trailing string table
-   for section names.  */
-
-/* This needs to be kept in sync with darwin.c.  Better yet, lto-macho.c
-   and lto-macho.h should be moved to config/, and likewise for lto-coff.*
-   and lto-elf.*.  */
-
-/* Segment name for LTO sections.  */
-#define LTO_SEGMENT_NAME "__GNU_LTO"
-
-/* Section name for LTO section names section.  */
-#define LTO_NAMES_SECTION "__section_names"
-
-/* 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
-
-/* Cached object file header.  We use a header_64 for this, since all
-   the fields we need are in there, in the same position as header_32.  */
-mach_o_header_64 cached_mach_o_header;
-uint32_t cached_mach_o_magic;
-
-/* The current output file.  */
-static lto_file *current_out_file;
-
-
-/* Is this a 32-bits or 64-bits Mach-O object file?  */
-static int
-mach_o_word_size (void)
-{
-  gcc_assert (cached_mach_o_magic != 0);
-  return (cached_mach_o_magic == MACH_O_MH_MAGIC_64
-         || cached_mach_o_magic == MACH_O_MH_CIGAM_64) ? 64 : 32;
-}
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
-
-/* Mach-O section structure constructor.  */
-
-static lto_mach_o_section
-mach_o_new_section (lto_mach_o_file *mach_o_file, const char *name)
-{
-  lto_mach_o_section ptr;
-
-  /* FIXME We could allocate these things on an obstack.  */
-  ptr = XCNEW (struct lto_mach_o_section_d);
-  if (name)
-    {
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-                  strlen(LTO_SECTION_NAME_PREFIX)) != 0)
-       sorry ("not implemented: Mach-O writer for non-LTO sections");
-      ptr->name = xstrdup (name);
-    }
-
-  VEC_safe_push (lto_mach_o_section, heap, mach_o_file->section_vec, ptr);
-
-  return ptr;
-}
-
-/* Mach-O section data block structure constructor.  */
-
-static lto_mach_o_data
-mach_o_new_data (lto_mach_o_section sec)
-{
-  lto_mach_o_data ptr, *chain_ptr_ptr;
-
-  /* FIXME We could allocate these things on an obstack.  */
-  ptr = XCNEW (struct lto_mach_o_data_d);
-
-  chain_ptr_ptr = &sec->data_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-/* Initialize FILE, an LTO file object for FILENAME.  Offset is the
-   offset into FILE where the object is located (e.g. in an archive).  */
-
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_mach_o_file *mach_o_file = (lto_mach_o_file *)lto_file;
-  lto_mach_o_section sec;
-  htab_t section_hash_table;
-  off_t strtab_offs;
-  ssize_t strtab_size;
-  char *strtab = NULL;
-  int i;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  /* Seek the string table.  */
-  /* FIXME The segment name should be in darwin.h, but can we include it
-     here in this file?  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
-       continue;
-      if (strncmp (sec->u.section.sectname, "__section_names", 16) == 0)
-        break;
-    }
-  if (! sec)
-    {
-      error ("invalid Mach-O LTO object file: no __section_names section found");
-      goto done;
-    }
-  mach_o_file->section_names_section = sec;
-
-  if (mach_o_word_size () == 64)
-    {
-      strtab_offs = (off_t) get_uint32 (&sec->u.section_64.offset[0]);
-      strtab_size = (size_t) get_uint64 (&sec->u.section_64.size[0]);
-    }
-  else
-    {
-      strtab_offs = (off_t) get_uint32 (&sec->u.section_32.offset[0]);
-      strtab_size = (size_t) get_uint32 (&sec->u.section_32.size[0]);
-    }
-
-  /* Seek to start of string table.  */
-  if (strtab_offs != lseek (mach_o_file->fd,
-                           mach_o_file->base.offset + strtab_offs,
-                           SEEK_SET))
-    {
-      error ("altered or invalid Mach-O object file");
-      goto done;
-    }
-
-  strtab = XNEWVEC (char, strtab_size);
-  if (read (mach_o_file->fd, strtab, strtab_size) != strtab_size)
-    {
-      error ("invalid Mach-O LTO object file __section_names section");
-      goto done;
-    }
-
-  /* Scan sections looking at names.  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      struct lto_section_slot s_slot;
-      void **slot;
-      char *new_name;
-      unsigned long stringoffset;
-      char name[17];
-
-      /* Ignore non-LTO sections.  Also ignore the __section_names section
-        which does not need renaming.  */
-      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
-       continue;
-      if (sec == mach_o_file->section_names_section)
-        continue;
-
-      /* Try to extract the offset of the real name for this section from
-        __section_names.  */
-      memcpy (&name[0], sec->u.section.sectname, 16);
-      name[16] = '\0';
-      if (name[0] != '_' || name[1] != '_'
-         || sscanf (&name[2], "%08lX", &stringoffset) != 1
-         || strtab_size < (ssize_t) stringoffset)
-       {
-         error ("invalid Mach-O LTO section name string: %s", name);
-         continue;
-       }
-
-      new_name = XNEWVEC (char, strlen (strtab + stringoffset) + 1);
-      strcpy (new_name, strtab + stringoffset);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-       {
-         struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-         new_slot->name = new_name;
-         if (mach_o_word_size() == 64)
-           {
-             new_slot->start =
-               (intptr_t) get_uint32 (&sec->u.section_64.offset[0]);
-             new_slot->len =
-               (size_t) get_uint64 (&sec->u.section_64.size[0]);
-           }
-         else
-           {
-             new_slot->start =
-               (intptr_t) get_uint32 (&sec->u.section_32.offset[0]);
-             new_slot->len =
-               (size_t) get_uint32 (&sec->u.section_32.size[0]);
-           }
-
-         *slot = new_slot;
-       }
-      else
-       {
-         error ("two or more sections for %s:", new_name);
-         goto done;
-       }
-    }
-
- done:
-  if (strtab)
-    free (strtab);
-  return section_hash_table;
-}
-
-
-/* Begin a new Mach-O section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_mach_o_file *file;
-
-  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-              strlen(LTO_SECTION_NAME_PREFIX)) != 0)
-    sorry ("not implemented: Mach-O writer for non-LTO sections");
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file (),
-  gcc_assert (file && file->writable && !file->scn);
-
-  /* Create a new section.  */
-  file->scn = mach_o_new_section (file, name);
-  if (!file->scn)
-    fatal_error ("could not create a new Mach-O section: %m");
-}
-
-
-/* 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
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_mach_o_file *file;
-  lto_mach_o_data mach_o_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  mach_o_data = mach_o_new_data (file->scn);
-  if (!mach_o_data)
-    fatal_error ("could not append data to Mach-O section: %m");
-
-  mach_o_data->d_buf = CONST_CAST (void *, data);
-  mach_o_data->d_size = len;
-
-  /* Chain all data blocks (from all sections) on one singly-linked
-     list for freeing en masse after the file is closed.  */
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_mach_o_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* Read a Mach-O header from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the file.
-   If cached_mach_o_header is uninitialized, caches the results.
-   On succes, returns true and moves file pointer to the start of the
-   load commands.  On failure, returns false.  */
-
-static bool
-validate_mach_o_header (lto_mach_o_file *mach_o_file)
-{
-  ssize_t i, n;
-  unsigned char magic[4];
-  uint32_t cputype;
-  off_t startpos;
-
-  /* Known header magics for validation, as an array.  */
-  static const unsigned int mach_o_known_formats[] = {
-    MACH_O_MH_MAGIC,
-    MACH_O_MH_CIGAM,
-    MACH_O_MH_MAGIC_64,
-    MACH_O_MH_CIGAM_64,
-  };
-#define MACH_O_NUM_KNOWN_FORMATS \
-  ((ssize_t) ARRAY_SIZE (mach_o_known_formats))
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-  if (read (mach_o_file->fd, &magic, sizeof (magic)) != 4
-      || lseek (mach_o_file->fd, -4, SEEK_CUR) != startpos)
-    {
-      error ("cannot read file %s", mach_o_file->base.filename);
-      return false;
-    }
-
-  for (i = 0; i < MACH_O_NUM_KNOWN_FORMATS; ++i)
-    if (get_uint32 (&magic[0]) == mach_o_known_formats[i])
-      break;
-  if (i == MACH_O_NUM_KNOWN_FORMATS)
-    goto not_for_target;
-
-  /* Check the endian-ness.  */
-  if (BYTES_BIG_ENDIAN && magic[0] != 0xfe)
-    goto not_for_target;
-
-  /* Set or check cached magic number.  */
-  if (cached_mach_o_magic == 0)
-    cached_mach_o_magic = get_uint32 (&magic[0]);
-  else if (cached_mach_o_magic != get_uint32 (&magic[0]))
-    goto not_for_target;
-  n = mach_o_word_size () == 64
-      ? sizeof (mach_o_header_64) : sizeof (mach_o_header_32);
-  if (read (mach_o_file->fd, &mach_o_file->u.header, n) != n)
-    goto not_for_target;
-
-  /* Is this a supported CPU?  */
-  /* ??? Would be nice to validate the exact target architecture.  */
-  cputype = get_uint32 (&mach_o_file->u.header.cputype[0]);
-  if (cputype == MACH_O_CPU_TYPE_I386
-      || cputype == MACH_O_CPU_TYPE_POWERPC)
-    {
-      if (mach_o_word_size () != 32)
-        goto not_for_target;
-    }
-  else if (cputype == MACH_O_CPU_TYPE_X86_64
-          || cputype == MACH_O_CPU_TYPE_POWERPC_64)
-    {
-      if (mach_o_word_size () != 64)
-        goto not_for_target;
-    }
-
-  /* Is this an MH_OBJECT file?  */
-  if (get_uint32 (&mach_o_file->u.header.filetype[0]) != MACH_O_MH_OBJECT)
-    error ("Mach-O file %s is not an MH_OBJECT file",
-          mach_o_file->base.filename);
-
-  /* Save the header for future use.  */
-  memcpy (&cached_mach_o_header, &mach_o_file->u.header,
-         sizeof (cached_mach_o_header));
-
-  return true;
-
- not_for_target:
-  error ("file %s is not a Mach-O object file for target",
-        mach_o_file->base.filename);
-  return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT command (32 bits) from MACH_O_FILE and
-   validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_segment_command_32 (lto_mach_o_file *mach_o_file)
-{
-  mach_o_segment_command_32 seg_cmd_32;
-  unsigned int i;
-  ssize_t n;
-  off_t startpos;
-
-  /* Fields we're interested in.  */
-  uint32_t cmd;
-  uint32_t cmdsize;
-  uint32_t nsects;
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
-  n = sizeof (mach_o_segment_command_32);
-  if (read (mach_o_file->fd, (void *) &seg_cmd_32, n) != n)
-    goto fail;
-
-  cmd = get_uint32 (&seg_cmd_32.cmd[0]);
-  cmdsize = get_uint32 (&seg_cmd_32.cmdsize[0]);
-  nsects = get_uint32 (&seg_cmd_32.nsects[0]);
-  gcc_assert (cmd == MACH_O_LC_SEGMENT);
-
-  /* Validate section table entries.  */
-  for (i = 0; i < nsects; i++)
-    {
-      mach_o_section_32 sec_32;
-      lto_mach_o_section ltosec;
-
-      n = sizeof (mach_o_section_32);
-      if (read (mach_o_file->fd, &sec_32, n) != n)
-       goto fail;
-
-      /* ??? Perform some checks.  */
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-        we build the hash table.  */
-      ltosec = mach_o_new_section (mach_o_file, NULL);
-      memcpy (&ltosec->u.section_32, &sec_32, sizeof (sec_32));
-    }
-
-  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
-    goto fail;
-
-  return true;
-
- fail:
-  error ("could not read LC_SEGMENT command in Mach-O file %s",
-        mach_o_file->base.filename);
-  return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT_64 command from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_segment_command_64 (lto_mach_o_file *mach_o_file)
-{
-  mach_o_segment_command_64 seg_cmd_64;
-  unsigned int i;
-  ssize_t n;
-  off_t startpos;
-
-  /* Fields we're interested in.  */
-  uint32_t cmd;
-  uint32_t cmdsize;
-  uint32_t nsects;
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
-  n = sizeof (mach_o_segment_command_64);
-  if (read (mach_o_file->fd, (void *) &seg_cmd_64, n) != n)
-    goto fail;
-
-  cmd = get_uint32 (&seg_cmd_64.cmd[0]);
-  cmdsize = get_uint32 (&seg_cmd_64.cmdsize[0]);
-  nsects = get_uint32 (&seg_cmd_64.nsects[0]);
-  gcc_assert (cmd == MACH_O_LC_SEGMENT_64);
-
-  /* Validate section table entries.  */
-  for (i = 0; i < nsects; i++)
-    {
-      mach_o_section_64 sec_64;
-      lto_mach_o_section ltosec;
-
-      n = sizeof (mach_o_section_64);
-      if (read (mach_o_file->fd, &sec_64, n) != n)
-       goto fail;
-
-      /* ??? Perform some checks.  */
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-        we build the hash table.  */
-      ltosec = mach_o_new_section (mach_o_file, NULL);
-      memcpy (&ltosec->u.section_64, &sec_64, sizeof (sec_64));
-    }
-
-  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
-    goto fail;
-
-  return true;
-
- fail:
-  error ("could not read LC_SEGMENT_64 command in Mach-O file %s",
-        mach_o_file->base.filename);
-  return false;
-}
-
-/* Read a Mach-O load commands from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_load_command (lto_mach_o_file *mach_o_file)
-{
-  mach_o_load_command load_command;
-  uint32_t cmd;
-  uint32_t cmdsize;
-  ssize_t n;
-
-  n = sizeof (load_command);
-  if (read (mach_o_file->fd, &load_command, n) != n)
-    {
-      error ("could not read load commands in Mach-O file %s",
-            mach_o_file->base.filename);
-      return false;
-    }
-  lseek (mach_o_file->fd, -1 * (off_t) sizeof (load_command), SEEK_CUR);
-
-  cmd = get_uint32 (&load_command.cmd[0]);
-  cmdsize = get_uint32 (&load_command.cmdsize[0]);
-  switch (cmd)
-    {
-    case MACH_O_LC_SEGMENT:
-      return validate_mach_o_segment_command_32 (mach_o_file);
-    case MACH_O_LC_SEGMENT_64:
-      return validate_mach_o_segment_command_64 (mach_o_file);
-
-    default:
-      /* Just skip over it.  */
-      lseek (mach_o_file->fd, cmdsize, SEEK_CUR);
-      return true;
-    }
-}
-
-/* Validate's MACH_O_FILE's executable header and, if cached_mach_o_header is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success, false on failure.  */
-
-static bool
-validate_file (lto_mach_o_file *mach_o_file)
-{
-  uint32_t i, ncmds;
-
-  /* Read and sanity check the raw header.  */
-  if (! validate_mach_o_header (mach_o_file))
-    return false;
-
-  ncmds = get_uint32 (&mach_o_file->u.header.ncmds[0]);
-  for (i = 0; i < ncmds; ++i)
-    if (! validate_mach_o_load_command (mach_o_file))
-      return false;
-
-  return true;
-}
-
-/* Initialize MACH_O_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_mach_o_header (lto_mach_o_file *mach_o_file)
-{
-  gcc_assert (cached_mach_o_magic != 0);
-  memcpy (&mach_o_file->u.header,
-         &cached_mach_o_header,
-         sizeof (mach_o_file->u.header));
-  put_uint32 (&mach_o_file->u.header.ncmds[0], 0);
-  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], 0);
-}
-
-/* Open Mach-O 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_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_mach_o_file *mach_o_file;
-  lto_file *result = NULL;
-  off_t offset;
-  const char *offset_p;
-  char *fname;
-  struct stat statbuf;
-
-  offset_p = strchr (filename, '@');
-  if (!offset_p)
-    {
-      fname = xstrdup (filename);
-      offset = 0;
-    }
-  else
-    {
-      /* The file started with '@' is a file containing command line
-        options.  Stop if it doesn't exist.  */
-      if (offset_p == filename)
-       fatal_error ("command line option file '%s' does not exist",
-                    filename);
-
-      fname = (char *) xmalloc (offset_p - filename + 1);
-      memcpy (fname, filename, offset_p - filename);
-      fname[offset_p - filename] = '\0';
-      offset_p += 3; /* skip the @0x */
-      offset = lto_parse_hex (offset_p);
-    }
-
-  /* Set up.  */
-  mach_o_file = XCNEW (lto_mach_o_file);
-  result = (lto_file *) mach_o_file;
-  lto_file_init (result, fname, offset);
-  mach_o_file->fd = -1;
-  mach_o_file->writable = writable;
-
-  /* Open the file.  */
-  mach_o_file->fd = open (fname,
-    O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
-  if (mach_o_file->fd == -1)
-    {
-      error ("could not open file %s", fname);
-      goto fail;
-    }
-
-  if (stat (fname, &statbuf) < 0)
-    {
-      error ("could not stat file %s", fname);
-      goto fail;
-    }
-
-  mach_o_file->file_size = statbuf.st_size;
-
-  /* If the object is in an archive, get it out.  */
-  if (offset != 0)
-    {
-      char ar_tail[12];
-      int size;
-
-      /* Surely not?  */
-      gcc_assert (!writable);
-
-      /* Seek to offset, or error.  */
-      if (lseek (mach_o_file->fd, offset, SEEK_SET) != (ssize_t) offset)
-       {
-         error ("could not find archive member @0x%lx", (long) offset);
-         goto fail;
-       }
-
-      /* Now seek back 12 chars and read the tail of the AR header to
-         find the length of the member file.  */
-      if (lseek (mach_o_file->fd, -12, SEEK_CUR) < 0
-         || read (mach_o_file->fd, ar_tail, 12) != 12
-         || lseek (mach_o_file->fd, 0, SEEK_CUR) != (ssize_t) offset
-         || ar_tail[10] != '`' || ar_tail[11] != '\n')
-       {
-         error ("could not find archive header @0x%lx", (long) offset);
-         goto fail;
-       }
-
-      ar_tail[11] = 0;
-      if (sscanf (ar_tail, "%d", &size) != 1)
-       {
-         error ("invalid archive header @0x%lx", (long) offset);
-         goto fail;
-       }
-      mach_o_file->file_size = size;
-    }
-
-  if (writable)
-    {
-      init_mach_o_header (mach_o_file);
-    }
-  else
-    if (! validate_file (mach_o_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* Write the data in MACH_O_FILE to a real Mach-O binary object.
-   We write a header, a segment load command, and section data.  */
-
-static bool
-mach_o_write_object_file (lto_mach_o_file *mach_o_file)
-{
-  lto_mach_o_section sec, snsec;
-  lto_mach_o_data snsec_data;
-  ssize_t hdrsize, cmdsize, secsize;
-  size_t num_sections, snsec_size, total_sec_size;
-  unsigned int sec_offs, strtab_offs;
-  int i;
-  bool write_err = false;
-
-  /* The number of sections we will write is the number of sections added by
-     the streamer, plus 1 for the section names section.  */
-  num_sections = VEC_length (lto_mach_o_section, mach_o_file->section_vec) + 1;
-
-  /* Calculate the size of the basic data structures on disk.  */
-  if (mach_o_word_size () == 64)
-    {
-      hdrsize = sizeof (mach_o_header_64);
-      secsize = sizeof (mach_o_section_64);
-      cmdsize = sizeof (mach_o_segment_command_64) + num_sections * secsize;
-    }
-  else
-    {
-      hdrsize = sizeof (mach_o_header_32);
-      secsize = sizeof (mach_o_section_32);
-      cmdsize = sizeof (mach_o_segment_command_32) + num_sections * secsize;
-    }
-  /* Allocate the section names section.  */
-  snsec_size = 0;
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    snsec_size += strlen (sec->name) + 1;
-  snsec = mach_o_new_section (mach_o_file, NULL);
-  snsec->name = LTO_NAMES_SECTION;
-  snsec_data = mach_o_new_data (snsec);
-  snsec_data->d_buf = XCNEWVEC (char, snsec_size);
-  snsec_data->d_size = snsec_size;
-
-  /* Position all the sections, and fill out their headers.  */
-  sec_offs = hdrsize + cmdsize;
-  strtab_offs = 0;
-  total_sec_size = 0;
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data data;
-      size_t data_size;
-      /* Put the section and segment names.  Add the section name to the
-         section names section (unless, of course, this *is* the section
-        names section).  */
-      if (sec == snsec)
-       snprintf (sec->u.section.sectname, 16, "%s", LTO_NAMES_SECTION);
-      else
-       {
-         sprintf (sec->u.section.sectname, "__%08X", strtab_offs);
-         memcpy ((char *) snsec_data->d_buf + strtab_offs, sec->name, strlen (sec->name));
-       }
-      memcpy (&sec->u.section.segname[0],
-             LTO_SEGMENT_NAME, strlen (LTO_SEGMENT_NAME));
-
-      /* Add layout and attributes.  */
-      for (data = sec->data_chain, data_size = 0; data; data = data->next)
-       data_size += data->d_size;
-      if (mach_o_word_size () == 64)
-       {
-         put_uint64 (&sec->u.section_64.addr[0], total_sec_size); 
-         put_uint64 (&sec->u.section_64.size[0], data_size); 
-         put_uint32 (&sec->u.section_64.offset[0], sec_offs); 
-         put_uint32 (&sec->u.section_64.flags[0], MACH_O_S_ATTR_DEBUG);
-       }
-      else
-       {
-         put_uint32 (&sec->u.section_64.addr[0], total_sec_size); 
-         put_uint32 (&sec->u.section_32.size[0], data_size); 
-         put_uint32 (&sec->u.section_32.offset[0], sec_offs); 
-         put_uint32 (&sec->u.section_32.flags[0], MACH_O_S_ATTR_DEBUG);
-       }
-
-      sec_offs += data_size;
-      total_sec_size += data_size;
-      strtab_offs += strlen (sec->name) + 1;
-    }
-
-  /* We can write the data now.  As there's no way to indicate an error return
-     from this hook, error handling is limited to not wasting our time doing
-     any more writes in the event that any one fails.  */
-
-  /* Write the header.  */
-  put_uint32 (&mach_o_file->u.header.ncmds[0], 1);
-  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], cmdsize);
-  write_err = (write (mach_o_file->fd,
-                     &mach_o_file->u.header, hdrsize) != hdrsize);
-  /* Write the segment load command.  */
-  if (mach_o_word_size () == 64)
-    {
-      mach_o_segment_command_64 lc;
-      ssize_t lc_size = sizeof (lc);
-      memset (&lc, 0, lc_size);
-      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT_64);
-      put_uint32 (&lc.cmdsize[0], cmdsize);
-      put_uint64 (&lc.fileoff[0], hdrsize + cmdsize);
-      put_uint64 (&lc.filesize[0], total_sec_size);
-      put_uint32 (&lc.nsects[0], num_sections);
-      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
-    }
-  else
-    {
-      mach_o_segment_command_32 lc;
-      ssize_t lc_size = sizeof (lc);
-      memset (&lc, 0, lc_size);
-      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT);
-      put_uint32 (&lc.cmdsize[0], cmdsize);
-      put_uint32 (&lc.fileoff[0], hdrsize + cmdsize);
-      put_uint32 (&lc.filesize[0], total_sec_size);
-      put_uint32 (&lc.nsects[0], num_sections);
-      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
-    }
-  for (i = 0;
-       !write_err
-       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    write_err = (write (mach_o_file->fd,
-                       &sec->u.section, secsize) != secsize);
-
-  gcc_assert (lseek (mach_o_file->fd, 0, SEEK_CUR) == hdrsize + cmdsize);
-
-  /* Write the section data.  */
-  for (i = 0;
-       !write_err
-       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data data;
-
-      for (data = sec->data_chain; data; data = data->next)
-       {
-         if (!write_err)
-           write_err = (write (mach_o_file->fd, data->d_buf, data->d_size)
-                        != data->d_size);
-         else
-           break;
-       }
-    }
-
-  return !write_err;
-}
-
-/* Close Mach-O file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's Mach-O data is written at this time.  Any
-   cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_mach_o_file *mach_o_file = (lto_mach_o_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-  lto_mach_o_section sec;
-  bool write_err = false;
-  int i;
-
-  /* If this file is open for writing, write a Mach-O object file.  */
-  if (mach_o_file->writable)
-    {
-      if (! mach_o_write_object_file (mach_o_file))
-        fatal_error ("cannot write Mach-O object file");
-    }
-
-  /* Close the file, we're done.  */
-  if (mach_o_file->fd != -1)
-    close (mach_o_file->fd);
-
-  /* Free any data buffers.  */
-  cur = mach_o_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  /* Free any sections and their data chains.  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data curdata, nextdata;
-      curdata = sec->data_chain;
-      while (curdata)
-       {
-         nextdata = curdata->next;
-         free (curdata);
-         curdata = nextdata;
-       }
-      free (sec);
-    }
-  VEC_free (lto_mach_o_section, heap, mach_o_file->section_vec);
-
-  free (file);
-
-  /* If there was an error, mention it.  */
-  if (write_err)
-    error ("I/O error writing Mach-O output file");
-}
-
diff --git a/gcc/lto/lto-macho.h b/gcc/lto/lto-macho.h
deleted file mode 100644 (file)
index dcd0de3..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* LTO routines for Mach-O object files.
-   Copyright 2010 Free Software Foundation, Inc.
-   Contributed by Steven Bosscher.
-
-This file is part of GCC.
-
-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
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#ifndef LTO_MACH_O_H
-#define LTO_MACH_O_H
-
-/* On-disk file structures.  */
-
-/* Mach-O header (32 bits version).  */
-struct mach_o_header_32
-{
-  unsigned char magic[4];      /* Magic number.  */
-  unsigned char cputype[4];    /* CPU that this object is for.  */
-  unsigned char cpusubtype[4]; /* CPU subtype.  */
-  unsigned char filetype[4];   /* Type of file.  */
-  unsigned char ncmds[4];      /* Number of load commands.  */
-  unsigned char sizeofcmds[4]; /* Total size of load commands.  */
-  unsigned char flags[4];      /* Flags for special featues.  */
-};
-typedef struct mach_o_header_32 mach_o_header_32;
-
-/* Mach-O header (64 bits version).  */
-struct mach_o_header_64
-{
-  unsigned char magic[4];      /* Magic number.  */
-  unsigned char cputype[4];    /* CPU that this object is for.  */
-  unsigned char cpusubtype[4]; /* CPU subtype.  */
-  unsigned char filetype[4];   /* Type of file.  */
-  unsigned char ncmds[4];      /* Number of load commands.  */
-  unsigned char sizeofcmds[4]; /* Total size of load commands.  */
-  unsigned char flags[4];      /* Flags for special featues.  */
-  unsigned char reserved[4];   /* Reserved.  Duh.  */
-};
-typedef struct mach_o_header_64 mach_o_header_64;
-
-/* Magic number.  */
-#define MACH_O_MH_MAGIC                        0xfeedface
-#define MACH_O_MH_CIGAM                        0xcefaedfe
-#define MACH_O_MH_MAGIC_64             0xfeedfacf
-#define MACH_O_MH_CIGAM_64             0xcffaedfe
-
-/* Supported CPU types.  */
-#define MACH_O_CPU_TYPE_I386           7
-#define MACH_O_CPU_TYPE_X86_64         7 + 0x1000000
-#define MACH_O_CPU_TYPE_POWERPC                18
-#define MACH_O_CPU_TYPE_POWERPC_64     18 + 0x1000000
-
-/* Supported file types.  */
-#define MACH_O_MH_OBJECT               0x01
-
-/* Mach-O load command data structure.  */
-struct mach_o_load_command
-{
-  unsigned char cmd[4];                /* The type of load command.  */
-  unsigned char cmdsize[4];    /* Size in bytes of load command data structure.  */
-};
-typedef struct mach_o_load_command mach_o_load_command;
-
-/* Supported load commands.  We support only the segment load commands.  */
-#define MACH_O_LC_SEGMENT              0x01
-#define MACH_O_LC_SEGMENT_64           0x19
-
-/* LC_SEGMENT load command.  */
-struct mach_o_segment_command_32
-{
-  unsigned char cmd[4];                /* The type of load command (LC_SEGMENT).  */
-  unsigned char cmdsize[4];    /* Size in bytes of load command data structure.  */
-  unsigned char segname[16];   /* Name of this segment.  */
-  unsigned char vmaddr[4];     /* Virtual memory address of this segment.  */
-  unsigned char vmsize[4];     /* Size there, in bytes.  */
-  unsigned char fileoff[4];    /* Offset in bytes of the data to be mapped.  */
-  unsigned char filesize[4];   /* Size in bytes on disk.  */
-  unsigned char maxprot[4];    /* Maximum permitted vmem protection.  */
-  unsigned char initprot[4];   /* Initial vmem protection.  */
-  unsigned char nsects[4];     /* Number of sections in this segment.  */
-  unsigned char flags[4];      /* Flags that affect the loading.  */
-};
-typedef struct mach_o_segment_command_32 mach_o_segment_command_32;
-
-/* LC_SEGMENT_64 load command.  Only nsects matters for us, really.  */
-struct mach_o_segment_command_64
-{
-  unsigned char cmd[4];                /* The type of load command (LC_SEGMENT_64).  */
-  unsigned char cmdsize[4];    /* Size in bytes of load command data structure.  */
-  unsigned char segname[16];   /* Name of this segment.  */
-  unsigned char vmaddr[8];     /* Virtual memory address of this segment.  */
-  unsigned char vmsize[8];     /* Size there, in bytes.  */
-  unsigned char fileoff[8];    /* Offset in bytes of the data to be mapped.  */
-  unsigned char filesize[8];   /* Size in bytes on disk.  */
-  unsigned char maxprot[4];    /* Maximum permitted vmem protection.  */
-  unsigned char initprot[4];   /* Initial vmem protection.  */
-  unsigned char nsects[4];     /* Number of sections in this segment.  */
-  unsigned char flags[4];      /* Flags that affect the loading.  */
-};
-typedef struct mach_o_segment_command_64 mach_o_segment_command_64;
-
-/* A Mach-O 32-bits section.  */
-struct mach_o_section_32
-{
-  unsigned char sectname[16];  /* Section name.  */
-  unsigned char segname[16];   /* Segment that the section belongs to.  */
-  unsigned char addr[4];       /* Address of this section in memory.  */
-  unsigned char size[4];       /* Size in bytes of this section.  */
-  unsigned char offset[4];     /* File offset of this section.  */
-  unsigned char align[4];      /* log2 of this section's alignment.  */
-  unsigned char reloff[4];     /* File offset of this section's relocs.  */
-  unsigned char nreloc[4];     /* Number of relocs for this section.  */
-  unsigned char flags[4];      /* Section flags/attributes.  */
-  unsigned char reserved1[4];
-  unsigned char reserved2[4];
-};
-typedef struct mach_o_section_32 mach_o_section_32;
-
-/* A Mach-O 64-bits section.  */
-struct mach_o_section_64
-{
-  unsigned char sectname[16];  /* Section name.  */
-  unsigned char segname[16];   /* Segment that the section belongs to.  */
-  unsigned char addr[8];       /* Address of this section in memory.  */
-  unsigned char size[8];       /* Size in bytes of this section.  */
-  unsigned char offset[4];     /* File offset of this section.  */
-  unsigned char align[4];      /* log2 of this section's alignment.  */
-  unsigned char reloff[4];     /* File offset of this section's relocs.  */
-  unsigned char nreloc[4];     /* Number of relocs for this section.  */
-  unsigned char flags[4];      /* Section flags/attributes.  */
-  unsigned char reserved1[4];
-  unsigned char reserved2[4];
-  unsigned char reserved3[4];
-};
-typedef struct mach_o_section_64 mach_o_section_64;
-
-/* Flags for Mach-O sections.  LTO sections are marked with S_ATTR_DEBUG
-   to instruct the linker to ignore the sections.  */
-#define MACH_O_S_ATTR_DEBUG                    0x02000000
-
-/* In-memory file structures.  */
-
-/* Section data in output files is made of these.  */
-struct lto_mach_o_data_d
-{
-  /* Pointer to data block.  */
-  void *d_buf;
-
-  /* Size of data block.  */
-  ssize_t d_size;
-
-  /* Next data block for this section.  */
-  struct lto_mach_o_data_d *next;
-};
-typedef struct lto_mach_o_data_d *lto_mach_o_data;
-
-/* This struct tracks the data for a section.  */
-struct lto_mach_o_section_d
-{
-  /* Singly-linked list of section's data blocks.  */
-  lto_mach_o_data data_chain;
-
-  /* Offset in string table of the section name.  */
-  size_t strtab_offs;
-
-  /* Section name.  */
-  const char *name;
-
-  /* Number of trailing padding bytes needed.  */
-  ssize_t pad_needed;
-
-  /* Raw section header data.  */
-  size_t section_size;
-  union {
-    struct {
-      char sectname[16];
-      char segname[16];
-    } section;
-    mach_o_section_32 section_32;
-    mach_o_section_64 section_64;
-  } u;
-
-  /* Next section for this file.  */
-  struct lto_mach_o_section_d *next;
-};
-typedef struct lto_mach_o_section_d *lto_mach_o_section;
-DEF_VEC_P (lto_mach_o_section);
-DEF_VEC_ALLOC_P (lto_mach_o_section, heap);
-
-/* A Mach-O file.  */
-struct lto_mach_o_file_d
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* Common file members:  */
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The file's overall header.  */
-  union {
-    /* We make use here of the fact that section_32 and section_64
-       have the same layout (except for section_64.reserved3).  We
-       read the struct of proper size, but only address the first
-       member of this union.  */
-    mach_o_header_64 header;
-    mach_o_header_32 header_32;
-    mach_o_header_64 header_64;
-  } u;
-
-  /* All sections in a varray.  */
-  VEC(lto_mach_o_section, heap) *section_vec;
-
-  /* Readable file members:  */
-
-  /* File total size.  */
-  off_t file_size;
-
-  /* True if this file is open for writing.  */
-  bool writable;
-
-  /* Section containing the __section_names section.  */
-  lto_mach_o_section section_names_section;
-
-  /* Writable file members:  */
-
-  /* The currently active section.  */
-  lto_mach_o_section scn;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  Which has been
-     faithfully reproduced here.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_mach_o_file_d lto_mach_o_file;
-
-#endif /* LTO_MACH_O_H */
-
diff --git a/gcc/lto/lto-object.c b/gcc/lto/lto-object.c
new file mode 100644 (file)
index 0000000..e4a9981
--- /dev/null
@@ -0,0 +1,376 @@
+/* LTO routines to use object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This file is part of GCC.
+
+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
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
+#include "lto.h"
+#include "tm.h"
+#include "lto-streamer.h"
+#include "libiberty.h"
+#include "simple-object.h"
+
+/* 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
+
+/* Segment name for LTO sections.  This is only used for Mach-O.
+   FIXME: This needs to be kept in sync with darwin.c.  */
+
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* An LTO file wrapped around an simple_object.  */
+
+struct lto_simple_object
+{
+  /* The base information.  */
+  lto_file base;
+
+  /* The system file descriptor.  */
+  int fd;
+
+  /* The simple_object if we are reading the file.  */
+  simple_object_read *sobj_r;
+
+  /* The simple_object if we are writing the file.  */
+  simple_object_write *sobj_w;
+
+  /* The currently active section.  */
+  simple_object_write_section *section;
+};
+
+/* Saved simple_object attributes.  FIXME: Once set, this is never
+   cleared.  */
+
+static simple_object_attributes *saved_attributes;
+
+/* Initialize FILE, an LTO file object for FILENAME.  */
+
+static void
+lto_file_init (lto_file *file, const char *filename, off_t offset)
+{
+  file->filename = filename;
+  file->offset = offset;
+}
+
+/* Open the file FILENAME.  It 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_file *
+lto_obj_file_open (const char *filename, bool writable)
+{
+  const char *offset_p;
+  long loffset;
+  int consumed;
+  char *fname;
+  off_t offset;
+  struct lto_simple_object *lo;
+  const char *errmsg;
+  int err;
+
+  offset_p = strrchr (filename, '@');
+  if (offset_p != NULL
+      && offset_p != filename
+      && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
+      && strlen (offset_p) == (unsigned int) consumed)
+    {
+      fname = XNEWVEC (char, offset_p - filename + 1);
+      memcpy (fname, filename, offset_p - filename);
+      fname[offset_p - filename] = '\0';
+      offset = (off_t) loffset;
+    }
+  else
+    {
+      fname = xstrdup (filename);
+      offset = 0;
+    }
+
+  lo = XCNEW (struct lto_simple_object);
+  lto_file_init ((lto_file *) lo, fname, offset);
+
+  lo->fd = open (fname,
+                (writable
+                 ? O_WRONLY | O_CREAT | O_BINARY
+                 : O_RDONLY | O_BINARY),
+                0666);
+  if (lo->fd == -1)
+    {
+      error ("open %s failed: %s", fname, xstrerror (errno));
+      goto fail;
+    }
+
+  if (!writable)
+    {
+      simple_object_attributes *attrs;
+
+      lo->sobj_r = simple_object_start_read (lo->fd, offset, LTO_SEGMENT_NAME,
+                                            &errmsg, &err);
+      if (lo->sobj_r == NULL)
+       goto fail_errmsg;
+
+      attrs = simple_object_fetch_attributes (lo->sobj_r, &errmsg, &err);
+      if (attrs == NULL)
+       goto fail_errmsg;
+
+      if (saved_attributes == NULL)
+       saved_attributes = attrs;
+      else
+       {
+         errmsg = simple_object_attributes_compare (saved_attributes, attrs,
+                                                    &err);
+         if (errmsg != NULL)
+           goto fail_errmsg;
+       }
+    }
+  else
+    {
+      gcc_assert (saved_attributes != NULL);
+      lo->sobj_w = simple_object_start_write (saved_attributes,
+                                             LTO_SEGMENT_NAME,
+                                             &errmsg, &err);
+      if (lo->sobj_w == NULL)
+       goto fail_errmsg;
+    }
+
+  return &lo->base;
+
+ fail_errmsg:
+  if (err == 0)
+    error ("%s: %s", fname, errmsg);
+  else
+    error ("%s: %s: %s", fname, errmsg, xstrerror (err));
+                                        
+ fail:
+  if (lo != NULL)
+    lto_obj_file_close ((lto_file *) lo);
+  return NULL;
+}
+
+/* Close FILE.  If FILE was opened for writing, it is written out
+   now.  */
+
+void
+lto_obj_file_close (lto_file *file)
+{
+  struct lto_simple_object *lo = (struct lto_simple_object *) file;
+
+  if (lo->sobj_r != NULL)
+    simple_object_release_read (lo->sobj_r);
+  else if (lo->sobj_w != NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      gcc_assert (lo->base.offset == 0);
+
+      errmsg = simple_object_write_to_file (lo->sobj_w, lo->fd, &err);
+      if (errmsg != NULL)
+       {
+         if (err == 0)
+           fatal_error ("%s", errmsg);
+         else
+           fatal_error ("%s: %s", errmsg, xstrerror (err));
+       }
+
+      simple_object_release_write (lo->sobj_w);
+    }
+
+  if (lo->fd != -1)
+    {
+      if (close (lo->fd) < 0)
+       fatal_error ("close: %s", xstrerror (errno));
+    }
+}
+
+/* This is passed to lto_obj_add_section.  */
+
+struct lto_obj_add_section_data
+{
+  /* The hash table of sections.  */
+  htab_t section_hash_table;
+  /* The offset of this file.  */
+  off_t base_offset;
+};
+
+/* This is called for each section in the file.  */
+
+static int
+lto_obj_add_section (void *data, const char *name, off_t offset,
+                    off_t length)
+{
+  struct lto_obj_add_section_data *loasd =
+    (struct lto_obj_add_section_data *) data;
+  htab_t section_hash_table = (htab_t) loasd->section_hash_table;
+  char *new_name;
+  struct lto_section_slot s_slot;
+  void **slot;
+
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+              strlen (LTO_SECTION_NAME_PREFIX)) != 0)
+    return 1;
+
+  new_name = xstrdup (name);
+  s_slot.name = new_name;
+  slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
+
+      new_slot->name = new_name;
+      new_slot->start = loasd->base_offset + offset;
+      new_slot->len = length;
+      *slot = new_slot;
+    }
+  else
+    {
+      error ("two or more sections for %s", new_name);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Build a hash table whose key is the section name and whose data is
+   the start and size of each section in the .o file.  */
+
+htab_t
+lto_obj_build_section_table (lto_file *lto_file)
+{
+  struct lto_simple_object *lo = (struct lto_simple_object *) lto_file;
+  htab_t section_hash_table;
+  struct lto_obj_add_section_data loasd;
+  const char *errmsg;
+  int err;
+
+  section_hash_table = lto_obj_create_section_hash_table ();
+
+  gcc_assert (lo->sobj_r != NULL && lo->sobj_w == NULL);
+  loasd.section_hash_table = section_hash_table;
+  loasd.base_offset = lo->base.offset;
+  errmsg = simple_object_find_sections (lo->sobj_r, lto_obj_add_section,
+                                       &loasd, &err);
+  if (errmsg != NULL)
+    {
+      if (err == 0)
+       error ("%s", errmsg);
+      else
+       error ("%s: %s", errmsg, xstrerror (err));
+      htab_delete (section_hash_table);
+      return NULL;
+    }
+
+  return section_hash_table;
+}
+
+/* The current output file.  */
+
+static lto_file *current_out_file;
+
+/* Set the current output file.  Return the old one.  */
+
+lto_file *
+lto_set_current_out_file (lto_file *file)
+{
+  lto_file *old_file;
+
+  old_file = current_out_file;
+  current_out_file = file;
+  return old_file;
+}
+
+/* Return the current output file.  */
+
+lto_file *
+lto_get_current_out_file (void)
+{
+  return current_out_file;
+}
+
+/* Begin writing a new section named NAME in the current output
+   file.  */
+
+void
+lto_obj_begin_section (const char *name)
+{
+  struct lto_simple_object *lo;
+  int align;
+  const char *errmsg;
+  int err;
+
+  lo = (struct lto_simple_object *) current_out_file;
+  gcc_assert (lo != NULL
+             && lo->sobj_r == NULL
+             && lo->sobj_w != NULL
+             && lo->section == NULL);
+
+  align = exact_log2 (POINTER_SIZE / BITS_PER_UNIT);
+  lo->section = simple_object_write_create_section (lo->sobj_w, name, align,
+                                                   &errmsg, &err);
+  if (lo->section == NULL)
+    {
+      if (err == 0)
+       fatal_error ("%s", errmsg);
+      else
+       fatal_error ("%s: %s", errmsg, xstrerror (errno));
+    }
+}
+
+/* Add data to a section.  BLOCK is a pointer to memory containing
+   DATA.  */
+
+void
+lto_obj_append_data (const void *data, size_t len, void *block)
+{
+  struct lto_simple_object *lo;
+  const char *errmsg;
+  int err;
+
+  lo = (struct lto_simple_object *) current_out_file;
+  gcc_assert (lo != NULL && lo->section != NULL);
+
+  errmsg = simple_object_write_add_data (lo->sobj_w, lo->section, data, len,
+                                        1, &err);
+  if (errmsg != NULL)
+    {
+      if (err == 0)
+       fatal_error ("%s", errmsg);
+      else
+       fatal_error ("%s: %s", errmsg, xstrerror (errno));
+    }
+
+  free (block);
+}
+
+/* Stop writing to the current output section.  */
+
+void
+lto_obj_end_section (void)
+{
+  struct lto_simple_object *lo;
+
+  lo = (struct lto_simple_object *) current_out_file;
+  gcc_assert (lo != NULL && lo->section != NULL);
+  lo->section = NULL;
+}