public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [lto] add direct-to-ELF serialization to lto1
@ 2008-06-25 19:04 Ollie Wild
  2008-06-26 13:38 ` Diego Novillo
  2008-06-26 22:10 ` Diego Novillo
  0 siblings, 2 replies; 15+ messages in thread
From: Ollie Wild @ 2008-06-25 19:04 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kenneth Zadeck, Diego Novillo, Doug Kwan (關振德)

[-- Attachment #1: Type: text/plain, Size: 6221 bytes --]

This patch provides the infrastructure for writing ELF files directly
from lto1.  This can be conceptually broken down as follows:

1) New routines have been added to lto-elf.c to implement the
low-level buffering and writing of ELF files.  In places where
distinct routines are required for 32- and 64-bit files, I've created
macros which expand to function definitions.  The low-level routines
use libelf, and where possible, rely on the input routines which are
already present.  Because libelf doesn't support the notion of
incremental writing, the data buffers for each output file must be
kept in memory until the file is written (and subsequently closed).
This is an unfortunate limitation of libelf, which we may want to
revisit later.  For the time being, this means that when we implement
WPA partitioning, we will want to write the output files sequentially
(rather than writing sections randomly).

2) The lto-section-out (and to a lesser degree, lto-function-out)
functions have been modified to force all writes through the
lto_output_stream abstraction.  This ensures the output blocks aren't
tied to the stack and allows the ELF code to take responsibility for
freeing them.

3) In response to feedback from Kenny, I've removed the LTO language
hooks and replaced them with an lto_set_out_hooks function.  This
mirrors the lto_set_in_hooks methodology, making things more
consistent.

Tested with a C/C++/LTO bootstrap and testsuite on i686-pc-linux-gnu.
In addition, I've verified the output can be fed back into lto1 to
generate correct assembly.

Ollie


2008-06-25  Ollie Wild  <aaw@google.com>

        * lto-elf.c (lto-section-out.h): New include.
        (struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
        and data members.
        (cached_file_attrs): New static variable.
        (lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
        Use cached_file_attrs for checking bits.
        (lto_elf_build_section_table): Remove elf_file argument from
        lto_elf_get_shdr and lto_elf_free_shdr calls.
        (DEFINE_INIT_SHDR): New macro.
        (init_shdr32, init_shdr64): New functions defined via the
        DEFINE_INIT_SHDR macro.
        (lto_elf_begin_section_with_type): New function.
        (lto_elf_begin_section): New function.
        (lto_elf_append_data): New function.
        (lto_elf_end_section): New function.
        (DEFINE_VALIDATE_EHDR): New macro.
        (validate_ehdr32, validate_ehdr64): New functions defined via the
        DEFINE_VALIDATE_EHDR macro.
        (validate_file): New function.
        (DEFINE_INIT_EHDR): New macro.
        (init_ehdr32, init_ehdr64): New functions defined via the
        DEFINE_INIT_EHDR macro.
        (init_ehdr): New function.
        (lto_elf_file_open): Add support for writable files.  Move some
        validation logic to validate_file.
        (lto_elf_file_close): Add support for writable files.  Write file data
        and free data blocks.
        (current_out_file): New static variable.
        (lto_set_current_out_file): New function.
        (lto_get_current_out_file): New function.
        * lto.c (lto_main): Call lto_set_hooks and add writable argument to
        lto_elf_file_open calls.  Add temporary initialization for testing
        ELF serialization.
        * lto.h (lto-section-out.h): New include.
        (struct lto_file_struct): Slight modification to comment.
        (lto_elf_file_open): Add writable parameter.
        (lto_elf_begin_section): New function declaration.
        (lto_elf_append_data): New function declaration.
        (lto_elf_end_section): New function declaration.
        (lto_set_current_out_file, lto_get_current_out_file): New function
        declarations.

2008-06-25  Ollie Wild  <aaw@google.com>

        * lto-section-out.h (lto_begin_section_f): New typedef.
        (lto_append_data_f): New typedef.
        (lto_end_section_f): New typedef.
        (lto_set_out_hooks): New function declaration.
        (lto_begin_section): New function declaration.
        (lto_end_section): New function declaration.
        (lto_output_data_stream): New function declaration.
        * lto-section-out.c (output.h): Remove include.
        (saved_section): New static variable.
        (default_begin_section): New function.
        (default_append_data): New function.
        (default_end_section): New function.
        (begin_section_f): New variable.
        (append_data_f): New variable.
        (end_section_f): New variable.
        (lto_set_out_hooks): New function.
        (lto_begin_section): New function.
        (lto_end_section): New function.
        (lto_write_stream): Replace lang_hooks call with append_data_f.
        Remove free call.
        (append_block): New function.
        (lto_output_1_stream): Replace block allocation with call to
        append_block.
        (lto_output_data_stream): New function.
        (lto_destroy_simple_output_block): Add header_stream.  Replace
        lang_hook calls with lto-section functions.
        (write_global_references): Add ref_stream.  Replace lang_hooks call
        with lto-section calls.
        (produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
        with lto-section calls.
        * lto-function-out.c (langhooks.h): Remove include.
        (produce_asm): Add header_stream.  Replace lang_hook calls with
        lto-section calls.
        * langhooks.h (struct lang_hooks_for_lto): Remove.
        (struct lang_hooks): Remove lto member.
        * langhooks-def.h (lhd_begin_section): Remove function declaration.
        (lhd_write_section_data): Remove function declaration.
        (lhd_end_section): Remove function declaration.
        (LANG_HOOKS_BEGIN_SECTION): Remove macro definition.
        (LANG_HOOKS_WRITE_SECTION_DATA): Remove macro definition.
        (LANG_HOOKS_END_SECTION): Remove macro definition.
        (LANG_HOOKS_LTO): Remove macro definition.
        (LANG_HOOKS_INITIALIZER): Remove LANG_HOOKS_LTO.
        * langhooks.c (output.h): Remove include.
        (saved_section): Remove.
        (lhd_begin_section): Remove.
        (lhd_write_section_data): Remove.
        (lhd_end_section): Remove.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: elf-out.patch --]
[-- Type: text/x-diff; name=elf-out.patch, Size: 41764 bytes --]

commit 7d4ceea582a4af699dcbbe75be1475b47dfbbb02
Author: Ollie Wild <aaw@google.com>
Date:   Fri Jun 20 16:36:20 2008 -0700

    Add support for ELF serialization.
    
    	gcc/lto/
    	* lto-elf.c (lto-section-out.h): New include.
    	(struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
    	and data members.
    	(cached_file_attrs): New static variable.
    	(lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
    	Use cached_file_attrs for checking bits.
    	(lto_elf_build_section_table): Remove elf_file argument from
    	lto_elf_get_shdr and lto_elf_free_shdr calls.
    	(DEFINE_INIT_SHDR): New macro.
    	(init_shdr32, init_shdr64): New functions defined via the
    	DEFINE_INIT_SHDR macro.
    	(lto_elf_begin_section_with_type): New function.
    	(lto_elf_begin_section): New function.
    	(lto_elf_append_data): New function.
    	(lto_elf_end_section): New function.
    	(DEFINE_VALIDATE_EHDR): New macro.
    	(validate_ehdr32, validate_ehdr64): New functions defined via the
    	DEFINE_VALIDATE_EHDR macro.
    	(validate_file): New function.
    	(DEFINE_INIT_EHDR): New macro.
    	(init_ehdr32, init_ehdr64): New functions defined via the
    	DEFINE_INIT_EHDR macro.
    	(init_ehdr): New function.
    	(lto_elf_file_open): Add support for writable files.  Move some
    	validation logic to validate_file.
    	(lto_elf_file_close): Add support for writable files.  Write file data
    	and free data blocks.
    	(current_out_file): New static variable.
    	(lto_set_current_out_file): New function.
    	(lto_get_current_out_file): New function.
    	* lto.c (lto_main): Call lto_set_hooks and add writable argument to
    	lto_elf_file_open calls.  Add temporary initialization for testing
    	ELF serialization.
    	* lto.h (lto-section-out.h): New include.
    	(struct lto_file_struct): Slight modification to comment.
    	(lto_elf_file_open): Add writable parameter.
    	(lto_elf_begin_section): New function declaration.
    	(lto_elf_append_data): New function declaration.
    	(lto_elf_end_section): New function declaration.
    	(lto_set_current_out_file, lto_get_current_out_file): New function
    	declarations.
    
    	gcc/
    	* lto-section-out.h (lto_begin_section_f): New typedef.
    	(lto_append_data_f): New typedef.
    	(lto_end_section_f): New typedef.
    	(lto_set_out_hooks): New function declaration.
    	(lto_begin_section): New function declaration.
    	(lto_end_section): New function declaration.
    	(lto_output_data_stream): New function declaration.
    	* lto-section-out.c (output.h): Remove include.
    	(saved_section): New static variable.
    	(default_begin_section): New function.
    	(default_append_data): New function.
    	(default_end_section): New function.
    	(begin_section_f): New variable.
    	(append_data_f): New variable.
    	(end_section_f): New variable.
    	(lto_set_out_hooks): New function.
    	(lto_begin_section): New function.
    	(lto_end_section): New function.
    	(lto_write_stream): Replace lang_hooks call with append_data_f.
    	Remove free call.
    	(append_block): New function.
    	(lto_output_1_stream): Replace block allocation with call to
    	append_block.
    	(lto_output_data_stream): New function.
    	(lto_destroy_simple_output_block): Add header_stream.  Replace
    	lang_hook calls with lto-section functions.
    	(write_global_references): Add ref_stream.  Replace lang_hooks call
    	with lto-section calls.
    	(produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
    	with lto-section calls.
    	* lto-function-out.c (langhooks.h): Remove include.
    	(produce_asm): Add header_stream.  Replace lang_hook calls with
    	lto-section calls.
    	* langhooks.h (struct lang_hooks_for_lto): Remove.
    	(struct lang_hooks): Remove lto member.
    	* langhooks-def.h (lhd_begin_section): Remove function declaration.
    	(lhd_write_section_data): Remove function declaration.
    	(lhd_end_section): Remove function declaration.
    	(LANG_HOOKS_BEGIN_SECTION): Remove macro definition.
    	(LANG_HOOKS_WRITE_SECTION_DATA): Remove macro definition.
    	(LANG_HOOKS_END_SECTION): Remove macro definition.
    	(LANG_HOOKS_LTO): Remove macro definition.
    	(LANG_HOOKS_INITIALIZER): Remove LANG_HOOKS_LTO.
    	* langhooks.c (output.h): Remove include.
    	(saved_section): Remove.
    	(lhd_begin_section): Remove.
    	(lhd_write_section_data): Remove.
    	(lhd_end_section): Remove.

diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e241ebe..6a68663 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -223,21 +223,6 @@ extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_OMP_CLAUSE_DTOR \
 }
 
-/* LTO hooks.  */
-extern void lhd_begin_section (const char *);
-extern void lhd_write_section_data (const void *, size_t);
-extern void lhd_end_section (void);
-
-#define LANG_HOOKS_BEGIN_SECTION lhd_begin_section
-#define LANG_HOOKS_WRITE_SECTION_DATA lhd_write_section_data
-#define LANG_HOOKS_END_SECTION lhd_end_section
-
-#define LANG_HOOKS_LTO { \
-  LANG_HOOKS_BEGIN_SECTION, \
-  LANG_HOOKS_WRITE_SECTION_DATA, \
-  LANG_HOOKS_END_SECTION \
-}
-
 /* The whole thing.  The structure is defined in langhooks.h.  */
 #define LANG_HOOKS_INITIALIZER { \
   LANG_HOOKS_NAME, \
@@ -282,7 +267,6 @@ extern void lhd_end_section (void);
   LANG_HOOKS_TREE_DUMP_INITIALIZER, \
   LANG_HOOKS_DECLS, \
   LANG_HOOKS_FOR_TYPES_INITIALIZER, \
-  LANG_HOOKS_LTO, \
   LANG_HOOKS_GIMPLIFY_EXPR, \
   LANG_HOOKS_FOLD_OBJ_TYPE_REF, \
   LANG_HOOKS_BUILTIN_FUNCTION, \
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 87ec94d..3943f02 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -37,7 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks-def.h"
 #include "ggc.h"
 #include "diagnostic.h"
-#include "output.h"
 
 /* Do nothing; in many cases the default hook.  */
 
@@ -577,52 +576,3 @@ lhd_builtin_function (tree decl)
   lang_hooks.decls.pushdecl (decl);
   return decl;
 }
-
-/* LTO hooks.  */
-
-/* Used to save and restore any previously active section.  */
-static section *saved_section;
-
-
-/* Begin a new LTO output section named NAME.  This default implementation
-   saves the old section and emits assembly code to switch to the new
-   section.  */
-
-void
-lhd_begin_section (const char *name)
-{
-  section *section;
-
-  /* Save the old section so we can restore it in lto_end_asm_section.  */
-  gcc_assert (!saved_section);
-  saved_section = in_section;
-
-  /* Create a new section and switch to it.  */
-  section = get_section (name, SECTION_DEBUG, NULL);
-  switch_to_section (section);
-}
-
-
-/* Write DATA of length LEN to the current LTO output section.  This default
-   implementation just calls assemble_string.  */
-
-void
-lhd_write_section_data (const void *data, size_t len)
-{
-  assemble_string ((const char *)data, len);
-}
-
-
-/* Finish the current LTO output section.  This default implementation emits
-   assembly code to switch to any section previously saved by
-   lhd_begin_section.  */
-
-void
-lhd_end_section (void)
-{
-  if (saved_section)
-    {
-      switch_to_section (saved_section);
-      saved_section = NULL;
-    }
-}
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 1a8b9bf..f37a41d 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -212,21 +212,6 @@ struct lang_hooks_for_decls
   tree (*omp_clause_dtor) (tree clause, tree decl);
 };
 
-/* Language hooks related to LTO serialization.  */
-
-struct lang_hooks_for_lto
-{
-  /* Begin a new LTO section named NAME.  */
-  void (*begin_section) (const char *name);
-
-  /* Write the data at DATA of length LEN to the currently open LTO
-     section.  */
-  void (*write_section_data) (const void *data, size_t len);
-
-  /* End the previously begun LTO section.  */
-  void (*end_section) (void);
-};
-
 /* Language-specific hooks.  See langhooks-def.h for defaults.  */
 
 struct lang_hooks
@@ -409,8 +394,6 @@ struct lang_hooks
 
   struct lang_hooks_for_types types;
 
-  struct lang_hooks_for_lto lto;
-
   /* Perform language-specific gimplification on the argument.  Returns an
      enum gimplify_status, though we can't see that type here.  */
   int (*gimplify_expr) (tree *, tree *, tree *);
diff --git a/gcc/lto-function-out.c b/gcc/lto-function-out.c
index db09592..8d52f2d 100644
--- a/gcc/lto-function-out.c
+++ b/gcc/lto-function-out.c
@@ -33,7 +33,6 @@ Boston, MA 02110-1301, USA.  */
 #include "input.h"
 #include "varray.h"
 #include "hashtab.h"
-#include "langhooks.h"
 #include "basic-block.h"
 #include "tree-iterator.h"
 #include "tree-pass.h"
@@ -1966,6 +1965,7 @@ produce_asm (struct output_block *ob, tree fn)
   enum lto_section_type section_type = ob->section_type;
   struct lto_function_header header;
   char *section_name;
+  struct lto_output_stream *header_stream;
 
   if (section_type == LTO_section_function_body)
     {
@@ -1975,7 +1975,7 @@ produce_asm (struct output_block *ob, tree fn)
   else
     section_name = lto_get_section_name (section_type, NULL);
 
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* The entire header is stream computed here.  */
@@ -2023,8 +2023,10 @@ produce_asm (struct output_block *ob, tree fn)
   header.debug_main_size = -1;
 #endif
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_function_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   /* Put all of the gimple and the string table out the asm file as a
      block of text.  */
@@ -2050,7 +2052,7 @@ produce_asm (struct output_block *ob, tree fn)
   lto_write_stream (ob->debug_main_stream);
 #endif
 
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 }
 
 
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
index 1b2ed2a..4b24098 100644
--- a/gcc/lto-section-out.c
+++ b/gcc/lto-section-out.c
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-section.h"
 #include "lto-section-out.h"
 #include "lto-tree-out.h"
+#include "output.h"
 #include <ctype.h>
 #include <strings.h>
 
@@ -187,11 +188,100 @@ lto_get_section_name (enum lto_section_type section_type, const char *name)
 }
 
 
+/* Default output hooks.  */
+
+/* Used to save and restore any previously active section.  */
+static section *saved_section;
+
+
+/* Begin a new output section named NAME.  This default implementation
+   saves the old section and emits assembly code to switch to the new
+   section.  */
+
+static void
+default_begin_section (const char *name)
+{
+  section *section;
+
+  /* Save the old section so we can restore it in default_end_section.  */
+  gcc_assert (!saved_section);
+  saved_section = in_section;
+
+  /* Create a new section and switch to it.  */
+  section = get_section (name, SECTION_DEBUG, NULL);
+  switch_to_section (section);
+}
+
+
+/* Write DATA of length LEN to the current output section.  This default
+   implementation just calls assemble_string and frees BASE.  */
+
+static void
+default_append_data (const void *data, size_t len,
+		     struct lto_char_ptr_base *base)
+{
+  assemble_string ((const char *)data, len);
+  free (base);
+}
+
+
+/* Finish the current output section.  This default implementation emits
+   assembly code to switch to any section previously saved by
+   default_begin_section.  */
+
+static void
+default_end_section (void)
+{
+  if (saved_section)
+    {
+      switch_to_section (saved_section);
+      saved_section = NULL;
+    }
+}
+
+
+static lto_begin_section_f *begin_section_f = default_begin_section;
+static lto_append_data_f *append_data_f = default_append_data;
+static lto_end_section_f *end_section_f = default_end_section;
+
+
+/* Install BEGIN_F, APPEND_F, and END_F as output hooks.  This is used by the
+   LTO front end to support writing directly to ELF files.  */
+
+void
+lto_set_out_hooks (lto_begin_section_f *begin_f,
+		   lto_append_data_f *append_f,
+		   lto_end_section_f *end_f)
+{
+  begin_section_f = begin_f;
+  append_data_f = append_f;
+  end_section_f = end_f;
+}
+
+
 /*****************************************************************************
    Output routines shared by all of the serialization passes.
 *****************************************************************************/
 
 
+/* Begin a new output section named NAME.  */
+
+void
+lto_begin_section (const char *name)
+{
+  begin_section_f (name);
+}
+
+
+/* End the current output section.  */
+
+void
+lto_end_section (void)
+{
+  end_section_f ();
+}
+
+
 /* Write all of the chars in OBS to the assembler.  Recycle the blocks
    in obs as this is being done.  */
 
@@ -217,13 +307,54 @@ lto_write_stream (struct lto_output_stream *obs)
       if (!block)
 	num_chars = num_chars - obs->left_in_block;
 
-      lang_hooks.lto.write_section_data (base, num_chars);
-      free (old_block);
+      append_data_f (base, num_chars, old_block);
       block_size *= 2;
     }
 }
 
 
+/* Adds a new block to output stream OBS.  */
+
+static void
+append_block (struct lto_output_stream *obs)
+{
+  struct lto_char_ptr_base *new_block;
+
+  gcc_assert (obs->left_in_block == 0);
+
+  if (obs->first_block == NULL)
+    {
+      /* This is the first time the stream has been written
+	 into.  */
+      obs->block_size = 1024;
+      new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
+      obs->first_block = new_block;
+    }
+  else
+    {
+      struct lto_char_ptr_base *tptr;
+      /* Get a new block that is twice as big as the last block
+	 and link it into the list.  */
+      obs->block_size *= 2;
+      new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
+      /* The first bytes of the block are reserved as a pointer to
+	 the next block.  Set the chain of the full block to the
+	 pointer to the new block.  */
+      tptr = obs->current_block;
+      tptr->ptr = (char *)new_block;
+    }
+
+  /* Set the place for the next char at the first position after the
+     chain to the next block.  */
+  obs->current_pointer
+    = ((char *)new_block) + sizeof (struct lto_char_ptr_base);
+  obs->current_block = new_block;
+  /* Null out the newly allocated block's pointer to the next block.  */
+  new_block->ptr = NULL;
+  obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
+}
+
+
 /* Write a character to the output block.  */
 
 void
@@ -231,40 +362,7 @@ lto_output_1_stream (struct lto_output_stream *obs, char c)
 {
   /* No space left.  */
   if (obs->left_in_block == 0)
-    {
-      struct lto_char_ptr_base *new_block;
-
-      if (obs->first_block == NULL)
-	{
-	  /* This is the first time the stream has been written
-	     into.  */
-	  obs->block_size = 1024;
-	  new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
-	  obs->first_block = new_block;
-	}
-      else
-	{
-	  struct lto_char_ptr_base *tptr;
-	  /* Get a new block that is twice as big as the last block
-	     and link it into the list.  */
-	  obs->block_size *= 2;
-	  new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
-	  /* The first bytes of the block are reserved as a pointer to
-	     the next block.  Set the chain of the full block to the
-	     pointer to the new block.  */
-	  tptr = obs->current_block;
-	  tptr->ptr = (char *)new_block;
-	}
-
-      /* Set the place for the next char at the first position after the
-	 chain to the next block.  */
-      obs->current_pointer
-	= ((char *)new_block) + sizeof (struct lto_char_ptr_base);
-      obs->current_block = new_block;
-      /* Null out the newly allocated block's pointer to the next block.  */
-      new_block->ptr = NULL;
-      obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
-    }
+    append_block (obs);
 
   /* Write the actual character.  */
   *obs->current_pointer = c;
@@ -274,6 +372,37 @@ lto_output_1_stream (struct lto_output_stream *obs, char c)
 }
 
 
+/* Write raw DATA of length LEN to the output block OB.  */
+
+void
+lto_output_data_stream (struct lto_output_stream *obs, const void *data,
+			size_t len)
+{
+  while (len)
+    {
+      size_t copy;
+
+      /* No space left.  */
+      if (obs->left_in_block == 0)
+	append_block (obs);
+
+      /* Determine how many bytes to copy in this loop.  */
+      if (len <= obs->left_in_block)
+	copy = len;
+      else
+	copy = obs->left_in_block;
+
+      /* Copy the data and do bookkeeping.  */
+      memcpy (obs->current_pointer, data, copy);
+      obs->current_pointer += copy;
+      obs->total_size += copy;
+      obs->left_in_block -= copy;
+      data = (char *)data + copy;
+      len -= copy;
+    }
+}
+
+
 /* Output an unsigned LEB128 quantity to OBS.  */
 
 void
@@ -561,9 +690,10 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
 {
   char *section_name;
   struct lto_simple_header header;
+  struct lto_output_stream *header_stream;
 
   section_name = lto_get_section_name (ob->section_type, NULL);
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* Write the header which says how to decode the pieces of the
@@ -582,8 +712,10 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
   header.debug_main_size = -1;
 #endif
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_simple_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   lto_write_stream (ob->main_stream);
 #ifdef LTO_STREAM_DEBUGGING
@@ -592,7 +724,7 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
 
   /* Put back the assembly section that was there before we started
      writing lto info.  */
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 
   free (ob->main_stream);
   LTO_CLEAR_DEBUGGING_STREAM (debug_main_stream);
@@ -738,14 +870,15 @@ write_global_references (struct output_block *ob, VEC(tree,heap) *v)
 {
   tree t;
   int index;
-  size_t size = VEC_length (tree, v) * sizeof (int32_t);
-  int32_t *refs = xmalloc (size);
+  struct lto_output_stream *ref_stream;
 
+  ref_stream = xcalloc (1, sizeof (struct lto_output_stream));
   for (index = 0; VEC_iterate(tree, v, index, t); index++)
     {
       void **slot;
       struct lto_decl_slot d_slot;
       struct lto_decl_slot *old_slot;
+      int32_t slot_num;
 
       d_slot.t = t;
       slot = htab_find_slot (ob->main_hash_table, &d_slot, NO_INSERT);
@@ -756,11 +889,12 @@ write_global_references (struct output_block *ob, VEC(tree,heap) *v)
       print_generic_expr (stderr, t, 0);
       fprintf (stderr, "\n");
 #endif
-      refs[index] = old_slot->slot_num;
+      slot_num = old_slot->slot_num;
+      lto_output_data_stream (ref_stream, &slot_num, sizeof slot_num);
     }
 
-  lang_hooks.lto.write_section_data (refs, size);
-  free (refs);
+  lto_write_stream (ref_stream);
+  free (ref_stream);
 }
 
 
@@ -777,6 +911,7 @@ produce_asm_for_decls (void)
   struct lto_decl_header header;
   char *section_name;
   struct output_block *ob = create_output_block (LTO_section_decls);
+  struct lto_output_stream *header_stream;
 
   free_lang_specifics ();
 
@@ -792,7 +927,7 @@ produce_asm_for_decls (void)
   memset (&header, 0, sizeof (struct lto_decl_header)); 
 
   section_name = lto_get_section_name (LTO_section_decls, NULL);
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* Make string 0 be a NULL string.  */
@@ -826,8 +961,10 @@ produce_asm_for_decls (void)
   header.string_size = ob->string_stream->total_size;
   header.debug_main_size = ob->debug_main_stream->total_size;
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_decl_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   /* We must write the types first.  */
   write_global_references (ob, out_state->types);
@@ -862,7 +999,7 @@ produce_asm_for_decls (void)
   VEC_free (tree, heap, out_state->namespace_decls);
   VEC_free (tree, heap, out_state->types);
 
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 }
 
 
diff --git a/gcc/lto-section-out.h b/gcc/lto-section-out.h
index 6b1d632..eba1011 100644
--- a/gcc/lto-section-out.h
+++ b/gcc/lto-section-out.h
@@ -132,6 +132,20 @@ struct lto_simple_output_block
 #endif
 };
 
+/* Begin a new output section.  */
+typedef void (lto_begin_section_f) (const char *);
+
+/* Append data of the given size to the currently active output section.  The
+   lto_char_ptr_base argument points to the beginning of allocated memory,
+   which will be freed when the output is written to disk.  */
+typedef void (lto_append_data_f) (const void *, size_t, struct
+					  lto_char_ptr_base *);
+
+/* Close the currently active output section.  */
+typedef void (lto_end_section_f) (void);
+
+void lto_set_out_hooks (lto_begin_section_f *, lto_append_data_f *,
+			lto_end_section_f *);
 
 void lto_set_flag (unsigned HOST_WIDEST_INT *, unsigned int);
 void lto_set_flags (unsigned HOST_WIDEST_INT *, unsigned int, unsigned int);
@@ -142,8 +156,11 @@ int lto_eq_type_slot_node (const void *, const void *);
 hashval_t lto_hash_global_slot_node (const void *);
 int lto_eq_global_slot_node (const void *, const void *);
 
+void lto_begin_section (const char *);
+void lto_end_section (void);
 void lto_write_stream (struct lto_output_stream *);
 void lto_output_1_stream (struct lto_output_stream *, char);
+void lto_output_data_stream (struct lto_output_stream *, const void *, size_t);
 void lto_output_uleb128_stream (struct lto_output_stream *,
 				unsigned HOST_WIDE_INT);
 void lto_output_widest_uint_uleb128_stream (struct lto_output_stream *,
diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c
index 57c5adf..db75db3 100644
--- a/gcc/lto/lto-elf.c
+++ b/gcc/lto/lto-elf.c
@@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA.  */
 #include "tm.h"
 #include "libiberty.h"
 #include "ggc.h"
+#include "lto-section-out.h"
 
 
 /* ### Moved lto_file_init and lto_file_close here from lto.c.
@@ -57,7 +58,7 @@ lto_file_close (lto_file *file ATTRIBUTE_UNUSED)
   ggc_free (file);
 }
 
-/* An ELF input file.  */
+/* An ELF file.  */
 struct lto_elf_file 
 {
   /* The base information.  */
@@ -66,23 +67,40 @@ struct lto_elf_file
   int fd;
   /* The libelf descriptor for the file.  */
   Elf *elf;
-  /* 32 or 64 bits? */
-  size_t bits;
   /* 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 (lto_elf_file *elf_file,
-		  Elf_Scn *section)
+lto_elf_get_shdr (Elf_Scn *section)
 {
   Elf64_Shdr *shdr;
 
-  switch (elf_file->bits)
+  switch (cached_file_attrs.bits)
     {
     case 32:
       {
@@ -122,9 +140,9 @@ lto_elf_get_shdr (lto_elf_file *elf_file,
 
 /* Free SHDR, previously allocated by lto_elf_get_shdr.  */
 static void
-lto_elf_free_shdr (lto_elf_file *elf_file, Elf64_Shdr *shdr)
+lto_elf_free_shdr (Elf64_Shdr *shdr)
 {
-  if (elf_file->bits != 64)
+  if (cached_file_attrs.bits != 64)
     free (shdr);
 }
 
@@ -184,7 +202,7 @@ lto_elf_build_section_table (lto_file *lto_file)
       struct lto_section_slot s_slot;
 
       /* Get the name of this section.  */
-      shdr = lto_elf_get_shdr (elf_file, section);
+      shdr = lto_elf_get_shdr (section);
       offset = shdr->sh_name;
       name = elf_strptr (elf_file->elf, 
 			 elf_file->sec_strtab,
@@ -194,7 +212,7 @@ lto_elf_build_section_table (lto_file *lto_file)
       if (strncmp (name, LTO_SECTION_NAME_PREFIX, 
 		   strlen (LTO_SECTION_NAME_PREFIX)) != 0)
 	{
-	  lto_elf_free_shdr (elf_file, shdr);
+	  lto_elf_free_shdr (shdr);
 	  continue;
 	}
 
@@ -218,49 +236,184 @@ lto_elf_build_section_table (lto_file *lto_file)
 	  error ("two or more sections for %s:", new_name);
 	  return NULL;
 	}
-      lto_elf_free_shdr (elf_file, shdr);
+      lto_elf_free_shdr (shdr);
     }
   return section_hash_table;
 }
 
 
-lto_file *
-lto_elf_file_open (const char *filename)
-{
-  lto_elf_file *elf_file;
-  size_t bits;
-  const char *elf_ident;
-  lto_file *result;
+/* 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)							      \
+    fatal_error ("elf"#BITS"_getshdr() failed: %s.", elf_errmsg(-1)); \
+								      \
+  shdr->sh_name = sh_name;					      \
+  shdr->sh_type = sh_type;					      \
+  shdr->sh_flags = 0;						      \
+  shdr->sh_entsize = 0;						      \
+}
 
-  /* Set up.  */
-  elf_file = GGC_NEW (lto_elf_file);
-  result = (lto_file *)elf_file;
-  lto_file_init (result, filename);
-  elf_file->fd = -1;
-  elf_file->elf = NULL;
+DEFINE_INIT_SHDR (32)
+DEFINE_INIT_SHDR (64)
 
-  /* Open the file.  */
-  elf_file->fd = open (filename, O_RDONLY);
-  if (elf_file->fd == -1)
-    {
-      error ("could not open");
-      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;
-    }
+/* Begin a new ELF section named NAME with type TYPE in the current output
+   file.  TYPE is an SHT_* macro from the libelf headers.  */
 
-  /* Open the ELF file descriptor.  */
-  elf_file->elf = elf_begin (elf_file->fd, ELF_C_READ, NULL);
-  if (!elf_file->elf)
+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 ("elf_newscn() failed: %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)
     {
-      error ("could not open ELF file: %s", elf_errmsg (0));
-      goto fail;
+    case 32:
+      init_shdr32 (scn, sh_name, type);
+      break;
+
+    case 64:
+      init_shdr64 (scn, sh_name, type);
+      break;
+
+    default:
+      gcc_unreachable ();
     }
+}
+
+
+/* Begin a new ELF section named NAME in the current output file.  */
+
+void
+lto_elf_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_elf_append_data (const void *data, size_t len,
+		     struct lto_char_ptr_base *base)
+{
+  lto_elf_file *file;
+  Elf_Data *elf_data;
+
+  /* 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 ("elf_newdata() failed: %s.", elf_errmsg(-1));
+
+  elf_data->d_align = 1;
+  elf_data->d_buf = (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_elf_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;
+}
+
+
+/* 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;	\
+								\
+  if (cached_file_attrs.elf_machine != elf_header->e_machine)	\
+    {								\
+      error ("inconsistent file architecture detected");	\
+      return false;						\
+    }								\
+								\
+  return true;							\
+}
+
+DEFINE_VALIDATE_EHDR (32)
+DEFINE_VALIDATE_EHDR (64)
+
+
+/* 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
@@ -270,61 +423,165 @@ lto_elf_file_open (const char *filename)
     {
       error ("could not read ELF identification information: %s",
 	      elf_errmsg (0));
-      goto fail;
+      return false;
 	     
     }
-  switch (elf_ident[EI_CLASS])
+
+  if (!cached_file_attrs.initialized)
     {
-    case ELFCLASS32:
-      bits = 32;
+      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);
+    }
+
+  if (memcmp (elf_ident, cached_file_attrs.elf_ident,
+	      sizeof cached_file_attrs.elf_ident))
+    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 ELFCLASS64:
-      bits = 64;
+
+    case 64:
+      if (!validate_ehdr64 (elf_file))
+	return false;
       break;
+
     default:
-      error ("unsupported ELF file class");
-      goto fail;
+      gcc_unreachable ();
     }
-  elf_file->bits = bits;
-
-  /* Check that the input file is a relocatable object file.  */
-#define ELF_CHECK_FILE_TYPE(N)						\
-  do {									\
-    Elf##N##_Ehdr *elf_header;						\
-    elf_header = elf##N##_getehdr (elf_file->elf);			\
-    if (!elf_header)							\
-      {									\
-	error ("could not read ELF header: %s", elf_errmsg (0));	\
-        goto fail;							\
-      }									\
-   if (elf_header->e_type != ET_REL)					\
-     {									\
-        error ("not a relocatable ELF object file");			\
-        goto fail;							\
-     }									\
-  } while (false)
-
-  switch (bits)
+
+  /* Read the string table used for section header names.  */
+  if (elf_getshstrndx (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)							      \
+    fatal_error ("elf"#BITS"_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_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:
-      ELF_CHECK_FILE_TYPE (32);
+      init_ehdr32 (elf_file);
       break;
+
     case 64:
-      ELF_CHECK_FILE_TYPE (64);
+      init_ehdr64 (elf_file);
       break;
+
     default:
       gcc_unreachable ();
     }
+}
 
-#undef ELF_CHECK_FILE_TYPE
 
-  /* Read the string table used for section header names.  */
-  if (elf_getshstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
+/* 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_elf_file_open (const char *filename, bool writable)
+{
+  lto_elf_file *elf_file;
+  lto_file *result;
+
+  /* Set up.  */
+  elf_file = GGC_CNEW (lto_elf_file);
+  result = (lto_file *)elf_file;
+  lto_file_init (result, filename);
+  elf_file->fd = -1;
+
+  /* Open the file.  */
+  elf_file->fd = open (filename, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666);
+  if (elf_file->fd == -1)
     {
-      error ("could not locate ELF string table: %s", elf_errmsg (0));
+      error ("could not open");
       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 ELF file: %s", elf_errmsg (0));
+      goto fail;
+    }
+
+  if (writable)
+    {
+      init_ehdr (elf_file);
+      elf_file->shstrtab_stream = xcalloc (1,
+					   sizeof (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:
@@ -332,13 +589,72 @@ lto_elf_file_open (const char *filename)
   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_elf_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)
+    {
+      lto_file *old_file = lto_set_current_out_file (file);
+
+      lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
+      elfx_update_shstrndx (elf_file->elf, elf_ndxscn (elf_file->scn));
+      lto_write_stream (elf_file->shstrtab_stream);
+      lto_elf_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);
+    }
+
   lto_file_close (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.c b/gcc/lto/lto.c
index bbc4de0..76c0420 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -415,15 +415,19 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
     = XNEWVEC (struct lto_file_decl_data*, num_in_fnames + 1);
   struct lto_file_decl_data* file_data = NULL;
 
-  /* Set the hooks so that all of the ipa passes can read in their data.  */
+  /* Set input hooks so that all of the ipa passes can read in their data.  */
   lto_set_in_hooks (all_file_decl_data, get_section_data,
 		    free_section_data);
 
+  /* Set output hooks.  */
+  lto_set_out_hooks (lto_elf_begin_section, lto_elf_append_data,
+		     lto_elf_end_section);
+
   /* Read all of the object files specified on the command line.  */
   for (i = 0; i < num_in_fnames; ++i)
     {
       htab_t section_hash_table;
-      current_lto_file = lto_elf_file_open (in_fnames[i]);
+      current_lto_file = lto_elf_file_open (in_fnames[i], /*writable=*/false);
       if (!current_lto_file)
 	break;
       file_data = lto_file_read (current_lto_file);
@@ -488,10 +492,33 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
                               /*top_level=*/1,
                               /*at_end=*/0);
 
+  /* This is some bogus wrapper code for development testing.  It will be
+     replaced once some basic WPA partitioning logic is implemented.  To use
+     this pass "-flto -fsyntax-only" to the lto1 invocation.  */
+  if (flag_generate_lto)
+    {
+      lto_file *file;
+
+      file = lto_elf_file_open ("bogus.lto.o", /*writable=*/true);
+      if (!file)
+	fatal_error ("lto_elf_file_open() failed");
+      lto_set_current_out_file (file);
+    }
+
   /* Let the middle end know that we have read and merged all of the
      input files.  */ 
   /*cgraph_finalize_compilation_unit ();*/
   cgraph_optimize ();
+
+  /* This is the continuation of the previous bogus wrapper code.  It will be
+     replaced once some basic WPA partitioning logic is implemented.  */
+  if (flag_generate_lto)
+    {
+      lto_file *file;
+
+      file = lto_set_current_out_file (NULL);
+      lto_elf_file_close (file);
+    }
 }
 
 #include "gt-lto-lto.h"
diff --git a/gcc/lto/lto.h b/gcc/lto/lto.h
index c39f983..ab614b0 100644
--- a/gcc/lto/lto.h
+++ b/gcc/lto/lto.h
@@ -30,8 +30,9 @@ Boston, MA 02110-1301, USA.  */
 #include <inttypes.h>
 #include "lto-header.h"
 #include "lto-section-in.h"
+#include "lto-section-out.h"
 
-/* An input file.  */
+/* A file.  */
 typedef struct lto_file_struct GTY(())
 {
   /* The name of the file.  */
@@ -55,8 +56,8 @@ extern void lto_main (int debug_p);
 
 /* lto-elf.c */
 
-/* Open the ELF input file indicated by FILENAME.  Return */
-extern lto_file *lto_elf_file_open (const char *filename);
+/* Open the ELF file indicated by FILENAME.  Return */
+extern lto_file *lto_elf_file_open (const char *filename, bool writable);
 
 /* Close an ELF input file.  */
 extern void lto_elf_file_close (lto_file *file);
@@ -64,6 +65,16 @@ extern void lto_elf_file_close (lto_file *file);
 /* Build and index of all lto sections in an elf file.  */
 extern htab_t lto_elf_build_section_table (lto_file *file);
 
+/* Hooks for writing LTO sections.  */
+extern void lto_elf_begin_section (const char *name);
+extern void lto_elf_append_data (const void *data, size_t len,
+				 struct lto_char_ptr_base *base);
+extern void lto_elf_end_section (void);
+
+/* Routines for setting/getting the current output file.  */
+extern lto_file *lto_set_current_out_file (lto_file *file);
+extern lto_file *lto_get_current_out_file (void);
+
 /* lto-symtab.c */
 
 /* The NEW_VAR (a VAR_DECL) has just been read.  If there is an

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-25 19:04 [lto] add direct-to-ELF serialization to lto1 Ollie Wild
@ 2008-06-26 13:38 ` Diego Novillo
  2008-06-26 17:57   ` Ollie Wild
  2008-06-26 18:30   ` Kenneth Zadeck
  2008-06-26 22:10 ` Diego Novillo
  1 sibling, 2 replies; 15+ messages in thread
From: Diego Novillo @ 2008-06-26 13:38 UTC (permalink / raw)
  To: Ollie Wild
  Cc: gcc-patches, Kenneth Zadeck,
	"Doug Kwan (關振德)"

On 6/25/08 2:56 PM, Ollie Wild wrote:

> 3) In response to feedback from Kenny, I've removed the LTO language
> hooks and replaced them with an lto_set_out_hooks function.  This
> mirrors the lto_set_in_hooks methodology, making things more
> consistent.

I don't understand this.  Why not use langhooks instead of using another 
hook mechanism?  It's the same thing, but it seems to me that it'd be 
more natural to just use the langhooks harness that we already have.

Kenny, any particular reason for having another hook mechanism?

Going through the rest of the patch now.


Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 13:38 ` Diego Novillo
@ 2008-06-26 17:57   ` Ollie Wild
  2008-06-26 18:40     ` Ollie Wild
  2008-06-26 18:58     ` Diego Novillo
  2008-06-26 18:30   ` Kenneth Zadeck
  1 sibling, 2 replies; 15+ messages in thread
From: Ollie Wild @ 2008-06-26 17:57 UTC (permalink / raw)
  To: Diego Novillo
  Cc: gcc-patches, Kenneth Zadeck,
	"Doug Kwan (關振德)"

On Thu, Jun 26, 2008 at 5:48 AM, Diego Novillo <dnovillo@google.com> wrote:
>
> I don't understand this.  Why not use langhooks instead of using another hook mechanism?  It's the same thing, but it seems to me that it'd be more natural to just use the langhooks harness that we already have.

One reason is because we will likely end up with multiple
implementations for the various object file formats (think Apple).
Having a dynamic registration facility simplifies this.  Otherwise,
the langhooks will end up being replaced by switch statements which
call the *real* langhooks.

Ollie

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 13:38 ` Diego Novillo
  2008-06-26 17:57   ` Ollie Wild
@ 2008-06-26 18:30   ` Kenneth Zadeck
  2008-06-26 19:06     ` Diego Novillo
  1 sibling, 1 reply; 15+ messages in thread
From: Kenneth Zadeck @ 2008-06-26 18:30 UTC (permalink / raw)
  To: Diego Novillo
  Cc: Ollie Wild, gcc-patches, "Doug Kwan (關振德)"

Diego Novillo wrote:
> On 6/25/08 2:56 PM, Ollie Wild wrote:
>
>> 3) In response to feedback from Kenny, I've removed the LTO language
>> hooks and replaced them with an lto_set_out_hooks function.  This
>> mirrors the lto_set_in_hooks methodology, making things more
>> consistent.
>
> I don't understand this.  Why not use langhooks instead of using 
> another hook mechanism?  It's the same thing, but it seems to me that 
> it'd be more natural to just use the langhooks harness that we already 
> have.
>
> Kenny, any particular reason for having another hook mechanism?
>
> Going through the rest of the patch now.
>
>
> Diego.
There were three issues here:

First, we want all of the lang hooks to go away.  So adding lang hooks, 
on the surface seemed confusing. 

Second, the lang hooks mechanism seemed complex and somewhat heavy 
weight.  The langhooks are to provide functionality that works 
differently depending on which front end is hooked in, all we were 
trying to do was make up for the fact that the gcc part cannot call 
directly into a front end.

Third, lang hooks are designed to work differently for each front end, 
but are generally stable for that front end.  What ollie has implemented 
are lto hooks that work differently based on what lto mode you are in. 

I realize that all of these are subtle arguments, but they add up.

kenny


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 17:57   ` Ollie Wild
@ 2008-06-26 18:40     ` Ollie Wild
  2008-06-26 18:58     ` Diego Novillo
  1 sibling, 0 replies; 15+ messages in thread
From: Ollie Wild @ 2008-06-26 18:40 UTC (permalink / raw)
  To: Diego Novillo
  Cc: gcc-patches, Kenneth Zadeck,
	"Doug Kwan (關振德)"

On Thu, Jun 26, 2008 at 10:48 AM, Ollie Wild <aaw@google.com> wrote:
>
> One reason is because we will likely end up with multiple
> implementations for the various object file formats (think Apple).
> Having a dynamic registration facility simplifies this.  Otherwise,
> the langhooks will end up being replaced by switch statements which
> call the *real* langhooks.

Diego has pointed out that the object format is uniquely determined at
build time.  Consequently, this can be handled with conditional
inclusion inside lto-lang.c, making my point mute.

Ollie

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 17:57   ` Ollie Wild
  2008-06-26 18:40     ` Ollie Wild
@ 2008-06-26 18:58     ` Diego Novillo
  1 sibling, 0 replies; 15+ messages in thread
From: Diego Novillo @ 2008-06-26 18:58 UTC (permalink / raw)
  To: Ollie Wild
  Cc: gcc-patches, Kenneth Zadeck,
	"Doug Kwan (關振德)"

On 2008-06-26, Ollie Wild <aaw@google.com> wrote:
> On Thu, Jun 26, 2008 at 5:48 AM, Diego Novillo <dnovillo@google.com> wrote:
>  >
>
> > I don't understand this.  Why not use langhooks instead of using another hook mechanism?  It's the same thing, but it seems to me that it'd be more natural to just use the langhooks harness that we already have.
>
>
> One reason is because we will likely end up with multiple
>  implementations for the various object file formats (think Apple).
>  Having a dynamic registration facility simplifies this.  Otherwise,
>  the langhooks will end up being replaced by switch statements which
>  call the *real* langhooks.

But in this case, we simply conditionally #define the langhooks for
each target format.   So, in langhooks-def.h we define
L_H_BEGIN_SECTION, L_H_WRITE_SECTION_DATA and L_H_END_SECTION to the
default (empty) versions.

In lto/lto-lang.c we conditionally define them based on the target
format, something like

#if defined OBJECT_FORMAT_ELF
#define LANG_HOOKS_BEGIN_SECTION elf_begin_section
...
#endif

Does this make sense?


Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 18:30   ` Kenneth Zadeck
@ 2008-06-26 19:06     ` Diego Novillo
  2008-06-26 20:07       ` Tom Tromey
  0 siblings, 1 reply; 15+ messages in thread
From: Diego Novillo @ 2008-06-26 19:06 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Ollie Wild, gcc-patches, "Doug Kwan (關振德)"

On 2008-06-26, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:

>  First, we want all of the lang hooks to go away.  So adding lang hooks, on
> the surface seemed confusing.

All of the lang hooks?  I don't think we want to get rid of all of
them.  Langhooks are useful when slightly similar front ends have
slightly different needs.  For instance, the C, Obj-C and Obj-C++ FEs
share quite a bit.  In this case the LTO FE would need to do slightly
different things depending on how it's configured.  The langhook
mechanism seems like a good fit for this.

I agree that we do not want langhooks slipping into the middle end.
My thinking is that right after we hand things off to the optimizers,
we clear out the lang_hooks structure to prevent any "leakage".

>  Second, the lang hooks mechanism seemed complex and somewhat heavy weight.
> The langhooks are to provide functionality that works differently depending
> on which front end is hooked in, all we were trying to do was make up for
> the fact that the gcc part cannot call directly into a front end.

Right, and this is one case of the FE needing to do different things
depending on how it's configured.  Initially, only the ELF
functionality will be bolted in.

The other option, of course, is for us to decide that we will only
ever support ELF.  In which case, I agree, we can do away with these
three hooks altogether.


Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 19:06     ` Diego Novillo
@ 2008-06-26 20:07       ` Tom Tromey
  2008-06-27 22:37         ` Mark Mitchell
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2008-06-26 20:07 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches

>>>>> "Diego" == Diego Novillo <dnovillo@google.com> writes:

Diego> All of the lang hooks?  I don't think we want to get rid of all
Diego> of them.

Yeah, we can't ever get rid of all of them -- we could do it nominally
but only by reintroducing the same thing under a different name.
E.g., you need a lang-hook-equivalent to call the FE's parser at all.

Diego> I agree that we do not want langhooks slipping into the middle end.

FWIW the way I usually think about this is that the bad lang hooks are
those that are required to explain the meaning of a tree.  Anything
like that ought to be directly in the IR -- this applies to random
globals, too... as discussed before.

Diego> My thinking is that right after we hand things off to the optimizers,
Diego> we clear out the lang_hooks structure to prevent any "leakage".

Nice.

Tom

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-25 19:04 [lto] add direct-to-ELF serialization to lto1 Ollie Wild
  2008-06-26 13:38 ` Diego Novillo
@ 2008-06-26 22:10 ` Diego Novillo
  2008-06-27 20:16   ` Ollie Wild
  1 sibling, 1 reply; 15+ messages in thread
From: Diego Novillo @ 2008-06-26 22:10 UTC (permalink / raw)
  To: Ollie Wild
  Cc: gcc-patches, Kenneth Zadeck, Doug Kwan (關振德)

On Wed, Jun 25, 2008 at 14:56, Ollie Wild <aaw@google.com> wrote:

> +  if (obs->first_block == NULL)
> +    {
> +      /* This is the first time the stream has been written
> +	 into.  */
> +      obs->block_size = 1024;

Does it make sense to #define or --param this number?

> +	 pointer to the new block.  */
> +      tptr = obs->current_block;
> +      tptr->ptr = (char *)new_block;

Space after typecast.

> +    }
> +
> +  /* Set the place for the next char at the first position after the
> +     chain to the next block.  */
> +  obs->current_pointer
> +    = ((char *)new_block) + sizeof (struct lto_char_ptr_base);

Likewise.

> @@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA.  */
>  #include "tm.h"
>  #include "libiberty.h"
>  #include "ggc.h"
> +#include "lto-section-out.h"

Needs corresponding changes in lto/Make-lang.in

> +  /* Grab the current output file and do some basic assertion checking.  */
> +  file = (lto_elf_file *)lto_get_current_out_file (),

Space after type cast.

> +  gcc_assert (file);
> +  gcc_assert (file->elf);
> +  gcc_assert (!file->scn);
> +
> +  /* Create a new section.  */
> +  scn = elf_newscn(file->elf);

Space after '('.

> +
> +  /* Free any ELF data buffers.  */
> +  cur = elf_file->data;
> +  while (cur)
> +    {
> +      tmp = cur;
> +      cur = (struct lto_char_ptr_base *)cur->ptr;

Space after typecast.

> +  /* This is some bogus wrapper code for development testing.  It will be
> +     replaced once some basic WPA partitioning logic is implemented.  To use
> +     this pass "-flto -fsyntax-only" to the lto1 invocation.  */
> +  if (flag_generate_lto)
> +    {
> +      lto_file *file;
> +
> +      file = lto_elf_file_open ("bogus.lto.o", /*writable=*/true);
> +      if (!file)
> +	fatal_error ("lto_elf_file_open() failed");
> +      lto_set_current_out_file (file);
> +    }
> +

I'm confused by this hunk.  What are you testing here?  It also
seems that it will trigger with just -flto.  Where does
-fsyntax-only come to play?

> -/* Open the ELF input file indicated by FILENAME.  Return */
> -extern lto_file *lto_elf_file_open (const char *filename);
> +/* Open the ELF file indicated by FILENAME.  Return */

Return what?


With the exception of the -fsyntax-only test and the langhooks,
the rest looks fine to me.


Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 22:10 ` Diego Novillo
@ 2008-06-27 20:16   ` Ollie Wild
  2008-06-27 20:54     ` Kenneth Zadeck
  2008-06-27 21:38     ` Diego Novillo
  0 siblings, 2 replies; 15+ messages in thread
From: Ollie Wild @ 2008-06-27 20:16 UTC (permalink / raw)
  To: Diego Novillo
  Cc: gcc-patches, Kenneth Zadeck, Doug Kwan (關振德)

[-- Attachment #1: Type: text/plain, Size: 6174 bytes --]

>> +      obs->block_size = 1024;
>
> Does it make sense to #define or --param this number?

This isn't my code.  It's just cut-and-pasted from Kenny's
lto_output_1_stream.  I think a discussion of how this algorithm could
be improved is worthwhile, but let's make it a separate discussion.


>> +  /* This is some bogus wrapper code for development testing.  It will be
>> +     replaced once some basic WPA partitioning logic is implemented.  To use
>> +     this pass "-flto -fsyntax-only" to the lto1 invocation.  */
>> +  if (flag_generate_lto)
>> +    {
>> +      lto_file *file;
>> +
>> +      file = lto_elf_file_open ("bogus.lto.o", /*writable=*/true);
>> +      if (!file)
>> +     fatal_error ("lto_elf_file_open() failed");
>> +      lto_set_current_out_file (file);
>> +    }
>> +
>
> I'm confused by this hunk.  What are you testing here?  It also
> seems that it will trigger with just -flto.  Where does
> -fsyntax-only come to play?

I'm verifying that I can create an ELF file and populate it with the
LTO sections that would normally be written to the assembly output.
The LTO langhooks will barf if we don't open a file first.

Strictly speaking, -fsyntax-only isn't required.  It is, however,
useful, as it suppresses the generation of assembly code.  When the
final code is in place, -fpartition will implicitly enable
-fsyntax-only and -flto.  This is the same mechanism gcj uses when
generating bytecode.


I've resolved the other formatting issues and reverted to a
langhooks-based approach.  Since the output blocks need to be saved
until the ELF file is actually written, I've modified the old
write_section_data hook to take a block argument and renamed it
append_data (to avoid the suggesting that data is actually being
written at this point).  This was done in the old patch as well but
was obscured by the fact that the langhooks were being removed.

Updated patch attached.

Ollie


2008-06-27  Ollie Wild  <aaw@google.com>

        * lto-elf.c (lto-section-out.h): New include.
        (struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
        and data members.
        (cached_file_attrs): New static variable.
        (lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
        Use cached_file_attrs for checking bits.
        (lto_elf_build_section_table): Remove elf_file argument from
        lto_elf_get_shdr and lto_elf_free_shdr calls.
        (DEFINE_INIT_SHDR): New macro.
        (init_shdr32, init_shdr64): New functions defined via the
        DEFINE_INIT_SHDR macro.
        (lto_elf_begin_section_with_type): New function.
        (lto_elf_begin_section): New function.
        (lto_elf_append_data): New function.
        (lto_elf_end_section): New function.
        (DEFINE_VALIDATE_EHDR): New macro.
        (validate_ehdr32, validate_ehdr64): New functions defined via the
        DEFINE_VALIDATE_EHDR macro.
        (validate_file): New function.
        (DEFINE_INIT_EHDR): New macro.
        (init_ehdr32, init_ehdr64): New functions defined via the
        DEFINE_INIT_EHDR macro.
        (init_ehdr): New function.
        (lto_elf_file_open): Add support for writable files.  Move some
        validation logic to validate_file.
        (lto_elf_file_close): Add support for writable files.  Write file data
        and free data blocks.
        (current_out_file): New static variable.
        (lto_set_current_out_file): New function.
        (lto_get_current_out_file): New function.
        * lto.c (lto_main): Add writable argument to lto_elf_file_open calls.
        Add temporary initialization for testing ELF serialization.
        * lto.h (lto-section-out.h): New include.
        (struct lto_file_struct): Slight modification to comment.
        (lto_elf_file_open): Add writable parameter.
        (lto_elf_begin_section): New function declaration.
        (lto_elf_append_data): New function declaration.
        (lto_elf_end_section): New function declaration.
        (lto_set_current_out_file, lto_get_current_out_file): New function
        declarations.
        * lto-lang.c (LANG_HOOKS_BEGIN_SECTION): Set as lto_elf_begin_section.
        (LANG_HOOKS_APPEND_DATA): Set as lto_elf_append_data.
        (LANG_HOOKS_END_SECTION): Set as lto_elf_end_section.
        * Make-lang.in (LTO_H): Add lto-section-out.h.

2008-06-27  Ollie Wild  <aaw@google.com>

        * lto-section-out.h (lto_begin_section): New function declaration.
        (lto_end_section): New function declaration.
        (lto_output_data_stream): New function declaration.
        * lto-section-out.c (lto_begin_section): New function.
        (lto_end_section): New function.
        (lto_write_stream): Modify lang_hooks call.  Remove free.
        (append_block): New function.
        (lto_output_1_stream): Replace block allocation with call to
        append_block.
        (lto_output_data_stream): New function.
        (lto_destroy_simple_output_block): Add header_stream.  Replace
        lang_hook calls with lto-section functions.
        (write_global_references): Add ref_stream.  Replace lang_hooks call
        with lto-section calls.
        (produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
        with lto-section calls.
        * lto-function-out.c (langhooks.h): Remove include.
        (produce_asm): Add header_stream.  Replace lang_hook calls with
        lto-section calls.
        * langhooks.h (struct lang_hooks_for_lto): Rename write_section_data
        to append_data.  Add a block parameter.
        * langhooks-def.h (lhd_append_data): Rename from
        lhd_write_section_data.  Add a new parameter.
        (lhd_write_section_data): Rename to lhd_append_data.
        (LANG_HOOKS_APPEND_DATA): Rename from LANG_HOOKS_WRITE_SECTION_DATA.
        Change lhd_write_section_data to lhd_append_data.
        (LANG_HOOKS_WRITE_SECTION_DATA): Rename to LANG_HOOKS_APPEND_DATA.
        (LANG_HOOKS_LTO): Change LANG_HOOKS_WRITE_SECTION-DATA to
        LANG_HOOKS_APPEND_DATA.
        * langhooks.c (lhd_append_data): Rename from lhd_write_section_data.
        Add a block parameter.
        (lhd_write_section_data): Rename to lhd_append_data.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: elf-out.patch --]
[-- Type: text/x-diff; name=elf-out.patch, Size: 37471 bytes --]

commit 1b2a62090f8c5d26aef52ec8e20be3a2ce43442b
Author: Ollie Wild <aaw@google.com>
Date:   Fri Jun 20 16:36:20 2008 -0700

    Add support for ELF serialization.
    
    	gcc/lto/
    	* lto-elf.c (lto-section-out.h): New include.
    	(struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
    	and data members.
    	(cached_file_attrs): New static variable.
    	(lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
    	Use cached_file_attrs for checking bits.
    	(lto_elf_build_section_table): Remove elf_file argument from
    	lto_elf_get_shdr and lto_elf_free_shdr calls.
    	(DEFINE_INIT_SHDR): New macro.
    	(init_shdr32, init_shdr64): New functions defined via the
    	DEFINE_INIT_SHDR macro.
    	(lto_elf_begin_section_with_type): New function.
    	(lto_elf_begin_section): New function.
    	(lto_elf_append_data): New function.
    	(lto_elf_end_section): New function.
    	(DEFINE_VALIDATE_EHDR): New macro.
    	(validate_ehdr32, validate_ehdr64): New functions defined via the
    	DEFINE_VALIDATE_EHDR macro.
    	(validate_file): New function.
    	(DEFINE_INIT_EHDR): New macro.
    	(init_ehdr32, init_ehdr64): New functions defined via the
    	DEFINE_INIT_EHDR macro.
    	(init_ehdr): New function.
    	(lto_elf_file_open): Add support for writable files.  Move some
    	validation logic to validate_file.
    	(lto_elf_file_close): Add support for writable files.  Write file data
    	and free data blocks.
    	(current_out_file): New static variable.
    	(lto_set_current_out_file): New function.
    	(lto_get_current_out_file): New function.
    	* lto.c (lto_main): Add writable argument to lto_elf_file_open calls.
    	Add temporary initialization for testing ELF serialization.
    	* lto.h (lto-section-out.h): New include.
    	(struct lto_file_struct): Slight modification to comment.
    	(lto_elf_file_open): Add writable parameter.
    	(lto_elf_begin_section): New function declaration.
    	(lto_elf_append_data): New function declaration.
    	(lto_elf_end_section): New function declaration.
    	(lto_set_current_out_file, lto_get_current_out_file): New function
    	declarations.
    	* lto-lang.c (LANG_HOOKS_BEGIN_SECTION): Set as lto_elf_begin_section.
    	(LANG_HOOKS_APPEND_DATA): Set as lto_elf_append_data.
    	(LANG_HOOKS_END_SECTION): Set as lto_elf_end_section.
    	* Make-lang.in (LTO_H): Add lto-section-out.h.
    
    	gcc/
    	* lto-section-out.h (lto_begin_section): New function declaration.
    	(lto_end_section): New function declaration.
    	(lto_output_data_stream): New function declaration.
    	* lto-section-out.c (lto_begin_section): New function.
    	(lto_end_section): New function.
    	(lto_write_stream): Modify lang_hooks call.  Remove free.
    	(append_block): New function.
    	(lto_output_1_stream): Replace block allocation with call to
    	append_block.
    	(lto_output_data_stream): New function.
    	(lto_destroy_simple_output_block): Add header_stream.  Replace
    	lang_hook calls with lto-section functions.
    	(write_global_references): Add ref_stream.  Replace lang_hooks call
    	with lto-section calls.
    	(produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
    	with lto-section calls.
    	* lto-function-out.c (langhooks.h): Remove include.
    	(produce_asm): Add header_stream.  Replace lang_hook calls with
    	lto-section calls.
    	* langhooks.h (struct lang_hooks_for_lto): Rename write_section_data
    	to append_data.  Add a block parameter.
    	* langhooks-def.h (lhd_append_data): Rename from
    	lhd_write_section_data.  Add a new parameter.
    	(lhd_write_section_data): Rename to lhd_append_data.
    	(LANG_HOOKS_APPEND_DATA): Rename from LANG_HOOKS_WRITE_SECTION_DATA.
    	Change lhd_write_section_data to lhd_append_data.
    	(LANG_HOOKS_WRITE_SECTION_DATA): Rename to LANG_HOOKS_APPEND_DATA.
    	(LANG_HOOKS_LTO): Change LANG_HOOKS_WRITE_SECTION-DATA to
    	LANG_HOOKS_APPEND_DATA.
    	* langhooks.c (lhd_append_data): Rename from lhd_write_section_data.
    	Add a block parameter.
    	(lhd_write_section_data): Rename to lhd_append_data.

diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e241ebe..3ca7fcc 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -225,16 +225,16 @@ extern tree lhd_make_node (enum tree_code);
 
 /* LTO hooks.  */
 extern void lhd_begin_section (const char *);
-extern void lhd_write_section_data (const void *, size_t);
+extern void lhd_append_data (const void *, size_t, void *);
 extern void lhd_end_section (void);
 
 #define LANG_HOOKS_BEGIN_SECTION lhd_begin_section
-#define LANG_HOOKS_WRITE_SECTION_DATA lhd_write_section_data
+#define LANG_HOOKS_APPEND_DATA lhd_append_data
 #define LANG_HOOKS_END_SECTION lhd_end_section
 
 #define LANG_HOOKS_LTO { \
   LANG_HOOKS_BEGIN_SECTION, \
-  LANG_HOOKS_WRITE_SECTION_DATA, \
+  LANG_HOOKS_APPEND_DATA, \
   LANG_HOOKS_END_SECTION \
 }
 
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 87ec94d..3cdec65 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -604,12 +604,13 @@ lhd_begin_section (const char *name)
 
 
 /* Write DATA of length LEN to the current LTO output section.  This default
-   implementation just calls assemble_string.  */
+   implementation just calls assemble_string and frees BLOCK.  */
 
 void
-lhd_write_section_data (const void *data, size_t len)
+lhd_append_data (const void *data, size_t len, void *block)
 {
   assemble_string ((const char *)data, len);
+  free (block);
 }
 
 
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 1a8b9bf..e4ce439 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -219,9 +219,11 @@ struct lang_hooks_for_lto
   /* Begin a new LTO section named NAME.  */
   void (*begin_section) (const char *name);
 
-  /* Write the data at DATA of length LEN to the currently open LTO
-     section.  */
-  void (*write_section_data) (const void *data, size_t len);
+  /* Write DATA of length LEN to the currently open LTO section.  BLOCK is a
+     pointer to the dynamically allocated memory containing DATA.  The
+     append_data function is responsible for freeing it when it is no longer
+     needed.  */
+  void (*append_data) (const void *data, size_t len, void *block);
 
   /* End the previously begun LTO section.  */
   void (*end_section) (void);
diff --git a/gcc/lto-function-out.c b/gcc/lto-function-out.c
index db09592..8d52f2d 100644
--- a/gcc/lto-function-out.c
+++ b/gcc/lto-function-out.c
@@ -33,7 +33,6 @@ Boston, MA 02110-1301, USA.  */
 #include "input.h"
 #include "varray.h"
 #include "hashtab.h"
-#include "langhooks.h"
 #include "basic-block.h"
 #include "tree-iterator.h"
 #include "tree-pass.h"
@@ -1966,6 +1965,7 @@ produce_asm (struct output_block *ob, tree fn)
   enum lto_section_type section_type = ob->section_type;
   struct lto_function_header header;
   char *section_name;
+  struct lto_output_stream *header_stream;
 
   if (section_type == LTO_section_function_body)
     {
@@ -1975,7 +1975,7 @@ produce_asm (struct output_block *ob, tree fn)
   else
     section_name = lto_get_section_name (section_type, NULL);
 
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* The entire header is stream computed here.  */
@@ -2023,8 +2023,10 @@ produce_asm (struct output_block *ob, tree fn)
   header.debug_main_size = -1;
 #endif
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_function_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   /* Put all of the gimple and the string table out the asm file as a
      block of text.  */
@@ -2050,7 +2052,7 @@ produce_asm (struct output_block *ob, tree fn)
   lto_write_stream (ob->debug_main_stream);
 #endif
 
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 }
 
 
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
index 1b2ed2a..d33d272 100644
--- a/gcc/lto-section-out.c
+++ b/gcc/lto-section-out.c
@@ -192,6 +192,24 @@ lto_get_section_name (enum lto_section_type section_type, const char *name)
 *****************************************************************************/
 
 
+/* Begin a new output section named NAME.  */
+
+void
+lto_begin_section (const char *name)
+{
+  lang_hooks.lto.begin_section (name);
+}
+
+
+/* End the current output section.  */
+
+void
+lto_end_section (void)
+{
+  lang_hooks.lto.end_section ();
+}
+
+
 /* Write all of the chars in OBS to the assembler.  Recycle the blocks
    in obs as this is being done.  */
 
@@ -217,13 +235,54 @@ lto_write_stream (struct lto_output_stream *obs)
       if (!block)
 	num_chars = num_chars - obs->left_in_block;
 
-      lang_hooks.lto.write_section_data (base, num_chars);
-      free (old_block);
+      lang_hooks.lto.append_data (base, num_chars, old_block);
       block_size *= 2;
     }
 }
 
 
+/* Adds a new block to output stream OBS.  */
+
+static void
+append_block (struct lto_output_stream *obs)
+{
+  struct lto_char_ptr_base *new_block;
+
+  gcc_assert (obs->left_in_block == 0);
+
+  if (obs->first_block == NULL)
+    {
+      /* This is the first time the stream has been written
+	 into.  */
+      obs->block_size = 1024;
+      new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
+      obs->first_block = new_block;
+    }
+  else
+    {
+      struct lto_char_ptr_base *tptr;
+      /* Get a new block that is twice as big as the last block
+	 and link it into the list.  */
+      obs->block_size *= 2;
+      new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
+      /* The first bytes of the block are reserved as a pointer to
+	 the next block.  Set the chain of the full block to the
+	 pointer to the new block.  */
+      tptr = obs->current_block;
+      tptr->ptr = (char *) new_block;
+    }
+
+  /* Set the place for the next char at the first position after the
+     chain to the next block.  */
+  obs->current_pointer
+    = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
+  obs->current_block = new_block;
+  /* Null out the newly allocated block's pointer to the next block.  */
+  new_block->ptr = NULL;
+  obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
+}
+
+
 /* Write a character to the output block.  */
 
 void
@@ -231,40 +290,7 @@ lto_output_1_stream (struct lto_output_stream *obs, char c)
 {
   /* No space left.  */
   if (obs->left_in_block == 0)
-    {
-      struct lto_char_ptr_base *new_block;
-
-      if (obs->first_block == NULL)
-	{
-	  /* This is the first time the stream has been written
-	     into.  */
-	  obs->block_size = 1024;
-	  new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
-	  obs->first_block = new_block;
-	}
-      else
-	{
-	  struct lto_char_ptr_base *tptr;
-	  /* Get a new block that is twice as big as the last block
-	     and link it into the list.  */
-	  obs->block_size *= 2;
-	  new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
-	  /* The first bytes of the block are reserved as a pointer to
-	     the next block.  Set the chain of the full block to the
-	     pointer to the new block.  */
-	  tptr = obs->current_block;
-	  tptr->ptr = (char *)new_block;
-	}
-
-      /* Set the place for the next char at the first position after the
-	 chain to the next block.  */
-      obs->current_pointer
-	= ((char *)new_block) + sizeof (struct lto_char_ptr_base);
-      obs->current_block = new_block;
-      /* Null out the newly allocated block's pointer to the next block.  */
-      new_block->ptr = NULL;
-      obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
-    }
+    append_block (obs);
 
   /* Write the actual character.  */
   *obs->current_pointer = c;
@@ -274,6 +300,37 @@ lto_output_1_stream (struct lto_output_stream *obs, char c)
 }
 
 
+/* Write raw DATA of length LEN to the output block OB.  */
+
+void
+lto_output_data_stream (struct lto_output_stream *obs, const void *data,
+			size_t len)
+{
+  while (len)
+    {
+      size_t copy;
+
+      /* No space left.  */
+      if (obs->left_in_block == 0)
+	append_block (obs);
+
+      /* Determine how many bytes to copy in this loop.  */
+      if (len <= obs->left_in_block)
+	copy = len;
+      else
+	copy = obs->left_in_block;
+
+      /* Copy the data and do bookkeeping.  */
+      memcpy (obs->current_pointer, data, copy);
+      obs->current_pointer += copy;
+      obs->total_size += copy;
+      obs->left_in_block -= copy;
+      data = (char *)data + copy;
+      len -= copy;
+    }
+}
+
+
 /* Output an unsigned LEB128 quantity to OBS.  */
 
 void
@@ -561,9 +618,10 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
 {
   char *section_name;
   struct lto_simple_header header;
+  struct lto_output_stream *header_stream;
 
   section_name = lto_get_section_name (ob->section_type, NULL);
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* Write the header which says how to decode the pieces of the
@@ -582,8 +640,10 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
   header.debug_main_size = -1;
 #endif
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_simple_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   lto_write_stream (ob->main_stream);
 #ifdef LTO_STREAM_DEBUGGING
@@ -592,7 +652,7 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
 
   /* Put back the assembly section that was there before we started
      writing lto info.  */
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 
   free (ob->main_stream);
   LTO_CLEAR_DEBUGGING_STREAM (debug_main_stream);
@@ -738,14 +798,15 @@ write_global_references (struct output_block *ob, VEC(tree,heap) *v)
 {
   tree t;
   int index;
-  size_t size = VEC_length (tree, v) * sizeof (int32_t);
-  int32_t *refs = xmalloc (size);
+  struct lto_output_stream *ref_stream;
 
+  ref_stream = xcalloc (1, sizeof (struct lto_output_stream));
   for (index = 0; VEC_iterate(tree, v, index, t); index++)
     {
       void **slot;
       struct lto_decl_slot d_slot;
       struct lto_decl_slot *old_slot;
+      int32_t slot_num;
 
       d_slot.t = t;
       slot = htab_find_slot (ob->main_hash_table, &d_slot, NO_INSERT);
@@ -756,11 +817,12 @@ write_global_references (struct output_block *ob, VEC(tree,heap) *v)
       print_generic_expr (stderr, t, 0);
       fprintf (stderr, "\n");
 #endif
-      refs[index] = old_slot->slot_num;
+      slot_num = old_slot->slot_num;
+      lto_output_data_stream (ref_stream, &slot_num, sizeof slot_num);
     }
 
-  lang_hooks.lto.write_section_data (refs, size);
-  free (refs);
+  lto_write_stream (ref_stream);
+  free (ref_stream);
 }
 
 
@@ -777,6 +839,7 @@ produce_asm_for_decls (void)
   struct lto_decl_header header;
   char *section_name;
   struct output_block *ob = create_output_block (LTO_section_decls);
+  struct lto_output_stream *header_stream;
 
   free_lang_specifics ();
 
@@ -792,7 +855,7 @@ produce_asm_for_decls (void)
   memset (&header, 0, sizeof (struct lto_decl_header)); 
 
   section_name = lto_get_section_name (LTO_section_decls, NULL);
-  lang_hooks.lto.begin_section (section_name);
+  lto_begin_section (section_name);
   free (section_name);
 
   /* Make string 0 be a NULL string.  */
@@ -826,8 +889,10 @@ produce_asm_for_decls (void)
   header.string_size = ob->string_stream->total_size;
   header.debug_main_size = ob->debug_main_stream->total_size;
 
-  lang_hooks.lto.write_section_data (&header,
-				     sizeof (struct lto_decl_header));
+  header_stream = xcalloc (1, sizeof (struct lto_output_stream));
+  lto_output_data_stream (header_stream, &header, sizeof header);
+  lto_write_stream (header_stream);
+  free (header_stream);
 
   /* We must write the types first.  */
   write_global_references (ob, out_state->types);
@@ -862,7 +927,7 @@ produce_asm_for_decls (void)
   VEC_free (tree, heap, out_state->namespace_decls);
   VEC_free (tree, heap, out_state->types);
 
-  lang_hooks.lto.end_section ();
+  lto_end_section ();
 }
 
 
diff --git a/gcc/lto-section-out.h b/gcc/lto-section-out.h
index 6b1d632..cef051f 100644
--- a/gcc/lto-section-out.h
+++ b/gcc/lto-section-out.h
@@ -142,8 +142,11 @@ int lto_eq_type_slot_node (const void *, const void *);
 hashval_t lto_hash_global_slot_node (const void *);
 int lto_eq_global_slot_node (const void *, const void *);
 
+void lto_begin_section (const char *);
+void lto_end_section (void);
 void lto_write_stream (struct lto_output_stream *);
 void lto_output_1_stream (struct lto_output_stream *, char);
+void lto_output_data_stream (struct lto_output_stream *, const void *, size_t);
 void lto_output_uleb128_stream (struct lto_output_stream *,
 				unsigned HOST_WIDE_INT);
 void lto_output_widest_uint_uleb128_stream (struct lto_output_stream *,
diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
index e9d2f5f..680b6f5 100644
--- a/gcc/lto/Make-lang.in
+++ b/gcc/lto/Make-lang.in
@@ -28,7 +28,8 @@ LTO_EXE = lto1$(exeext)
 # The LTO-specific object files inclued in $(LTO_EXE).
 LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o \
 	lto/lto-symtab.o attribs.o
-LTO_H = lto/lto.h lto-header.h lto-section-in.h $(HASHTAB_H) $(TREE_H)
+LTO_H = lto/lto.h lto-header.h lto-section-in.h lto-section-out.h \
+	$(HASHTAB_H) $(TREE_H)
 
 ########################################################################
 # Rules
diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c
index 57c5adf..111b94f 100644
--- a/gcc/lto/lto-elf.c
+++ b/gcc/lto/lto-elf.c
@@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA.  */
 #include "tm.h"
 #include "libiberty.h"
 #include "ggc.h"
+#include "lto-section-out.h"
 
 
 /* ### Moved lto_file_init and lto_file_close here from lto.c.
@@ -57,7 +58,7 @@ lto_file_close (lto_file *file ATTRIBUTE_UNUSED)
   ggc_free (file);
 }
 
-/* An ELF input file.  */
+/* An ELF file.  */
 struct lto_elf_file 
 {
   /* The base information.  */
@@ -66,23 +67,40 @@ struct lto_elf_file
   int fd;
   /* The libelf descriptor for the file.  */
   Elf *elf;
-  /* 32 or 64 bits? */
-  size_t bits;
   /* 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 (lto_elf_file *elf_file,
-		  Elf_Scn *section)
+lto_elf_get_shdr (Elf_Scn *section)
 {
   Elf64_Shdr *shdr;
 
-  switch (elf_file->bits)
+  switch (cached_file_attrs.bits)
     {
     case 32:
       {
@@ -122,9 +140,9 @@ lto_elf_get_shdr (lto_elf_file *elf_file,
 
 /* Free SHDR, previously allocated by lto_elf_get_shdr.  */
 static void
-lto_elf_free_shdr (lto_elf_file *elf_file, Elf64_Shdr *shdr)
+lto_elf_free_shdr (Elf64_Shdr *shdr)
 {
-  if (elf_file->bits != 64)
+  if (cached_file_attrs.bits != 64)
     free (shdr);
 }
 
@@ -184,7 +202,7 @@ lto_elf_build_section_table (lto_file *lto_file)
       struct lto_section_slot s_slot;
 
       /* Get the name of this section.  */
-      shdr = lto_elf_get_shdr (elf_file, section);
+      shdr = lto_elf_get_shdr (section);
       offset = shdr->sh_name;
       name = elf_strptr (elf_file->elf, 
 			 elf_file->sec_strtab,
@@ -194,7 +212,7 @@ lto_elf_build_section_table (lto_file *lto_file)
       if (strncmp (name, LTO_SECTION_NAME_PREFIX, 
 		   strlen (LTO_SECTION_NAME_PREFIX)) != 0)
 	{
-	  lto_elf_free_shdr (elf_file, shdr);
+	  lto_elf_free_shdr (shdr);
 	  continue;
 	}
 
@@ -218,49 +236,184 @@ lto_elf_build_section_table (lto_file *lto_file)
 	  error ("two or more sections for %s:", new_name);
 	  return NULL;
 	}
-      lto_elf_free_shdr (elf_file, shdr);
+      lto_elf_free_shdr (shdr);
     }
   return section_hash_table;
 }
 
 
-lto_file *
-lto_elf_file_open (const char *filename)
-{
-  lto_elf_file *elf_file;
-  size_t bits;
-  const char *elf_ident;
-  lto_file *result;
+/* 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)							      \
+    fatal_error ("elf"#BITS"_getshdr() failed: %s.", elf_errmsg(-1)); \
+								      \
+  shdr->sh_name = sh_name;					      \
+  shdr->sh_type = sh_type;					      \
+  shdr->sh_flags = 0;						      \
+  shdr->sh_entsize = 0;						      \
+}
 
-  /* Set up.  */
-  elf_file = GGC_NEW (lto_elf_file);
-  result = (lto_file *)elf_file;
-  lto_file_init (result, filename);
-  elf_file->fd = -1;
-  elf_file->elf = NULL;
+DEFINE_INIT_SHDR (32)
+DEFINE_INIT_SHDR (64)
 
-  /* Open the file.  */
-  elf_file->fd = open (filename, O_RDONLY);
-  if (elf_file->fd == -1)
-    {
-      error ("could not open");
-      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;
-    }
+/* Begin a new ELF section named NAME with type TYPE in the current output
+   file.  TYPE is an SHT_* macro from the libelf headers.  */
 
-  /* Open the ELF file descriptor.  */
-  elf_file->elf = elf_begin (elf_file->fd, ELF_C_READ, NULL);
-  if (!elf_file->elf)
+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 ("elf_newscn() failed: %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)
     {
-      error ("could not open ELF file: %s", elf_errmsg (0));
-      goto fail;
+    case 32:
+      init_shdr32 (scn, sh_name, type);
+      break;
+
+    case 64:
+      init_shdr64 (scn, sh_name, type);
+      break;
+
+    default:
+      gcc_unreachable ();
     }
+}
+
+
+/* Begin a new ELF section named NAME in the current output file.  */
+
+void
+lto_elf_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_elf_append_data (const void *data, size_t len, void *block)
+{
+  lto_elf_file *file;
+  Elf_Data *elf_data;
+  struct lto_char_ptr_base *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 ("elf_newdata() failed: %s.", elf_errmsg(-1));
+
+  elf_data->d_align = 1;
+  elf_data->d_buf = (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_elf_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;
+}
+
+
+/* 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;	\
+								\
+  if (cached_file_attrs.elf_machine != elf_header->e_machine)	\
+    {								\
+      error ("inconsistent file architecture detected");	\
+      return false;						\
+    }								\
+								\
+  return true;							\
+}
+
+DEFINE_VALIDATE_EHDR (32)
+DEFINE_VALIDATE_EHDR (64)
+
+
+/* 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
@@ -270,61 +423,165 @@ lto_elf_file_open (const char *filename)
     {
       error ("could not read ELF identification information: %s",
 	      elf_errmsg (0));
-      goto fail;
+      return false;
 	     
     }
-  switch (elf_ident[EI_CLASS])
+
+  if (!cached_file_attrs.initialized)
     {
-    case ELFCLASS32:
-      bits = 32;
+      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);
+    }
+
+  if (memcmp (elf_ident, cached_file_attrs.elf_ident,
+	      sizeof cached_file_attrs.elf_ident))
+    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 ELFCLASS64:
-      bits = 64;
+
+    case 64:
+      if (!validate_ehdr64 (elf_file))
+	return false;
       break;
+
     default:
-      error ("unsupported ELF file class");
-      goto fail;
+      gcc_unreachable ();
     }
-  elf_file->bits = bits;
-
-  /* Check that the input file is a relocatable object file.  */
-#define ELF_CHECK_FILE_TYPE(N)						\
-  do {									\
-    Elf##N##_Ehdr *elf_header;						\
-    elf_header = elf##N##_getehdr (elf_file->elf);			\
-    if (!elf_header)							\
-      {									\
-	error ("could not read ELF header: %s", elf_errmsg (0));	\
-        goto fail;							\
-      }									\
-   if (elf_header->e_type != ET_REL)					\
-     {									\
-        error ("not a relocatable ELF object file");			\
-        goto fail;							\
-     }									\
-  } while (false)
-
-  switch (bits)
+
+  /* Read the string table used for section header names.  */
+  if (elf_getshstrndx (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)							      \
+    fatal_error ("elf"#BITS"_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_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:
-      ELF_CHECK_FILE_TYPE (32);
+      init_ehdr32 (elf_file);
       break;
+
     case 64:
-      ELF_CHECK_FILE_TYPE (64);
+      init_ehdr64 (elf_file);
       break;
+
     default:
       gcc_unreachable ();
     }
+}
 
-#undef ELF_CHECK_FILE_TYPE
 
-  /* Read the string table used for section header names.  */
-  if (elf_getshstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
+/* 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_elf_file_open (const char *filename, bool writable)
+{
+  lto_elf_file *elf_file;
+  lto_file *result;
+
+  /* Set up.  */
+  elf_file = GGC_CNEW (lto_elf_file);
+  result = (lto_file *)elf_file;
+  lto_file_init (result, filename);
+  elf_file->fd = -1;
+
+  /* Open the file.  */
+  elf_file->fd = open (filename, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666);
+  if (elf_file->fd == -1)
     {
-      error ("could not locate ELF string table: %s", elf_errmsg (0));
+      error ("could not open");
       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 ELF file: %s", elf_errmsg (0));
+      goto fail;
+    }
+
+  if (writable)
+    {
+      init_ehdr (elf_file);
+      elf_file->shstrtab_stream = xcalloc (1,
+					   sizeof (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:
@@ -332,13 +589,72 @@ lto_elf_file_open (const char *filename)
   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_elf_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)
+    {
+      lto_file *old_file = lto_set_current_out_file (file);
+
+      lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
+      elfx_update_shstrndx (elf_file->elf, elf_ndxscn (elf_file->scn));
+      lto_write_stream (elf_file->shstrtab_stream);
+      lto_elf_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);
+    }
+
   lto_file_close (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-lang.c b/gcc/lto/lto-lang.c
index e08bd5c..629f4aa 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -672,6 +672,14 @@ static void lto_init_ts (void)
 #define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true
 #undef LANG_HOOKS_TYPES_COMPATIBLE_P
 #define LANG_HOOKS_TYPES_COMPATIBLE_P lto_types_compatible_p
+
+#undef LANG_HOOKS_BEGIN_SECTION
+#define LANG_HOOKS_BEGIN_SECTION lto_elf_begin_section
+#undef LANG_HOOKS_APPEND_DATA
+#define LANG_HOOKS_APPEND_DATA lto_elf_append_data
+#undef LANG_HOOKS_END_SECTION
+#define LANG_HOOKS_END_SECTION lto_elf_end_section
+
 #undef LANG_HOOKS_INIT_TS
 #define LANG_HOOKS_INIT_TS lto_init_ts
 
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index bbc4de0..855c30f 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -423,7 +423,7 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
   for (i = 0; i < num_in_fnames; ++i)
     {
       htab_t section_hash_table;
-      current_lto_file = lto_elf_file_open (in_fnames[i]);
+      current_lto_file = lto_elf_file_open (in_fnames[i], /*writable=*/false);
       if (!current_lto_file)
 	break;
       file_data = lto_file_read (current_lto_file);
@@ -488,10 +488,33 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
                               /*top_level=*/1,
                               /*at_end=*/0);
 
+  /* This is some bogus wrapper code for development testing.  It will be
+     replaced once some basic WPA partitioning logic is implemented.  To use
+     this pass "-flto -fsyntax-only" to the lto1 invocation.  */
+  if (flag_generate_lto)
+    {
+      lto_file *file;
+
+      file = lto_elf_file_open ("bogus.lto.o", /*writable=*/true);
+      if (!file)
+	fatal_error ("lto_elf_file_open() failed");
+      lto_set_current_out_file (file);
+    }
+
   /* Let the middle end know that we have read and merged all of the
      input files.  */ 
   /*cgraph_finalize_compilation_unit ();*/
   cgraph_optimize ();
+
+  /* This is the continuation of the previous bogus wrapper code.  It will be
+     replaced once some basic WPA partitioning logic is implemented.  */
+  if (flag_generate_lto)
+    {
+      lto_file *file;
+
+      file = lto_set_current_out_file (NULL);
+      lto_elf_file_close (file);
+    }
 }
 
 #include "gt-lto-lto.h"
diff --git a/gcc/lto/lto.h b/gcc/lto/lto.h
index c39f983..de44c84 100644
--- a/gcc/lto/lto.h
+++ b/gcc/lto/lto.h
@@ -30,8 +30,9 @@ Boston, MA 02110-1301, USA.  */
 #include <inttypes.h>
 #include "lto-header.h"
 #include "lto-section-in.h"
+#include "lto-section-out.h"
 
-/* An input file.  */
+/* A file.  */
 typedef struct lto_file_struct GTY(())
 {
   /* The name of the file.  */
@@ -55,8 +56,8 @@ extern void lto_main (int debug_p);
 
 /* lto-elf.c */
 
-/* Open the ELF input file indicated by FILENAME.  Return */
-extern lto_file *lto_elf_file_open (const char *filename);
+/* Open the ELF file indicated by FILENAME.  */
+extern lto_file *lto_elf_file_open (const char *filename, bool writable);
 
 /* Close an ELF input file.  */
 extern void lto_elf_file_close (lto_file *file);
@@ -64,6 +65,15 @@ extern void lto_elf_file_close (lto_file *file);
 /* Build and index of all lto sections in an elf file.  */
 extern htab_t lto_elf_build_section_table (lto_file *file);
 
+/* Hooks for writing LTO sections.  */
+extern void lto_elf_begin_section (const char *name);
+extern void lto_elf_append_data (const void *data, size_t len, void *block);
+extern void lto_elf_end_section (void);
+
+/* Routines for setting/getting the current output file.  */
+extern lto_file *lto_set_current_out_file (lto_file *file);
+extern lto_file *lto_get_current_out_file (void);
+
 /* lto-symtab.c */
 
 /* The NEW_VAR (a VAR_DECL) has just been read.  If there is an

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-27 20:16   ` Ollie Wild
@ 2008-06-27 20:54     ` Kenneth Zadeck
  2008-06-27 21:45       ` Diego Novillo
  2008-06-27 21:38     ` Diego Novillo
  1 sibling, 1 reply; 15+ messages in thread
From: Kenneth Zadeck @ 2008-06-27 20:54 UTC (permalink / raw)
  To: Ollie Wild; +Cc: Diego Novillo, gcc-patches, "Doug Kwan (???)"

Ollie Wild wrote:
>>> +      obs->block_size = 1024;
>>>       
>> Does it make sense to #define or --param this number?
>>     
>
>   
This number is pretty harmless.   I store the data for the output 
streams in a set of blocks that are linked together.   Since i have no 
idea how much data will be generated, i use an adaptive algorithm.  1024 
is the size of the first block.   Each subsequent block doubles in size. 

This would not be something that you would want to use if you knew the 
size of the section you were going to copy to the output, but for data 
sections generated on the fly, this is pretty good. 

> This isn't my code.  It's just cut-and-pasted from Kenny's
> lto_output_1_stream.  I think a discussion of how this algorithm could
> be improved is worthwhile, but let's make it a separate discussion.
>
>
>   
>>> +  /* This is some bogus wrapper code for development testing.  It will be
>>> +     replaced once some basic WPA partitioning logic is implemented.  To use
>>> +     this pass "-flto -fsyntax-only" to the lto1 invocation.  */
>>> +  if (flag_generate_lto)
>>> +    {
>>> +      lto_file *file;
>>> +
>>> +      file = lto_elf_file_open ("bogus.lto.o", /*writable=*/true);
>>> +      if (!file)
>>> +     fatal_error ("lto_elf_file_open() failed");
>>> +      lto_set_current_out_file (file);
>>> +    }
>>> +
>>>       
>> I'm confused by this hunk.  What are you testing here?  It also
>> seems that it will trigger with just -flto.  Where does
>> -fsyntax-only come to play?
>>     
>
> I'm verifying that I can create an ELF file and populate it with the
> LTO sections that would normally be written to the assembly output.
> The LTO langhooks will barf if we don't open a file first.
>
> Strictly speaking, -fsyntax-only isn't required.  It is, however,
> useful, as it suppresses the generation of assembly code.  When the
> final code is in place, -fpartition will implicitly enable
> -fsyntax-only and -flto.  This is the same mechanism gcj uses when
> generating bytecode.
>
>
> I've resolved the other formatting issues and reverted to a
> langhooks-based approach.  Since the output blocks need to be saved
> until the ELF file is actually written, I've modified the old
> write_section_data hook to take a block argument and renamed it
> append_data (to avoid the suggesting that data is actually being
> written at this point).  This was done in the old patch as well but
> was obscured by the fact that the langhooks were being removed.
>
> Updated patch attached.
>
> Ollie
>
>
> 2008-06-27  Ollie Wild  <aaw@google.com>
>
>         * lto-elf.c (lto-section-out.h): New include.
>         (struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
>         and data members.
>         (cached_file_attrs): New static variable.
>         (lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
>         Use cached_file_attrs for checking bits.
>         (lto_elf_build_section_table): Remove elf_file argument from
>         lto_elf_get_shdr and lto_elf_free_shdr calls.
>         (DEFINE_INIT_SHDR): New macro.
>         (init_shdr32, init_shdr64): New functions defined via the
>         DEFINE_INIT_SHDR macro.
>         (lto_elf_begin_section_with_type): New function.
>         (lto_elf_begin_section): New function.
>         (lto_elf_append_data): New function.
>         (lto_elf_end_section): New function.
>         (DEFINE_VALIDATE_EHDR): New macro.
>         (validate_ehdr32, validate_ehdr64): New functions defined via the
>         DEFINE_VALIDATE_EHDR macro.
>         (validate_file): New function.
>         (DEFINE_INIT_EHDR): New macro.
>         (init_ehdr32, init_ehdr64): New functions defined via the
>         DEFINE_INIT_EHDR macro.
>         (init_ehdr): New function.
>         (lto_elf_file_open): Add support for writable files.  Move some
>         validation logic to validate_file.
>         (lto_elf_file_close): Add support for writable files.  Write file data
>         and free data blocks.
>         (current_out_file): New static variable.
>         (lto_set_current_out_file): New function.
>         (lto_get_current_out_file): New function.
>         * lto.c (lto_main): Add writable argument to lto_elf_file_open calls.
>         Add temporary initialization for testing ELF serialization.
>         * lto.h (lto-section-out.h): New include.
>         (struct lto_file_struct): Slight modification to comment.
>         (lto_elf_file_open): Add writable parameter.
>         (lto_elf_begin_section): New function declaration.
>         (lto_elf_append_data): New function declaration.
>         (lto_elf_end_section): New function declaration.
>         (lto_set_current_out_file, lto_get_current_out_file): New function
>         declarations.
>         * lto-lang.c (LANG_HOOKS_BEGIN_SECTION): Set as lto_elf_begin_section.
>         (LANG_HOOKS_APPEND_DATA): Set as lto_elf_append_data.
>         (LANG_HOOKS_END_SECTION): Set as lto_elf_end_section.
>         * Make-lang.in (LTO_H): Add lto-section-out.h.
>
> 2008-06-27  Ollie Wild  <aaw@google.com>
>
>         * lto-section-out.h (lto_begin_section): New function declaration.
>         (lto_end_section): New function declaration.
>         (lto_output_data_stream): New function declaration.
>         * lto-section-out.c (lto_begin_section): New function.
>         (lto_end_section): New function.
>         (lto_write_stream): Modify lang_hooks call.  Remove free.
>         (append_block): New function.
>         (lto_output_1_stream): Replace block allocation with call to
>         append_block.
>         (lto_output_data_stream): New function.
>         (lto_destroy_simple_output_block): Add header_stream.  Replace
>         lang_hook calls with lto-section functions.
>         (write_global_references): Add ref_stream.  Replace lang_hooks call
>         with lto-section calls.
>         (produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
>         with lto-section calls.
>         * lto-function-out.c (langhooks.h): Remove include.
>         (produce_asm): Add header_stream.  Replace lang_hook calls with
>         lto-section calls.
>         * langhooks.h (struct lang_hooks_for_lto): Rename write_section_data
>         to append_data.  Add a block parameter.
>         * langhooks-def.h (lhd_append_data): Rename from
>         lhd_write_section_data.  Add a new parameter.
>         (lhd_write_section_data): Rename to lhd_append_data.
>         (LANG_HOOKS_APPEND_DATA): Rename from LANG_HOOKS_WRITE_SECTION_DATA.
>         Change lhd_write_section_data to lhd_append_data.
>         (LANG_HOOKS_WRITE_SECTION_DATA): Rename to LANG_HOOKS_APPEND_DATA.
>         (LANG_HOOKS_LTO): Change LANG_HOOKS_WRITE_SECTION-DATA to
>         LANG_HOOKS_APPEND_DATA.
>         * langhooks.c (lhd_append_data): Rename from lhd_write_section_data.
>         Add a block parameter.
>         (lhd_write_section_data): Rename to lhd_append_data.
>   

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-27 20:16   ` Ollie Wild
  2008-06-27 20:54     ` Kenneth Zadeck
@ 2008-06-27 21:38     ` Diego Novillo
  2008-06-27 22:15       ` Ollie Wild
  1 sibling, 1 reply; 15+ messages in thread
From: Diego Novillo @ 2008-06-27 21:38 UTC (permalink / raw)
  To: Ollie Wild
  Cc: gcc-patches, Kenneth Zadeck, Doug Kwan (關振德)

On Fri, Jun 27, 2008 at 15:26, Ollie Wild <aaw@google.com> wrote:

> Strictly speaking, -fsyntax-only isn't required.  It is, however,
> useful, as it suppresses the generation of assembly code.  When the
> final code is in place, -fpartition will implicitly enable
> -fsyntax-only and -flto.  This is the same mechanism gcj uses when
> generating bytecode.

Ah, OK.  Thanks.

> I've resolved the other formatting issues and reverted to a
> langhooks-based approach.  Since the output blocks need to be saved
> until the ELF file is actually written, I've modified the old
> write_section_data hook to take a block argument and renamed it
> append_data (to avoid the suggesting that data is actually being
> written at this point).  This was done in the old patch as well but
> was obscured by the fact that the langhooks were being removed.

Sounds good.

> 2008-06-27  Ollie Wild  <aaw@google.com>
>
>        * lto-elf.c (lto-section-out.h): New include.
>        (struct lto_elf_file): Remove bits member.  Add scn, shstrtab_stream,
>        and data members.
>        (cached_file_attrs): New static variable.
>        (lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter.
>        Use cached_file_attrs for checking bits.
>        (lto_elf_build_section_table): Remove elf_file argument from
>        lto_elf_get_shdr and lto_elf_free_shdr calls.
>        (DEFINE_INIT_SHDR): New macro.
>        (init_shdr32, init_shdr64): New functions defined via the
>        DEFINE_INIT_SHDR macro.
>        (lto_elf_begin_section_with_type): New function.
>        (lto_elf_begin_section): New function.
>        (lto_elf_append_data): New function.
>        (lto_elf_end_section): New function.
>        (DEFINE_VALIDATE_EHDR): New macro.
>        (validate_ehdr32, validate_ehdr64): New functions defined via the
>        DEFINE_VALIDATE_EHDR macro.
>        (validate_file): New function.
>        (DEFINE_INIT_EHDR): New macro.
>        (init_ehdr32, init_ehdr64): New functions defined via the
>        DEFINE_INIT_EHDR macro.
>        (init_ehdr): New function.
>        (lto_elf_file_open): Add support for writable files.  Move some
>        validation logic to validate_file.
>        (lto_elf_file_close): Add support for writable files.  Write file data
>        and free data blocks.
>        (current_out_file): New static variable.
>        (lto_set_current_out_file): New function.
>        (lto_get_current_out_file): New function.
>        * lto.c (lto_main): Add writable argument to lto_elf_file_open calls.
>        Add temporary initialization for testing ELF serialization.
>        * lto.h (lto-section-out.h): New include.
>        (struct lto_file_struct): Slight modification to comment.
>        (lto_elf_file_open): Add writable parameter.
>        (lto_elf_begin_section): New function declaration.
>        (lto_elf_append_data): New function declaration.
>        (lto_elf_end_section): New function declaration.
>        (lto_set_current_out_file, lto_get_current_out_file): New function
>        declarations.
>        * lto-lang.c (LANG_HOOKS_BEGIN_SECTION): Set as lto_elf_begin_section.
>        (LANG_HOOKS_APPEND_DATA): Set as lto_elf_append_data.
>        (LANG_HOOKS_END_SECTION): Set as lto_elf_end_section.
>        * Make-lang.in (LTO_H): Add lto-section-out.h.

>
> 2008-06-27  Ollie Wild  <aaw@google.com>
>
>        * lto-section-out.h (lto_begin_section): New function declaration.
>        (lto_end_section): New function declaration.
>        (lto_output_data_stream): New function declaration.
>        * lto-section-out.c (lto_begin_section): New function.
>        (lto_end_section): New function.
>        (lto_write_stream): Modify lang_hooks call.  Remove free.
>        (append_block): New function.
>        (lto_output_1_stream): Replace block allocation with call to
>        append_block.
>        (lto_output_data_stream): New function.
>        (lto_destroy_simple_output_block): Add header_stream.  Replace
>        lang_hook calls with lto-section functions.
>        (write_global_references): Add ref_stream.  Replace lang_hooks call
>        with lto-section calls.
>        (produce_asm_for_decls): Add header_stream.  Replace lang_hook calls
>        with lto-section calls.
>        * lto-function-out.c (langhooks.h): Remove include.
>        (produce_asm): Add header_stream.  Replace lang_hook calls with
>        lto-section calls.
>        * langhooks.h (struct lang_hooks_for_lto): Rename write_section_data
>        to append_data.  Add a block parameter.
>        * langhooks-def.h (lhd_append_data): Rename from
>        lhd_write_section_data.  Add a new parameter.
>        (lhd_write_section_data): Rename to lhd_append_data.
>        (LANG_HOOKS_APPEND_DATA): Rename from LANG_HOOKS_WRITE_SECTION_DATA.
>        Change lhd_write_section_data to lhd_append_data.
>        (LANG_HOOKS_WRITE_SECTION_DATA): Rename to LANG_HOOKS_APPEND_DATA.
>        (LANG_HOOKS_LTO): Change LANG_HOOKS_WRITE_SECTION-DATA to
>        LANG_HOOKS_APPEND_DATA.
>        * langhooks.c (lhd_append_data): Rename from lhd_write_section_data.
>        Add a block parameter.
>        (lhd_write_section_data): Rename to lhd_append_data.
>


OK.


Thanks.  Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-27 20:54     ` Kenneth Zadeck
@ 2008-06-27 21:45       ` Diego Novillo
  0 siblings, 0 replies; 15+ messages in thread
From: Diego Novillo @ 2008-06-27 21:45 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Ollie Wild, gcc-patches, "Doug Kwan (???)"

On Fri, Jun 27, 2008 at 16:49, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:

> This number is pretty harmless.   I store the data for the output streams in
> a set of blocks that are linked together.   Since i have no idea how much
> data will be generated, i use an adaptive algorithm.  1024 is the size of
> the first block.   Each subsequent block doubles in size.

OK, thanks.


Diego.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-27 21:38     ` Diego Novillo
@ 2008-06-27 22:15       ` Ollie Wild
  0 siblings, 0 replies; 15+ messages in thread
From: Ollie Wild @ 2008-06-27 22:15 UTC (permalink / raw)
  To: Diego Novillo
  Cc: gcc-patches, Kenneth Zadeck, Doug Kwan (關振德)

On Fri, Jun 27, 2008 at 2:37 PM, Diego Novillo <dnovillo@google.com> wrote:
>
> OK.

Submitted.

Ollie

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [lto] add direct-to-ELF serialization to lto1
  2008-06-26 20:07       ` Tom Tromey
@ 2008-06-27 22:37         ` Mark Mitchell
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Mitchell @ 2008-06-27 22:37 UTC (permalink / raw)
  To: tromey; +Cc: Diego Novillo, gcc-patches

Tom Tromey wrote:
>>>>>> "Diego" == Diego Novillo <dnovillo@google.com> writes:
> 
> Diego> All of the lang hooks?  I don't think we want to get rid of all
> Diego> of them.
> 
> Yeah, we can't ever get rid of all of them -- we could do it nominally
> but only by reintroducing the same thing under a different name.
> E.g., you need a lang-hook-equivalent to call the FE's parser at all.

Indeed.  We've discussed this multiple times on the lists, but since 
there still seems to be confusion, let's say it again: we only want to 
remove langhooks that affect the semantic interpretation of IL.  The 
middle-end IL should have meaning independent of the source language. 
However, how that IL is generated, or how we format error messages, 
etc., are perfectly reasonable uses of langhooks.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2008-06-27 22:33 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-06-25 19:04 [lto] add direct-to-ELF serialization to lto1 Ollie Wild
2008-06-26 13:38 ` Diego Novillo
2008-06-26 17:57   ` Ollie Wild
2008-06-26 18:40     ` Ollie Wild
2008-06-26 18:58     ` Diego Novillo
2008-06-26 18:30   ` Kenneth Zadeck
2008-06-26 19:06     ` Diego Novillo
2008-06-26 20:07       ` Tom Tromey
2008-06-27 22:37         ` Mark Mitchell
2008-06-26 22:10 ` Diego Novillo
2008-06-27 20:16   ` Ollie Wild
2008-06-27 20:54     ` Kenneth Zadeck
2008-06-27 21:45       ` Diego Novillo
2008-06-27 21:38     ` Diego Novillo
2008-06-27 22:15       ` Ollie Wild

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).