[patch] LTO support for Mach-O (apple-darwin)

Steven Bosscher stevenb.gcc@gmail.com
Sun May 2 10:54:00 GMT 2010


Hi,

This patch adds support for LTO on Mach-O targets, i.e. darwin.

The approach I've taken in implementing this is similar to what Dave
Korn did for LTO on COFF targets: There is a minimal Mach-O binary
reader/writer in lto-macho.? and section names are stored in a
separate string table.

There are a couple of funny things this patch does to make LTO work on
Mach-O. The most noticeable is that I had to capture assembler output
in the LTO generate phase and redirect it to a temporary file. The
reason is that you can only define relocations in a relocatable Mach-O
object for the first 255 sections, although there doesn't seem to be a
limit to the number of sections you can add. So I want all non-LTO
sections output before the LTO sections.

The patch only enables LTO for x86_64-darwin. The patch implements an
64-bits and 32-bits Mach-O reader/writer, and both have been tested
and appear to work, but I run into some issues with Mach-O PIC on
32-bits darwin that I don't know (yet?) how to fix. So 32-bits Mach-O
LTO support is left as an exercise for the interested reader ;-)

The middle-end bits have already been reviewed by Richi, and Mike has
already looked at the darwin bits.

Bootstrapped and tested on x86_64-apple-darwin10.3.0 (thanks to Jack Howarth).
OK for trunk?

Ciao!
Steven

ChangeLog:
	* configure.ac (--enable-lto): Add x86_64-apple-darwin* as
	a platform that supports LTO.
	* configure: Regenerate.

gcc/ChangeLog:
	* config.gcc (i[34567]86-*-darwin*, x86_64-*-darwin*): Add
	lto-macho as lto_binary_reader.
	* target.h (struct gcc_target): New hooks lto_start and	lto_end.
	* target-def.h (TARGET_ASM_LTO_START, TARGET_ASM_LTO_END): Define.
	* cgraphunit.c (ipa_passes): Wrap LTO assembler output generation
	in lto_start and lto_end calls.
	(is_elf_or_coff): Rename to maybe_lto_object_file.  Add Mach-O
	magic numbers.
	(scan_prog_file): Update is_elf_or_coff call.
	* doc/tm.text (TARGET_ASM_LTO_START, TARGET_ASM_LTO_END): Document.

	* collect2.c (main): Fix enum comparison.

	* config/darwin-protos.h (darwin_asm_lto_start, darwin_asm_lto_end):
	Add prototypes.
	* darwin9.h (LINK_COMMAND_SPEC): Pass -flto and -fwhopr to the linker.
	* darwin.h (LINK_COMMAND_SPEC): Likewise.  Define TARGET_ASM_LTO_START
	and TARGET_ASM_LTO_END.
	* darwin.c: Include obstack.h and lto-streamer.h.
	(lto_section_names_offset, lto_section_names_obstack,
	lto_asm_out_file, lto_asm_out_name, saved_asm_out_file): New static
	global variables.
	(LTO_SEGMENT_NAME, LTO_NAMES_SECTION): New defines.
	(darwin_asm_lto_start): New function.  Redirect output to asm_out_file
	to a temporary file.
	(darwin_asm_lto_end): New function.  Restore asm_out_file.
	(darwin_asm_named_section): For LTO sections, replace the name with
	the offset of the section name in a string table, and build this
	table.
	(darwin_file_start): Initialize global vars for LTO support.
	(darwin_file_end): If output to asm_out_file was redirected, append it
	to the proper asm_out_file here.  Add the section names section.

lto/ChangeLog:
	* lto.h (struct lto_file_struct): Document offset member.
	* lto-endian.h: New file.
	* lto-macho.h: New file.
	* lto-macho.c: New file.
	* Make-lang.in: Add rule for lto-macho.o.
-------------- next part --------------
ChangeLog:
	* configure.ac (--enable-lto): Add x86_64-apple-darwin* as
	a platform that supports LTO.
	* configure: Regenerate.

gcc/ChangeLog:
	* config.gcc (i[34567]86-*-darwin*, x86_64-*-darwin*): Add
	lto-macho as lto_binary_reader.
	* target.h (struct gcc_target): New hooks lto_start and	lto_end.
	* target-def.h (TARGET_ASM_LTO_START, TARGET_ASM_LTO_END): Define.
	* cgraphunit.c (ipa_passes): Wrap LTO assembler output generation
	in lto_start and lto_end calls.
	(is_elf_or_coff): Rename to maybe_lto_object_file.  Add Mach-O
	magic numbers.
	(scan_prog_file): Update is_elf_or_coff call.
	* doc/tm.text (TARGET_ASM_LTO_START, TARGET_ASM_LTO_END): Document.

	* collect2.c (main): Fix enum comparison.

	* config/darwin-protos.h (darwin_asm_lto_start, darwin_asm_lto_end):
	Add prototypes.
	* darwin9.h (LINK_COMMAND_SPEC): Pass -flto and -fwhopr to the linker.
	* darwin.h (LINK_COMMAND_SPEC): Likewise.  Define TARGET_ASM_LTO_START
	and TARGET_ASM_LTO_END.
	* darwin.c: Include obstack.h and lto-streamer.h.
	(lto_section_names_offset, lto_section_names_obstack,
	lto_asm_out_file, lto_asm_out_name, saved_asm_out_file): New static
	global variables.
	(LTO_SEGMENT_NAME, LTO_NAMES_SECTION): New defines.
	(darwin_asm_lto_start): New function.  Redirect output to asm_out_file
	to a temporary file.
	(darwin_asm_lto_end): New function.  Restore asm_out_file.
	(darwin_asm_named_section): For LTO sections, replace the name with
	the offset of the section name in a string table, and build this
	table.
	(darwin_file_start): Initialize global vars for LTO support.
	(darwin_file_end): If output to asm_out_file was redirected, append it
	to the proper asm_out_file here.  Add the section names section.

lto/ChangeLog:
	* lto.h (struct lto_file_struct): Document offset member.
	* lto-endian.h: New file.
	* lto-macho.h: New file.
	* lto-macho.c: New file.
	* Make-lang.in: Add rule for lto-macho.o.

Index: configure.ac
===================================================================
--- configure.ac	(revision 158938)
+++ configure.ac	(working copy)
@@ -1805,6 +1805,7 @@ fi],[if test x"$default_enable_lto" = x"
   # -flto it won't be needed until after installation anyway.
     case $target in
       *-cygwin*|*-mingw*) ;;
+      x86_64-apple-darwin*) ;;
       *) if test x"$enable_lto" = x"yes"; then
 	AC_MSG_ERROR([LTO support is not enabled for this target.])
         fi
Index: configure
===================================================================
--- configure	(revision 158938)
+++ configure	(working copy)
@@ -6688,6 +6688,7 @@ else
   # -flto it won't be needed until after installation anyway.
     case $target in
       *-cygwin*|*-mingw*) ;;
+      x86_64-apple-darwin*) ;;
       *) if test x"$enable_lto" = x"yes"; then
 	as_fn_error "LTO support is not enabled for this target." "$LINENO" 5
         fi
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 158938)
+++ gcc/config.gcc	(working copy)
@@ -1079,11 +1079,13 @@ i[34567]86-*-darwin*)
 	# support.
 	with_cpu=${with_cpu:-generic}
 	tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm"
+	lto_binary_reader=lto-macho
 	;;
 x86_64-*-darwin*)
 	with_cpu=${with_cpu:-generic}
 	tmake_file="${tmake_file} t-darwin ${cpu_type}/t-darwin64 t-slibgcc-darwin i386/t-crtpc i386/t-crtfm"
 	tm_file="${tm_file} ${cpu_type}/darwin64.h"
+	lto_binary_reader=lto-macho
 	;;
 i[34567]86-*-elf*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h"
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 158938)
+++ gcc/target.h	(working copy)
@@ -238,6 +238,14 @@ struct gcc_target
        translation unit.  */
     void (*file_end) (void);
 
+    /* Output any boilerplate text needed at the beginning of an
+       LTO output stream.  */
+    void (*lto_start) (void);
+
+    /* Output any boilerplate text needed at the end of an
+       LTO output stream.  */
+    void (*lto_end) (void);
+
     /* Output any boilerplace text needed at the end of a
        translation unit before debug and unwind info is emitted.  */
     void (*code_end) (void);
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 158938)
+++ gcc/target-def.h	(working copy)
@@ -204,6 +204,14 @@
 #define TARGET_ASM_FILE_END hook_void_void
 #endif
 
+#ifndef TARGET_ASM_LTO_START
+#define TARGET_ASM_LTO_START hook_void_void
+#endif
+
+#ifndef TARGET_ASM_LTO_END
+#define TARGET_ASM_LTO_END hook_void_void
+#endif
+
 #ifndef TARGET_ASM_CODE_END
 #define TARGET_ASM_CODE_END hook_void_void
 #endif
@@ -296,6 +304,8 @@
                         TARGET_ASM_CAN_OUTPUT_MI_THUNK,         \
                         TARGET_ASM_FILE_START,                  \
                         TARGET_ASM_FILE_END,			\
+                        TARGET_ASM_LTO_START,			\
+                        TARGET_ASM_LTO_END,			\
                         TARGET_ASM_CODE_END,			\
 			TARGET_ASM_EXTERNAL_LIBCALL,            \
                         TARGET_ASM_MARK_DECL_PRESERVED,		\
Index: gcc/cgraphunit.c
===================================================================
--- gcc/cgraphunit.c	(revision 158938)
+++ gcc/cgraphunit.c	(working copy)
@@ -1866,11 +1866,19 @@ ipa_passes (void)
       execute_ipa_summary_passes
 	((struct ipa_opt_pass_d *) all_regular_ipa_passes);
     }
+
+  /* Some targets need to handle LTO assembler output specially.  */
+  if (flag_generate_lto)
+    targetm.asm_out.lto_start ();
+
   execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes);
 
   if (!in_lto_p)
     ipa_write_summaries ();
 
+  if (flag_generate_lto)
+    targetm.asm_out.lto_end ();
+
   if (!flag_ltrans)
     execute_ipa_pass_list (all_regular_ipa_passes);
   invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL);
Index: gcc/collect2.c
===================================================================
--- gcc/collect2.c	(revision 158938)
+++ gcc/collect2.c	(working copy)
@@ -1821,7 +1821,7 @@ main (int argc, char **argv)
 	if (export_file != 0 && export_file[0])
 	  maybe_unlink (export_file);
 #endif
-	if (lto_mode)
+	if (lto_mode != LTO_MODE_NONE)
 	  maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
 
 	maybe_unlink (c_file);
@@ -2567,16 +2567,23 @@ write_aix_file (FILE *stream, struct id 
 

 #ifdef OBJECT_FORMAT_NONE
 
-/* Check to make sure the file is an ELF file.  LTO objects must
-   be in ELF format.  */
+/* Check to make sure the file is an LTO object file.  */
 
 static bool
-is_elf_or_coff (const char *prog_name)
+maybe_lto_object_file (const char *prog_name)
 {
   FILE *f;
-  char buf[4];
-  static char magic[4] = { 0x7f, 'E', 'L', 'F' };
-  static char coffmag[2] = { 0x4c, 0x01 };
+  unsigned char buf[4];
+  int i;
+
+  static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' };
+  static unsigned char coffmagic[2] = { 0x4c, 0x01 };
+  static unsigned char machomagic[4][4] = {
+    { 0xcf, 0xfa, 0xed, 0xfe },
+    { 0xce, 0xfa, 0xed, 0xfe },
+    { 0xfe, 0xed, 0xfa, 0xcf },
+    { 0xfe, 0xed, 0xfa, 0xce }
+  };
 
   f = fopen (prog_name, "rb");
   if (f == NULL)
@@ -2584,8 +2591,15 @@ is_elf_or_coff (const char *prog_name)
   if (fread (buf, sizeof (buf), 1, f) != 1)
     buf[0] = 0;
   fclose (f);
-  return memcmp (buf, magic, sizeof (magic)) == 0
-	|| memcmp (buf, coffmag, sizeof (coffmag)) == 0;
+
+  if (memcmp (buf, elfmagic, sizeof (elfmagic)) == 0
+      || memcmp (buf, coffmagic, sizeof (coffmagic)) == 0)
+    return true;
+  for (i = 0; i < 4; i++)
+    if (memcmp (buf, machomagic[i], sizeof (machomagic[i])) == 0)
+      return true;
+
+  return false;
 }
 
 /* Generic version to scan the name list of the loaded program for
@@ -2615,7 +2629,7 @@ scan_prog_file (const char *prog_name, s
   /* LTO objects must be in a known format.  This check prevents
      us from accepting an archive containing LTO objects, which
      gcc cannnot currently handle.  */
-  if (which_pass == PASS_LTOINFO && !is_elf_or_coff (prog_name))
+  if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name))
     return;
 
   /* If we do not have an `nm', complain.  */
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 158938)
+++ gcc/doc/tm.texi	(working copy)
@@ -7153,6 +7153,18 @@ need to do other things in that hook, ha
 this function.
 @end deftypefun
 
+@deftypefn {Target Hook} void TARGET_ASM_LTO_START (void)
+Output to @code{asm_out_file} any text which the assembler expects
+to find at the start of an LTO section.  The default is to output
+nothing.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_ASM_LTO_END (void)
+Output to @code{asm_out_file} any text which the assembler expects
+to find at the end of an LTO section.  The default is to output
+nothing.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_ASM_CODE_END (void)
 Output to @code{asm_out_file} any text which is needed before emitting
 unwind info and debug info at the end of a file.  Some targets emit
Index: gcc/config/darwin-protos.h
===================================================================
--- gcc/config/darwin-protos.h	(revision 158938)
+++ gcc/config/darwin-protos.h	(working copy)
@@ -71,6 +71,9 @@ extern void darwin_pragma_ms_struct (str
 extern void darwin_file_start (void);
 extern void darwin_file_end (void);
 
+extern void darwin_asm_lto_start (void);
+extern void darwin_asm_lto_end (void);
+
 extern void darwin_mark_decl_preserved (const char *);
 
 extern tree darwin_handle_kext_attribute (tree *, tree, tree, int, bool *);
Index: gcc/config/darwin9.h
===================================================================
--- gcc/config/darwin9.h	(revision 158938)
+++ gcc/config/darwin9.h	(working copy)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  
     %{o*}%{!o:-o a.out} \
     %{!A:%{!nostdlib:%{!nostartfiles:%S}}} \
     %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
+    %{flto} %{fwhopr} \
     %{fopenmp|ftree-parallelize-loops=*: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
     %{!nostdlib:%{!nodefaultlibs:  %(link_ssp) %G %L }} \
Index: gcc/config/darwin.h
===================================================================
--- gcc/config/darwin.h	(revision 158938)
+++ gcc/config/darwin.h	(working copy)
@@ -273,6 +273,7 @@ extern GTY(()) int darwin_ms_struct;
     %{o*}%{!o:-o a.out} \
     %{!A:%{!nostdlib:%{!nostartfiles:%S}}} \
     %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
+    %{flto} %{fwhopr} \
     %{fopenmp|ftree-parallelize-loops=*: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
     %{!nostdlib:%{!nodefaultlibs: %(link_ssp) %G %L }} \
@@ -581,6 +582,16 @@ extern GTY(()) int darwin_ms_struct;
 #undef  TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END darwin_file_end
 
+/* Because Mach-O relocations have a counter from 1 to 255 for the
+   section number they apply to, it is necessary to output all
+   normal sections before the LTO sections, to make sure that the
+   sections that may have relocations always have a section number
+   smaller than 255.  */
+#undef  TARGET_ASM_LTO_START
+#define TARGET_ASM_LTO_START darwin_asm_lto_start
+#undef  TARGET_ASM_LTO_END
+#define TARGET_ASM_LTO_END darwin_asm_lto_end
+
 #define ASM_OUTPUT_SKIP(FILE,SIZE)  \
   fprintf (FILE, "\t.space "HOST_WIDE_INT_PRINT_UNSIGNED"\n", SIZE)
 
Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c	(revision 158938)
+++ gcc/config/darwin.c	(working copy)
@@ -46,6 +46,8 @@ along with GCC; see the file COPYING3.  
 #include "hashtab.h"
 #include "df.h"
 #include "debug.h"
+#include "obstack.h"
+#include "lto-streamer.h"
 
 /* Darwin supports a feature called fix-and-continue, which is used
    for rapid turn around debugging.  When code is compiled with the
@@ -1387,12 +1389,88 @@ darwin_label_is_anonymous_local_objc_nam
   return (!strncmp ((const char *)p, "_OBJC_", 6));
 }
 
+/* LTO support for Mach-O.  */
+
+/* Section names for LTO sections.  */
+static unsigned int lto_section_names_offset = 0;
+
+/* This is the obstack which we use to allocate the many strings.  */
+static struct obstack lto_section_names_obstack;
+
+/* Segment name for LTO sections.  */
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* Section name for LTO section names section.  */
+#define LTO_NAMES_SECTION "__section_names"
+
+/* File to temporarily store LTO data.  This is appended to asm_out_file
+   in darwin_end_file.  */
+static FILE *lto_asm_out_file, *saved_asm_out_file;
+static char *lto_asm_out_name;
+
+/* Prepare asm_out_file for LTO output.  For darwin, this means hiding
+   asm_out_file and switching to an alternative output file.  */
+void
+darwin_asm_lto_start (void)
+{
+  gcc_assert (! saved_asm_out_file);
+  saved_asm_out_file = asm_out_file;
+  if (! lto_asm_out_name)
+    lto_asm_out_name = make_temp_file (".lto.s");
+  lto_asm_out_file = fopen (lto_asm_out_name, "a");
+  if (lto_asm_out_file == NULL)
+    fatal_error ("failed to open temporary file %s for LTO output",
+		 lto_asm_out_name);
+  asm_out_file = lto_asm_out_file;
+}
+
+/* Restore asm_out_file.  */
+void
+darwin_asm_lto_end (void)
+{
+  gcc_assert (saved_asm_out_file);
+  fclose (lto_asm_out_file);
+  asm_out_file = saved_asm_out_file;
+  saved_asm_out_file = NULL;
+}
+
 void
 darwin_asm_named_section (const char *name,
-			  unsigned int flags ATTRIBUTE_UNUSED,
+			  unsigned int flags,
 			  tree decl ATTRIBUTE_UNUSED)
 {
-  fprintf (asm_out_file, "\t.section %s\n", name);
+  /* LTO sections go in a special segment __GNU_LTO.  We want to replace the
+     section name with something we can use to represent arbitrary-length
+     names (section names in Mach-O are at most 16 characters long).  */
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+	       strlen (LTO_SECTION_NAME_PREFIX)) == 0)
+    {
+      /* We expect certain flags to be set...  */
+      gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+		  == (SECTION_DEBUG | SECTION_NAMED));
+
+      /* Add the section name to the things to output when we end the
+	 current assembler output file.
+	 This is all not very efficient, but that doesn't matter -- this
+	 shouldn't be a hot path in the compiler...  */
+      obstack_1grow (&lto_section_names_obstack, '\t');
+      obstack_grow (&lto_section_names_obstack, ".ascii ", 7);
+      obstack_1grow (&lto_section_names_obstack, '"');
+      obstack_grow (&lto_section_names_obstack, name, strlen (name));
+      obstack_grow (&lto_section_names_obstack, "\\0\"\n", 4);
+
+      /* Output the dummy section name.  */
+      fprintf (asm_out_file, "\t.section %s,__%08X,regular,debug\t# %s\n",
+	       LTO_SEGMENT_NAME, lto_section_names_offset, name);
+
+      /* Update the offset for the next section name.  Make sure we stay
+	 within reasonable length.  */  
+      lto_section_names_offset += strlen (name) + 1;
+      gcc_assert (lto_section_names_offset > 0
+		  && lto_section_names_offset < ((unsigned) 1 << 31));
+    }
+  else
+    fprintf (asm_out_file, "\t.section %s\n", name);
 }
 
 void
@@ -1585,7 +1663,8 @@ darwin_asm_output_dwarf_delta (FILE *fil
     fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
 }
 
-/* Output labels for the start of the DWARF sections if necessary.  */
+/* Output labels for the start of the DWARF sections if necessary.
+   Initialize the stuff we need for LTO long section names support.  */
 void
 darwin_file_start (void)
 {
@@ -1620,6 +1699,11 @@ darwin_file_start (void)
 	  fprintf (asm_out_file, "Lsection%.*s:\n", namelen, debugnames[i] + 8);
 	}
     }
+
+  /* We fill this obstack with the complete section text for the lto section
+     names to write in darwin_file_end.  */
+  obstack_init (&lto_section_names_obstack);
+  lto_section_names_offset = 0;
 }
 
 /* Output an offset in a DWARF section on Darwin.  On Darwin, DWARF section
@@ -1646,6 +1730,8 @@ darwin_asm_output_dwarf_offset (FILE *fi
 void
 darwin_file_end (void)
 {
+  const char *lto_section_names;
+
   machopic_finish (asm_out_file);
   if (strcmp (lang_hooks.name, "GNU C++") == 0)
     {
@@ -1653,6 +1739,52 @@ darwin_file_end (void)
       switch_to_section (darwin_sections[destructor_section]);
       ASM_OUTPUT_ALIGN (asm_out_file, 1);
     }
+
+  /* If there was LTO assembler output, append it to asm_out_file.  */
+  if (lto_asm_out_name)
+    {
+      int n;
+      char *buf, *lto_asm_txt;
+
+      /* Shouldn't be here if we failed to switch back.  */
+      gcc_assert (! saved_asm_out_file);
+
+      lto_asm_out_file = fopen (lto_asm_out_name, "r");
+      if (lto_asm_out_file == NULL)
+	fatal_error ("failed to open temporary file %s with LTO output",
+		     lto_asm_out_name);
+      fseek (lto_asm_out_file, 0, SEEK_END);
+      n = ftell (lto_asm_out_file);
+      if (n > 0)
+        {
+	  fseek (lto_asm_out_file, 0, SEEK_SET);
+	  lto_asm_txt = buf = (char *) xmalloc (n + 1);
+	  while (fgets (lto_asm_txt, n, lto_asm_out_file))
+	    fputs (lto_asm_txt, asm_out_file);
+	}
+
+      /* Remove the temporary file.  */
+      fclose (lto_asm_out_file);
+      unlink_if_ordinary (lto_asm_out_name);
+      free (lto_asm_out_name);
+    }
+
+  /* Finish the LTO section names obstack.  Don't output anything if
+     there are no recorded section names.  */
+  obstack_1grow (&lto_section_names_obstack, '\0');
+  lto_section_names = XOBFINISH (&lto_section_names_obstack, const char *);
+  if (strlen (lto_section_names) > 0)
+    {
+      fprintf (asm_out_file,
+	       "\t.section %s,%s,regular,debug\n",
+	       LTO_SEGMENT_NAME, LTO_NAMES_SECTION);
+      fprintf (asm_out_file,
+	       "\t# Section names in %s are offsets into this table\n",
+	       LTO_SEGMENT_NAME);
+      fprintf (asm_out_file, "%s\n", lto_section_names);
+    }
+  obstack_free (&lto_section_names_obstack, NULL);
+
   fprintf (asm_out_file, "\t.subsections_via_symbols\n");
 }
 
Index: gcc/lto/lto.h
===================================================================
--- gcc/lto/lto.h	(revision 158938)
+++ gcc/lto/lto.h	(working copy)
@@ -1,5 +1,5 @@
 /* LTO declarations.
-   Copyright 2009 Free Software Foundation, Inc.
+   Copyright 2009, 2010 Free Software Foundation, Inc.
    Contributed by CodeSourcery, Inc.
 
 This file is part of GCC.
@@ -28,6 +28,7 @@ typedef struct lto_file_struct
 {
   /* The name of the file.  */
   const char *filename;
+  /* The offset for the object inside an ar archive file (or zero).  */
   off_t offset;
 } lto_file;
 
Index: gcc/lto/lto-endian.h
===================================================================
--- gcc/lto/lto-endian.h	(revision 0)
+++ gcc/lto/lto-endian.h	(revision 0)
@@ -0,0 +1,205 @@
+/* Very simple endian-ness layer for LTO object file handling
+   Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This header file provides a simple way to handle object files in
+   another endian-ness than the host machine.  This is necesarry to
+   enable cross-compilation with LTO enabled.  Targets that use the
+   ELF binary object format do not need this (libelf already handles
+   endian-ness) but for COFF and Mach-O the functions in this header
+   are used in the minimal binary object reader/writer.
+   
+   For all functions in this header, the user is responsible for
+   making sure that the memory accesses are valid.  */
+
+#ifndef GCC_LTO_ENDIAN_H
+#define GCC_LTO_ENDIAN_H
+
+#include <stdint.h>
+#include <inttypes.h>
+
+static inline uint16_t
+get_uint16_le (const unsigned char *ptr)
+{
+  return ptr[0] | (ptr[1] << 8);
+}
+
+static inline uint32_t
+get_uint32_le (const unsigned char *ptr)
+{
+  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
+
+static inline uint64_t
+get_uint64_le (const unsigned char *ptr_)
+{
+#define ptr (uint64_t) ptr_
+  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)
+         | (ptr[4] << 32) | (ptr[5] << 40) | (ptr[6] << 48) | (ptr[7] << 56);
+#undef ptr
+}
+
+static inline uint16_t
+get_uint16_be (const unsigned char *ptr)
+{
+  return ptr[1] | (ptr[2] << 8);
+}
+
+static inline uint32_t
+get_uint32_be (const unsigned char *ptr)
+{
+  return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
+}
+
+static inline uint64_t
+get_uint64_be (const unsigned char *ptr_)
+{
+#define ptr (uint64_t) ptr_
+  return ptr[7] | (ptr[6] << 8) | (ptr[5] << 16) | (ptr[4] << 24)
+         | (ptr[3] << 32) | (ptr[2] << 40) | (ptr[1] << 48) | (ptr[0] << 56);
+#undef ptr
+}
+
+static inline void
+put_uint16_le (unsigned char *ptr, uint16_t data)
+{
+  ptr[0] = data & 0xff;
+  ptr[1] = (data >> 8) & 0xff;
+}
+
+static inline void
+put_uint32_le (unsigned char *ptr, uint32_t data)
+{
+  ptr[0] = data & 0xff;
+  ptr[1] = (data >> 8) & 0xff;
+  ptr[2] = (data >> 16) & 0xff;
+  ptr[3] = (data >> 24) & 0xff;
+}
+
+static inline void
+put_uint64_le (unsigned char *ptr, uint64_t data)
+{
+  ptr[0] = data & 0xff;
+  ptr[1] = (data >> 8) & 0xff;
+  ptr[2] = (data >> 16) & 0xff;
+  ptr[3] = (data >> 24) & 0xff;
+  ptr[4] = (data >> 32) & 0xff;
+  ptr[5] = (data >> 40) & 0xff;
+  ptr[6] = (data >> 48) & 0xff;
+  ptr[7] = (data >> 56) & 0xff;
+}
+
+static inline void
+put_uint16_be (unsigned char *ptr, uint16_t data)
+{
+  ptr[1] = data & 0xff;
+  ptr[0] = (data >> 8) & 0xff;
+}
+
+static inline void
+put_uint32_be (unsigned char *ptr, uint32_t data)
+{
+  ptr[3] = data & 0xff;
+  ptr[2] = (data >> 8) & 0xff;
+  ptr[1] = (data >> 16) & 0xff;
+  ptr[0] = (data >> 24) & 0xff;
+}
+
+static inline void
+put_uint64_be (unsigned char *ptr, uint64_t data)
+{
+  ptr[7] = data & 0xff;
+  ptr[6] = (data >> 8) & 0xff;
+  ptr[5] = (data >> 16) & 0xff;
+  ptr[4] = (data >> 24) & 0xff;
+  ptr[3] = (data >> 32) & 0xff;
+  ptr[2] = (data >> 40) & 0xff;
+  ptr[1] = (data >> 48) & 0xff;
+  ptr[0] = (data >> 56) & 0xff;
+}
+
+static inline void
+get_string (unsigned char *ptr, char *dest, size_t len)
+{
+  memcpy (dest, ptr, len);
+}
+
+static inline void
+put_string (unsigned char *ptr, char *src, size_t len)
+{
+  memcpy (ptr, src, len);
+}
+
+/* Use the target macro BYTES_BIG_ENDIAN to choose.  */
+
+static inline uint16_t
+get_uint16 (const unsigned char *ptr)
+{
+  if (BYTES_BIG_ENDIAN)
+    return get_uint16_be (ptr);
+  else
+    return get_uint16_le (ptr);
+}
+
+static inline uint32_t
+get_uint32 (const unsigned char *ptr)
+{
+  if (BYTES_BIG_ENDIAN)
+    return get_uint32_be (ptr);
+  else
+    return get_uint32_le (ptr);
+}
+
+static inline uint64_t
+get_uint64 (const unsigned char *ptr)
+{
+  if (BYTES_BIG_ENDIAN)
+    return get_uint64_be (ptr);
+  else
+    return get_uint64_le (ptr);
+}
+
+static inline void
+put_uint16 (unsigned char *ptr, uint16_t data)
+{
+  if (BYTES_BIG_ENDIAN)
+    put_uint16_be (ptr, data);
+  else
+    put_uint16_le (ptr, data);
+}
+
+static inline void
+put_uint32 (unsigned char *ptr, uint32_t data)
+{
+  if (BYTES_BIG_ENDIAN)
+    put_uint32_be (ptr, data);
+  else
+    put_uint32_le (ptr, data);
+}
+
+static inline void
+put_uint64 (unsigned char *ptr, uint64_t data)
+{
+  if (BYTES_BIG_ENDIAN)
+    put_uint64_be (ptr, data);
+  else
+    put_uint64_le (ptr, data);
+}
+
+#endif /* GCC_LTO_ENDIAN_H  */
+
Index: gcc/lto/lto-macho.c
===================================================================
--- gcc/lto/lto-macho.c	(revision 0)
+++ gcc/lto/lto-macho.c	(revision 0)
@@ -0,0 +1,978 @@
+/* LTO routines for Mach-O object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Contributed by Steven Bosscher.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "lto.h"
+#include "tm.h"
+#include "libiberty.h"
+#include "lto-streamer.h"
+#include "lto/lto-endian.h"
+#include "lto/lto-macho.h"
+
+/* Rather than implementing a libmacho to match libelf, or attempting to
+   integrate libbfd into GCC, this file is a self-contained (and very
+   minimal) Mach-O format object file reader/writer.  The generated files
+   will contain a Mach-O header, a number of Mach-O load commands an
+   section headers, the  section data itself, and a trailing string table
+   for section names.  */
+
+/* This needs to be kept in sync with darwin.c.  Better yet, lto-macho.c
+   and lto-macho.h should be moved to config/, and likewise for lto-coff.*
+   and lto-elf.*.  */
+
+/* Segment name for LTO sections.  */
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* Section name for LTO section names section.  */
+#define LTO_NAMES_SECTION "__section_names"
+
+/* Handle opening elf files on hosts, such as Windows, that may use 
+   text file handling that will break binary access.  */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* Cached object file header.  We use a header_64 for this, since all
+   the fields we need are in there, in the same position as header_32.  */
+mach_o_header_64 cached_mach_o_header;
+uint32_t cached_mach_o_magic;
+
+/* The current output file.  */
+static lto_file *current_out_file;
+
+
+/* Is this a 32-bits or 64-bits Mach-O object file?  */
+static int
+mach_o_word_size (void)
+{
+  gcc_assert (cached_mach_o_magic != 0);
+  return (cached_mach_o_magic == MACH_O_MH_MAGIC_64
+	  || cached_mach_o_magic == MACH_O_MH_CIGAM_64) ? 64 : 32;
+}
+
+/* Sets the current output file to FILE.  Returns the old output file or
+   NULL.  */
+
+lto_file *
+lto_set_current_out_file (lto_file *file)
+{
+  lto_file *old_file = current_out_file;
+  current_out_file = file;
+  return old_file;
+}
+
+
+/* Returns the current output file.  */
+
+lto_file *
+lto_get_current_out_file (void)
+{
+  return current_out_file;
+}
+
+/* Mach-O section structure constructor.  */
+
+static lto_mach_o_section
+mach_o_new_section (lto_mach_o_file *mach_o_file, const char *name)
+{
+  lto_mach_o_section ptr;
+
+  /* FIXME We could allocate these things on an obstack.  */
+  ptr = XCNEW (struct lto_mach_o_section_d);
+  if (name)
+    {
+      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+		   strlen(LTO_SECTION_NAME_PREFIX)) != 0)
+	sorry ("not implemented: Mach-O writer for non-LTO sections");
+      ptr->name = xstrdup (name);
+    }
+
+  VEC_safe_push (lto_mach_o_section, heap, mach_o_file->section_vec, ptr);
+
+  return ptr;
+}
+
+/* Mach-O section data block structure constructor.  */
+
+static lto_mach_o_data
+mach_o_new_data (lto_mach_o_section sec)
+{
+  lto_mach_o_data ptr, *chain_ptr_ptr;
+
+  /* FIXME We could allocate these things on an obstack.  */
+  ptr = XCNEW (struct lto_mach_o_data_d);
+
+  chain_ptr_ptr = &sec->data_chain;
+  while (*chain_ptr_ptr)
+    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
+  *chain_ptr_ptr = ptr;
+
+  return ptr;
+}
+
+/* Initialize FILE, an LTO file object for FILENAME.  Offset is the
+   offset into FILE where the object is located (e.g. in an archive).  */
+
+static void
+lto_file_init (lto_file *file, const char *filename, off_t offset)
+{
+  file->filename = filename;
+  file->offset = offset;
+}
+
+/* Return an error string after an error, or a predetermined one
+   if ERRCODE is not -1.  */
+
+static const char *
+mach_o_errmsg (int errcode)
+{
+  return strerror (errcode == -1 ? errno : errcode);
+}
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_name (const void *p)
+{
+  const struct lto_section_slot *s = (const struct lto_section_slot *) p;
+  return (hashval_t) htab_hash_string (s->name);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_name (const void *p1, const void *p2)
+{
+  const struct lto_section_slot *s1 =
+    (const struct lto_section_slot *) p1;
+  const struct lto_section_slot *s2 =
+    (const struct lto_section_slot *) p2;
+
+  return strcmp (s1->name, s2->name) == 0;
+}
+
+/* Build a hash table whose key is the section names and whose data is
+   the start and size of each section in the .o file.  */
+
+htab_t
+lto_obj_build_section_table (lto_file *lto_file) 
+{
+  lto_mach_o_file *mach_o_file = (lto_mach_o_file *)lto_file;
+  lto_mach_o_section sec;
+  htab_t section_hash_table;
+  off_t strtab_offs;
+  ssize_t strtab_size;
+  char *strtab = NULL;
+  int i;
+
+  section_hash_table = htab_create (37, hash_name, eq_name, free);
+
+  /* Seek the string table.  */
+  /* FIXME The segment name should be in darwin.h, but can we include it
+     here in this file?  */
+  for (i = 0;
+       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    {
+      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
+	continue;
+      if (strncmp (sec->u.section.sectname, "__section_names", 16) == 0)
+        break;
+    }
+  if (! sec)
+    {
+      error ("invalid Mach-O LTO object file: no __section_names section found");
+      goto done;
+    }
+  mach_o_file->section_names_section = sec;
+
+  if (mach_o_word_size () == 64)
+    {
+      strtab_offs = (off_t) get_uint32 (&sec->u.section_64.offset[0]);
+      strtab_size = (size_t) get_uint64 (&sec->u.section_64.size[0]);
+    }
+  else
+    {
+      strtab_offs = (off_t) get_uint32 (&sec->u.section_32.offset[0]);
+      strtab_size = (size_t) get_uint32 (&sec->u.section_32.size[0]);
+    }
+
+  /* Seek to start of string table.  */
+  if (strtab_offs != lseek (mach_o_file->fd,
+			    mach_o_file->base.offset + strtab_offs,
+			    SEEK_SET))
+    {
+      error ("altered or invalid Mach-O object file");
+      goto done;
+    }
+
+  strtab = XNEWVEC (char, strtab_size);
+  if (read (mach_o_file->fd, strtab, strtab_size) != strtab_size)
+    {
+      error ("invalid Mach-O LTO object file __section_names section");
+      goto done;
+    }
+
+  /* Scan sections looking at names.  */
+  for (i = 0;
+       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    {
+      struct lto_section_slot s_slot;
+      void **slot;
+      char *new_name;
+      unsigned long stringoffset;
+      char name[17];
+
+      /* Ignore non-LTO sections.  Also ignore the __section_names section
+	 which does not need renaming.  */
+      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
+	continue;
+      if (sec == mach_o_file->section_names_section)
+        continue;
+
+      /* Try to extract the offset of the real name for this section from
+	 __section_names.  */
+      memcpy (&name[0], sec->u.section.sectname, 16);
+      name[16] = '\0';
+      if (name[0] != '_' || name[1] != '_'
+	  || sscanf (&name[2], "%08lX", &stringoffset) != 1
+	  || strtab_size < (ssize_t) stringoffset)
+	{
+	  error ("invalid Mach-O LTO section name string: %s", name);
+	  continue;
+	}
+
+      new_name = XNEWVEC (char, strlen (strtab + stringoffset) + 1);
+      strcpy (new_name, strtab + stringoffset);
+      s_slot.name = new_name;
+      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
+      if (*slot == NULL)
+	{
+	  struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
+
+	  new_slot->name = new_name;
+	  if (mach_o_word_size() == 64)
+	    {
+	      new_slot->start =
+		(intptr_t) get_uint32 (&sec->u.section_64.offset[0]);
+	      new_slot->len =
+		(size_t) get_uint64 (&sec->u.section_64.size[0]);
+	    }
+	  else
+	    {
+	      new_slot->start =
+		(intptr_t) get_uint32 (&sec->u.section_32.offset[0]);
+	      new_slot->len =
+		(size_t) get_uint32 (&sec->u.section_32.size[0]);
+	    }
+
+	  *slot = new_slot;
+	}
+      else
+	{
+	  error ("two or more sections for %s:", new_name);
+	  goto done;
+	}
+    }
+
+ done:
+  if (strtab)
+    free (strtab);
+  return section_hash_table;
+}
+
+
+/* Begin a new Mach-O section named NAME in the current output file.  */
+
+void
+lto_obj_begin_section (const char *name)
+{
+  lto_mach_o_file *file;
+
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+	       strlen(LTO_SECTION_NAME_PREFIX)) != 0)
+    sorry ("not implemented: Mach-O writer for non-LTO sections");
+
+  /* Grab the current output file and do some basic assertion checking.  */
+  file = (lto_mach_o_file *) lto_get_current_out_file (),
+  gcc_assert (file && file->writable && !file->scn);
+
+  /* Create a new section.  */
+  file->scn = mach_o_new_section (file, name);
+  if (!file->scn)
+    fatal_error ("could not create a new Mach-O section: %s", mach_o_errmsg (-1));
+}
+
+
+/* Append DATA of length LEN to the current output section.  BASE is a pointer
+   to the output page containing DATA.  It is freed once the output file has
+   been written.  */
+
+void
+lto_obj_append_data (const void *data, size_t len, void *block)
+{
+  lto_mach_o_file *file;
+  lto_mach_o_data mach_o_data;
+  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
+
+  /* Grab the current output file and do some basic assertion checking.  */
+  file = (lto_mach_o_file *) lto_get_current_out_file ();
+  gcc_assert (file);
+  gcc_assert (file->scn);
+
+  mach_o_data = mach_o_new_data (file->scn);
+  if (!mach_o_data)
+    fatal_error ("could not append data to Mach-O section: %s", mach_o_errmsg (-1));
+
+  mach_o_data->d_buf = CONST_CAST (void *, data);
+  mach_o_data->d_size = len;
+
+  /* Chain all data blocks (from all sections) on one singly-linked
+     list for freeing en masse after the file is closed.  */
+  base->ptr = (char *)file->data;
+  file->data = base;
+}
+
+
+/* End the current output section.  This just does some assertion checking
+   and sets the current output file's scn member to NULL.  */
+
+void
+lto_obj_end_section (void)
+{
+  lto_mach_o_file *file;
+
+  /* Grab the current output file and validate some basic assertions.  */
+  file = (lto_mach_o_file *) lto_get_current_out_file ();
+  gcc_assert (file);
+  gcc_assert (file->scn);
+
+  file->scn = NULL;
+}
+
+
+/* Read a Mach-O header from MACH_O_FILE and validate it.
+   The file descriptor in MACH_O_FILE points at the start of the file.
+   If cached_mach_o_header is uninitialized, caches the results.
+   On succes, returns true and moves file pointer to the start of the
+   load commands.  On failure, returns false.  */
+
+static bool
+validate_mach_o_header (lto_mach_o_file *mach_o_file)
+{
+  ssize_t i, n;
+  unsigned char magic[4];
+  uint32_t cputype;
+  off_t startpos;
+
+  /* Known header magics for validation, as an array.  */
+  static const unsigned int mach_o_known_formats[] = {
+    MACH_O_MH_MAGIC,
+    MACH_O_MH_CIGAM,
+    MACH_O_MH_MAGIC_64,
+    MACH_O_MH_CIGAM_64,
+  };
+#define MACH_O_NUM_KNOWN_FORMATS \
+  ((ssize_t) ARRAY_SIZE (mach_o_known_formats))
+
+  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
+  if (read (mach_o_file->fd, &magic, sizeof (magic)) != 4
+      || lseek (mach_o_file->fd, -4, SEEK_CUR) != startpos)
+    {
+      error ("cannot read file %s", mach_o_file->base.filename);
+      return false;
+    }
+
+  for (i = 0; i < MACH_O_NUM_KNOWN_FORMATS; ++i)
+    if (get_uint32 (&magic[0]) == mach_o_known_formats[i])
+      break;
+  if (i == MACH_O_NUM_KNOWN_FORMATS)
+    goto not_for_target;
+
+  /* Check the endian-ness.  */
+  if (BYTES_BIG_ENDIAN && magic[0] != 0xfe)
+    goto not_for_target;
+
+  /* Set or check cached magic number.  */
+  if (cached_mach_o_magic == 0)
+    cached_mach_o_magic = get_uint32 (&magic[0]);
+  else if (cached_mach_o_magic != get_uint32 (&magic[0]))
+    goto not_for_target;
+ 
+  n = mach_o_word_size () == 64
+      ? sizeof (mach_o_header_64) : sizeof (mach_o_header_32);
+  if (read (mach_o_file->fd, &mach_o_file->u.header, n) != n)
+    goto not_for_target;
+
+  /* Is this a supported CPU?  */
+  /* ??? Would be nice to validate the exact target architecture.  */
+  cputype = get_uint32 (&mach_o_file->u.header.cputype[0]);
+  if (cputype == MACH_O_CPU_TYPE_I386
+      || cputype == MACH_O_CPU_TYPE_POWERPC)
+    {
+      if (mach_o_word_size () != 32)
+        goto not_for_target;
+    }
+  else if (cputype == MACH_O_CPU_TYPE_X86_64
+	   || cputype == MACH_O_CPU_TYPE_POWERPC_64)
+    {
+      if (mach_o_word_size () != 64)
+        goto not_for_target;
+    }
+
+  /* Is this an MH_OBJECT file?  */
+  if (get_uint32 (&mach_o_file->u.header.filetype[0]) != MACH_O_MH_OBJECT)
+    error ("Mach-O file %s is not an MH_OBJECT file",
+	   mach_o_file->base.filename);
+
+  /* Save the header for future use.  */
+  memcpy (&cached_mach_o_header, &mach_o_file->u.header,
+	  sizeof (cached_mach_o_header));
+
+  return true;
+
+ not_for_target:
+  error ("file %s is not a Mach-O object file for target",
+	 mach_o_file->base.filename);
+  return false;
+}
+
+
+/* Read a Mach-O LC_SEGMENT command (32 bits) from MACH_O_FILE and
+   validate it.
+   The file descriptor in MACH_O_FILE points at the start of the load
+   command.  On sucess, returns true and advances the file pointer
+   past the end of the load command.  On failure, returns false.  */
+
+static bool
+validate_mach_o_segment_command_32 (lto_mach_o_file *mach_o_file)
+{
+  mach_o_segment_command_32 seg_cmd_32;
+  unsigned int i;
+  ssize_t n;
+  off_t startpos;
+
+  /* Fields we're interested in.  */
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t nsects;
+
+  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
+
+  n = sizeof (mach_o_segment_command_32);
+  if (read (mach_o_file->fd, (void *) &seg_cmd_32, n) != n)
+    goto fail;
+
+  cmd = get_uint32 (&seg_cmd_32.cmd[0]);
+  cmdsize = get_uint32 (&seg_cmd_32.cmdsize[0]);
+  nsects = get_uint32 (&seg_cmd_32.nsects[0]);
+  gcc_assert (cmd == MACH_O_LC_SEGMENT);
+
+  /* Validate section table entries.  */
+  for (i = 0; i < nsects; i++)
+    {
+      mach_o_section_32 sec_32;
+      lto_mach_o_section ltosec;
+
+      n = sizeof (mach_o_section_32);
+      if (read (mach_o_file->fd, &sec_32, n) != n)
+	goto fail;
+
+      /* ??? Perform some checks.  */
+
+      /* Looks ok, so record its details.  We don't read the 
+         string table or set up names yet; we'll do that when
+	 we build the hash table.  */
+      ltosec = mach_o_new_section (mach_o_file, NULL);
+      memcpy (&ltosec->u.section_32, &sec_32, sizeof (sec_32));
+    }
+
+  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
+    goto fail;
+
+  return true;
+
+ fail:
+  error ("could not read LC_SEGMENT command in Mach-O file %s",
+	 mach_o_file->base.filename);
+  return false;
+}
+
+
+/* Read a Mach-O LC_SEGMENT_64 command from MACH_O_FILE and validate it.
+   The file descriptor in MACH_O_FILE points at the start of the load
+   command.  On sucess, returns true and advances the file pointer
+   past the end of the load command.  On failure, returns false.  */
+
+static bool
+validate_mach_o_segment_command_64 (lto_mach_o_file *mach_o_file)
+{
+  mach_o_segment_command_64 seg_cmd_64;
+  unsigned int i;
+  ssize_t n;
+  off_t startpos;
+
+  /* Fields we're interested in.  */
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t nsects;
+
+  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
+
+  n = sizeof (mach_o_segment_command_64);
+  if (read (mach_o_file->fd, (void *) &seg_cmd_64, n) != n)
+    goto fail;
+
+  cmd = get_uint32 (&seg_cmd_64.cmd[0]);
+  cmdsize = get_uint32 (&seg_cmd_64.cmdsize[0]);
+  nsects = get_uint32 (&seg_cmd_64.nsects[0]);
+  gcc_assert (cmd == MACH_O_LC_SEGMENT_64);
+
+  /* Validate section table entries.  */
+  for (i = 0; i < nsects; i++)
+    {
+      mach_o_section_64 sec_64;
+      lto_mach_o_section ltosec;
+
+      n = sizeof (mach_o_section_64);
+      if (read (mach_o_file->fd, &sec_64, n) != n)
+	goto fail;
+
+      /* ??? Perform some checks.  */
+
+      /* Looks ok, so record its details.  We don't read the 
+         string table or set up names yet; we'll do that when
+	 we build the hash table.  */
+      ltosec = mach_o_new_section (mach_o_file, NULL);
+      memcpy (&ltosec->u.section_64, &sec_64, sizeof (sec_64));
+    }
+
+  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
+    goto fail;
+
+  return true;
+
+ fail:
+  error ("could not read LC_SEGMENT_64 command in Mach-O file %s",
+	 mach_o_file->base.filename);
+  return false;
+}
+
+/* Read a Mach-O load commands from MACH_O_FILE and validate it.
+   The file descriptor in MACH_O_FILE points at the start of the load
+   command.  On sucess, returns true and advances the file pointer
+   past the end of the load command.  On failure, returns false.  */
+
+static bool
+validate_mach_o_load_command (lto_mach_o_file *mach_o_file)
+{
+  mach_o_load_command load_command;
+  uint32_t cmd;
+  uint32_t cmdsize;
+  ssize_t n;
+
+  n = sizeof (load_command);
+  if (read (mach_o_file->fd, &load_command, n) != n)
+    {
+      error ("could not read load commands in Mach-O file %s",
+	     mach_o_file->base.filename);
+      return false;
+    }
+  lseek (mach_o_file->fd, -1 * (off_t) sizeof (load_command), SEEK_CUR);
+
+  cmd = get_uint32 (&load_command.cmd[0]);
+  cmdsize = get_uint32 (&load_command.cmdsize[0]);
+  switch (cmd)
+    {
+    case MACH_O_LC_SEGMENT:
+      return validate_mach_o_segment_command_32 (mach_o_file);
+    case MACH_O_LC_SEGMENT_64:
+      return validate_mach_o_segment_command_64 (mach_o_file);
+
+    default:
+      /* Just skip over it.  */
+      lseek (mach_o_file->fd, cmdsize, SEEK_CUR);
+      return true;
+    }
+}
+
+/* Validate's MACH_O_FILE's executable header and, if cached_mach_o_header is
+   uninitialized, caches the results.  Also records the section header string
+   table's section index.  Returns true on success, false on failure.  */
+
+static bool
+validate_file (lto_mach_o_file *mach_o_file)
+{
+  uint32_t i, ncmds;
+
+  /* Read and sanity check the raw header.  */
+  if (! validate_mach_o_header (mach_o_file))
+    return false;
+
+  ncmds = get_uint32 (&mach_o_file->u.header.ncmds[0]);
+  for (i = 0; i < ncmds; ++i)
+    if (! validate_mach_o_load_command (mach_o_file))
+      return false;
+
+  return true;
+}
+
+/* Initialize MACH_O_FILE's executable header using cached data from previously
+   read files.  */
+
+static void
+init_mach_o_header (lto_mach_o_file *mach_o_file)
+{
+  gcc_assert (cached_mach_o_magic != 0);
+  memcpy (&mach_o_file->u.header,
+	  &cached_mach_o_header,
+	  sizeof (mach_o_file->u.header));
+  put_uint32 (&mach_o_file->u.header.ncmds[0], 0);
+  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], 0);
+}
+
+/* Open Mach-O file FILENAME.  If WRITABLE is true, the file is opened for write
+   and, if necessary, created.  Otherwise, the file is opened for reading.
+   Returns the opened file.  */
+
+lto_file *
+lto_obj_file_open (const char *filename, bool writable)
+{
+  lto_mach_o_file *mach_o_file;
+  lto_file *result = NULL;
+  off_t offset;
+  const char *offset_p;
+  char *fname;
+  struct stat statbuf;
+
+  offset_p = strchr (filename, '@');
+  if (!offset_p)
+    {
+      fname = xstrdup (filename);
+      offset = 0;
+    }
+  else
+    {
+      /* The file started with '@' is a file containing command line
+	 options.  Stop if it doesn't exist.  */
+      if (offset_p == filename)
+	fatal_error ("command line option file '%s' does not exist",
+		     filename);
+
+      fname = (char *) xmalloc (offset_p - filename + 1);
+      memcpy (fname, filename, offset_p - filename);
+      fname[offset_p - filename] = '\0';
+      offset_p += 3; /* skip the @0x */
+      offset = lto_parse_hex (offset_p);
+    }
+
+  /* Set up.  */
+  mach_o_file = XCNEW (lto_mach_o_file);
+  result = (lto_file *) mach_o_file;
+  lto_file_init (result, fname, offset);
+  mach_o_file->fd = -1;
+  mach_o_file->writable = writable;
+
+  /* Open the file.  */
+  mach_o_file->fd = open (fname,
+    O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
+
+  if (mach_o_file->fd == -1)
+    {
+      error ("could not open file %s", fname);
+      goto fail;
+    }
+
+  if (stat (fname, &statbuf) < 0)
+    {
+      error ("could not stat file %s", fname);
+      goto fail;
+    }
+
+  mach_o_file->file_size = statbuf.st_size;
+
+  /* If the object is in an archive, get it out.  */
+  if (offset != 0)
+    {
+      char ar_tail[12];
+      int size;
+
+      /* Surely not?  */
+      gcc_assert (!writable);
+
+      /* Seek to offset, or error.  */
+      if (lseek (mach_o_file->fd, offset, SEEK_SET) != (ssize_t) offset)
+	{
+	  error ("could not find archive member @0x%lx", (long) offset);
+	  goto fail;
+	}
+
+      /* Now seek back 12 chars and read the tail of the AR header to
+         find the length of the member file.  */
+      if (lseek (mach_o_file->fd, -12, SEEK_CUR) < 0
+	  || read (mach_o_file->fd, ar_tail, 12) != 12
+	  || lseek (mach_o_file->fd, 0, SEEK_CUR) != (ssize_t) offset
+	  || ar_tail[10] != '`' || ar_tail[11] != '\n')
+	{
+	  error ("could not find archive header @0x%lx", (long) offset);
+	  goto fail;
+	}
+
+      ar_tail[11] = 0;
+      if (sscanf (ar_tail, "%d", &size) != 1)
+	{
+	  error ("invalid archive header @0x%lx", (long) offset);
+	  goto fail;
+	}
+      mach_o_file->file_size = size;
+    }
+
+  if (writable)
+    {
+      init_mach_o_header (mach_o_file);
+    }
+  else
+    if (! validate_file (mach_o_file))
+      goto fail;
+
+  return result;
+
+ fail:
+  if (result)
+    lto_obj_file_close (result);
+  return NULL;
+}
+
+
+/* Write the data in MACH_O_FILE to a real Mach-O binary object.
+   We write a header, a segment load command, and section data.  */
+
+static bool
+mach_o_write_object_file (lto_mach_o_file *mach_o_file)
+{
+  lto_mach_o_section sec, snsec;
+  lto_mach_o_data snsec_data;
+  ssize_t hdrsize, cmdsize, secsize;
+  size_t num_sections, snsec_size, total_sec_size;
+  unsigned int sec_offs, strtab_offs;
+  int i;
+  bool write_err = false;
+
+  /* The number of sections we will write is the number of sections added by
+     the streamer, plus 1 for the section names section.  */
+  num_sections = VEC_length (lto_mach_o_section, mach_o_file->section_vec) + 1;
+
+  /* Calculate the size of the basic data structures on disk.  */
+  if (mach_o_word_size () == 64)
+    {
+      hdrsize = sizeof (mach_o_header_64);
+      secsize = sizeof (mach_o_section_64);
+      cmdsize = sizeof (mach_o_segment_command_64) + num_sections * secsize;
+    }
+  else
+    {
+      hdrsize = sizeof (mach_o_header_32);
+      secsize = sizeof (mach_o_section_32);
+      cmdsize = sizeof (mach_o_segment_command_32) + num_sections * secsize;
+    }
+ 
+  /* Allocate the section names section.  */
+  snsec_size = 0;
+  for (i = 0;
+       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    snsec_size += strlen (sec->name) + 1;
+  snsec = mach_o_new_section (mach_o_file, NULL);
+  snsec->name = LTO_NAMES_SECTION;
+  snsec_data = mach_o_new_data (snsec);
+  snsec_data->d_buf = XCNEWVEC (char, snsec_size);
+  snsec_data->d_size = snsec_size;
+
+  /* Position all the sections, and fill out their headers.  */
+  sec_offs = hdrsize + cmdsize;
+  strtab_offs = 0;
+  total_sec_size = 0;
+  for (i = 0;
+       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    {
+      lto_mach_o_data data;
+      size_t data_size;
+      /* Put the section and segment names.  Add the section name to the
+         section names section (unless, of course, this *is* the section
+	 names section).  */
+      if (sec == snsec)
+	snprintf (sec->u.section.sectname, 16, "%s", LTO_NAMES_SECTION);
+      else
+	{
+	  sprintf (sec->u.section.sectname, "__%08X", strtab_offs);
+	  memcpy ((char *) snsec_data->d_buf + strtab_offs, sec->name, strlen (sec->name));
+	}
+      memcpy (&sec->u.section.segname[0],
+	      LTO_SEGMENT_NAME, strlen (LTO_SEGMENT_NAME));
+
+      /* Add layout and attributes.  */
+      for (data = sec->data_chain, data_size = 0; data; data = data->next)
+	data_size += data->d_size;
+      if (mach_o_word_size () == 64)
+	{
+	  put_uint64 (&sec->u.section_64.addr[0], total_sec_size); 
+	  put_uint64 (&sec->u.section_64.size[0], data_size); 
+	  put_uint32 (&sec->u.section_64.offset[0], sec_offs); 
+	  put_uint32 (&sec->u.section_64.flags[0], MACH_O_S_ATTR_DEBUG);
+	}
+      else
+	{
+	  put_uint32 (&sec->u.section_64.addr[0], total_sec_size); 
+	  put_uint32 (&sec->u.section_32.size[0], data_size); 
+	  put_uint32 (&sec->u.section_32.offset[0], sec_offs); 
+	  put_uint32 (&sec->u.section_32.flags[0], MACH_O_S_ATTR_DEBUG);
+	}
+
+      sec_offs += data_size;
+      total_sec_size += data_size;
+      strtab_offs += strlen (sec->name) + 1;
+    }
+
+  /* We can write the data now.  As there's no way to indicate an error return
+     from this hook, error handling is limited to not wasting our time doing
+     any more writes in the event that any one fails.  */
+
+  /* Write the header.  */
+  put_uint32 (&mach_o_file->u.header.ncmds[0], 1);
+  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], cmdsize);
+  write_err = (write (mach_o_file->fd,
+		      &mach_o_file->u.header, hdrsize) != hdrsize);
+  /* Write the segment load command.  */
+  if (mach_o_word_size () == 64)
+    {
+      mach_o_segment_command_64 lc;
+      ssize_t lc_size = sizeof (lc);
+      memset (&lc, 0, lc_size);
+      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT_64);
+      put_uint32 (&lc.cmdsize[0], cmdsize);
+      put_uint64 (&lc.fileoff[0], hdrsize + cmdsize);
+      put_uint64 (&lc.filesize[0], total_sec_size);
+      put_uint32 (&lc.nsects[0], num_sections);
+      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
+    }
+  else
+    {
+      mach_o_segment_command_32 lc;
+      ssize_t lc_size = sizeof (lc);
+      memset (&lc, 0, lc_size);
+      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT);
+      put_uint32 (&lc.cmdsize[0], cmdsize);
+      put_uint32 (&lc.fileoff[0], hdrsize + cmdsize);
+      put_uint32 (&lc.filesize[0], total_sec_size);
+      put_uint32 (&lc.nsects[0], num_sections);
+      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
+    }
+  for (i = 0;
+       !write_err
+       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    write_err = (write (mach_o_file->fd,
+			&sec->u.section, secsize) != secsize);
+
+  gcc_assert (lseek (mach_o_file->fd, 0, SEEK_CUR) == hdrsize + cmdsize);
+
+  /* Write the section data.  */
+  for (i = 0;
+       !write_err
+       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    {
+      lto_mach_o_data data;
+
+      for (data = sec->data_chain; data; data = data->next)
+	{
+	  if (!write_err)
+	    write_err = (write (mach_o_file->fd, data->d_buf, data->d_size)
+			 != data->d_size);
+	  else
+	    break;
+	}
+    }
+
+  return !write_err;
+}
+
+/* Close Mach-O file FILE and clean up any associated data structures.  If FILE
+   was opened for writing, the file's Mach-O data is written at this time.  Any
+   cached data buffers are freed.  */
+
+void
+lto_obj_file_close (lto_file *file)
+{
+  lto_mach_o_file *mach_o_file = (lto_mach_o_file *) file;
+  struct lto_char_ptr_base *cur, *tmp;
+  lto_mach_o_section sec;
+  bool write_err = false;
+  int i;
+
+  /* If this file is open for writing, write a Mach-O object file.  */
+  if (mach_o_file->writable)
+    {
+      if (! mach_o_write_object_file (mach_o_file))
+        fatal_error ("cannot write Mach-O object file");
+    }
+
+  /* Close the file, we're done.  */
+  if (mach_o_file->fd != -1)
+    close (mach_o_file->fd);
+
+  /* Free any data buffers.  */
+  cur = mach_o_file->data;
+  while (cur)
+    {
+      tmp = cur;
+      cur = (struct lto_char_ptr_base *) cur->ptr;
+      free (tmp);
+    }
+
+  /* Free any sections and their data chains.  */
+  for (i = 0;
+       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
+       i++)
+    {
+      lto_mach_o_data curdata, nextdata;
+      curdata = sec->data_chain;
+      while (curdata)
+	{
+	  nextdata = curdata->next;
+	  free (curdata);
+	  curdata = nextdata;
+	}
+      free (sec);
+    }
+  VEC_free (lto_mach_o_section, heap, mach_o_file->section_vec);
+
+  free (file);
+
+  /* If there was an error, mention it.  */
+  if (write_err)
+    error ("I/O error writing Mach-O output file");
+}
+
Index: gcc/lto/lto-macho.h
===================================================================
--- gcc/lto/lto-macho.h	(revision 0)
+++ gcc/lto/lto-macho.h	(revision 0)
@@ -0,0 +1,251 @@
+/* LTO routines for Mach-O object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Contributed by Steven Bosscher.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LTO_MACH_O_H
+#define LTO_MACH_O_H
+
+/* On-disk file structures.  */
+
+/* Mach-O header (32 bits version).  */
+struct mach_o_header_32
+{
+  unsigned char magic[4];	/* Magic number.  */
+  unsigned char cputype[4];	/* CPU that this object is for.  */
+  unsigned char cpusubtype[4];	/* CPU subtype.  */
+  unsigned char filetype[4];	/* Type of file.  */
+  unsigned char ncmds[4];	/* Number of load commands.  */
+  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
+  unsigned char flags[4];	/* Flags for special featues.  */
+};
+typedef struct mach_o_header_32 mach_o_header_32;
+
+/* Mach-O header (64 bits version).  */
+struct mach_o_header_64
+{
+  unsigned char magic[4];	/* Magic number.  */
+  unsigned char cputype[4];	/* CPU that this object is for.  */
+  unsigned char cpusubtype[4];	/* CPU subtype.  */
+  unsigned char filetype[4];	/* Type of file.  */
+  unsigned char ncmds[4];	/* Number of load commands.  */
+  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
+  unsigned char flags[4];	/* Flags for special featues.  */
+  unsigned char reserved[4];	/* Reserved.  Duh.  */
+};
+typedef struct mach_o_header_64 mach_o_header_64;
+
+/* Magic number.  */
+#define MACH_O_MH_MAGIC			0xfeedface
+#define MACH_O_MH_CIGAM			0xcefaedfe
+#define MACH_O_MH_MAGIC_64		0xfeedfacf
+#define MACH_O_MH_CIGAM_64		0xcffaedfe
+
+/* Supported CPU types.  */
+#define MACH_O_CPU_TYPE_I386		7
+#define MACH_O_CPU_TYPE_X86_64		7 + 0x1000000
+#define MACH_O_CPU_TYPE_POWERPC		18
+#define MACH_O_CPU_TYPE_POWERPC_64	18 + 0x1000000
+
+/* Supported file types.  */
+#define MACH_O_MH_OBJECT		0x01
+
+/* Mach-O load command data structure.  */
+struct mach_o_load_command
+{
+  unsigned char cmd[4];		/* The type of load command.  */
+  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
+};
+typedef struct mach_o_load_command mach_o_load_command;
+
+/* Supported load commands.  We support only the segment load commands.  */
+#define MACH_O_LC_SEGMENT		0x01
+#define MACH_O_LC_SEGMENT_64		0x19
+
+/* LC_SEGMENT load command.  */
+struct mach_o_segment_command_32
+{
+  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT).  */
+  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
+  unsigned char segname[16];	/* Name of this segment.  */
+  unsigned char vmaddr[4];	/* Virtual memory address of this segment.  */
+  unsigned char vmsize[4];	/* Size there, in bytes.  */
+  unsigned char fileoff[4];	/* Offset in bytes of the data to be mapped.  */
+  unsigned char filesize[4];	/* Size in bytes on disk.  */
+  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
+  unsigned char initprot[4];	/* Initial vmem protection.  */
+  unsigned char nsects[4];	/* Number of sections in this segment.  */
+  unsigned char flags[4];	/* Flags that affect the loading.  */
+};
+typedef struct mach_o_segment_command_32 mach_o_segment_command_32;
+
+/* LC_SEGMENT_64 load command.  Only nsects matters for us, really.  */
+struct mach_o_segment_command_64
+{
+  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT_64).  */
+  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
+  unsigned char segname[16];	/* Name of this segment.  */
+  unsigned char vmaddr[8];	/* Virtual memory address of this segment.  */
+  unsigned char vmsize[8];	/* Size there, in bytes.  */
+  unsigned char fileoff[8];	/* Offset in bytes of the data to be mapped.  */
+  unsigned char filesize[8];	/* Size in bytes on disk.  */
+  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
+  unsigned char initprot[4];	/* Initial vmem protection.  */
+  unsigned char nsects[4];	/* Number of sections in this segment.  */
+  unsigned char flags[4];	/* Flags that affect the loading.  */
+};
+typedef struct mach_o_segment_command_64 mach_o_segment_command_64;
+
+/* A Mach-O 32-bits section.  */
+struct mach_o_section_32
+{
+  unsigned char sectname[16];	/* Section name.  */
+  unsigned char segname[16];	/* Segment that the section belongs to.  */
+  unsigned char addr[4];	/* Address of this section in memory.  */
+  unsigned char size[4];	/* Size in bytes of this section.  */
+  unsigned char offset[4];	/* File offset of this section.  */
+  unsigned char align[4];	/* log2 of this section's alignment.  */
+  unsigned char reloff[4];	/* File offset of this section's relocs.  */
+  unsigned char nreloc[4];	/* Number of relocs for this section.  */
+  unsigned char flags[4];	/* Section flags/attributes.  */
+  unsigned char reserved1[4];
+  unsigned char reserved2[4];
+};
+typedef struct mach_o_section_32 mach_o_section_32;
+
+/* A Mach-O 64-bits section.  */
+struct mach_o_section_64
+{
+  unsigned char sectname[16];	/* Section name.  */
+  unsigned char segname[16];	/* Segment that the section belongs to.  */
+  unsigned char addr[8];	/* Address of this section in memory.  */
+  unsigned char size[8];	/* Size in bytes of this section.  */
+  unsigned char offset[4];	/* File offset of this section.  */
+  unsigned char align[4];	/* log2 of this section's alignment.  */
+  unsigned char reloff[4];	/* File offset of this section's relocs.  */
+  unsigned char nreloc[4];	/* Number of relocs for this section.  */
+  unsigned char flags[4];	/* Section flags/attributes.  */
+  unsigned char reserved1[4];
+  unsigned char reserved2[4];
+  unsigned char reserved3[4];
+};
+typedef struct mach_o_section_64 mach_o_section_64;
+
+/* Flags for Mach-O sections.  LTO sections are marked with S_ATTR_DEBUG
+   to instruct the linker to ignore the sections.  */
+#define MACH_O_S_ATTR_DEBUG			0x02000000
+
+/* In-memory file structures.  */
+
+/* Section data in output files is made of these.  */
+struct lto_mach_o_data_d
+{
+  /* Pointer to data block.  */
+  void *d_buf;
+
+  /* Size of data block.  */
+  ssize_t d_size;
+
+  /* Next data block for this section.  */
+  struct lto_mach_o_data_d *next;
+};
+typedef struct lto_mach_o_data_d *lto_mach_o_data;
+
+/* This struct tracks the data for a section.  */
+struct lto_mach_o_section_d
+{
+  /* Singly-linked list of section's data blocks.  */
+  lto_mach_o_data data_chain;
+
+  /* Offset in string table of the section name.  */
+  size_t strtab_offs;
+
+  /* Section name.  */
+  const char *name;
+
+  /* Number of trailing padding bytes needed.  */
+  ssize_t pad_needed;
+
+  /* Raw section header data.  */
+  size_t section_size;
+  union {
+    struct {
+      char sectname[16];
+      char segname[16];
+    } section;
+    mach_o_section_32 section_32;
+    mach_o_section_64 section_64;
+  } u;
+
+  /* Next section for this file.  */
+  struct lto_mach_o_section_d *next;
+};
+typedef struct lto_mach_o_section_d *lto_mach_o_section;
+DEF_VEC_P (lto_mach_o_section);
+DEF_VEC_ALLOC_P (lto_mach_o_section, heap);
+
+/* A Mach-O file.  */
+struct lto_mach_o_file_d
+{
+  /* The base information.  */
+  lto_file base;
+
+  /* Common file members:  */
+
+  /* The system file descriptor for the file.  */
+  int fd;
+
+  /* The file's overall header.  */
+  union {
+    /* We make use here of the fact that section_32 and section_64
+       have the same layout (except for section_64.reserved3).  We
+       read the struct of proper size, but only address the first
+       member of this union.  */
+    mach_o_header_64 header;
+    mach_o_header_32 header_32;
+    mach_o_header_64 header_64;
+  } u;
+
+  /* All sections in a varray.  */
+  VEC(lto_mach_o_section, heap) *section_vec;
+
+  /* Readable file members:  */
+
+  /* File total size.  */
+  off_t file_size;
+
+  /* True if this file is open for writing.  */
+  bool writable;
+
+  /* Section containing the __section_names section.  */
+  lto_mach_o_section section_names_section;
+
+  /* Writable file members:  */
+
+  /* The currently active section.  */
+  lto_mach_o_section scn;
+
+  /* Linked list of data which must be freed *after* the file has been
+     closed.  This is an annoying limitation of libelf.  Which has been
+     faithfully reproduced here.  */
+  struct lto_char_ptr_base *data;
+};
+typedef struct lto_mach_o_file_d lto_mach_o_file;
+
+#endif /* LTO_MACH_O_H */
+
Index: gcc/lto/Make-lang.in
===================================================================
--- gcc/lto/Make-lang.in	(revision 158938)
+++ gcc/lto/Make-lang.in	(working copy)
@@ -91,3 +91,6 @@ lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H)
 lto/lto-coff.o: lto/lto-coff.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
 	toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
 	lto/lto-coff.h
+lto/lto-macho.o: lto/lto-macho.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
+	toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
+	lto/lto-macho.h lto/lto-endian.h


More information about the Gcc-patches mailing list