diff mbox

Discussion about merging Go frontend

Message ID mcr1v79bx8q.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 29, 2010, 1:31 a.m. UTC
Dave Korn <dave.korn.cygwin@gmail.com> writes:

>   What would be even nicer would be if we could share the same code-reader
> interface between lto and go (and the lto-plugin), thereby getting object
> format independence equally everywhere for no extra cost.

How about this?

This implements an object file reader/writer which does everything
required by LTO and gccgo.  The ELF code works.  I have not tested the
Mach-O and COFF code at all beyond compiling it; I hope that somebody
else can test those targets and fix them.

With this patch, libelf is no longer needed.

I've bootstrapped this on x86_64-unknown-linux-gnu, and I've run the LTO
testsuite.

This patch puts the code in libiberty, but it could equally well go in
gcc.  Anybody want to make an argument one way or another?

Does the general interface look OK?

This patch requires approval from the LTO maintainers.  I don't need
approval for the libiberty changes (if the code stays in libiberty) but
of course I would appreciate it if somebody could look it over.  I think
the configure and Makefile changes are sufficiently obvious given the
other changes as to not require approval.

If this patch is accepted, then gccgo will not require elfcpp.

Ian


include/ChangeLog:

2010-10-28  Ian Lance Taylor  <iant@google.com>

	* objfile.h: New file.

libiberty/ChangeLog:

2010-10-28  Ian Lance Taylor  <iant@google.com>

	* objfile.c: New file.
	* objfile-common.h: New file.
	* objfile-elf.c: New file.
	* objfile-mach-o.c: New file.
	* objfile-coff.c: New file.
	* configure.ac: Add AC_TYPE_SSIZE_T.
	* Makefile.in: Rebuild dependencies.
	(CFILES): Add objfile.c, objfile-coff, objfile-elf.c,
	objfile-mach-o.c.
	(REQUIRED_OFILES): Add corresponding object files.
	* configure: Rebuild.
	* config.in: Rebuild.

gcc/ChangeLog:

2010-10-28  Ian Lance Taylor  <iant@google.com>

	* configure.ac: Remove elf_getshdrstrndx test.  Don't substitute
	LTO_BINARY_READER or LTO_USE_LIBELF.  Remove LIBELFLIBS and
	LIBELFINC.  Remove HAVE_libelf.
	* gcc/config.gcc: Don't set lto_binary_reader.
	* gcc/Makefile.in (LIBELFLIBS, LIBELFINC): Remove variables.
	(LTO_BINARY_READER, LTO_USE_LIBELF): Remove variables.
	(LIBS): Remove $(LIBELFLIBS).
	(INCLUDES): Remove $(LIBELFINC).
	* doc/install.texi (Prerequisites): Remove libelf paragraphs.
	(Configuration): Mention --disable-lto.  Remove --with-libelf
	paragraph.
	* configure: Rebuild.
	* config.in: Rebuild.

gcc/lto/ChangeLog:

2010-10-28  Ian Lance Taylor  <iant@google.com>

	* lto-objfile.c: New file.
	* lto-elf.c: Remove file.
	* lto-macho.c: Remove file.
	* lto-macho.h: Remove file.
	* lto-coff.c: Remove file.
	* lto-coff.h: Remove file.
	* Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to
	lto/lto-objfile.o.
	($(LTO_EXE)): Remove $(LTO_USE_LIBELF)
	(lto/lto-objfile.o): New target.
	(lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets.

./ChangeLog:

2010-10-28  Ian Lance Taylor  <iant@google.com>

	* configure.ac: Don't set default_enable_lto.  Remove libelf tests.
	* configure: Rebuild.

Comments

Dave Korn Oct. 29, 2010, 8:56 a.m. UTC | #1
On 29/10/2010 02:31, Ian Lance Taylor wrote:
> Dave Korn <dave.korn.cygwin@  writes:
> 
>>   What would be even nicer would be if we could share the same code-reader
>> interface between lto and go (and the lto-plugin), thereby getting object
>> format independence equally everywhere for no extra cost.
> 
> How about this?

  That looks excellent, thank you!

> This implements an object file reader/writer which does everything
> required by LTO and gccgo.  The ELF code works.  I have not tested the
> Mach-O and COFF code at all beyond compiling it; I hope that somebody
> else can test those targets and fix them.

  I'm right here :) Can't help with Darwin but hopefully Jack/Iain will be
available.

> With this patch, libelf is no longer needed.
> 
> I've bootstrapped this on x86_64-unknown-linux-gnu, and I've run the LTO
> testsuite.
> 
> This patch puts the code in libiberty, but it could equally well go in
> gcc.  Anybody want to make an argument one way or another?

  Libiberty is better for sharing with lto-plugin, I think.  I sent a patch
that commoned out some of the COFF-reader code into gcc/, but I only put it
there because it was a single header file with no associated object file.  Now
there's actual code to be linked in, I think libiberty is a better choice than
lto-plugin trying to share .o files from the ../gcc/ objdir.

> Does the general interface look OK?
> 
> This patch requires approval from the LTO maintainers.

  Also, I have a patch outstanding to COFF-ize the lto-plugin(*), so if we can
get an early "OK in principle" I'll get cracking on respinning it to use this
new interface.

    cheers,
      DaveK
Iain Sandoe Oct. 29, 2010, 11:09 a.m. UTC | #2
On 29 Oct 2010, at 09:56, Dave Korn wrote:
>> This implements an object file reader/writer which does everything
>> required by LTO and gccgo.  The ELF code works.  I have not tested  
>> the
>> Mach-O and COFF code at all beyond compiling it; I hope that somebody
>> else can test those targets and fix them.
>
>  I'm right here :) Can't help with Darwin but hopefully Jack/Iain  
> will be
> available.


I tried with 166058 on ppc-darwin9 (my other machines are tied up  
right now)

-flto fails on link with missing _main.
e.g:
Executing on host: /Volumes/ScratchCS/gcc-4-6-trunk-build/gcc/xgcc -B/ 
Volumes/ScratchCS/gcc-4-6-trunk-build/gcc/ c_lto_20081024_0.o  -
O0 -flto       -m32 -o gcc-dg-lto-20081024-21    (timeout = 60)
Undefined symbols:
   "_main", referenced from:
       start in crt1.10.5.o

-whopr ices with:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x007f8e18 in objfile_mach_o_find_sections (objfile=0x40e078b0,  
pfn=0x1d7ec <lto_obj_add_section>, data=0xbffff19c, err=0xbffff198)  
at /GCC/gcc-live-trunk/libiberty/objfile-mach-o.c:469
469           memcpy (name, sechdr + sectname_offset, MACH_O_NAME_LEN);
(gdb) bt
#0  0x007f8e18 in objfile_mach_o_find_sections (objfile=0x40e078b0,  
pfn=0x1d7ec <lto_obj_add_section>, data=0xbffff19c, err=0xbffff198)  
at /GCC/gcc-live-trunk/libiberty/objfile-mach-o.c:469
#1  0x007f5dbc in objfile_find_sections (objfile=<value temporarily  
unavailable, due to optimizations>, pfn=<value temporarily  
unavailable, due to optimizations>, data=<value temporarily  
unavailable, due to optimizations>, err=<value temporarily  
unavailable, due to optimizations>) at /GCC/gcc-live-trunk/libiberty/ 
objfile.c:173
#2  0x0001dc60 in lto_obj_build_section_table (lto_file=<value  
temporarily unavailable, due to optimizations>) at /GCC/gcc-live-trunk/ 
gcc/lto/lto-objfile.c:270
#3  0x0001af80 in lto_read_all_file_options () at /GCC/gcc-live-trunk/ 
gcc/lto/lto.c:2052
#4  0x00003960 in lto_post_options (pfilename=<value temporarily  
unavailable, due to optimizations>) at /GCC/gcc-live-trunk/gcc/lto/lto- 
lang.c:709
#5  0x004f0eec in toplev_main (argc=15, argv=Cannot access memory at  
address 0x1c
) at /GCC/gcc-live-trunk/gcc/toplev.c:1778
#6  0x00001944 in start ()

if you need more analysis - ping me with what and I'll try and do sth  
-- or maybe Jack can help with a user on his machine.

cheers,
Iain
Jack Howarth Oct. 29, 2010, 1:18 p.m. UTC | #3
On Fri, Oct 29, 2010 at 09:56:02AM +0100, Dave Korn wrote:
> On 29/10/2010 02:31, Ian Lance Taylor wrote:
> > Dave Korn <dave.korn.cygwin@  writes:
> > 
> >>   What would be even nicer would be if we could share the same code-reader
> >> interface between lto and go (and the lto-plugin), thereby getting object
> >> format independence equally everywhere for no extra cost.
> > 
> > How about this?
> 
>   That looks excellent, thank you!
> 
> > This implements an object file reader/writer which does everything
> > required by LTO and gccgo.  The ELF code works.  I have not tested the
> > Mach-O and COFF code at all beyond compiling it; I hope that somebody
> > else can test those targets and fix them.
> 
>   I'm right here :) Can't help with Darwin but hopefully Jack/Iain will be
> available.
> 

Dave,
   Doesn't the go compiler require functional split stack support? Mike Stump
left me with the impression that split stack support would require additional
linker support on darwin.
               Jack

> > With this patch, libelf is no longer needed.
> > 
> > I've bootstrapped this on x86_64-unknown-linux-gnu, and I've run the LTO
> > testsuite.
> > 
> > This patch puts the code in libiberty, but it could equally well go in
> > gcc.  Anybody want to make an argument one way or another?
> 
>   Libiberty is better for sharing with lto-plugin, I think.  I sent a patch
> that commoned out some of the COFF-reader code into gcc/, but I only put it
> there because it was a single header file with no associated object file.  Now
> there's actual code to be linked in, I think libiberty is a better choice than
> lto-plugin trying to share .o files from the ../gcc/ objdir.
> 
> > Does the general interface look OK?
> > 
> > This patch requires approval from the LTO maintainers.
> 
>   Also, I have a patch outstanding to COFF-ize the lto-plugin(*), so if we can
> get an early "OK in principle" I'll get cracking on respinning it to use this
> new interface.
> 
>     cheers,
>       DaveK
> -- 
> (*) - http://gcc.gnu.org/ml/gcc-patches/2010-10/msg02176.html
Richard Biener Oct. 29, 2010, 1:31 p.m. UTC | #4
On Fri, Oct 29, 2010 at 3:31 AM, Ian Lance Taylor <iant@google.com> wrote:
> Dave Korn <dave.korn.cygwin@gmail.com> writes:
>
>>   What would be even nicer would be if we could share the same code-reader
>> interface between lto and go (and the lto-plugin), thereby getting object
>> format independence equally everywhere for no extra cost.
>
> How about this?
>
> This implements an object file reader/writer which does everything
> required by LTO and gccgo.  The ELF code works.  I have not tested the
> Mach-O and COFF code at all beyond compiling it; I hope that somebody
> else can test those targets and fix them.
>
> With this patch, libelf is no longer needed.
>
> I've bootstrapped this on x86_64-unknown-linux-gnu, and I've run the LTO
> testsuite.
>
> This patch puts the code in libiberty, but it could equally well go in
> gcc.  Anybody want to make an argument one way or another?
>
> Does the general interface look OK?
>
> This patch requires approval from the LTO maintainers.  I don't need
> approval for the libiberty changes (if the code stays in libiberty) but
> of course I would appreciate it if somebody could look it over.  I think
> the configure and Makefile changes are sufficiently obvious given the
> other changes as to not require approval.
>
> If this patch is accepted, then gccgo will not require elfcpp.

Nice!

The LTO changes are ok (I suppose you'll be around in helping people
debug eventual problems).

Richard.

> Ian
>
>
> include/ChangeLog:
>
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
>        * objfile.h: New file.
>
> libiberty/ChangeLog:
>
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
>        * objfile.c: New file.
>        * objfile-common.h: New file.
>        * objfile-elf.c: New file.
>        * objfile-mach-o.c: New file.
>        * objfile-coff.c: New file.
>        * configure.ac: Add AC_TYPE_SSIZE_T.
>        * Makefile.in: Rebuild dependencies.
>        (CFILES): Add objfile.c, objfile-coff, objfile-elf.c,
>        objfile-mach-o.c.
>        (REQUIRED_OFILES): Add corresponding object files.
>        * configure: Rebuild.
>        * config.in: Rebuild.
>
> gcc/ChangeLog:
>
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
>        * configure.ac: Remove elf_getshdrstrndx test.  Don't substitute
>        LTO_BINARY_READER or LTO_USE_LIBELF.  Remove LIBELFLIBS and
>        LIBELFINC.  Remove HAVE_libelf.
>        * gcc/config.gcc: Don't set lto_binary_reader.
>        * gcc/Makefile.in (LIBELFLIBS, LIBELFINC): Remove variables.
>        (LTO_BINARY_READER, LTO_USE_LIBELF): Remove variables.
>        (LIBS): Remove $(LIBELFLIBS).
>        (INCLUDES): Remove $(LIBELFINC).
>        * doc/install.texi (Prerequisites): Remove libelf paragraphs.
>        (Configuration): Mention --disable-lto.  Remove --with-libelf
>        paragraph.
>        * configure: Rebuild.
>        * config.in: Rebuild.
>
> gcc/lto/ChangeLog:
>
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
>        * lto-objfile.c: New file.
>        * lto-elf.c: Remove file.
>        * lto-macho.c: Remove file.
>        * lto-macho.h: Remove file.
>        * lto-coff.c: Remove file.
>        * lto-coff.h: Remove file.
>        * Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to
>        lto/lto-objfile.o.
>        ($(LTO_EXE)): Remove $(LTO_USE_LIBELF)
>        (lto/lto-objfile.o): New target.
>        (lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets.
>
> ./ChangeLog:
>
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
>        * configure.ac: Don't set default_enable_lto.  Remove libelf tests.
>        * configure: Rebuild.
>
>
>
Ian Lance Taylor Oct. 29, 2010, 1:49 p.m. UTC | #5
Jack Howarth <howarth@bromo.med.uc.edu> writes:

>    Doesn't the go compiler require functional split stack support? Mike Stump
> left me with the impression that split stack support would require additional
> linker support on darwin.

The Go compiler can work without split stack support.  The effect is
that you are limited in the number of goroutines you can create,
particularly on a 32-bit system.  And you are also limited in the depth
of recursion and size of local variables you can create.  But you can
write working Go programs.

The objfile patch, however, is not really about Go, although gccgo will
use it.  It's really about LTO.  If it works for LTO, it will work for
gccgo.

Ian
Ian Lance Taylor Oct. 29, 2010, 1:54 p.m. UTC | #6
IainS <developer@sandoe-acoustics.co.uk> writes:

> -whopr ices with:
>
> Program received signal EXC_BAD_ACCESS, Could not access memory.
> Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
> 0x007f8e18 in objfile_mach_o_find_sections (objfile=0x40e078b0,
> pfn=0x1d7ec <lto_obj_add_section>, data=0xbffff19c, err=0xbffff198)
> at /GCC/gcc-live-trunk/libiberty/objfile-mach-o.c:469
> 469           memcpy (name, sechdr + sectname_offset, MACH_O_NAME_LEN);
> (gdb) bt
> #0  0x007f8e18 in objfile_mach_o_find_sections (objfile=0x40e078b0,
> pfn=0x1d7ec <lto_obj_add_section>, data=0xbffff19c, err=0xbffff198)
> at /GCC/gcc-live-trunk/libiberty/objfile-mach-o.c:469
> #1  0x007f5dbc in objfile_find_sections (objfile=<value temporarily
> unavailable, due to optimizations>, pfn=<value temporarily
> unavailable, due to optimizations>, data=<value temporarily
> unavailable, due to optimizations>, err=<value temporarily
> unavailable, due to optimizations>) at /GCC/gcc-live-trunk/libiberty/
> objfile.c:173
> #2  0x0001dc60 in lto_obj_build_section_table (lto_file=<value
> temporarily unavailable, due to optimizations>) at
> /GCC/gcc-live-trunk/ gcc/lto/lto-objfile.c:270
> #3  0x0001af80 in lto_read_all_file_options () at /GCC/gcc-live-trunk/
> gcc/lto/lto.c:2052
> #4  0x00003960 in lto_post_options (pfilename=<value temporarily
> unavailable, due to optimizations>) at
> /GCC/gcc-live-trunk/gcc/lto/lto- 
> lang.c:709
> #5  0x004f0eec in toplev_main (argc=15, argv=Cannot access memory at
> address 0x1c
> ) at /GCC/gcc-live-trunk/gcc/toplev.c:1778
> #6  0x00001944 in start ()
>
> if you need more analysis - ping me with what and I'll try and do sth
> -- or maybe Jack can help with a user on his machine.

Thanks for looking at it.  For this problem, I've attached a new version
of libiberty/objfile-mach-o.c.

In general I'm going to need somebody who can debug the code running on
Darwin.

Ian
Dave Korn Oct. 29, 2010, 2:07 p.m. UTC | #7
On 29/10/2010 14:31, Richard Guenther wrote:
> On Fri, Oct 29, 2010 at 3:31 AM, Ian Lance Taylor <iant@google.com> wrote:

>> This patch requires approval from the LTO maintainers.  I don't need
>> approval for the libiberty changes (if the code stays in libiberty) but
>> of course I would appreciate it if somebody could look it over.  I think
>> the configure and Makefile changes are sufficiently obvious given the
>> other changes as to not require approval.
>>
>> If this patch is accepted, then gccgo will not require elfcpp.
> 
> Nice!
> 
> The LTO changes are ok (I suppose you'll be around in helping people
> debug eventual problems).

  I'll start work on porting the lto-plugin to use the new interface.  It'll
subsume my plugin-for-coff patch.

    cheers,
      DaveK
Dave Korn Oct. 29, 2010, 2:08 p.m. UTC | #8
On 29/10/2010 14:18, Jack Howarth wrote:
> On Fri, Oct 29, 2010 at 09:56:02AM +0100, Dave Korn wrote:
>> On 29/10/2010 02:31, Ian Lance Taylor wrote:
>>> Dave Korn <dave.korn.cygwin@  writes:
>>>
>>>>   What would be even nicer would be if we could share the same code-reader
>>>> interface between lto and go (and the lto-plugin), thereby getting object
>>>> format independence equally everywhere for no extra cost.
>>> How about this?
>>   That looks excellent, thank you!
>>
>>> This implements an object file reader/writer which does everything
>>> required by LTO and gccgo.  The ELF code works.  I have not tested the
>>> Mach-O and COFF code at all beyond compiling it; I hope that somebody
>>> else can test those targets and fix them.
>>   I'm right here :) Can't help with Darwin but hopefully Jack/Iain will be
>> available.
>>
> 
> Dave,
>    Doesn't the go compiler require functional split stack support? 

  Ian will have to answer that, I don't know.

> Mike Stump
> left me with the impression that split stack support would require additional
> linker support on darwin.

  Well, this also affects LTO, since it refactors the object file support
underlying that.  As Iain has discovered...

    cheers,
      DaveK
Jack Howarth Oct. 29, 2010, 2:33 p.m. UTC | #9
On Fri, Oct 29, 2010 at 06:49:51AM -0700, Ian Lance Taylor wrote:
> Jack Howarth <howarth@bromo.med.uc.edu> writes:
> 
> >    Doesn't the go compiler require functional split stack support? Mike Stump
> > left me with the impression that split stack support would require additional
> > linker support on darwin.
> 
> The Go compiler can work without split stack support.  The effect is
> that you are limited in the number of goroutines you can create,
> particularly on a 32-bit system.  And you are also limited in the depth
> of recursion and size of local variables you can create.  But you can
> write working Go programs.

Ian,
   Is split stack support unique to the go compiler or might it eventually
be leveraged in the other compilers as well? We could submit a radar for
the addition of split stack support for the linker in Xcode 4.0 or later
but it would helpful if the eventual usage was greater than just the go
compiler.
             Jack

> 
> The objfile patch, however, is not really about Go, although gccgo will
> use it.  It's really about LTO.  If it works for LTO, it will work for
> gccgo.
> 
> Ian
Mark Mitchell Oct. 29, 2010, 2:50 p.m. UTC | #10
On 10/28/2010 6:31 PM, Ian Lance Taylor wrote:

> This patch requires approval from the LTO maintainers.  I don't need
> approval for the libiberty changes (if the code stays in libiberty) but
> of course I would appreciate it if somebody could look it over.  I think
> the configure and Makefile changes are sufficiently obvious given the
> other changes as to not require approval.

This all looks good to me, and seems like a reasonable solution.  I
think libiberty is as good a place as any for the routines, FWIW.

Thanks,
Richard Henderson Oct. 30, 2010, 12:23 a.m. UTC | #11
> +extern objfile_read *
> +objfile_open_read (int descriptor, off_t offset, const char *segment_name,
> +		   const char **errmsg, int *err);
...
> +extern objfile_write *
> +objfile_start_write (objfile_attributes *ATTRS, const char *segment_name,
> +		     const char **errmsg, int *err);

Mismatch in naming conventions?  I like the use of "release"
to clearly indicate non-closure of the FD.

> +  shdr_size = (cl == ELFCLASS32
> +	       ? sizeof (Elf32_External_Shdr)
> +	       : sizeof (Elf64_External_Shdr));
> +  memset (buf, 0, shdr_size);

Constant size memset is easier to optimize.  You might as well
zero all of BUF, even if we're not going to use it all.  The
slop between 32 and 64 is minimal.

> +  if (!objfile_internal_read (objfile->descriptor,
> +			      objfile->offset + eor->shoff + shdr_size,
> +			      shdrs,
> +			      shdr_size * (shnum - 1),
> +			      &errmsg, err))

Do we really want to keep re-reading section data for every section
lookup we do?  Can't we do this in objfile_open_read?

> +  set_32 (hdr + offsetof (struct external_scnhdr, s_flags),
> +	  (STYP_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE
> +	   | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ));

You're not recording alignment in the coff object file?
IMAGE_SCN_ALIGN_<N>BYTES, 1 <= N <= 8192, are all defined
with a simple function in that nibble.


r~
Dave Korn Oct. 30, 2010, 8:16 a.m. UTC | #12
On 30/10/2010 01:23, Richard Henderson wrote:

>> +  if (!objfile_internal_read (objfile->descriptor,
>> +			      objfile->offset + eor->shoff + shdr_size,
>> +			      shdrs,
>> +			      shdr_size * (shnum - 1),
>> +			      &errmsg, err))
> 
> Do we really want to keep re-reading section data for every section
> lookup we do?  Can't we do this in objfile_open_read?

  It should only be necessary to do one section lookup per object file anyway.
 Keep extra data hanging around in memory in the backend just so that we can
write algorithmically inefficient code in the client?  Seems like a bad
tradeoff to me!

>> +  set_32 (hdr + offsetof (struct external_scnhdr, s_flags),
>> +	  (STYP_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE
>> +	   | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ));
> 
> You're not recording alignment in the coff object file?

  It looks to me like he's recording an alignment of 1 byte.

> IMAGE_SCN_ALIGN_<N>BYTES, 1 <= N <= 8192, are all defined
> with a simple function in that nibble.

  The line you quoted uses IMAGE_SCN_ALIGN_1BYTES.  That's all we'll ever need
for LTO sections.

    cheers,
      DaveK
Dave Korn Oct. 30, 2010, 10:44 a.m. UTC | #13
On 29/10/2010 02:31, Ian Lance Taylor wrote:

> This implements an object file reader/writer which does everything
> required by LTO and gccgo.  The ELF code works.  I have not tested the
> Mach-O and COFF code at all beyond compiling it; I hope that somebody
> else can test those targets and fix them.
> 
> With this patch, libelf is no longer needed.

  Almost, but not quite!  The attached patch switches the lto-plugin over to
use the new objfile reader as well.

lto-plugin/ChangeLog:

	* configure.ac: Don't use libelf, don't source config.gcc.
	(LIBELFLIBS): Delete.
	(LIBELFINC): Delete.
	(LTO_FORMAT): Delete.
	(SYM_STYLE): New AC_SUBST var set based on $target.
	* Makefile.am (LIBELFLIBS): Delete.
	(LIBELFINC): Delete.
	(LTO_FORMAT): Delete.
	(SYM_STYLE): Import.
	(AM_CPPFLAGS): Use it.  Don't use LIBELFINC.
	(liblto_plugin_la_SOURCES): Don't use LTO_FORMAT, don't include
	any object-format-specific source file in the link.
	(liblto_plugin_la_LIBADD): Don't use LIBELFLIBS.
	* configure: Regenerate.
	* Makefile.in: Regenerate.
	* lto-plugin-elf.c: Delete.
	* lto-plugin-coff.c: Delete.
	* lto-plugin.h: Delete.
	* lto-plugin.c (O_BINARY): Definition moved here from lto-plugin.h.
	(LTO_SEGMENT_NAME): New definition.
	(LTO_SECTION_PREFIX): Definition moved here from lto-plugin.h.
	(LTO_SECTION_PREFIX_LEN): New definition.
	(struct sym_aux): Struct definition moved here from lto-plugin.h.
	(struct plugin_symtab): Likewise.
	(struct plugin_objfile): Likewise.
	(struct plugin_objfile): New struct def.
	(enum symbol_style): New enum type.
	(add_symbols): Make static.
	(claimed_files): Likewise.
	(num_claimed_files): Likewise.
	(sym_style): New global.
	(check): Make static.
	(parse_table_entry): Likewise.  Respect sym_style when extracting
	symbol from symtab entry.
	(translate): Make static.
	(resolve_conflicts): Likewise.
	(process_symtab): New function, per-section callback version of
	old object-format-specific handling from deleted lto-plugin-elf.c.
	(claim_file_handler): Convert ELF-specific version from deleted
	lto-plugin-elf.c to objfile interface and move here.
	(process_options): Allow new '-sym-style=' option.
	(onload): Don't call deleted onload_format_checks hook.

  Bootstrapped and tested all languages except java and ada on
x86_64-unknown-linux-gnu, no regressions.  There are still a couple of bugs to
iron out of the COFF-specific part of the objfile reader which I'll have fixed
later today.

  OK for trunk (once the objfile changes have gone in)?

    cheers,
      DaveK
Dave Korn Oct. 30, 2010, 3:28 p.m. UTC | #14
On 29/10/2010 02:31, Ian Lance Taylor wrote:

> 	* objfile-coff.c: New file.

  A few bugs have cropped up:

> +      if (namebuf[0] == '/')
> +	{
> +	  size_t strindex;
> +	  char *end;
> +
> +	  strindex = strtol (namebuf, &end, 10);

  Needs to be strtol (namebuf + 1, ....

> +  /* We don't write out any symbols.  We'll see if that causes any
> +     problems.  */

  Not a chance of getting away with that, I'm afraid.  Everything expects
there to be file and section symbols and their auxiliaries.

> +  set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
> +  set_16 (hdr + offsetof (struct external_filehdr, f_magic), nscns);

  Cut'n'pasto.  Second f_magic should be f_nscns.

> +	  name_offset += namelen;

  Also needs to be namelen + 1.

  Attached are the revised version of the file, and a diff to show what I
changed.  With this version, all the tests in gcc.dg/lto/lto.exp pass as
before (i.e. there are still a couple of pre-existing FAILs that aren't affected).

    cheers,
      DaveK
/* objfile-coff.c -- routines to manipulate COFF object files.
   Copyright 2010 Free Software Foundation, Inc.
   Written by Ian Lance Taylor, Google.

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

This program 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 this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.  */

#include "config.h"
#include "libiberty.h"
#include "objfile.h"

#include <errno.h>
#include <stddef.h>

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

#include "objfile-common.h"

/* COFF structures and constants.  */

/* COFF file header.  */

struct external_filehdr
{
  unsigned char f_magic[2];	/* magic number			*/
  unsigned char f_nscns[2];	/* number of sections		*/
  unsigned char f_timdat[4];	/* time & date stamp		*/
  unsigned char f_symptr[4];	/* file pointer to symtab	*/
  unsigned char f_nsyms[4];	/* number of symtab entries	*/
  unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
  unsigned char f_flags[2];	/* flags			*/
};

/* Bits for filehdr f_flags field.  */

#define F_EXEC			(0x0002)
#define IMAGE_FILE_SYSTEM	(0x1000)
#define IMAGE_FILE_DLL		(0x2000)

/* COFF section header.  */

struct external_scnhdr
{
  unsigned char s_name[8];	/* section name				*/
  unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
  unsigned char s_vaddr[4];	/* virtual address			*/
  unsigned char s_size[4];	/* section size				*/
  unsigned char s_scnptr[4];	/* file ptr to raw data for section 	*/
  unsigned char s_relptr[4];	/* file ptr to relocation		*/
  unsigned char s_lnnoptr[4];	/* file ptr to line numbers		*/
  unsigned char s_nreloc[2];	/* number of relocation entries		*/
  unsigned char s_nlnno[2];	/* number of line number entries	*/
  unsigned char s_flags[4];	/* flags				*/
};

/* The length of the s_name field in struct external_scnhdr.  */

#define SCNNMLEN (8)

/* Bits for scnhdr s_flags field.  This includes some bits defined
   only for PE.  This may need to be moved into coff_magic.  */

#define STYP_DATA			(1 << 6)
#define IMAGE_SCN_ALIGN_1BYTES		(1 << 20)
#define IMAGE_SCN_MEM_DISCARDABLE	(1 << 25)
#define IMAGE_SCN_MEM_SHARED		(1 << 28)
#define IMAGE_SCN_MEM_READ		(1 << 30)

/* COFF symbol table entry.  */

#define E_SYMNMLEN	8	/* # characters in a symbol name	*/

struct external_syment
{
  union
  {
    unsigned char e_name[E_SYMNMLEN];

    struct
    {
      unsigned char e_zeroes[4];
      unsigned char e_offset[4];
    } e;
  } e;

  unsigned char e_value[4];
  unsigned char e_scnum[2];
  unsigned char e_type[2];
  unsigned char e_sclass[1];
  unsigned char e_numaux[1];
};

/* Length allowed for filename in aux sym format 4.  */

#define E_FILNMLEN	18

/* Omits x_sym and other unused variants.  */

union external_auxent
{
  /* Aux sym format 4: file.  */
  union
  {
    char x_fname[E_FILNMLEN];
    struct
    {
      unsigned char x_zeroes[4];
      unsigned char x_offset[4];
    } x_n;
  } x_file;
  /* Aux sym format 5: section.  */
  struct
  {
    unsigned char x_scnlen[4];		/* section length		*/
    unsigned char x_nreloc[2];		/* # relocation entries		*/
    unsigned char x_nlinno[2];		/* # line numbers		*/
    unsigned char x_checksum[4];	/* section COMDAT checksum	*/
    unsigned char x_associated[2];	/* COMDAT assoc section index	*/
    unsigned char x_comdat[1];		/* COMDAT selection number	*/
  } x_scn;
};

/* Symbol-related constants.  */

#define IMAGE_SYM_DEBUG		(-2)
#define IMAGE_SYM_TYPE_NULL	(0)
#define IMAGE_SYM_DTYPE_NULL	(0)
#define IMAGE_SYM_CLASS_STATIC	(3)
#define IMAGE_SYM_CLASS_FILE	(103)

#define IMAGE_SYM_TYPE \
  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)

/* Private data for an objfile_read.  */

struct objfile_coff_read
{
  /* Magic number.  */
  unsigned short magic;
  /* Whether the file is big-endian.  */
  unsigned char is_big_endian;
  /* Number of sections.  */
  unsigned short nscns;
  /* File offset of symbol table.  */
  off_t symptr;
  /* Number of symbol table entries.  */
  unsigned int nsyms;
  /* Flags.  */
  unsigned short flags;
  /* Offset of section headers in file.  */
  off_t scnhdr_offset;
};

/* Private data for an objfile_attributes.  */

struct objfile_coff_attributes
{
  /* Magic number.  */
  unsigned short magic;
  /* Whether the file is big-endian.  */
  unsigned char is_big_endian;
  /* Flags.  */
  unsigned short flags;
};

/* There is no magic number which indicates a COFF file as opposed to
   any other sort of file.  Instead, each COFF file starts with a
   two-byte magic number which also indicates the type of the target.
   This struct holds a magic number as well as characteristics of that
   COFF format.  */

struct coff_magic_struct
{
  /* Magic number.  */
  unsigned short magic;
  /* Whether this magic number is for a big-endian file.  */
  unsigned char is_big_endian;
  /* Flag bits, in the f_flags fields, which indicates that this file
     is not a relocatable object file.  There is no flag which
     specifically indicates a relocatable object file, it is only
     implied by the absence of these flags.  */
  unsigned short non_object_flags;
};

/* This is a list of the COFF magic numbers which we recognize, namely
   the ones used on Windows.  More can be added as needed.  */

static const struct coff_magic_struct coff_magic[] =
{
  /* i386.  */
  { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
  /* x86_64.  */
  { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
};

/* See if we have a COFF file.  */

static void *
objfile_coff_match (unsigned char header[OBJFILE_MATCH_HEADER_LEN],
		    int descriptor, off_t offset,
		    const char *segment_name ATTRIBUTE_UNUSED,
		    const char **errmsg, int *err)
{
  size_t c;
  unsigned short magic_big;
  unsigned short magic_little;
  unsigned short magic;
  size_t i;
  int is_big_endian;
  unsigned short (*fetch_16) (const unsigned char *);
  unsigned int (*fetch_32) (const unsigned char *);
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
  unsigned short flags;
  struct objfile_coff_read *ocr;

  c = sizeof (coff_magic) / sizeof (coff_magic[0]);
  magic_big = objfile_fetch_big_16 (header);
  magic_little = objfile_fetch_little_16 (header);
  for (i = 0; i < c; ++i)
    {
      if (coff_magic[i].is_big_endian
	  ? coff_magic[i].magic == magic_big
	  : coff_magic[i].magic == magic_little)
	break;
    }
  if (i >= c)
    {
      *errmsg = NULL;
      *err = 0;
      return NULL;
    }
  is_big_endian = coff_magic[i].is_big_endian;

  magic = is_big_endian ? magic_big : magic_little;
  fetch_16 = (is_big_endian
	      ? objfile_fetch_big_16
	      : objfile_fetch_little_16);
  fetch_32 = (is_big_endian
	      ? objfile_fetch_big_32
	      : objfile_fetch_little_32);

  if (!objfile_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
			      errmsg, err))
    return NULL;

  flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
  if ((flags & coff_magic[i].non_object_flags) != 0)
    {
      *errmsg = "not relocatable object file";
      *err = 0;
      return NULL;
    }

  ocr = XNEW (struct objfile_coff_read);
  ocr->magic = magic;
  ocr->is_big_endian = is_big_endian;
  ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
  ocr->symptr = fetch_32 (hdrbuf
			  + offsetof (struct external_filehdr, f_symptr));
  ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
  ocr->flags = flags;
  ocr->scnhdr_offset = (sizeof (struct external_filehdr)
			+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
						       f_opthdr)));

  return (void *) ocr;
}

/* Read the string table in a COFF file.  */

static char *
objfile_coff_read_strtab (objfile_read *objfile, size_t *strtab_size,
			  const char **errmsg, int *err)
{
  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
  off_t strtab_offset;
  unsigned char strsizebuf[4];
  size_t strsize;
  char *strtab;

  strtab_offset = ocr->symptr + ocr->nsyms * sizeof (struct external_syment);
  if (!objfile_internal_read (objfile->descriptor, strtab_offset,
			      strsizebuf, 4, errmsg, err))
    return NULL;
  strsize = (ocr->is_big_endian
	     ? objfile_fetch_big_32 (strsizebuf)
	     : objfile_fetch_little_32 (strsizebuf));
  strtab = XNEWVEC (char, strsize);
  if (!objfile_internal_read (objfile->descriptor, strtab_offset,
			      (unsigned char *) strtab, strsize, errmsg, err))
    {
      XDELETEVEC (strtab);
      return NULL;
    }
  *strtab_size = strsize;
  return strtab;
}

/* Find all sections in a COFF file.  */

static const char *
objfile_coff_find_sections (objfile_read *objfile,
			    int (*pfn) (void *, const char *, off_t offset,
					off_t length),
			    void *data,
			    int *err)
{
  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
  size_t scnhdr_size;
  unsigned char *scnbuf;
  const char *errmsg;
  unsigned int (*fetch_32) (const unsigned char *);
  unsigned int nscns;
  char *strtab;
  size_t strtab_size;
  unsigned int i;

  scnhdr_size = sizeof (struct external_scnhdr);
  scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
  if (!objfile_internal_read (objfile->descriptor,
			      objfile->offset + ocr->scnhdr_offset,
			      scnbuf, scnhdr_size * ocr->nscns, &errmsg, err))
    {
      XDELETEVEC (scnbuf);
      return errmsg;
    }

  fetch_32 = (ocr->is_big_endian
	      ? objfile_fetch_big_32
	      : objfile_fetch_little_32);

  nscns = ocr->nscns;
  strtab = NULL;
  strtab_size = 0;
  for (i = 0; i < nscns; ++i)
    {
      unsigned char *scnhdr;
      unsigned char *scnname;
      char namebuf[SCNNMLEN + 1];
      char *name;
      off_t scnptr;
      unsigned int size;

      scnhdr = scnbuf + i * scnhdr_size;
      scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
      memcpy (namebuf, scnname, SCNNMLEN);
      namebuf[SCNNMLEN] = '\0';
      name = &namebuf[0];
      if (namebuf[0] == '/')
	{
	  size_t strindex;
	  char *end;

	  strindex = strtol (namebuf + 1, &end, 10);
	  if (*end == '\0')
	    {
	      /* The real section name is found in the string
		 table.  */
	      if (strtab == NULL)
		{
		  strtab = objfile_coff_read_strtab (objfile, &strtab_size,
						     &errmsg, err);
		  if (strtab == NULL)
		    {
		      XDELETEVEC (scnbuf);
		      return errmsg;
		    }
		}

	      if (strindex < 4 || strindex >= strtab_size)
		{
		  XDELETEVEC (strtab);
		  XDELETEVEC (scnbuf);
		  *err = 0;
		  return "section string index out of range";
		}

	      name = strtab + strindex;
	    }
	}

      scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
      size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));

      if (!(*pfn) (data, name, scnptr, size))
	break;
    }

  if (strtab != NULL)
    XDELETEVEC (strtab);
  XDELETEVEC (scnbuf);

  return NULL;
}

/* Fetch the attributes for an objfile_read.  */

static void *
objfile_coff_fetch_attributes (objfile_read *objfile,
			       const char **errmsg ATTRIBUTE_UNUSED,
			       int *err ATTRIBUTE_UNUSED)
{
  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
  struct objfile_coff_attributes *ret;

  ret = XNEW (struct objfile_coff_attributes);
  ret->magic = ocr->magic;
  ret->is_big_endian = ocr->is_big_endian;
  ret->flags = ocr->flags;
  return ret;
}

/* Release the private data for an objfile_read.  */

static void
objfile_coff_release_read (void *data)
{
  XDELETE (data);
}

/* Compare two attributes structures.  */

static const char *
objfile_coff_attributes_compare (void *data1, void *data2, int *err)
{
  struct objfile_coff_attributes *attrs1 =
    (struct objfile_coff_attributes *) data1;
  struct objfile_coff_attributes *attrs2 =
    (struct objfile_coff_attributes *) data2;

  if (attrs1->magic != attrs2->magic
      || attrs1->is_big_endian != attrs2->is_big_endian)
    {
      *err = 0;
      return "COFF object format mismatch";
    }
  return NULL;
}

/* Release the private data for an attributes structure.  */

static void
objfile_coff_release_attributes (void *data)
{
  XDELETE (data);
}

/* Prepare to write out a file.  */

static void *
objfile_coff_start_write (void *attributes_data,
			  const char **errmsg ATTRIBUTE_UNUSED,
			  int *err ATTRIBUTE_UNUSED)
{
  struct objfile_coff_attributes *attrs =
    (struct objfile_coff_attributes *) attributes_data;
  struct objfile_coff_attributes *ret;

  /* We're just going to record the attributes, but we need to make a
     copy because the user may delete them.  */
  ret = XNEW (struct objfile_coff_attributes);
  *ret = *attrs;
  return ret;
}

/* Write out a COFF filehdr.  */

static int
objfile_coff_write_filehdr (objfile_write *objfile, int descriptor,
			    unsigned int nscns, size_t symtab_offset,
			    unsigned int nsyms, const char **errmsg, int *err)
{
  struct objfile_coff_attributes *attrs =
    (struct objfile_coff_attributes *) objfile->data;
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
  unsigned char *hdr;
  void (*set_16) (unsigned char *, unsigned short);
  void (*set_32) (unsigned char *, unsigned int);

  hdr = &hdrbuf[0];

  set_16 = (attrs->is_big_endian
	    ? objfile_set_big_16
	    : objfile_set_little_16);
  set_32 = (attrs->is_big_endian
	    ? objfile_set_big_32
	    : objfile_set_little_32);

  memset (hdr, 0, sizeof (struct external_filehdr));

  set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
  set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
  /* f_timdat left as zero.  */
  set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
  set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
  /* f_opthdr left as zero.  */
  set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);

  return objfile_internal_write (descriptor, 0, hdrbuf,
				 sizeof (struct external_filehdr),
				 errmsg, err);
}

/* Write out a COFF section header.  */

static int
objfile_coff_write_scnhdr (objfile_write *objfile, int descriptor,
			   const char *name, size_t *name_offset,
			   off_t scnhdr_offset, size_t scnsize, off_t offset,
			   const char **errmsg, int *err)
{
  struct objfile_coff_attributes *attrs =
    (struct objfile_coff_attributes *) objfile->data;
  void (*set_32) (unsigned char *, unsigned int);
  unsigned char hdrbuf[sizeof (struct external_scnhdr)];
  unsigned char *hdr;
  size_t namelen;

  set_32 = (attrs->is_big_endian
	    ? objfile_set_big_32
	    : objfile_set_little_32);

  memset (hdrbuf, 0, sizeof hdrbuf);
  hdr = &hdrbuf[0];

  namelen = strlen (name);
  if (namelen <= SCNNMLEN)
    strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
	     SCNNMLEN);
  else
    {
      snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
      *name_offset += namelen + 1;
    }

  /* s_paddr left as zero.  */
  /* s_vaddr left as zero.  */
  set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
  set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
  /* s_relptr left as zero.  */
  /* s_lnnoptr left as zero.  */
  /* s_nreloc left as zero.  */
  /* s_nlnno left as zero.  */
  set_32 (hdr + offsetof (struct external_scnhdr, s_flags),
	  (STYP_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE
	   | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ));

  return objfile_internal_write (descriptor, scnhdr_offset, hdrbuf,
				 sizeof (struct external_scnhdr),
				 errmsg, err);
}

/* Write out a complete COFF file.  */

static const char *
objfile_coff_write_to_file (objfile_write *objfile, int descriptor, int *err)
{
  struct objfile_coff_attributes *attrs =
    (struct objfile_coff_attributes *) objfile->data;
  unsigned int nscns, secnum;
  objfile_write_section *section;
  off_t scnhdr_offset;
  size_t symtab_offset;
  off_t secsym_offset;
  unsigned int nsyms;
  size_t offset;
  size_t name_offset;
  const char *errmsg;
  unsigned char strsizebuf[4];
  /* The interface doesn't give us access to the name of the input file
     yet.  We want to use its basename for the FILE symbol.  This is
     what 'gas' uses when told to assemble from stdin.  */
  const char *source_filename = "fake";
  union
  {
    struct external_syment sym;
    union external_auxent aux;
  } syms[2];
  void (*set_16) (unsigned char *, unsigned short);
  void (*set_32) (unsigned char *, unsigned int);

  set_16 = (attrs->is_big_endian
	    ? objfile_set_big_16
	    : objfile_set_little_16);
  set_32 = (attrs->is_big_endian
	    ? objfile_set_big_32
	    : objfile_set_little_32);

  nscns = 0;
  for (section = objfile->sections; section != NULL; section = section->next)
    ++nscns;

  scnhdr_offset = sizeof (struct external_filehdr);
  offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
  name_offset = 4;
  for (section = objfile->sections; section != NULL; section = section->next)
    {
      size_t mask;
      size_t new_offset;
      size_t scnsize;
      struct objfile_write_section_buffer *buffer;

      mask = (1U << section->align) - 1;
      new_offset = offset & mask;
      new_offset &= ~ mask;
      while (new_offset > offset)
	{
	  unsigned char zeroes[16];
	  size_t write;

	  memset (zeroes, 0, sizeof zeroes);
	  write = new_offset - offset;
	  if (write > sizeof zeroes)
	    write = sizeof zeroes;
	  if (!objfile_internal_write (descriptor, offset, zeroes, write,
				       &errmsg, err))
	    return errmsg;
	}

      scnsize = 0;
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
	{
	  if (!objfile_internal_write (descriptor, offset + scnsize,
				       (const unsigned char *) buffer->buffer,
				       buffer->size, &errmsg, err))
	    return errmsg;
	  scnsize += buffer->size;
	}

      if (!objfile_coff_write_scnhdr (objfile, descriptor, section->name,
				      &name_offset, scnhdr_offset,
				      scnsize, offset, &errmsg, err))
	return errmsg;

      scnhdr_offset += sizeof (struct external_scnhdr);
      offset += scnsize;
    }

  /* Symbol table is always half-word aligned.  */
  offset += (offset & 1);
  /* There is a file symbol and a section symbol per section,
     and each of these has a single auxiliary symbol following.  */
  nsyms = 2 * (nscns + 1);
  symtab_offset = offset;
  /* Advance across space reserved for symbol table to locate
     start of string table.  */
  offset += nsyms * sizeof (struct external_syment);

  /* Write out file symbol.  */
  memset (&syms[0], 0, sizeof (syms));
  strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
  set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
  set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
  syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
  syms[0].sym.e_numaux[0] = 1;
  /* The name need not be nul-terminated if it fits into the x_fname field
     directly, but must be if it has to be placed into the string table.  */
  if (strlen (source_filename) <= E_FILNMLEN)
    {
      memcpy (&syms[1].aux.x_file.x_fname[0], source_filename,
		strlen (source_filename));
    }
  else
    {
      set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
      if (!objfile_internal_write (descriptor, offset + name_offset,
		(const unsigned char *) source_filename,
		strlen (source_filename) + 1, &errmsg, err))
	return errmsg;
      name_offset += strlen (source_filename) + 1;
    }
  if (!objfile_internal_write (descriptor, symtab_offset,
	(const unsigned char *) &syms[0], sizeof (syms), &errmsg, err))
    return errmsg;

  /* Write the string table length, followed by the strings and section
     symbols in step with each other.  */
  set_32 (strsizebuf, name_offset);
  if (!objfile_internal_write (descriptor, offset, strsizebuf, 4, &errmsg, err))
    return errmsg;

  name_offset = 4;
  secsym_offset = symtab_offset + sizeof (syms);
  memset (&syms[0], 0, sizeof (syms));
  set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
  syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
  syms[0].sym.e_numaux[0] = 1;
  secnum = 1;

  for (section = objfile->sections; section != NULL; section = section->next)
    {
      size_t namelen;
      size_t scnsize;
      struct objfile_write_section_buffer *buffer;

      namelen = strlen (section->name);
      set_16 (&syms[0].sym.e_scnum[0], secnum++);
      scnsize = 0;
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
	scnsize += buffer->size;
      set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
      if (namelen > SCNNMLEN)
	{
	  set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
	  set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
	  if (!objfile_internal_write (descriptor, offset + name_offset,
				       (const unsigned char *) section->name,
				       namelen + 1, &errmsg, err))
	    return errmsg;
	  name_offset += namelen + 1;
	}
      else
	{
	  memcpy (&syms[0].sym.e.e_name[0], section->name,
		strlen (section->name));
	  memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
		E_SYMNMLEN - strlen (section->name));
	}

      if (!objfile_internal_write (descriptor, secsym_offset,
	  (const unsigned char *) &syms[0], sizeof (syms), &errmsg, err))
	return errmsg;
      secsym_offset += sizeof (syms);
    }

  if (!objfile_coff_write_filehdr (objfile, descriptor, nscns, symtab_offset,
				   nsyms, &errmsg, err))
    return errmsg;

  return NULL;
}

/* Release the private data for an objfile_write structure.  */

static void
objfile_coff_release_write (void *data)
{
  XDELETE (data);
}

/* The COFF functions.  */

const struct objfile_functions objfile_coff_functions =
{
  objfile_coff_match,
  objfile_coff_find_sections,
  objfile_coff_fetch_attributes,
  objfile_coff_release_read,
  objfile_coff_attributes_compare,
  objfile_coff_release_attributes,
  objfile_coff_start_write,
  objfile_coff_write_to_file,
  objfile_coff_release_write
};
Dave Korn Oct. 30, 2010, 4:49 p.m. UTC | #15
On 30/10/2010 11:44, Dave Korn wrote:
> On 29/10/2010 02:31, Ian Lance Taylor wrote:
> 
>> This implements an object file reader/writer which does everything
>> required by LTO and gccgo.  The ELF code works.  I have not tested the
>> Mach-O and COFF code at all beyond compiling it; I hope that somebody
>> else can test those targets and fix them.
>>
>> With this patch, libelf is no longer needed.
> 
>   Almost, but not quite!  The attached patch switches the lto-plugin over to
> use the new objfile reader as well.

>   Bootstrapped and tested all languages except java and ada on
> x86_64-unknown-linux-gnu, no regressions.  There are still a couple of bugs to
> iron out of the COFF-specific part of the objfile reader which I'll have fixed
> later today.
> 
>   OK for trunk (once the objfile changes have gone in)?

  As you'll see elsethread, I fixed the COFF problems.  This is the remaining
chunk of patch required to make the lto-plugin work on cygming targets.

gcc/ChangeLog:

	* gcc.c (PLUGIN_PASSTHROUGH_SPEC): New macro factored out from
	LINK_COMMAND_SPEC.
	(LINK_COMMAND_SPEC): Use it.
	(static_spec_functions[]): Add pass-through-libs entry.
	(pass_through_libs_spec_func): Add related spec function.
	* config/i386/cygming.h (PLUGIN_PASSTHROUGH_SPEC): Define.
	* doc/tm.texi.in (PLUGIN_PASSTHROUGH_SPEC): Document.
	(LINK_COMMAND_SPEC): Mention it.
	* doc/tm.texi: Regenerate.
	* doc/invoke.texi (pass-through-libs): Mention new spec function.

  Taking this for a bootstrap and test cycle now (on top of the objfile
changes).  Assuming no regressions, and one new PASS (the sole LTO test that
exercises -fuse-linker-plugin), and once all the other patches have gone in: OK?

    cheers,
      DaveK
Richard Henderson Oct. 30, 2010, 5:57 p.m. UTC | #16
On 10/30/2010 01:16 AM, Dave Korn wrote:
>> Do we really want to keep re-reading section data for every section
>> lookup we do?  Can't we do this in objfile_open_read?
> 
>   It should only be necessary to do one section lookup per object file anyway.
>  Keep extra data hanging around in memory in the backend just so that we can
> write algorithmically inefficient code in the client?  Seems like a bad
> tradeoff to me!

Uh, really?  I thought there were like a half-dozen lto sections...

>   The line you quoted uses IMAGE_SCN_ALIGN_1BYTES.  That's all we'll ever need
> for LTO sections.

Perhaps, but there's an argument to the create_section function that
specifies the alignment.  If we only need 1-byte alignment that's fine,
but we should either assert that's true, omit the argument, or properly
support it.


r~
Richard Henderson Oct. 30, 2010, 6:24 p.m. UTC | #17
On 10/30/2010 11:37 AM, Dave Korn wrote:
>> Uh, really?  I thought there were like a half-dozen lto sections...
> 
>   Which we iterate over just once, and record them all in a hash table from
> the per-section callback, unless I've missed something.

Oh, right.  Nevermind then.


r~
Dave Korn Oct. 30, 2010, 6:37 p.m. UTC | #18
On 30/10/2010 18:57, Richard Henderson wrote:
> On 10/30/2010 01:16 AM, Dave Korn wrote:
>>> Do we really want to keep re-reading section data for every section
>>> lookup we do?  Can't we do this in objfile_open_read?
>>   It should only be necessary to do one section lookup per object file anyway.
>>  Keep extra data hanging around in memory in the backend just so that we can
>> write algorithmically inefficient code in the client?  Seems like a bad
>> tradeoff to me!
> 
> Uh, really?  I thought there were like a half-dozen lto sections...

  Which we iterate over just once, and record them all in a hash table from
the per-section callback, unless I've missed something.

>>   The line you quoted uses IMAGE_SCN_ALIGN_1BYTES.  That's all we'll ever need
>> for LTO sections.
> 
> Perhaps, but there's an argument to the create_section function that
> specifies the alignment.  If we only need 1-byte alignment that's fine,
> but we should either assert that's true, omit the argument, or properly
> support it.

  Fair point.

    cheers,
      DaveK
Dave Korn Oct. 30, 2010, 6:58 p.m. UTC | #19
On 30/10/2010 19:24, Richard Henderson wrote:
> On 10/30/2010 11:37 AM, Dave Korn wrote:
>>> Uh, really?  I thought there were like a half-dozen lto sections...
>>   Which we iterate over just once, and record them all in a hash table from
>> the per-section callback, unless I've missed something.
> 
> Oh, right.  Nevermind then.
> 
> 
> r~

  It'd be worth putting a warning comment on the find_section (no "s")
function saying that it's pretty inefficient and that it is best practice to
call find_sections just once and record details rather than make multiple
calls to find_section.  (Both lto FE and lto-plugin are already architected
that way.)

    cheers,
      DaveK
Ian Lance Taylor Oct. 31, 2010, 5:55 p.m. UTC | #20
Dave Korn <dave.korn.cygwin@gmail.com> writes:

> On 30/10/2010 19:24, Richard Henderson wrote:
>> On 10/30/2010 11:37 AM, Dave Korn wrote:
>>>> Uh, really?  I thought there were like a half-dozen lto sections...
>>>   Which we iterate over just once, and record them all in a hash table from
>>> the per-section callback, unless I've missed something.
>> 
>> Oh, right.  Nevermind then.
>> 
>> 
>> r~
>
>   It'd be worth putting a warning comment on the find_section (no "s")
> function saying that it's pretty inefficient and that it is best practice to
> call find_sections just once and record details rather than make multiple
> calls to find_section.  (Both lto FE and lto-plugin are already architected
> that way.)
>
>     cheers,
>       DaveK

I added a sentence "Note that calling this multiple times is
inefficient; use objfile_find_sections instead."

I added the function because it's what the gccgo frontend needs: it only
needs to find one section.

Ian
Ian Lance Taylor Oct. 31, 2010, 6:04 p.m. UTC | #21
Richard Henderson <rth@redhat.com> writes:

>> +extern objfile_read *
>> +objfile_open_read (int descriptor, off_t offset, const char *segment_name,
>> +		   const char **errmsg, int *err);
> ...
>> +extern objfile_write *
>> +objfile_start_write (objfile_attributes *ATTRS, const char *segment_name,
>> +		     const char **errmsg, int *err);
>
> Mismatch in naming conventions?  I like the use of "release"
> to clearly indicate non-closure of the FD.

You're right.  I changed the first to objfile_start_read.

>
>> +  shdr_size = (cl == ELFCLASS32
>> +	       ? sizeof (Elf32_External_Shdr)
>> +	       : sizeof (Elf64_External_Shdr));
>> +  memset (buf, 0, shdr_size);
>
> Constant size memset is easier to optimize.  You might as well
> zero all of BUF, even if we're not going to use it all.  The
> slop between 32 and 64 is minimal.

True.  Fixed.


>> +  if (!objfile_internal_read (objfile->descriptor,
>> +			      objfile->offset + eor->shoff + shdr_size,
>> +			      shdrs,
>> +			      shdr_size * (shnum - 1),
>> +			      &errmsg, err))
>
> Do we really want to keep re-reading section data for every section
> lookup we do?  Can't we do this in objfile_open_read?

I think this is OK as discussed elsewhere.


>> +  set_32 (hdr + offsetof (struct external_scnhdr, s_flags),
>> +	  (STYP_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE
>> +	   | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ));
>
> You're not recording alignment in the coff object file?
> IMAGE_SCN_ALIGN_<N>BYTES, 1 <= N <= 8192, are all defined
> with a simple function in that nibble.

Changed to this:

  flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
	   | IMAGE_SCN_MEM_READ);
  /* PE can represent alignment up to 13.  */
  if (align > 13)
    align = 13;
  flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
  set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);

Thanks.

Ian
Ian Lance Taylor Oct. 31, 2010, 6:05 p.m. UTC | #22
Dave Korn <dave.korn.cygwin@gmail.com> writes:

>   Attached are the revised version of the file, and a diff to show what I
> changed.  With this version, all the tests in gcc.dg/lto/lto.exp pass as
> before (i.e. there are still a couple of pre-existing FAILs that aren't affected).

Excellent, thanks.  I have incorporated your objfile-coff.c in my
working directory, and will commit it when I commit the whole patch set.

I think it can be committed as soon as objfile-mach-o.c is working.

Ian
Tom Tromey Nov. 1, 2010, 4:45 p.m. UTC | #23
>>>>> "Ian" == Ian Lance Taylor <iant@google.com> writes:

Ian> This patch puts the code in libiberty, but it could equally well go in
Ian> gcc.  Anybody want to make an argument one way or another?

Ian> +extern const char *
Ian> +objfile_attributes_compare (objfile_attributes *attrs1,

GDB already uses the name "objfile" for one of its modules.
I don't think we have any name clashes with this patch right now, but I
would prefer to avoid the eventual confusion.
So, if this is in libiberty, could it please have a different name?

thanks,
Tom
Ian Lance Taylor Nov. 1, 2010, 6:17 p.m. UTC | #24
Tom Tromey <tromey@redhat.com> writes:

>>>>>> "Ian" == Ian Lance Taylor <iant@google.com> writes:
>
> Ian> This patch puts the code in libiberty, but it could equally well go in
> Ian> gcc.  Anybody want to make an argument one way or another?
>
> Ian> +extern const char *
> Ian> +objfile_attributes_compare (objfile_attributes *attrs1,
>
> GDB already uses the name "objfile" for one of its modules.
> I don't think we have any name clashes with this patch right now, but I
> would prefer to avoid the eventual confusion.
> So, if this is in libiberty, could it please have a different name?

Sure.

Any suggestions?

Ian
Paolo Bonzini Nov. 2, 2010, 10:50 a.m. UTC | #25
On 11/01/2010 07:17 PM, Ian Lance Taylor wrote:
> Tom Tromey<tromey@redhat.com>  writes:
>
>>>>>>> "Ian" == Ian Lance Taylor<iant@google.com>  writes:
>>
>> Ian>  This patch puts the code in libiberty, but it could equally well go in
>> Ian>  gcc.  Anybody want to make an argument one way or another?
>>
>> Ian>  +extern const char *
>> Ian>  +objfile_attributes_compare (objfile_attributes *attrs1,
>>
>> GDB already uses the name "objfile" for one of its modules.
>> I don't think we have any name clashes with this patch right now, but I
>> would prefer to avoid the eventual confusion.
>> So, if this is in libiberty, could it please have a different name?
>
> Sure.
>
> Any suggestions?

readobj/objread?

Paolo
Paolo Bonzini Nov. 2, 2010, 10:52 a.m. UTC | #26
On 11/02/2010 11:50 AM, Paolo Bonzini wrote:
> On 11/01/2010 07:17 PM, Ian Lance Taylor wrote:
>> Tom Tromey<tromey@redhat.com> writes:
>>
>>> Ian> This patch puts the code in libiberty, but it could equally well
>>> go in
>>> Ian> gcc. Anybody want to make an argument one way or another?
>>>
>>> Ian> +extern const char *
>>> Ian> +objfile_attributes_compare (objfile_attributes *attrs1,
>>>
>>> GDB already uses the name "objfile" for one of its modules.
>>> I don't think we have any name clashes with this patch right now, but I
>>> would prefer to avoid the eventual confusion.
>>> So, if this is in libiberty, could it please have a different name?
>>
>> Sure.
>>
>> Any suggestions?
>
> readobj/objread?

This obviously meant objread/objwrite. :)

Paolo
Ian Lance Taylor Nov. 2, 2010, 3:06 p.m. UTC | #27
Dave Korn <dave.korn.cygwin@gmail.com> writes:

> +# Trying to get this information from gcc's config is tricky.
> +case $target in
> +  x86_64*-mingw*)
> +    SYM_STYLE=-DSYM_STYLE=ss_none
> +    ;;
> +  *-cygwin* | i?86*-mingw* )
> +    SYM_STYLE=-DSYM_STYLE=ss_win32
> +    ;;
> +  *)
> +    SYM_STYLE=-DSYM_STYLE=ss_none
> +    ;;
>  esac
> -
> -AC_SUBST(LTO_FORMAT)
> +AC_SUBST(SYM_STYLE)

It would seem more natural to use AC_DEFINE here.  Any reason not to do
that?


> +  else if (!strncmp (option, "-sym-style=", sizeof ("-sym-style=") - 1))
> +    {
> +      switch (option[sizeof ("-sym-style=")])
> +	{
> +	case 'w':
> +	  sym_style = ss_win32;
> +	  break;
> +	case 'u':
> +	  sym_style = ss_uscore;
> +	  break;
> +	default:
> +	  sym_style = ss_none;
> +	  break;
> +	}
> +    }

This looks wrong, because sizeof ("-sym-style=") will be 1 too large in
the switch clause.

And of course this code now has to use simple_object rather than
objfile.

Ian
Ian Lance Taylor Nov. 2, 2010, 10:30 p.m. UTC | #28
Dave Korn <dave.korn.cygwin@gmail.com> writes:

> On 02/11/2010 15:06, Ian Lance Taylor wrote:
>
>> It would seem more natural to use AC_DEFINE here.  Any reason not to do
>> that?
>
>   It seems a bit much overkill.  There's only a single -D right now, so why
> not pass it straight through?  With AC_DEFINE I'd still have to import @DEFS@
> into the makefile, just to get HAVE_CONFIG_H available at build time, and then
> add a config.h with a single #define in it.  If there were several symbols to
> define, or if there was already an AC_CONFIG_HEADER, I'd do it, but there
> isn't yet, so why haul all that extra weight?

Because we will almost inevitably want it eventually?  I often agree
with that kind of argument, but in this case I lean more toward "start
as you plan to proceed."


>> And of course this code now has to use simple_object rather than
>> objfile.
>
>   Yep, I'm just revising it now.  Will spin those fixes in at the same time,
> thanks for reviewing.  Let me know if you really want to insist on the
> AC_DEFINE change, but if it's up to me I'd rather just leave it as it is.

I've CC'ed the official lto-plugin maintainer, Cary Coutant, to make the
call here.

Ian
Dave Korn Nov. 2, 2010, 10:44 p.m. UTC | #29
On 02/11/2010 15:06, Ian Lance Taylor wrote:
> Dave Korn writes:
> 
>> +# Trying to get this information from gcc's config is tricky.
>> +case $target in
>> +  x86_64*-mingw*)
>> +    SYM_STYLE=-DSYM_STYLE=ss_none
>> +    ;;
>> +  *-cygwin* | i?86*-mingw* )
>> +    SYM_STYLE=-DSYM_STYLE=ss_win32
>> +    ;;
>> +  *)
>> +    SYM_STYLE=-DSYM_STYLE=ss_none
>> +    ;;
>>  esac
>> -
>> -AC_SUBST(LTO_FORMAT)
>> +AC_SUBST(SYM_STYLE)
> 
> It would seem more natural to use AC_DEFINE here.  Any reason not to do
> that?

  It seems a bit much overkill.  There's only a single -D right now, so why
not pass it straight through?  With AC_DEFINE I'd still have to import @DEFS@
into the makefile, just to get HAVE_CONFIG_H available at build time, and then
add a config.h with a single #define in it.  If there were several symbols to
define, or if there was already an AC_CONFIG_HEADER, I'd do it, but there
isn't yet, so why haul all that extra weight?

>> +  else if (!strncmp (option, "-sym-style=", sizeof ("-sym-style=") - 1))
>> +    {
>> +      switch (option[sizeof ("-sym-style=")])
>> +	{
>> +	case 'w':
>> +	  sym_style = ss_win32;
>> +	  break;
>> +	case 'u':
>> +	  sym_style = ss_uscore;
>> +	  break;
>> +	default:
>> +	  sym_style = ss_none;
>> +	  break;
>> +	}
>> +    }
> 
> This looks wrong, because sizeof ("-sym-style=") will be 1 too large in
> the switch clause.

  Oops, yes, thanks.

> And of course this code now has to use simple_object rather than
> objfile.

  Yep, I'm just revising it now.  Will spin those fixes in at the same time,
thanks for reviewing.  Let me know if you really want to insist on the
AC_DEFINE change, but if it's up to me I'd rather just leave it as it is.

    cheers,
      DaveK
Dave Korn Nov. 2, 2010, 10:55 p.m. UTC | #30
On 02/11/2010 22:30, Ian Lance Taylor wrote:

> Because we will almost inevitably want it eventually?  I often agree
> with that kind of argument, but in this case I lean more toward "start
> as you plan to proceed."

  Ah, hell with it.  I know you're right really.  :)

  I'll do it the full way.

    cheers,
      DaveK
Ralf Wildenhues Nov. 3, 2010, 5:58 a.m. UTC | #31
* Dave Korn wrote on Tue, Nov 02, 2010 at 11:44:49PM CET:
> On 02/11/2010 15:06, Ian Lance Taylor wrote:
> > Dave Korn writes:
> > 
> >> -AC_SUBST(LTO_FORMAT)
> >> +AC_SUBST(SYM_STYLE)
> > 
> > It would seem more natural to use AC_DEFINE here.  Any reason not to do
> > that?
> 
>   It seems a bit much overkill.  There's only a single -D right now, so why
> not pass it straight through?  With AC_DEFINE I'd still have to import @DEFS@
> into the makefile, just to get HAVE_CONFIG_H available at build time, and then
> add a config.h with a single #define in it.  If there were several symbols to
> define, or if there was already an AC_CONFIG_HEADER, I'd do it, but there
> isn't yet, so why haul all that extra weight?

FWIW, you don't need an AC_CONFIG_HEADER.  If you don't have one, @DEFS@
will expand to all the defines defined by AC_DEFINE.

Cheers,
Ralf
Dave Korn Nov. 3, 2010, 6:36 a.m. UTC | #32
On 03/11/2010 05:58, Ralf Wildenhues wrote:

> 
> FWIW, you don't need an AC_CONFIG_HEADER.  If you don't have one, @DEFS@
> will expand to all the defines defined by AC_DEFINE.

  Ah well, I did it now anyway.  Noted for next time, thanks! :)

    cheers,
      DaveK
Ian Lance Taylor Nov. 5, 2010, 9:35 p.m. UTC | #33
Dave Korn <dave.korn.cygwin@gmail.com> writes:

> gcc/ChangeLog:
>
> 	* gcc.c (PLUGIN_PASSTHROUGH_SPEC): New macro factored out from
> 	LINK_COMMAND_SPEC.
> 	(LINK_COMMAND_SPEC): Use it.
> 	(static_spec_functions[]): Add pass-through-libs entry.
> 	(pass_through_libs_spec_func): Add related spec function.
> 	* config/i386/cygming.h (PLUGIN_PASSTHROUGH_SPEC): Define.
> 	* doc/tm.texi.in (PLUGIN_PASSTHROUGH_SPEC): Document.
> 	(LINK_COMMAND_SPEC): Mention it.
> 	* doc/tm.texi: Regenerate.
> 	* doc/invoke.texi (pass-through-libs): Mention new spec function.

> @@ -658,10 +667,8 @@
>      %{fuse-linker-plugin: \
>      -plugin %(linker_plugin_file) \
>      -plugin-opt=%(lto_wrapper) \
> -    -plugin-opt=-fresolution=%u.res \
> -    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}	\
> -    %{static:-plugin-opt=-pass-through=-lc}	\
> -    } \
> +    -plugin-opt=-fresolution=%u.res " \
> +    PLUGIN_PASSTHROUGH_SPEC " } \
>      %{flto:%<fcompare-debug*} %{fwhopr*:%<fcompare-debug*} \
>      %{flto} %{fwhopr*} %l " LINK_PIE_SPEC \
>     "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\

Any reason not to make PLUGIN_PASSTHROUGH_SPEC into a proper spec,
invoked by %(plugin_passthrough) rather than by preprocessor string
concatenation?

Ian
Dave Korn Nov. 5, 2010, 10:26 p.m. UTC | #34
On 05/11/2010 21:35, Ian Lance Taylor wrote:
> Dave Korn <dave.korn.cygwin@gmail.com> writes:
> 
>> gcc/ChangeLog:
>>
>> 	* gcc.c (PLUGIN_PASSTHROUGH_SPEC): New macro factored out from
>> 	LINK_COMMAND_SPEC.
>> 	(LINK_COMMAND_SPEC): Use it.
>> 	(static_spec_functions[]): Add pass-through-libs entry.
>> 	(pass_through_libs_spec_func): Add related spec function.
>> 	* config/i386/cygming.h (PLUGIN_PASSTHROUGH_SPEC): Define.
>> 	* doc/tm.texi.in (PLUGIN_PASSTHROUGH_SPEC): Document.
>> 	(LINK_COMMAND_SPEC): Mention it.
>> 	* doc/tm.texi: Regenerate.
>> 	* doc/invoke.texi (pass-through-libs): Mention new spec function.
> 
>> @@ -658,10 +667,8 @@
>>      %{fuse-linker-plugin: \
>>      -plugin %(linker_plugin_file) \
>>      -plugin-opt=%(lto_wrapper) \
>> -    -plugin-opt=-fresolution=%u.res \
>> -    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}	\
>> -    %{static:-plugin-opt=-pass-through=-lc}	\
>> -    } \
>> +    -plugin-opt=-fresolution=%u.res " \
>> +    PLUGIN_PASSTHROUGH_SPEC " } \
>>      %{flto:%<fcompare-debug*} %{fwhopr*:%<fcompare-debug*} \
>>      %{flto} %{fwhopr*} %l " LINK_PIE_SPEC \
>>     "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
> 
> Any reason not to make PLUGIN_PASSTHROUGH_SPEC into a proper spec,
> invoked by %(plugin_passthrough) rather than by preprocessor string
> concatenation?

  Well, "I didn't think of it" is the main reason :)  I don't suppose there's
going to be any call to change or override it on any kind of regular basis, I
very much expect we'll have the default one for ELF targets and an override
for COFF targets and that's all that will ever be needed.  So I didn't think
it ever likely to need a name of its own to refer to it by.

  If you can see some advantage to making it a real spec, feel free to file an
enhancement PR against my name.

    cheers,
      DaveK
Eric Botcazou Nov. 6, 2010, 7:57 p.m. UTC | #35
> 2010-10-28  Ian Lance Taylor  <iant@google.com>
>
> 	* lto-objfile.c: New file.
> 	* lto-elf.c: Remove file.

This has removed the support for compatible architectures present in lto-elf.c 
and hasn't added any replacement in libiberty, so a bunch of LTO tests fail 
again on 32-bit SPARC/Solaris.

The old code reads:

/* Return true if ELF_MACHINE is compatible with the cached value of the
   architecture and possibly update the latter.  Return false otherwise.

   Note: if you want to add more EM_* cases, you'll need to provide the
   corresponding definitions at the beginning of the file.  */

static bool
is_compatible_architecture (Elf64_Half elf_machine)
{
  if (cached_file_attrs.elf_machine == elf_machine)
    return true;

  switch (cached_file_attrs.elf_machine)
    {
    case EM_SPARC:
      if (elf_machine == EM_SPARC32PLUS)
	{
	  cached_file_attrs.elf_machine = elf_machine;
	  return true;
	}
      break;

    case EM_SPARC32PLUS:
      if (elf_machine == EM_SPARC)
	return true;
      break;

    default:
      break;
    }

  return false;
}

so it was not only accepting object files with compatible architectures in the 
same LTO compilation, but also updating the current architecture for later 
write operations.  This is modelled on the linker.
Dave Korn Nov. 16, 2010, 4:45 p.m. UTC | #36
On 05/11/2010 21:35, Ian Lance Taylor wrote:
> Dave Korn writes:
> 
>> gcc/ChangeLog:
>>
>> 	* gcc.c (PLUGIN_PASSTHROUGH_SPEC): New macro factored out from
>> 	LINK_COMMAND_SPEC.
>> 	(LINK_COMMAND_SPEC): Use it.
>> 	(static_spec_functions[]): Add pass-through-libs entry.
>> 	(pass_through_libs_spec_func): Add related spec function.
>> 	* config/i386/cygming.h (PLUGIN_PASSTHROUGH_SPEC): Define.
>> 	* doc/tm.texi.in (PLUGIN_PASSTHROUGH_SPEC): Document.
>> 	(LINK_COMMAND_SPEC): Mention it.
>> 	* doc/tm.texi: Regenerate.
>> 	* doc/invoke.texi (pass-through-libs): Mention new spec function.
> 
>> @@ -658,10 +667,8 @@
>>      %{fuse-linker-plugin: \
>>      -plugin %(linker_plugin_file) \
>>      -plugin-opt=%(lto_wrapper) \
>> -    -plugin-opt=-fresolution=%u.res \
>> -    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}	\
>> -    %{static:-plugin-opt=-pass-through=-lc}	\
>> -    } \
>> +    -plugin-opt=-fresolution=%u.res " \
>> +    PLUGIN_PASSTHROUGH_SPEC " } \
>>      %{flto:%<fcompare-debug*} %{fwhopr*:%<fcompare-debug*} \
>>      %{flto} %{fwhopr*} %l " LINK_PIE_SPEC \
>>     "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
> 
> Any reason not to make PLUGIN_PASSTHROUGH_SPEC into a proper spec,
> invoked by %(plugin_passthrough) rather than by preprocessor string
> concatenation?
> 
> Ian

  I found a better way to do it(*), since there turned out not to be any need
for a separate spec at all, as the functionality required here by PE-COFF also
solves the problems seen on other platforms as in e.g., PR42690.  Patch withdrawn.

    cheers,
      DaveK
diff mbox

Patch

Index: include/objfile.h
===================================================================
--- include/objfile.h	(revision 0)
+++ include/objfile.h	(revision 0)
@@ -0,0 +1,198 @@ 
+/* objfile.h -- routines to manipulate object files
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This header file provides four types with associated functions.
+   They are used to read and write object files.  This is a minimal
+   interface, intended to support the needs of gcc without bringing in
+   all the power and complexity of BFD.  */
+
+/* The type objfile_read * is used to read an existing object
+   file.  */
+
+typedef struct objfile_read_struct objfile_read;
+
+/* Create an objfile_rd given DESCRIPTOR, an open file descriptor, and
+   OFFSET, an offset within the file.  The offset is for use with
+   archives, and should be 0 for an ordinary object file.  The
+   descriptor must remain open until done with the returned
+   objfile_read.  SEGMENT_NAME is used on Mach-O and is required on
+   that platform: it means to only look at sections within the segment
+   with that name.  It is ignored for other object file formats.  On
+   error, this function returns NULL, and sets *ERRMSG to an error
+   string and sets *ERR to an errno value or 0 if there is no relevant
+   errno.  */
+
+extern objfile_read *
+objfile_open_read (int descriptor, off_t offset, const char *segment_name,
+		   const char **errmsg, int *err);
+
+/* Call PFN for each section in OBJFILE, passing it the section name,
+   offset within the file of the section contents, and length of the
+   section contents.  The offset within the file is relative to the
+   offset passed to objfile_open_read.  The DATA argument to
+   objfile_find_sections is passed on to PFN.  If PFN returns 0, the
+   loop is stopped and objfile_find_sections returns.  If PFN returns
+   non-zero, the loop continues.  On success this returns NULL.  On
+   error it returns an error string, and sets *ERR to an errno value
+   or 0 if there is no relevant errno.  */
+
+extern const char *
+objfile_find_sections (objfile_read *objfile,
+		       int (*pfn) (void *data, const char *, off_t offset,
+				   off_t length),
+		       void *data,
+		       int *err);
+
+/* Look for the section NAME in OBJFILE.  This returns information for
+   the first section NAME in OBJFILE.
+
+   If found, return 1 and set *OFFSET to the offset in the file of the
+   section contents and set *LENGTH to the length of the section
+   contents.  *OFFSET will be relative to the offset passed to
+   objfile_open_read.
+
+   If the section is not found, and no error occurs, return 0 and set
+   *ERRMSG to NULL.
+
+   If an error occurs, return 0, set *ERRMSG to an error message, and
+   set *ERR to an errno value or 0 if there is no relevant errno.  */
+
+extern int
+objfile_find_section (objfile_read *objfile, const char *name,
+		      off_t *offset, off_t *length,
+		      const char **errmsg, int *err);
+
+/* Release all resources associated with OBJFILE.  This does not close
+   the file descriptor.  */
+
+extern void
+objfile_release_read (objfile_read *);
+
+/* The type objfile_attributes holds the attributes of an object file
+   that matter for creating a file or ensuring that two files are
+   compatible.  This is a set of magic numbers.  */
+
+typedef struct objfile_attributes_struct objfile_attributes;
+
+/* Fetch the attributes of OBJFILE.  This information will persist
+   until objfile_attributes_release is called, even if OBJFILE is
+   closed.  On error this returns NULL, sets *ERRMSG to an error
+   message, and sets *ERR to an errno value or 0 if there isn't
+   one.  */
+
+extern objfile_attributes *
+objfile_fetch_attributes (objfile_read *objfile, const char **errmsg,
+			  int *err);
+
+/* Compare ATTRS1 and ATTRS2.  If they could be linked together
+   without error, return NULL.  Otherwise, return an error message,
+   set *ERR to an errno value or 0 if there isn't one.  */
+
+extern const char *
+objfile_attributes_compare (objfile_attributes *attrs1,
+			    objfile_attributes *attrs2,
+			    int *err);
+
+/* Release all resources associated with ATTRS.  */
+
+extern void
+objfile_release_attributes (objfile_attributes *attrs);
+
+/* The type objfile_write is used to create a new object file.  */
+
+typedef struct objfile_write_struct objfile_write;
+
+/* Start creating a new object file which is like ATTRS.  You must
+   fetch attribute information from an existing object file before you
+   can create a new one.  There is currently no support for creating
+   an object file de novo.  The segment name is only used on Mach-O,
+   where it is required.  It means that all sections are created
+   within that segment.  It is ignored for other object file formats.
+   On error this function returns NULL, sets *ERRMSG to an error
+   message, and sets *ERR to an errno value or 0 if there isn't
+   one.  */
+
+extern objfile_write *
+objfile_start_write (objfile_attributes *ATTRS, const char *segment_name,
+		     const char **errmsg, int *err);
+
+/* The type objfile_write_section is a handle for a section which is
+   being written.  */
+
+typedef struct objfile_write_section_struct objfile_write_section;
+
+/* Add a section to OBJFILE.  NAME is the name of the new section.
+   ALIGN is the required alignment expressed as the number of required
+   low-order 0 bits (e.g., 2 for alignment to a 32-bit boundary).  The
+   section is created as containing data, readable, not writable, not
+   executable, not loaded at runtime.  On error this returns NULL,
+   sets *ERRMSG to an error message, and sets *ERR to an errno value
+   or 0 if there isn't one.  */
+
+extern objfile_write_section *
+objfile_write_create_section (objfile_write *objfile, const char *name,
+			      unsigned int align, const char **errmsg,
+			      int *err);
+
+/* Add data BUFFER/SIZE to SECTION in OBJFILE.  If COPY is non-zero,
+   the data will be copied into memory if necessary.  If COPY is zero,
+   BUFFER must persist until OBJFILE is released.  On success this
+   returns NULL.  On error this returns an error message, and sets
+   *ERR to an errno value or 0 if there isn't one.  */
+
+extern const char *
+objfile_write_add_data (objfile_write *objfile,
+			objfile_write_section *section,
+			const void *buffer, size_t size,
+			int copy, int *err);
+
+/* Write the complete object file to DESCRIPTOR, an open file
+   descriptor.  This returns NULL on success.  On error this returns
+   an error message, and sets *ERR to an errno value or 0 if there
+   isn't one.  */
+
+extern const char *
+objfile_write_to_file (objfile_write *objfile, int descriptor,
+		       int *err);
+
+/* Release all resources associated with OBJFILE, including any
+   objfile_write_section's that may have been created.  */
+
+extern void
+objfile_release_write (objfile_write *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: libiberty/objfile-mach-o.c
===================================================================
--- libiberty/objfile-mach-o.c	(revision 0)
+++ libiberty/objfile-mach-o.c	(revision 0)
@@ -0,0 +1,1014 @@ 
+/* objfile-mach-o.c -- routines to manipulate Mach-O object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+#include "objfile.h"
+
+#include <stddef.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "objfile-common.h"
+
+/* Mach-O structures and constants.  */
+
+/* Mach-O header (32-bit 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.  */
+};
+
+/* Mach-O header (64-bit 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.  */
+};
+
+/* For magic field in header.  */
+
+#define MACH_O_MH_MAGIC			0xfeedface
+#define MACH_O_MH_MAGIC_64		0xfeedfacf
+
+/* For filetype field in header.  */
+
+#define MACH_O_MH_OBJECT		0x01
+
+/* A Mach-O file is a list of load commands.  This is the header of a
+   load command.  */
+
+struct mach_o_load_command
+{
+  unsigned char cmd[4];		/* The type of load command.  */
+  unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
+};
+
+/* For cmd field in load command.   */
+
+#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 entire command.  */
+  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.  */
+};
+
+/* LC_SEGMENT_64 load command.  */
+
+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 entire command.  */
+  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.  */
+};
+
+/* 32-bit section header.  */
+
+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];
+};
+
+/* 64-bit section header.  */
+
+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];
+};
+
+/* Flags for Mach-O sections.  */
+
+#define MACH_O_S_ATTR_DEBUG			0x02000000
+
+/* The length of a segment or section name.  */
+
+#define MACH_O_NAME_LEN (16)
+
+/* A GNU specific extension for long section names.  */
+
+#define GNU_SECTION_NAMES "__section_names"
+
+/* Private data for an objfile_read.  */
+
+struct objfile_mach_o_read
+{
+  /* User specified segment name.  */
+  char *segment_name;
+  /* Magic number.  */
+  unsigned int magic;
+  /* Whether this file is big-endian.  */
+  int is_big_endian;
+  /* CPU type from header.  */
+  unsigned int cputype;
+  /* CPU subtype from header.  */
+  unsigned int cpusubtype;
+  /* Number of commands, from header.  */
+  unsigned int ncmds;
+  /* Flags from header.  */
+  unsigned int flags;
+  /* Reserved field from header, only used on 64-bit.  */
+  unsigned int reserved;
+};
+
+/* Private data for an objfile_attributes.  */
+
+struct objfile_mach_o_attributes
+{
+  /* Magic number.  */
+  unsigned int magic;
+  /* Whether this file is big-endian.  */
+  int is_big_endian;
+  /* CPU type from header.  */
+  unsigned int cputype;
+  /* CPU subtype from header.  */
+  unsigned int cpusubtype;
+  /* Flags from header.  */
+  unsigned int flags;
+  /* Reserved field from header, only used on 64-bit.  */
+  unsigned int reserved;
+};
+
+/* See if we have a Mach-O file.  */
+
+static void *
+objfile_mach_o_match (unsigned char header[OBJFILE_MATCH_HEADER_LEN],
+		      int descriptor, off_t offset, const char *segment_name,
+		      const char **errmsg, int *err)
+{
+  unsigned int magic;
+  int is_big_endian;
+  unsigned int (*fetch_32) (const unsigned char *);
+  unsigned int filetype;
+  struct objfile_mach_o_read *omr;
+  unsigned char buf[sizeof (struct mach_o_header_64)];
+  unsigned char *b;
+
+  magic = objfile_fetch_big_32 (header);
+  if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
+    is_big_endian = 1;
+  else
+    {
+      magic = objfile_fetch_little_32 (header);
+      if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
+	is_big_endian = 0;
+      else
+	{
+	  *errmsg = NULL;
+	  *err = 0;
+	  return NULL;
+	}
+    }
+
+#ifndef UNSIGNED_64BIT_TYPE
+  if (magic == MACH_O_MH_MAGIC_64)
+    {
+      *errmsg = "64-bit Mach-O objects not supported";
+      *err = 0;
+      return NULL;
+    }
+#endif
+
+  /* We require the user to provide a segment name.  This is
+     unfortunate but I don't see any good choices here.  */
+
+  if (segment_name == NULL)
+    {
+      *errmsg = "Mach-O file found but no segment name specified";
+      *err = 0;
+      return NULL;
+    }
+
+  if (strlen (segment_name) > MACH_O_NAME_LEN)
+    {
+      *errmsg = "Mach-O segment name too long";
+      *err = 0;
+      return NULL;
+    }
+
+  /* The 32-bit and 64-bit headers are similar enough that we can use
+     the same code.  */
+
+  fetch_32 = is_big_endian ? objfile_fetch_big_32 : objfile_fetch_little_32;
+
+  if (!objfile_internal_read (descriptor, offset, buf,
+			      (magic == MACH_O_MH_MAGIC
+			       ? sizeof (struct mach_o_header_32)
+			       : sizeof (struct mach_o_header_64)),
+			      errmsg, err))
+    return NULL;
+
+  b = &buf[0];
+
+  filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
+  if (filetype != MACH_O_MH_OBJECT)
+    {
+      *errmsg = "Mach-O file is not object file";
+      *err = 0;
+      return NULL;
+    }
+
+  omr = XNEW (struct objfile_mach_o_read);
+  omr->segment_name = xstrdup (segment_name);
+  omr->magic = magic;
+  omr->is_big_endian = is_big_endian;
+  omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
+  omr->cpusubtype = (*fetch_32) (b
+				 + offsetof (struct mach_o_header_32,
+					     cpusubtype));
+  omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
+  omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
+  if (magic == MACH_O_MH_MAGIC)
+    omr->reserved = 0;
+  else
+    omr->reserved = (*fetch_32) (b
+				 + offsetof (struct mach_o_header_64,
+					     reserved));
+
+  return (void *) omr;
+}
+
+/* Get the file offset and size from a section header.  */
+
+static void
+objfile_mach_o_section_info (int is_big_endian, int is_32,
+			     const unsigned char *sechdr, off_t *offset,
+			     size_t *size)
+{
+  unsigned int (*fetch_32) (const unsigned char *);
+  ulong_type (*fetch_64) (const unsigned char *);
+
+  fetch_32 = (is_big_endian
+	      ? objfile_fetch_big_32
+	      : objfile_fetch_little_32);
+
+  fetch_64 = NULL;
+#ifdef UNSIGNED_64BIT_TYPE
+  fetch_64 = (is_big_endian
+	      ? objfile_fetch_big_64
+	      : objfile_fetch_little_64);
+#endif
+
+  if (is_32)
+    {
+      *offset = fetch_32 (sechdr
+			  + offsetof (struct mach_o_section_32, offset));
+      *size = fetch_32 (sechdr
+			+ offsetof (struct mach_o_section_32, size));
+    }
+  else
+    {
+      *offset = fetch_32 (sechdr
+			  + offsetof (struct mach_o_section_64, offset));
+      *size = fetch_64 (sechdr
+			+ offsetof (struct mach_o_section_64, size));
+    }
+}
+
+/* Handle a segment in a Mach-O file.  Return 1 if we should continue,
+   0 if the caller should return.  */
+
+static int
+objfile_mach_o_segment (objfile_read *objfile, off_t offset,
+			const unsigned char *segbuf,
+			int (*pfn) (void *, const char *, off_t offset,
+				    off_t length),
+			void *data,
+			const char **errmsg, int *err)
+{
+  struct objfile_mach_o_read *omr =
+    (struct objfile_mach_o_read *) objfile->data;
+  unsigned int (*fetch_32) (const unsigned char *);
+  ulong_type (*fetch_64) (const unsigned char *);
+  int is_32;
+  size_t seghdrsize;
+  size_t sechdrsize;
+  size_t sectname_offset;
+  unsigned int nsects;
+  unsigned char *secdata;
+  unsigned int i;
+  unsigned int strtab_index;
+  char *strtab;
+  size_t strtab_size;
+
+  fetch_32 = (omr->is_big_endian
+	      ? objfile_fetch_big_32
+	      : objfile_fetch_little_32);
+
+  fetch_64 = NULL;
+#ifdef UNSIGNED_64BIT_TYPE
+  fetch_64 = (omr->is_big_endian
+	      ? objfile_fetch_big_64
+	      : objfile_fetch_little_64);
+#endif
+
+  is_32 = omr->magic == MACH_O_MH_MAGIC;
+
+  if (is_32)
+    {
+      seghdrsize = sizeof (struct mach_o_segment_command_32);
+      sechdrsize = sizeof (struct mach_o_section_32);
+      sectname_offset = offsetof (struct mach_o_section_32, sectname);
+      nsects = (*fetch_32) (segbuf
+			    + offsetof (struct mach_o_segment_command_32,
+					nsects));
+    }
+  else
+    {
+      seghdrsize = sizeof (struct mach_o_segment_command_64);
+      sechdrsize = sizeof (struct mach_o_section_64);
+      sectname_offset = offsetof (struct mach_o_section_64, sectname);
+      nsects = (*fetch_32) (segbuf
+			    + offsetof (struct mach_o_segment_command_64,
+					nsects));
+    }
+
+  secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
+  if (!objfile_internal_read (objfile->descriptor, offset + seghdrsize,
+			      secdata, nsects * sechdrsize, errmsg, err))
+    {
+      XDELETEVEC (secdata);
+      return 0;
+    }
+
+  /* Scan for a __section_names section.  This is in effect a GNU
+     extension that permits section names longer than 16 chars.  */
+
+  for (i = 0; i < nsects; ++i)
+    {
+      size_t nameoff;
+
+      nameoff = i * sechdrsize + sectname_offset;
+      if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
+	break;
+    }
+
+  strtab_index = i;
+  if (strtab_index >= nsects)
+    {
+      strtab = NULL;
+      strtab_size = 0;
+    }
+  else
+    {
+      off_t strtab_offset;
+
+      objfile_mach_o_section_info (omr->is_big_endian, is_32,
+				   secdata + strtab_index * sechdrsize,
+				   &strtab_offset, &strtab_size);
+      strtab = XNEWVEC (char, strtab_size);
+      if (!objfile_internal_read (objfile->descriptor, strtab_offset,
+				  (unsigned char *) strtab, strtab_size,
+				  errmsg, err))
+	{
+	  XDELETEVEC (strtab);
+	  XDELETEVEC (secdata);
+	  return 0;
+	}
+    }
+
+  /* Process the sections.  */
+
+  for (i = 0; i < nsects; ++i)
+    {
+      const unsigned char *sechdr;
+      char namebuf[MACH_O_NAME_LEN + 1];
+      char *name;
+      off_t secoffset;
+      size_t secsize;
+
+      if (i == strtab_index)
+	continue;
+
+      sechdr = secdata + i * sechdrsize;
+      memcpy (name, sechdr + sectname_offset, MACH_O_NAME_LEN);
+      namebuf[MACH_O_NAME_LEN] = '\0';
+
+      name = &namebuf[0];
+      if (strtab != NULL && name[0] == '_' && name[1] == '_')
+	{
+	  unsigned long stringoffset;
+
+	  if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
+	    {
+	      if (stringoffset >= strtab_size)
+		{
+		  *errmsg = "section name offset out of range";
+		  *err = 0;
+		  XDELETEVEC (strtab);
+		  XDELETEVEC (secdata);
+		  return 0;
+		}
+
+	      name = strtab + stringoffset;
+	    }
+	}
+
+      objfile_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
+				   &secoffset, &secsize);
+
+      if (!(*pfn) (data, name, secoffset, secsize))
+	{
+	  *errmsg = NULL;
+	  *err = 0;
+	  XDELETEVEC (strtab);
+	  XDELETEVEC (secdata);
+	  return 0;
+	}
+    }
+
+  XDELETEVEC (strtab);
+  XDELETEVEC (secdata);
+
+  return 1;
+}
+
+/* Find all sections in a Mach-O file.  */
+
+static const char *
+objfile_mach_o_find_sections (objfile_read *objfile,
+			      int (*pfn) (void *, const char *, off_t offset,
+					  off_t length),
+			      void *data,
+			      int *err)
+{
+  struct objfile_mach_o_read *omr =
+    (struct objfile_mach_o_read *) objfile->data;
+  off_t offset;
+  size_t seghdrsize;
+  unsigned int (*fetch_32) (const unsigned char *);
+  const char *errmsg;
+  unsigned int i;
+
+  if (omr->magic == MACH_O_MH_MAGIC)
+    {
+      offset = sizeof (struct mach_o_header_32);
+      seghdrsize = sizeof (struct mach_o_segment_command_32);
+    }
+  else
+    {
+      offset = sizeof (struct mach_o_header_64);
+      seghdrsize = sizeof (struct mach_o_segment_command_64);
+    }
+
+  fetch_32 = (omr->is_big_endian
+	      ? objfile_fetch_big_32
+	      : objfile_fetch_little_32);
+
+  for (i = 0; i < omr->ncmds; ++i)
+    {
+      unsigned char loadbuf[sizeof (struct mach_o_load_command)];
+      unsigned int cmd;
+      unsigned int cmdsize;
+
+      if (!objfile_internal_read (objfile->descriptor,
+				  objfile->offset + offset,
+				  loadbuf, sizeof (struct mach_o_load_command),
+				  &errmsg, err))
+	return errmsg;
+
+      cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
+      cmdsize = (*fetch_32) (loadbuf
+			     + offsetof (struct mach_o_load_command, cmdsize));
+
+      if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
+	{
+	  unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
+	  char *segname;
+
+	  if (!objfile_internal_read (objfile->descriptor, offset, segbuf,
+				      seghdrsize, &errmsg, err))
+	    return errmsg;
+
+	  /* The segment name is in the same position for both 32-bit
+	     and 64-bit.  */
+	  segname = (char *) (&segbuf[0]
+			      + offsetof (struct mach_o_segment_command_32,
+					  segname));
+	  if (strncmp (omr->segment_name, segname, MACH_O_NAME_LEN) == 0)
+	    {
+	      int r;
+
+	      r = objfile_mach_o_segment (objfile, offset, segbuf, pfn,
+					  data, &errmsg, err);
+	      if (!r)
+		return errmsg;
+
+	      /* We can probably just return NULL here.  There
+		 probably won't be another function with the same
+		 name.  */
+	    }
+	}
+
+      offset += cmdsize;
+    }
+
+  return NULL;
+}
+
+/* Fetch the attributes for an objfile_read.  */
+
+static void *
+objfile_mach_o_fetch_attributes (objfile_read *objfile,
+				 const char **errmsg ATTRIBUTE_UNUSED,
+				 int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_mach_o_read *omr =
+    (struct objfile_mach_o_read *) objfile->data;
+  struct objfile_mach_o_attributes *ret;
+
+  ret = XNEW (struct objfile_mach_o_attributes);
+  ret->magic = omr->magic;
+  ret->is_big_endian = omr->is_big_endian;
+  ret->cputype = omr->cputype;
+  ret->cpusubtype = omr->cpusubtype;
+  ret->flags = omr->flags;
+  ret->reserved = omr->reserved;
+  return ret;
+}
+
+/* Release the private data for an objfile_read.  */
+
+static void
+objfile_mach_o_release_read (void *data)
+{
+  struct objfile_mach_o_read *omr =
+    (struct objfile_mach_o_read *) data;
+
+  free (omr->segment_name);
+  XDELETE (omr);
+}
+
+/* Compare two attributes structures.  */
+
+static const char *
+objfile_mach_o_attributes_compare (void *data1, void *data2, int *err)
+{
+  struct objfile_mach_o_attributes *attrs1 =
+    (struct objfile_mach_o_attributes *) data1;
+  struct objfile_mach_o_attributes *attrs2 =
+    (struct objfile_mach_o_attributes *) data2;
+
+  if (attrs1->magic != attrs2->magic
+      || attrs1->is_big_endian != attrs2->is_big_endian
+      || attrs1->cputype != attrs2->cputype)
+    {
+      *err = 0;
+      return "Mach-O object format mismatch";
+    }
+  return NULL;
+}
+
+/* Release the private data for an attributes structure.  */
+
+static void
+objfile_mach_o_release_attributes (void *data)
+{
+  XDELETE (data);
+}
+
+/* Prepare to write out a file.  */
+
+static void *
+objfile_mach_o_start_write (void *attributes_data,
+			    const char **errmsg ATTRIBUTE_UNUSED,
+			    int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_mach_o_attributes *attrs =
+    (struct objfile_mach_o_attributes *) attributes_data;
+  struct objfile_mach_o_attributes *ret;
+
+  /* We're just going to record the attributes, but we need to make a
+     copy because the user may delete them.  */
+  ret = XNEW (struct objfile_mach_o_attributes);
+  *ret = *attrs;
+  return ret;
+}
+
+/* Write out the header of a Mach-O file.  */
+
+static int
+objfile_mach_o_write_header (objfile_write *objfile, int descriptor,
+			     size_t nsects, const char **errmsg, int *err)
+{
+  struct objfile_mach_o_attributes *attrs =
+    (struct objfile_mach_o_attributes *) objfile->data;
+  void (*set_32) (unsigned char *, unsigned int);
+  unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
+  unsigned char *hdr;
+  size_t wrsize;
+
+  set_32 = (attrs->is_big_endian
+	    ? objfile_set_big_32
+	    : objfile_set_little_32);
+
+  memset (hdrbuf, 0, sizeof hdrbuf);
+
+  /* The 32-bit and 64-bit headers start out the same.  */
+
+  hdr = &hdrbuf[0];
+  set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
+  set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
+  set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
+	  attrs->cpusubtype);
+  set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
+  set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
+  set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
+  if (attrs->magic == MACH_O_MH_MAGIC)
+    {
+      wrsize = sizeof (struct mach_o_header_32);
+      set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
+	      (sizeof (struct mach_o_segment_command_32)
+	       + nsects * sizeof (struct mach_o_section_32)));
+    }
+  else
+    {
+      set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
+	      (sizeof (struct mach_o_segment_command_64)
+	       + nsects * sizeof (struct mach_o_section_64)));
+      set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
+	      attrs->reserved);
+      wrsize = sizeof (struct mach_o_header_64);
+    }
+
+  return objfile_internal_write (descriptor, 0, hdrbuf, wrsize, errmsg, err);
+}
+
+/* Write a Mach-O section header.  */
+
+static int
+objfile_mach_o_write_section_header (objfile_write *objfile, int descriptor,
+				     size_t sechdr_offset, const char *name,
+				     size_t secaddr, size_t secsize,
+				     size_t offset, unsigned int align,
+				     const char **errmsg, int *err)
+{
+  struct objfile_mach_o_attributes *attrs =
+    (struct objfile_mach_o_attributes *) objfile->data;
+  void (*set_32) (unsigned char *, unsigned int);
+  unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
+  unsigned char *hdr;
+  size_t sechdrsize;
+
+  set_32 = (attrs->is_big_endian
+	    ? objfile_set_big_32
+	    : objfile_set_little_32);
+
+  memset (hdrbuf, 0, sizeof hdrbuf);
+
+  hdr = &hdrbuf[0];
+  if (attrs->magic == MACH_O_MH_MAGIC)
+    {
+      strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
+	       name, MACH_O_NAME_LEN);
+      strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
+	       objfile->segment_name, MACH_O_NAME_LEN);
+      set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
+      set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
+      set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
+      set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
+      /* reloff left as zero.  */
+      /* nreloc left as zero.  */
+      set_32 (hdr + offsetof (struct mach_o_section_32, flags),
+	      MACH_O_S_ATTR_DEBUG);
+      /* reserved1 left as zero.  */
+      /* reserved2 left as zero.  */
+      sechdrsize = sizeof (struct mach_o_section_32);
+    }
+  else
+    {
+#ifdef UNSIGNED_64BIT_TYPE
+      void (*set_64) (unsigned char *, ulong_type);
+
+      set_64 = (attrs->is_big_endian
+		? objfile_set_big_64
+		: objfile_set_little_64);
+
+      strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
+	       name, MACH_O_NAME_LEN);
+      strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
+	       objfile->segment_name, MACH_O_NAME_LEN);
+      set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
+      set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
+      set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
+      set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
+      /* reloff left as zero.  */
+      /* nreloc left as zero.  */
+      set_32 (hdr + offsetof (struct mach_o_section_64, flags),
+	      MACH_O_S_ATTR_DEBUG);
+      /* reserved1 left as zero.  */
+      /* reserved2 left as zero.  */
+      /* reserved3 left as zero.  */
+#endif
+      sechdrsize = sizeof (struct mach_o_section_64);
+    }
+
+  return objfile_internal_write (descriptor, sechdr_offset, hdr,
+				 sechdrsize, errmsg, err);
+}
+
+/* Write out the single segment and the sections of a Mach-O file.  */
+
+static int
+objfile_mach_o_write_segment (objfile_write *objfile, int descriptor,
+			      size_t nsects, const char **errmsg, int *err)
+{
+  struct objfile_mach_o_attributes *attrs =
+    (struct objfile_mach_o_attributes *) objfile->data;
+  void (*set_32) (unsigned char *, unsigned int);
+  size_t hdrsize;
+  size_t seghdrsize;
+  size_t sechdrsize;
+  size_t cmdsize;
+  size_t offset;
+  size_t sechdr_offset;
+  size_t secaddr;
+  unsigned int name_offset;
+  objfile_write_section *section;
+  unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
+  unsigned char *hdr;
+
+  set_32 = (attrs->is_big_endian
+	    ? objfile_set_big_32
+	    : objfile_set_little_32);
+
+  /* Write out the sections first.  */
+
+  if (attrs->magic == MACH_O_MH_MAGIC)
+    {
+      hdrsize = sizeof (struct mach_o_header_32);
+      seghdrsize = sizeof (struct mach_o_segment_command_32);
+      sechdrsize = sizeof (struct mach_o_section_32);
+    }
+  else
+    {
+      hdrsize = sizeof (struct mach_o_header_64);
+      seghdrsize = sizeof (struct mach_o_segment_command_64);
+      sechdrsize = sizeof (struct mach_o_section_64);
+    }
+
+  sechdr_offset = hdrsize + seghdrsize;
+  cmdsize = seghdrsize + nsects * sechdrsize;
+  offset = hdrsize + cmdsize;
+  name_offset = 0;
+  secaddr = 0;
+
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t mask;
+      size_t new_offset;
+      size_t secsize;
+      struct objfile_write_section_buffer *buffer;
+      char namebuf[MACH_O_NAME_LEN + 1];
+
+      mask = (1U << section->align) - 1;
+      new_offset = offset + mask;
+      new_offset &= ~ mask;
+      while (new_offset > offset)
+	{
+	  unsigned char zeroes[16];
+	  size_t write;
+
+	  memset (zeroes, 0, sizeof zeroes);
+	  write = new_offset - offset;
+	  if (write > sizeof zeroes)
+	    write = sizeof zeroes;
+	  if (!objfile_internal_write (descriptor, offset, zeroes, write,
+				       errmsg, err))
+	    return 0;
+	  offset += write;
+	}
+
+      secsize = 0;
+      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
+	{
+	  if (!objfile_internal_write (descriptor, offset + secsize,
+				       (const unsigned char *) buffer->buffer,
+				       buffer->size, errmsg, err))
+	    return 0;
+	  secsize += buffer->size;
+	}
+
+      snprintf (namebuf, sizeof namebuf, "__%08X", name_offset);
+      if (!objfile_mach_o_write_section_header (objfile, descriptor,
+						sechdr_offset, namebuf,
+						secaddr, secsize, offset,
+						section->align, errmsg, err))
+	return 0;
+
+      sechdr_offset += sechdrsize;
+      offset += secsize;
+      name_offset += strlen (section->name) + 1;
+      secaddr += secsize;
+    }
+
+  /* Write out the section names.  */
+
+  if (!objfile_mach_o_write_section_header (objfile, descriptor, sechdr_offset,
+					    GNU_SECTION_NAMES, secaddr,
+					    name_offset, offset, 0,
+					    errmsg, err))
+    return 0;
+
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t namelen;
+
+      namelen = strlen (section->name) + 1;
+      if (!objfile_internal_write (descriptor, offset,
+				   (const unsigned char *) section->name,
+				   namelen, errmsg, err))
+	return 0;
+      offset += namelen;
+    }
+
+  /* Write out the segment header.  */
+
+  memset (hdrbuf, 0, sizeof hdrbuf);
+
+  hdr = &hdrbuf[0];
+  if (attrs->magic == MACH_O_MH_MAGIC)
+    {
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
+	      MACH_O_LC_SEGMENT);
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
+	      cmdsize);
+      strncpy (((char *) hdr
+		+ offsetof (struct mach_o_segment_command_32, segname)),
+	       objfile->segment_name, MACH_O_NAME_LEN);
+      /* vmaddr left as zero.  */
+      /* vmsize left as zero.  */
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
+	      hdrsize + cmdsize);
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
+	      offset - (hdrsize + cmdsize));
+      /* maxprot left as zero.  */
+      /* initprot left as zero.  */
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
+	      nsects);
+      /* flags left as zero.  */
+    }
+  else
+    {
+#ifdef UNSIGNED_64BIT_TYPE
+      void (*set_64) (unsigned char *, ulong_type);
+
+      set_64 = (attrs->is_big_endian
+		? objfile_set_big_64
+		: objfile_set_little_64);
+
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
+	      MACH_O_LC_SEGMENT);
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
+	      cmdsize);
+      strncpy (((char *) hdr
+		+ offsetof (struct mach_o_segment_command_32, segname)),
+	       objfile->segment_name, MACH_O_NAME_LEN);
+      /* vmaddr left as zero.  */
+      /* vmsize left as zero.  */
+      set_64 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
+	      hdrsize + cmdsize);
+      set_64 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
+	      offset - (hdrsize + cmdsize));
+      /* maxprot left as zero.  */
+      /* initprot left as zero.  */
+      set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
+	      nsects);
+      /* flags left as zero.  */
+#endif
+    }
+
+  return objfile_internal_write (descriptor, hdrsize, hdr, seghdrsize,
+				 errmsg, err);
+}
+
+/* Write out a complete Mach-O file.  */
+
+static const char *
+objfile_mach_o_write_to_file (objfile_write *objfile, int descriptor, int *err)
+{
+  size_t nsects;
+  objfile_write_section *section;
+  const char *errmsg;
+
+  /* Start at 1 for symbol_names section.  */
+  nsects = 1;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    ++nsects;
+
+  if (!objfile_mach_o_write_header (objfile, descriptor, nsects, &errmsg, err))
+    return errmsg;
+
+  if (!objfile_mach_o_write_segment (objfile, descriptor, nsects, &errmsg, err))
+    return errmsg;
+
+  return NULL;
+}
+
+/* Release the private data for an objfile_write structure.  */
+
+static void
+objfile_mach_o_release_write (void *data)
+{
+  XDELETE (data);
+}
+
+/* The Mach-O functions.  */
+
+const struct objfile_functions objfile_mach_o_functions =
+{
+  objfile_mach_o_match,
+  objfile_mach_o_find_sections,
+  objfile_mach_o_fetch_attributes,
+  objfile_mach_o_release_read,
+  objfile_mach_o_attributes_compare,
+  objfile_mach_o_release_attributes,
+  objfile_mach_o_start_write,
+  objfile_mach_o_write_to_file,
+  objfile_mach_o_release_write
+};
Index: libiberty/configure.ac
===================================================================
--- libiberty/configure.ac	(revision 166002)
+++ libiberty/configure.ac	(working copy)
@@ -290,6 +290,7 @@  fi
 
 AC_TYPE_INTPTR_T
 AC_TYPE_UINTPTR_T
+AC_TYPE_SSIZE_T
 
 # Given the above check, we always have uintptr_t or a fallback
 # definition.  So define HAVE_UINTPTR_T in case any imported code
Index: libiberty/objfile-common.h
===================================================================
--- libiberty/objfile-common.h	(revision 0)
+++ libiberty/objfile-common.h	(revision 0)
@@ -0,0 +1,352 @@ 
+/* objfile-common.h -- common structs for object file manipulation.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* Forward reference.  */
+struct objfile_functions;
+
+/* An object file opened for reading.  */
+
+struct objfile_read_struct
+{
+  /* The file descriptor.  */
+  int descriptor;
+  /* The offset within the file.  */
+  off_t offset;
+  /* The functions which do the actual work.  */
+  const struct objfile_functions *functions;
+  /* Private data for the object file format.  */
+  void *data;
+};
+
+/* Object file attributes.  */
+
+struct objfile_attributes_struct
+{
+  /* The functions which do the actual work.  */
+  const struct objfile_functions *functions;
+  /* Private data for the object file format.  */
+  void *data;
+};
+
+/* An object file being created.  */
+
+struct objfile_write_struct
+{
+  /* The functions which do the actual work.  */
+  const struct objfile_functions *functions;
+  /* The segment_name argument from the user.  */
+  char *segment_name;
+  /* The start of the list of sections.  */
+  objfile_write_section *sections;
+  /* The last entry in the list of sections.  */
+  objfile_write_section *last_section;
+  /* Private data for the object file format.  */
+  void *data;
+};
+
+/* A section in an object file being created.  */
+
+struct objfile_write_section_struct
+{
+  /* Next in the list of sections attached to an objfile_write.  */
+  objfile_write_section *next;
+  /* The name of this section.  */
+  char *name;
+  /* The required alignment.  */
+  unsigned int align;
+  /* The first data attached to this section.  */
+  struct objfile_write_section_buffer *buffers;
+  /* The last data attached to this section.  */
+  struct objfile_write_section_buffer *last_buffer;
+};
+
+/* Data attached to a section.  */
+
+struct objfile_write_section_buffer
+{
+  /* The next data for this section.  */
+  struct objfile_write_section_buffer *next;
+  /* The size of the buffer.  */
+  size_t size;
+  /* The actual bytes.  */
+  const void *buffer;
+  /* A buffer to free, or NULL.  */
+  void *free_buffer;
+};
+
+/* The number of bytes we read from the start of the file to pass to
+   the match function.  */
+#define OBJFILE_MATCH_HEADER_LEN (16)
+
+/* Format-specific object file functions.  */
+
+struct objfile_functions
+{
+  /* If this file matches these functions, return a new value for the
+     private data for an objfile_read.  HEADER is the first 16 bytes
+     of the file.  DESCRIPTOR, OFFSET, SEGMENT_NAME, ERRMSG, and ERR
+     are as for objfile_open_read.  If this file does not match, this
+     function should return NULL with *ERRMSG set to NULL.  */
+  void *(*match) (unsigned char header[OBJFILE_MATCH_HEADER_LEN],
+		  int descriptor, off_t offset, const char *segment_name,
+		  const char **errmsg, int *err);
+
+  /* Implement objfile_find_sections.  */
+  const char *(*find_sections) (objfile_read *,
+				int (*pfn) (void *, const char *,
+					    off_t offset, off_t length),
+				void *data,
+				int *err);
+
+  /* Return the private data for the attributes for OBJFILE.  */
+  void *(*fetch_attributes) (objfile_read *objfile, const char **errmsg,
+			     int *err);
+
+  /* Release the private data for an objfile_read.  */
+  void (*release_read) (void *);
+
+  /* Compare the private data for the attributes of two files.  If
+     they are the same, in the sense that they could be linked
+     together, return NULL.  Otherwise return an error message.  */
+  const char *(*attributes_compare) (void *, void *, int *err);
+
+  /* Release the private data for an objfile_attributes.  */
+  void (*release_attributes) (void *);
+
+  /* Start creating an object file.  */
+  void *(*start_write) (void *attributes_data, const char **errmsg,
+			int *err);
+
+  /* Write the complete object file.  */
+  const char *(*write_to_file) (objfile_write *objfile, int descriptor,
+				int *err);
+
+  /* Release the private data for an objfile_write.  */
+  void (*release_write) (void *);
+};
+
+/* The known object file formats.  */
+
+extern const struct objfile_functions objfile_coff_functions;
+extern const struct objfile_functions objfile_elf_functions;
+extern const struct objfile_functions objfile_mach_o_functions;
+
+/* Read SIZE bytes from DESCRIPTOR at file offset OFFSET into BUFFER.
+   Return non-zero on success.  On failure return 0 and set *ERRMSG
+   and *ERR.  */
+
+extern int
+objfile_internal_read (int descriptor, off_t offset, unsigned char *buffer,
+		       size_t size, const char **errmsg, int *err);
+
+/* Write SIZE bytes from BUFFER to DESCRIPTOR at file offset OFFSET.
+   Return non-zero on success.  On failure return 0 and set *ERRMSG
+   and *ERR.  */
+
+extern int
+objfile_internal_write (int descriptor, off_t offset,
+			const unsigned char *buffer, size_t size,
+			const char **errmsg, int *err);
+
+/* Define ulong_type as an unsigned 64-bit type if available.
+   Otherwise just make it unsigned long.  */
+
+#ifdef UNSIGNED_64BIT_TYPE
+__extension__ typedef UNSIGNED_64BIT_TYPE ulong_type;
+#else
+typedef unsigned long ulong_type;
+#endif
+
+/* Fetch a big-endian 16-bit value.  */
+
+static inline unsigned short
+objfile_fetch_big_16 (const unsigned char *buf)
+{
+  return ((unsigned short) buf[0] << 8) | (unsigned short) buf[1];
+}
+
+/* Fetch a little-endian 16-bit value.  */
+
+static inline unsigned short
+objfile_fetch_little_16 (const unsigned char *buf)
+{
+  return ((unsigned short) buf[1] << 8) | (unsigned short) buf[0];
+}
+
+/* Fetch a big-endian 32-bit value.  */
+
+static inline unsigned int
+objfile_fetch_big_32 (const unsigned char *buf)
+{
+  return (((unsigned int) buf[0] << 24)
+	  | ((unsigned int) buf[1] << 16)
+	  | ((unsigned int) buf[2] << 8)
+	  | (unsigned int) buf[3]);
+}
+
+/* Fetch a little-endian 32-bit value.  */
+
+static inline unsigned int
+objfile_fetch_little_32 (const unsigned char *buf)
+{
+  return (((unsigned int) buf[3] << 24)
+	  | ((unsigned int) buf[2] << 16)
+	  | ((unsigned int) buf[1] << 8)
+	  | (unsigned int) buf[0]);
+}
+
+/* Fetch a big-endian 32-bit value as a ulong_type.  */
+
+static inline ulong_type
+objfile_fetch_big_32_ulong (const unsigned char *buf)
+{
+  return (ulong_type) objfile_fetch_big_32 (buf);
+}
+
+/* Fetch a little-endian 32-bit value as a ulong_type.  */
+
+static inline ulong_type
+objfile_fetch_little_32_ulong (const unsigned char *buf)
+{
+  return (ulong_type) objfile_fetch_little_32 (buf);
+}
+
+#ifdef UNSIGNED_64BIT_TYPE
+
+/* Fetch a big-endian 64-bit value.  */
+
+static inline ulong_type
+objfile_fetch_big_64 (const unsigned char *buf)
+{
+  return (((ulong_type) buf[0] << 56)
+	  | ((ulong_type) buf[1] << 48)
+	  | ((ulong_type) buf[2] << 40)
+	  | ((ulong_type) buf[3] << 32)
+	  | ((ulong_type) buf[4] << 24)
+	  | ((ulong_type) buf[5] << 16)
+	  | ((ulong_type) buf[6] << 8)
+	  | (ulong_type) buf[7]);
+}
+
+/* Fetch a little-endian 64-bit value.  */
+
+static inline ulong_type
+objfile_fetch_little_64 (const unsigned char *buf)
+{
+  return (((ulong_type) buf[7] << 56)
+	  | ((ulong_type) buf[6] << 48)
+	  | ((ulong_type) buf[5] << 40)
+	  | ((ulong_type) buf[4] << 32)
+	  | ((ulong_type) buf[3] << 24)
+	  | ((ulong_type) buf[2] << 16)
+	  | ((ulong_type) buf[1] << 8)
+	  | (ulong_type) buf[0]);
+}
+
+#endif
+
+/* Store a big-endian 16-bit value.  */
+
+static inline void
+objfile_set_big_16 (unsigned char *buf, unsigned short val)
+{
+  buf[0] = (val >> 8) & 0xff;
+  buf[1] = val & 0xff;
+}
+
+/* Store a little-endian 16-bit value.  */
+
+static inline void
+objfile_set_little_16 (unsigned char *buf, unsigned short val)
+{
+  buf[1] = (val >> 8) & 0xff;
+  buf[0] = val & 0xff;
+}
+
+/* Store a big-endian 32-bit value.  */
+
+static inline void
+objfile_set_big_32 (unsigned char *buf, unsigned int val)
+{
+  buf[0] = (val >> 24) & 0xff;
+  buf[1] = (val >> 16) & 0xff;
+  buf[2] = (val >> 8) & 0xff;
+  buf[3] = val & 0xff;
+}
+
+/* Store a little-endian 32-bit value.  */
+
+static inline void
+objfile_set_little_32 (unsigned char *buf, unsigned int val)
+{
+  buf[3] = (val >> 24) & 0xff;
+  buf[2] = (val >> 16) & 0xff;
+  buf[1] = (val >> 8) & 0xff;
+  buf[0] = val & 0xff;
+}
+
+/* Store a big-endian 32-bit value coming in as a ulong_type.  */
+
+static inline void
+objfile_set_big_32_ulong (unsigned char *buf, ulong_type val)
+{
+  objfile_set_big_32 (buf, val);
+}
+
+/* Store a little-endian 32-bit value coming in as a ulong_type.  */
+
+static inline void
+objfile_set_little_32_ulong (unsigned char *buf, ulong_type val)
+{
+  objfile_set_little_32 (buf, val);
+}
+
+#ifdef UNSIGNED_64BIT_TYPE
+
+/* Store a big-endian 64-bit value.  */
+
+static inline void
+objfile_set_big_64 (unsigned char *buf, ulong_type val)
+{
+  buf[0] = (val >> 56) & 0xff;
+  buf[1] = (val >> 48) & 0xff;
+  buf[2] = (val >> 40) & 0xff;
+  buf[3] = (val >> 32) & 0xff;
+  buf[4] = (val >> 24) & 0xff;
+  buf[5] = (val >> 16) & 0xff;
+  buf[6] = (val >> 8) & 0xff;
+  buf[7] = val & 0xff;
+}
+
+/* Store a little-endian 64-bit value.  */
+
+static inline void
+objfile_set_little_64 (unsigned char *buf, ulong_type val)
+{
+  buf[7] = (val >> 56) & 0xff;
+  buf[6] = (val >> 48) & 0xff;
+  buf[5] = (val >> 40) & 0xff;
+  buf[4] = (val >> 32) & 0xff;
+  buf[3] = (val >> 24) & 0xff;
+  buf[2] = (val >> 16) & 0xff;
+  buf[1] = (val >> 8) & 0xff;
+  buf[0] = val & 0xff;
+}
+
+#endif
Index: libiberty/objfile.c
===================================================================
--- libiberty/objfile.c	(revision 0)
+++ libiberty/objfile.c	(revision 0)
@@ -0,0 +1,418 @@ 
+/* objfile.c -- routines to manipulate object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+#include "objfile.h"
+
+#include <errno.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#include "objfile-common.h"
+
+/* The known object file formats.  */
+
+static const struct objfile_functions * const format_functions[] =
+{
+  &objfile_elf_functions,
+  &objfile_mach_o_functions,
+  &objfile_coff_functions
+};
+
+/* Read data from a file using the objfile error reporting
+   conventions.  */
+
+int
+objfile_internal_read (int descriptor, off_t offset, unsigned char *buffer,
+		       size_t size, const char **errmsg, int *err)
+{
+  ssize_t got;
+
+  if (lseek (descriptor, offset, SEEK_SET) < 0)
+    {
+      *errmsg = "lseek";
+      *err = errno;
+      return 0;
+    }
+
+  got = read (descriptor, buffer, size);
+  if (got < 0)
+    {
+      *errmsg = "read";
+      *err = errno;
+      return 0;
+    }
+
+  if ((size_t) got < size)
+    {
+      *errmsg = "file too short";
+      *err = 0;
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Write data to a file using the objfile error reporting
+   conventions.  */
+
+int
+objfile_internal_write (int descriptor, off_t offset,
+			const unsigned char *buffer, size_t size,
+			const char **errmsg, int *err)
+{
+  ssize_t wrote;
+
+  if (lseek (descriptor, offset, SEEK_SET) < 0)
+    {
+      *errmsg = "lseek";
+      *err = errno;
+      return 0;
+    }
+
+  wrote = write (descriptor, buffer, size);
+  if (wrote < 0)
+    {
+      *errmsg = "write";
+      *err = errno;
+      return 0;
+    }
+
+  if ((size_t) wrote < size)
+    {
+      *errmsg = "short write";
+      *err = 0;
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Open for read.  */
+
+objfile_read *
+objfile_open_read (int descriptor, off_t offset, const char *segment_name,
+		   const char **errmsg, int *err)
+{
+  unsigned char header[OBJFILE_MATCH_HEADER_LEN];
+  size_t len, i;
+
+  if (!objfile_internal_read (descriptor, offset, header,
+			      OBJFILE_MATCH_HEADER_LEN,
+			      errmsg, err))
+    return NULL;
+
+  len = sizeof (format_functions) / sizeof (format_functions[0]);
+  for (i = 0; i < len; ++i)
+    {
+      void *data;
+
+      data = format_functions[i]->match (header, descriptor, offset,
+					 segment_name, errmsg, err);
+      if (data != NULL)
+	{
+	  objfile_read *ret;
+
+	  ret = XNEW (objfile_read);
+	  ret->descriptor = descriptor;
+	  ret->offset = offset;
+	  ret->functions = format_functions[i];
+	  ret->data = data;
+	  return ret;
+	}
+    }
+
+  *errmsg = "file not recognized";
+  *err = 0;
+  return NULL;
+}
+
+/* Find all sections.  */
+
+const char *
+objfile_find_sections (objfile_read *objfile,
+		       int (*pfn) (void *, const char *, off_t, off_t),
+		       void *data,
+		       int *err)
+{
+  return objfile->functions->find_sections (objfile, pfn, data, err);
+}
+
+/* Internal data passed to find_one_section.  */
+
+struct find_one_section_data
+{
+  /* The section we are looking for.  */
+  const char *name;
+  /* Where to store the section offset.  */
+  off_t *offset;
+  /* Where to store the section length.  */
+  off_t *length;
+  /* Set if the name is found.  */
+  int found;
+};
+
+/* Internal function passed to find_sections.  */
+
+static int
+find_one_section (void *data, const char *name, off_t offset, off_t length)
+{
+  struct find_one_section_data *fosd = (struct find_one_section_data *) data;
+
+  if (strcmp (name, fosd->name) != 0)
+    return 1;
+
+  *fosd->offset = offset;
+  *fosd->length = length;
+  fosd->found = 1;
+
+  /* Stop iteration.  */
+  return 0;
+}
+
+/* Find a section.  */
+
+int
+objfile_find_section (objfile_read *objfile, const char *name,
+		      off_t *offset, off_t *length,
+		      const char **errmsg, int *err)
+{
+  struct find_one_section_data fosd;
+
+  fosd.name = name;
+  fosd.offset = offset;
+  fosd.length = length;
+  fosd.found = 0;
+
+  *errmsg = objfile_find_sections (objfile, find_one_section,
+				   (void *) &fosd, err);
+  if (*errmsg != NULL)
+    return 0;
+  if (!fosd.found)
+    return 0;
+  return 1;
+}
+
+/* Fetch attributes.  */
+
+objfile_attributes *
+objfile_fetch_attributes (objfile_read *objfile, const char **errmsg,
+			  int *err)
+{
+  void *data;
+  objfile_attributes *ret;
+
+  data = objfile->functions->fetch_attributes (objfile, errmsg, err);
+  if (data == NULL)
+    return NULL;
+  ret = XNEW (objfile_attributes);
+  ret->functions = objfile->functions;
+  ret->data = data;
+  return ret;
+}
+
+/* Release an objfile_read.  */
+
+void
+objfile_release_read (objfile_read *objfile)
+{
+  objfile->functions->release_read (objfile->data);
+  XDELETE (objfile);
+}
+
+/* Compare attributes.  */
+
+const char *
+objfile_attributes_compare (objfile_attributes *attrs1,
+			    objfile_attributes *attrs2,
+			    int *err)
+{
+  if (attrs1->functions != attrs2->functions)
+    {
+      *err = 0;
+      return "different object file format";
+    }
+  return attrs1->functions->attributes_compare (attrs1->data, attrs2->data,
+						err);
+}
+
+/* Release an attributes structure.  */
+
+void
+objfile_release_attributes (objfile_attributes *attrs)
+{
+  attrs->functions->release_attributes (attrs->data);
+  XDELETE (attrs);
+}
+
+/* Start creating an object file.  */
+
+objfile_write *
+objfile_start_write (objfile_attributes *attrs, const char *segment_name,
+		     const char **errmsg, int *err)
+{
+  void *data;
+  objfile_write *ret;
+
+  data = attrs->functions->start_write (attrs->data, errmsg, err);
+  if (data == NULL)
+    return NULL;
+  ret = XNEW (objfile_write);
+  ret->functions = attrs->functions;
+  ret->segment_name = xstrdup (segment_name);
+  ret->sections = NULL;
+  ret->last_section = NULL;
+  ret->data = data;
+  return ret;
+}
+
+/* Start creating a section.  */
+
+objfile_write_section *
+objfile_write_create_section (objfile_write *objfile, const char *name,
+			      unsigned int align,
+			      const char **errmsg ATTRIBUTE_UNUSED,
+			      int *err ATTRIBUTE_UNUSED)
+{
+  objfile_write_section *ret;
+
+  ret = XNEW (objfile_write_section);
+  ret->next = NULL;
+  ret->name = xstrdup (name);
+  ret->align = align;
+  ret->buffers = NULL;
+  ret->last_buffer = NULL;
+
+  if (objfile->last_section == NULL)
+    {
+      objfile->sections = ret;
+      objfile->last_section = ret;
+    }
+  else
+    {
+      objfile->last_section->next = ret;
+      objfile->last_section = ret;
+    }
+
+  return ret;
+}
+
+/* Add data to a section.  */
+
+const char *
+objfile_write_add_data (objfile_write *objfile ATTRIBUTE_UNUSED,
+			objfile_write_section *section, const void *buffer,
+			size_t size, int copy,
+			int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_write_section_buffer *wsb;
+
+  wsb = XNEW (struct objfile_write_section_buffer);
+  wsb->next = NULL;
+  wsb->size = size;
+
+  if (!copy)
+    {
+      wsb->buffer = buffer;
+      wsb->free_buffer = NULL;
+    }
+  else
+    {
+      wsb->free_buffer = (void *) XNEWVEC (char, size);
+      memcpy (wsb->free_buffer, buffer, size);
+      wsb->buffer = wsb->free_buffer;
+    }
+
+  if (section->last_buffer == NULL)
+    {
+      section->buffers = wsb;
+      section->last_buffer = wsb;
+    }
+  else
+    {
+      section->last_buffer->next = wsb;
+      section->last_buffer = wsb;
+    }
+
+  return NULL;
+}
+
+/* Write the complete object file.  */
+
+const char *
+objfile_write_to_file (objfile_write *objfile, int descriptor, int *err)
+{
+  return objfile->functions->write_to_file (objfile, descriptor, err);
+}
+
+/* Release an objfile_write.  */
+
+void
+objfile_release_write (objfile_write *objfile)
+{
+  objfile_write_section *section;
+
+  free (objfile->segment_name);
+
+  section = objfile->sections;
+  while (section != NULL)
+    {
+      struct objfile_write_section_buffer *buffer;
+      objfile_write_section *next_section;
+
+      buffer = section->buffers;
+      while (buffer != NULL)
+	{
+	  struct objfile_write_section_buffer *next_buffer;
+
+	  if (buffer->free_buffer != NULL)
+	    XDELETEVEC (buffer->free_buffer);
+	  next_buffer = buffer->next;
+	  XDELETE (buffer);
+	  buffer = next_buffer;
+	}
+
+      next_section = section->next;
+      free (section->name);
+      XDELETE (section);
+      section = next_section;
+    }
+
+  objfile->functions->release_write (objfile->data);
+  XDELETE (objfile);
+}
Index: libiberty/Makefile.in
===================================================================
--- libiberty/Makefile.in	(revision 166002)
+++ libiberty/Makefile.in	(working copy)
@@ -138,7 +138,9 @@  CFILES = alloca.c argv.c asprintf.c atex
 	make-relative-prefix.c						\
 	make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmem.c	\
 	 memmove.c mempcpy.c memset.c mkstemps.c			\
-	objalloc.c obstack.c						\
+	objalloc.c							\
+	 objfile.c objfile-coff.c objfile-elf.c objfile-mach-o.c	\
+	 obstack.c							\
 	partition.c pexecute.c						\
 	 pex-common.c pex-djgpp.c pex-msdos.c pex-one.c			\
 	 pex-unix.c pex-win32.c						\
@@ -172,7 +174,10 @@  REQUIRED_OFILES =							\
 	./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext)	\
 	./lbasename.$(objext) ./lrealpath.$(objext)			\
 	./make-relative-prefix.$(objext) ./make-temp-file.$(objext)	\
-	./objalloc.$(objext) ./obstack.$(objext)			\
+	./objalloc.$(objext)						\
+	./objfile.$(objext) ./objfile-coff.$(objext)			\
+	./objfile-elf.$(objext)	./objfile-mach-o.$(objext)		\
+	./obstack.$(objext)						\
 	./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext)	\
 	./pex-common.$(objext) ./pex-one.$(objext)			\
 	./@pexecute@.$(objext)						\
@@ -833,6 +838,38 @@  $(CONFIGURED_OFILES): stamp-picdir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/objalloc.c $(OUTPUT_OPTION)
 
+./objfile-coff.$(objext): $(srcdir)/objfile-coff.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h $(srcdir)/objfile-common.h \
+	$(INCDIR)/objfile.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/objfile-coff.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/objfile-coff.c $(OUTPUT_OPTION)
+
+./objfile-elf.$(objext): $(srcdir)/objfile-elf.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h $(srcdir)/objfile-common.h \
+	$(INCDIR)/objfile.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/objfile-elf.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/objfile-elf.c $(OUTPUT_OPTION)
+
+./objfile-mach-o.$(objext): $(srcdir)/objfile-mach-o.c config.h \
+	$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
+	$(srcdir)/objfile-common.h $(INCDIR)/objfile.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/objfile-mach-o.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/objfile-mach-o.c $(OUTPUT_OPTION)
+
+./objfile.$(objext): $(srcdir)/objfile.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h $(srcdir)/objfile-common.h \
+	$(INCDIR)/objfile.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/objfile.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/objfile.c $(OUTPUT_OPTION)
+
 ./obstack.$(objext): $(srcdir)/obstack.c config.h $(INCDIR)/obstack.h
 	if [ x"$(PICFLAG)" != x ]; then \
 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/obstack.c -o pic/$@; \
Index: libiberty/objfile-elf.c
===================================================================
--- libiberty/objfile-elf.c	(revision 0)
+++ libiberty/objfile-elf.c	(revision 0)
@@ -0,0 +1,909 @@ 
+/* objfile-elf.c -- routines to manipulate ELF object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+#include "objfile.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "objfile-common.h"
+
+/* ELF structures and constants.  */
+
+/* 32-bit ELF file header.  */
+
+typedef struct {
+  unsigned char	e_ident[16];		/* ELF "magic number" */
+  unsigned char	e_type[2];		/* Identifies object file type */
+  unsigned char	e_machine[2];		/* Specifies required architecture */
+  unsigned char	e_version[4];		/* Identifies object file version */
+  unsigned char	e_entry[4];		/* Entry point virtual address */
+  unsigned char	e_phoff[4];		/* Program header table file offset */
+  unsigned char	e_shoff[4];		/* Section header table file offset */
+  unsigned char	e_flags[4];		/* Processor-specific flags */
+  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
+  unsigned char	e_phentsize[2];		/* Program header table entry size */
+  unsigned char	e_phnum[2];		/* Program header table entry count */
+  unsigned char	e_shentsize[2];		/* Section header table entry size */
+  unsigned char	e_shnum[2];		/* Section header table entry count */
+  unsigned char	e_shstrndx[2];		/* Section header string table index */
+} Elf32_External_Ehdr;
+
+/* 64-bit ELF file header.  */
+
+typedef struct {
+  unsigned char	e_ident[16];		/* ELF "magic number" */
+  unsigned char	e_type[2];		/* Identifies object file type */
+  unsigned char	e_machine[2];		/* Specifies required architecture */
+  unsigned char	e_version[4];		/* Identifies object file version */
+  unsigned char	e_entry[8];		/* Entry point virtual address */
+  unsigned char	e_phoff[8];		/* Program header table file offset */
+  unsigned char	e_shoff[8];		/* Section header table file offset */
+  unsigned char	e_flags[4];		/* Processor-specific flags */
+  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
+  unsigned char	e_phentsize[2];		/* Program header table entry size */
+  unsigned char	e_phnum[2];		/* Program header table entry count */
+  unsigned char	e_shentsize[2];		/* Section header table entry size */
+  unsigned char	e_shnum[2];		/* Section header table entry count */
+  unsigned char	e_shstrndx[2];		/* Section header string table index */
+} Elf64_External_Ehdr;
+
+/* Indexes and values in e_ident field of Ehdr.  */
+
+#define EI_MAG0		0	/* File identification byte 0 index */
+#define ELFMAG0		   0x7F	/* Magic number byte 0 */
+
+#define EI_MAG1		1	/* File identification byte 1 index */
+#define ELFMAG1		    'E'	/* Magic number byte 1 */
+
+#define EI_MAG2		2	/* File identification byte 2 index */
+#define ELFMAG2		    'L'	/* Magic number byte 2 */
+
+#define EI_MAG3		3	/* File identification byte 3 index */
+#define ELFMAG3		    'F'	/* Magic number byte 3 */
+
+#define EI_CLASS	4	/* File class */
+#define ELFCLASSNONE	      0	/* Invalid class */
+#define ELFCLASS32	      1	/* 32-bit objects */
+#define ELFCLASS64	      2	/* 64-bit objects */
+
+#define EI_DATA		5	/* Data encoding */
+#define ELFDATANONE	      0	/* Invalid data encoding */
+#define ELFDATA2LSB	      1	/* 2's complement, little endian */
+#define ELFDATA2MSB	      2	/* 2's complement, big endian */
+
+#define EI_VERSION	6	/* File version */
+#define EV_CURRENT	1		/* Current version */
+
+#define EI_OSABI	7	/* Operating System/ABI indication */
+
+/* Values for e_type field of Ehdr.  */
+
+#define ET_REL		1	/* Relocatable file */
+
+/* Special section index values.  */
+
+#define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
+#define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
+
+/* 32-bit ELF program header.  */
+
+typedef struct {
+  unsigned char	p_type[4];		/* Identifies program segment type */
+  unsigned char	p_offset[4];		/* Segment file offset */
+  unsigned char	p_vaddr[4];		/* Segment virtual address */
+  unsigned char	p_paddr[4];		/* Segment physical address */
+  unsigned char	p_filesz[4];		/* Segment size in file */
+  unsigned char	p_memsz[4];		/* Segment size in memory */
+  unsigned char	p_flags[4];		/* Segment flags */
+  unsigned char	p_align[4];		/* Segment alignment, file & memory */
+} Elf32_External_Phdr;
+
+/* 64-bit ELF program header.  */
+
+typedef struct {
+  unsigned char	p_type[4];		/* Identifies program segment type */
+  unsigned char	p_flags[4];		/* Segment flags */
+  unsigned char	p_offset[8];		/* Segment file offset */
+  unsigned char	p_vaddr[8];		/* Segment virtual address */
+  unsigned char	p_paddr[8];		/* Segment physical address */
+  unsigned char	p_filesz[8];		/* Segment size in file */
+  unsigned char	p_memsz[8];		/* Segment size in memory */
+  unsigned char	p_align[8];		/* Segment alignment, file & memory */
+} Elf64_External_Phdr;
+
+/* 32-bit ELF section header */
+
+typedef struct {
+  unsigned char	sh_name[4];		/* Section name, index in string tbl */
+  unsigned char	sh_type[4];		/* Type of section */
+  unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
+  unsigned char	sh_addr[4];		/* Section virtual addr at execution */
+  unsigned char	sh_offset[4];		/* Section file offset */
+  unsigned char	sh_size[4];		/* Size of section in bytes */
+  unsigned char	sh_link[4];		/* Index of another section */
+  unsigned char	sh_info[4];		/* Additional section information */
+  unsigned char	sh_addralign[4];	/* Section alignment */
+  unsigned char	sh_entsize[4];		/* Entry size if section holds table */
+} Elf32_External_Shdr;
+
+/* 64-bit ELF section header.  */
+
+typedef struct {
+  unsigned char	sh_name[4];		/* Section name, index in string tbl */
+  unsigned char	sh_type[4];		/* Type of section */
+  unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
+  unsigned char	sh_addr[8];		/* Section virtual addr at execution */
+  unsigned char	sh_offset[8];		/* Section file offset */
+  unsigned char	sh_size[8];		/* Size of section in bytes */
+  unsigned char	sh_link[4];		/* Index of another section */
+  unsigned char	sh_info[4];		/* Additional section information */
+  unsigned char	sh_addralign[8];	/* Section alignment */
+  unsigned char	sh_entsize[8];		/* Entry size if section holds table */
+} Elf64_External_Shdr;
+
+/* Values for sh_type field.  */
+
+#define SHT_PROGBITS	1		/* Program data */
+#define SHT_STRTAB	3		/* A string table */
+
+/* Functions to fetch and store different ELF types, depending on the
+   endianness and size.  */
+
+struct elf_type_functions
+{
+  unsigned short (*fetch_Elf_Half) (const unsigned char *);
+  unsigned int (*fetch_Elf_Word) (const unsigned char *);
+  ulong_type (*fetch_Elf_Addr) (const unsigned char *);
+  void (*set_Elf_Half) (unsigned char *, unsigned short);
+  void (*set_Elf_Word) (unsigned char *, unsigned int);
+  void (*set_Elf_Addr) (unsigned char *, ulong_type);
+};
+
+static const struct elf_type_functions elf_big_32_functions =
+{
+  objfile_fetch_big_16,
+  objfile_fetch_big_32,
+  objfile_fetch_big_32_ulong,
+  objfile_set_big_16,
+  objfile_set_big_32,
+  objfile_set_big_32_ulong
+};
+
+static const struct elf_type_functions elf_little_32_functions =
+{
+  objfile_fetch_little_16,
+  objfile_fetch_little_32,
+  objfile_fetch_little_32_ulong,
+  objfile_set_little_16,
+  objfile_set_little_32,
+  objfile_set_little_32_ulong
+};
+
+#ifdef UNSIGNED_64BIT_TYPE
+
+static const struct elf_type_functions elf_big_64_functions =
+{
+  objfile_fetch_big_16,
+  objfile_fetch_big_32,
+  objfile_fetch_big_64,
+  objfile_set_big_16,
+  objfile_set_big_32,
+  objfile_set_big_64
+};
+
+static const struct elf_type_functions elf_little_64_functions =
+{
+  objfile_fetch_little_16,
+  objfile_fetch_little_32,
+  objfile_fetch_little_64,
+  objfile_set_little_16,
+  objfile_set_little_32,
+  objfile_set_little_64
+};
+
+#endif
+
+/* Hideous macro to fetch the value of a field from an external ELF
+   struct of some sort.  TYPEFUNCS is the set of type functions.
+   BUFFER points to the external data.  STRUCTTYPE is the appropriate
+   struct type.  FIELD is a field within the struct.  TYPE is the type
+   of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
+
+#define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
+  ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
+
+/* Even more hideous macro to fetch the value of FIELD from BUFFER.
+   SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
+   elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
+   the struct.  TYPE is the type of the field in the struct: Elf_Half,
+   Elf_Word, or Elf_Addr.  */
+
+#define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
+			      FIELD, TYPE)				\
+  ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
+			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
+			  FIELD, BUFFER, TYPE)
+
+/* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
+
+#define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
+			FIELD, TYPE)					\
+  ((CLASS) == ELFCLASS32						\
+    ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
+			     TYPE)					\
+    : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
+			     TYPE))
+
+/* Hideous macro to set the value of a field in an external ELF
+   structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
+   points to the external data.  STRUCTTYPE is the appropriate
+   structure type.  FIELD is a field within the struct.  TYPE is the
+   type of the field in the struct: Elf_Half, Elf_Word, or
+   Elf_Addr.  */
+
+#define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
+  (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
+
+/* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
+   SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
+   elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
+   the struct.  TYPE is the type of the field in the struct: Elf_Half,
+   Elf_Word, or Elf_Addr.  */
+
+#define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
+			    TYPE, VAL)					\
+  ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
+			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
+			FIELD, BUFFER, TYPE, VAL)
+
+/* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
+
+#define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
+		      TYPE, VAL)					\
+  ((CLASS) == ELFCLASS32						\
+    ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
+			   TYPE, VAL)					\
+    : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
+			   TYPE, VAL))
+
+/* Private data for an objfile_read.  */
+
+struct objfile_elf_read
+{
+  /* Type functions.  */
+  const struct elf_type_functions* type_functions;
+  /* Elf data.  */
+  unsigned char ei_data;
+  /* Elf class.  */
+  unsigned char ei_class;
+  /* ELF OS ABI.  */
+  unsigned char ei_osabi;
+  /* Elf machine number.  */
+  unsigned short machine;
+  /* Processor specific flags.  */
+  unsigned int flags;
+  /* File offset of section headers.  */
+  ulong_type shoff;
+  /* Number of sections.  */
+  unsigned int shnum;
+  /* Index of string table section header.  */
+  unsigned int shstrndx;
+};
+
+/* Private data for an objfile_attributes.  */
+
+struct objfile_elf_attributes
+{
+  /* Type functions.  */
+  const struct elf_type_functions* type_functions;
+  /* Elf data.  */
+  unsigned char ei_data;
+  /* Elf class.  */
+  unsigned char ei_class;
+  /* ELF OS ABI.  */
+  unsigned char ei_osabi;
+  /* Elf machine number.  */
+  unsigned short machine;
+  /* Processor specific flags.  */
+  unsigned int flags;
+};
+
+/* See if we have an ELF file.  */
+
+static void *
+objfile_elf_match (unsigned char header[OBJFILE_MATCH_HEADER_LEN],
+		   int descriptor, off_t offset,
+		   const char *segment_name ATTRIBUTE_UNUSED,
+		   const char **errmsg, int *err)
+{
+  unsigned char ei_data;
+  unsigned char ei_class;
+  const struct elf_type_functions *type_functions;
+  unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
+  struct objfile_elf_read *eor;
+
+  if (header[EI_MAG0] != ELFMAG0
+      || header[EI_MAG1] != ELFMAG1
+      || header[EI_MAG2] != ELFMAG2
+      || header[EI_MAG3] != ELFMAG3
+      || header[EI_VERSION] != EV_CURRENT)
+    {
+      *errmsg = NULL;
+      *err = 0;
+      return NULL;
+    }
+
+  ei_data = header[EI_DATA];
+  if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
+    {
+      *errmsg = "unknown ELF endianness";
+      *err = 0;
+      return NULL;
+    }
+
+  ei_class = header[EI_CLASS];
+  switch (ei_class)
+    {
+    case ELFCLASS32:
+      type_functions = (ei_data == ELFDATA2LSB
+			? &elf_little_32_functions
+			: &elf_big_32_functions);
+      break;
+
+    case ELFCLASS64:
+#ifndef UNSIGNED_64BIT_TYPE
+      *errmsg = "64-bit ELF objects not supported";
+      *err = 0;
+      return NULL;
+#else
+      type_functions = (ei_data == ELFDATA2LSB
+			? &elf_little_64_functions
+			: &elf_big_64_functions);
+      break;
+#endif
+
+    default:
+      *errmsg = "unrecognized ELF size";
+      *err = 0;
+      return NULL;
+    }
+
+  if (!objfile_internal_read (descriptor, offset, ehdr, sizeof ehdr,
+			      errmsg, err))
+    return NULL;
+
+  eor = XNEW (struct objfile_elf_read);
+  eor->type_functions = type_functions;
+  eor->ei_data = ei_data;
+  eor->ei_class = ei_class;
+  eor->ei_osabi = header[EI_OSABI];
+  eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
+				  e_machine, Elf_Half);
+  eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
+				e_flags, Elf_Word);
+  eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
+				e_shoff, Elf_Addr);
+  eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
+				e_shnum, Elf_Half);
+  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
+				   e_shstrndx, Elf_Half);
+
+  if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
+      && eor->shoff != 0)
+    {
+      unsigned char shdr[sizeof (Elf64_External_Shdr)];
+
+      /* Object file has more than 0xffff sections.  */
+
+      if (!objfile_internal_read (descriptor, offset + eor->shoff, shdr,
+				  (ei_class == ELFCLASS32
+				   ? sizeof (Elf32_External_Shdr)
+				   : sizeof (Elf64_External_Shdr)),
+				  errmsg, err))
+	{
+	  XDELETE (eor);
+	  return NULL;
+	}
+
+      if (eor->shnum == 0)
+	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				      shdr, sh_size, Elf_Addr);
+
+      if (eor->shstrndx == SHN_XINDEX)
+	{
+	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+					   shdr, sh_link, Elf_Word);
+
+	  /* Versions of the GNU binutils between 2.12 and 2.18 did
+	     not handle objects with more than SHN_LORESERVE sections
+	     correctly.  All large section indexes were offset by
+	     0x100.  There is more information at
+	     http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
+	     Fortunately these object files are easy to detect, as the
+	     GNU binutils always put the section header string table
+	     near the end of the list of sections.  Thus if the
+	     section header string table index is larger than the
+	     number of sections, then we know we have to subtract
+	     0x100 to get the real section index.  */
+	  if (eor->shstrndx >= eor->shnum
+	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
+	    eor->shstrndx -= 0x100;
+	}
+    }
+
+  if (eor->shstrndx >= eor->shnum)
+    {
+      *errmsg = "invalid ELF shstrndx >= shnum";
+      *err = 0;
+      XDELETE (eor);
+      return NULL;
+    }
+
+  return (void *) eor;
+}
+
+/* Find all sections in an ELF file.  */
+
+static const char *
+objfile_elf_find_sections (objfile_read *objfile,
+			   int (*pfn) (void *, const char *, off_t offset,
+				       off_t length),
+			   void *data,
+			   int *err)
+{
+  struct objfile_elf_read *eor = (struct objfile_elf_read *) objfile->data;
+  const struct elf_type_functions *type_functions = eor->type_functions;
+  unsigned char ei_class = eor->ei_class;
+  size_t shdr_size;
+  unsigned int shnum;
+  unsigned char *shdrs;
+  const char *errmsg;
+  unsigned char *shstrhdr;
+  size_t name_size;
+  off_t shstroff;
+  unsigned char *names;
+  unsigned int i;
+
+  shdr_size = (ei_class == ELFCLASS32
+	       ? sizeof (Elf32_External_Shdr)
+	       : sizeof (Elf64_External_Shdr));
+
+  /* Read the section headers.  We skip section 0, which is not a
+     useful section.  */
+
+  shnum = eor->shnum;
+  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+  if (!objfile_internal_read (objfile->descriptor,
+			      objfile->offset + eor->shoff + shdr_size,
+			      shdrs,
+			      shdr_size * (shnum - 1),
+			      &errmsg, err))
+    {
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  /* Read the section names.  */
+
+  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+			       shstrhdr, sh_size, Elf_Addr);
+  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+			      shstrhdr, sh_offset, Elf_Addr);
+  names = XNEWVEC (unsigned char, name_size);
+  if (!objfile_internal_read (objfile->descriptor,
+			      objfile->offset + shstroff,
+			      names, name_size, &errmsg, err))
+    {
+      XDELETEVEC (names);
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_name;
+      const char *name;
+      off_t offset;
+      off_t length;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_name, Elf_Word);
+      if (sh_name >= name_size)
+	{
+	  *err = 0;
+	  XDELETEVEC (names);
+	  XDELETEVEC (shdrs);
+	  return "ELF section name out of range";
+	}
+
+      name = (const char *) names + sh_name;
+      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				shdr, sh_offset, Elf_Addr);
+      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				shdr, sh_size, Elf_Addr);
+
+      if (!(*pfn) (data, name, offset, length))
+	break;
+    }
+
+  XDELETEVEC (names);
+  XDELETEVEC (shdrs);
+
+  return NULL;
+}
+
+/* Fetch the attributes for an objfile_read.  */
+
+static void *
+objfile_elf_fetch_attributes (objfile_read *objfile,
+			      const char **errmsg ATTRIBUTE_UNUSED,
+			      int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_elf_read *eor = (struct objfile_elf_read *) objfile->data;
+  struct objfile_elf_attributes *ret;
+
+  ret = XNEW (struct objfile_elf_attributes);
+  ret->type_functions = eor->type_functions;
+  ret->ei_data = eor->ei_data;
+  ret->ei_class = eor->ei_class;
+  ret->ei_osabi = eor->ei_osabi;
+  ret->machine = eor->machine;
+  ret->flags = eor->flags;
+  return ret;
+}
+
+/* Release the privata data for an objfile_read.  */
+
+static void
+objfile_elf_release_read (void *data)
+{
+  XDELETE (data);
+}
+
+/* Compare two attributes structures.  */
+
+static const char *
+objfile_elf_attributes_compare (void *data1, void *data2, int *err)
+{
+  struct objfile_elf_attributes *attrs1 =
+    (struct objfile_elf_attributes *) data1;
+  struct objfile_elf_attributes *attrs2 =
+    (struct objfile_elf_attributes *) data2;
+
+  if (attrs1->ei_data != attrs2->ei_data
+      || attrs1->ei_class != attrs2->ei_class
+      || attrs1->machine != attrs2->machine)
+    {
+      *err = 0;
+      return "ELF object format mismatch";
+    }
+  return NULL;
+}
+
+/* Release the private data for an attributes structure.  */
+
+static void
+objfile_elf_release_attributes (void *data)
+{
+  XDELETE (data);
+}
+
+/* Prepare to write out a file.  */
+
+static void *
+objfile_elf_start_write (void *attributes_data,
+			 const char **errmsg ATTRIBUTE_UNUSED,
+			 int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_elf_attributes *attrs =
+    (struct objfile_elf_attributes *) attributes_data;
+  struct objfile_elf_attributes *ret;
+
+  /* We're just going to record the attributes, but we need to make a
+     copy because the user may delete them.  */
+  ret = XNEW (struct objfile_elf_attributes);
+  *ret = *attrs;
+  return ret;
+}
+
+/* Write out an ELF ehdr.  */
+
+static int
+objfile_elf_write_ehdr (objfile_write *objfile, int descriptor,
+			const char **errmsg, int *err)
+{
+  struct objfile_elf_attributes *attrs =
+    (struct objfile_elf_attributes *) objfile->data;
+  const struct elf_type_functions* fns;
+  unsigned char cl;
+  size_t ehdr_size;
+  unsigned char buf[sizeof (Elf64_External_Ehdr)];
+  objfile_write_section *section;
+  unsigned int shnum;
+
+  fns = attrs->type_functions;
+  cl = attrs->ei_class;
+
+  shnum = 0;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    ++shnum;
+  if (shnum > 0)
+    {
+      /* Add a section header for the dummy section and one for
+	 .shstrtab.  */
+      shnum += 2;
+    }
+
+  ehdr_size = (cl == ELFCLASS32
+	       ? sizeof (Elf32_External_Ehdr)
+	       : sizeof (Elf64_External_Ehdr));
+  memset (buf, 0, ehdr_size);
+
+  buf[EI_MAG0] = ELFMAG0;
+  buf[EI_MAG1] = ELFMAG1;
+  buf[EI_MAG2] = ELFMAG2;
+  buf[EI_MAG3] = ELFMAG3;
+  buf[EI_CLASS] = cl;
+  buf[EI_DATA] = attrs->ei_data;
+  buf[EI_VERSION] = EV_CURRENT;
+  buf[EI_OSABI] = attrs->ei_osabi;
+
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
+  /* e_entry left as zero.  */
+  /* e_phoff left as zero.  */
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
+		 (cl == ELFCLASS32
+		  ? sizeof (Elf32_External_Phdr)
+		  : sizeof (Elf64_External_Phdr)));
+  /* e_phnum left as zero.  */
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
+		 (cl == ELFCLASS32
+		  ? sizeof (Elf32_External_Shdr)
+		  : sizeof (Elf64_External_Shdr)));
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
+		 shnum == 0 ? 0 : shnum - 1);
+
+  return objfile_internal_write (descriptor, 0, buf, ehdr_size, errmsg, err);
+}
+
+/* Write out an ELF shdr.  */
+
+static int
+objfile_elf_write_shdr (objfile_write *objfile, int descriptor, off_t offset,
+			unsigned int sh_name, unsigned int sh_type,
+			unsigned int sh_flags, unsigned int sh_offset,
+			unsigned int sh_size, unsigned int sh_addralign,
+			const char **errmsg, int *err)
+{
+  struct objfile_elf_attributes *attrs =
+    (struct objfile_elf_attributes *) objfile->data;
+  const struct elf_type_functions* fns;
+  unsigned char cl;
+  size_t shdr_size;
+  unsigned char buf[sizeof (Elf64_External_Shdr)];
+
+  fns = attrs->type_functions;
+  cl = attrs->ei_class;
+
+  shdr_size = (cl == ELFCLASS32
+	       ? sizeof (Elf32_External_Shdr)
+	       : sizeof (Elf64_External_Shdr));
+  memset (buf, 0, shdr_size);
+
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
+  /* sh_link left as zero.  */
+  /* sh_info left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
+  /* sh_entsize left as zero.  */
+
+  return objfile_internal_write (descriptor, offset, buf, shdr_size,
+				 errmsg, err);
+}
+
+/* Write out a complete ELF file.
+   Ehdr
+   initial dummy Shdr
+   user-created Shdrs
+   .shstrtab Shdr
+   user-created section data
+   .shstrtab data  */
+
+static const char *
+objfile_elf_write_to_file (objfile_write *objfile, int descriptor, int *err)
+{
+  struct objfile_elf_attributes *attrs =
+    (struct objfile_elf_attributes *) objfile->data;
+  unsigned char cl;
+  size_t ehdr_size;
+  size_t shdr_size;
+  const char *errmsg;
+  objfile_write_section *section;
+  unsigned int shnum;
+  size_t shdr_offset;
+  size_t sh_offset;
+  size_t sh_name;
+  unsigned char zero;
+
+  if (!objfile_elf_write_ehdr (objfile, descriptor, &errmsg, err))
+    return errmsg;
+
+  cl = attrs->ei_class;
+  if (cl == ELFCLASS32)
+    {
+      ehdr_size = sizeof (Elf32_External_Ehdr);
+      shdr_size = sizeof (Elf32_External_Shdr);
+    }
+  else
+    {
+      ehdr_size = sizeof (Elf64_External_Ehdr);
+      shdr_size = sizeof (Elf64_External_Shdr);
+    }
+
+  shnum = 0;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    ++shnum;
+  if (shnum == 0)
+    return NULL;
+
+  /* Add initial dummy Shdr and .shstrtab.  */
+  shnum += 2;
+
+  shdr_offset = ehdr_size;
+  sh_offset = shdr_offset + shnum * shdr_size;
+
+  if (!objfile_elf_write_shdr (objfile, descriptor, shdr_offset,
+			       0, 0, 0, 0, 0, 0, &errmsg, err))
+    return errmsg;
+
+  shdr_offset += shdr_size;
+
+  sh_name = 1;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t mask;
+      size_t new_sh_offset;
+      size_t sh_size;
+      struct objfile_write_section_buffer *buffer;
+
+      mask = (1U << section->align) - 1;
+      new_sh_offset = sh_offset + mask;
+      new_sh_offset &= ~ mask;
+      while (new_sh_offset > sh_offset)
+	{
+	  unsigned char zeroes[16];
+	  size_t write;
+
+	  memset (zeroes, 0, sizeof zeroes);
+	  write = new_sh_offset - sh_offset;
+	  if (write > sizeof zeroes)
+	    write = sizeof zeroes;
+	  if (!objfile_internal_write (descriptor, sh_offset, zeroes,
+				       write, &errmsg, err))
+	    return errmsg;
+	  sh_offset += write;
+	}
+
+      sh_size = 0;
+      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
+	{
+	  if (!objfile_internal_write (descriptor, sh_offset + sh_size,
+				       (const unsigned char *) buffer->buffer,
+				       buffer->size, &errmsg, err))
+	    return errmsg;
+	  sh_size += buffer->size;
+	}
+
+      if (!objfile_elf_write_shdr (objfile, descriptor, shdr_offset,
+				   sh_name, SHT_PROGBITS, 0, sh_offset,
+				   sh_size, 1U << section->align,
+				   &errmsg, err))
+	return errmsg;
+
+      shdr_offset += shdr_size;
+      sh_name += strlen (section->name) + 1;
+      sh_offset += sh_size;
+    }
+
+  if (!objfile_elf_write_shdr (objfile, descriptor, shdr_offset,
+			       sh_name, SHT_STRTAB, 0, sh_offset,
+			       sh_name + strlen (".shstrtab") + 1,
+			       1, &errmsg, err))
+    return errmsg;
+
+  /* .shstrtab has a leading zero byte.  */
+  zero = 0;
+  if (!objfile_internal_write (descriptor, sh_offset, &zero, 1, &errmsg, err))
+    return errmsg;
+  ++sh_offset;
+
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t len;
+
+      len = strlen (section->name) + 1;
+      if (!objfile_internal_write (descriptor, sh_offset,
+				   (const unsigned char *) section->name,
+				   len, &errmsg, err))
+	return errmsg;
+      sh_offset += len;
+    }
+
+  if (!objfile_internal_write (descriptor, sh_offset,
+			       (const unsigned char *) ".shstrtab",
+			       strlen (".shstrtab") + 1, &errmsg, err))
+    return errmsg;
+
+  return NULL;
+}
+
+/* Release the private data for an objfile_write structure.  */
+
+static void
+objfile_elf_release_write (void *data)
+{
+  XDELETE (data);
+}
+
+/* The ELF functions.  */
+
+const struct objfile_functions objfile_elf_functions =
+{
+  objfile_elf_match,
+  objfile_elf_find_sections,
+  objfile_elf_fetch_attributes,
+  objfile_elf_release_read,
+  objfile_elf_attributes_compare,
+  objfile_elf_release_attributes,
+  objfile_elf_start_write,
+  objfile_elf_write_to_file,
+  objfile_elf_release_write
+};
Index: libiberty/objfile-coff.c
===================================================================
--- libiberty/objfile-coff.c	(revision 0)
+++ libiberty/objfile-coff.c	(revision 0)
@@ -0,0 +1,661 @@ 
+/* objfile-coff.c -- routines to manipulate COFF object files.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+#include "objfile.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "objfile-common.h"
+
+/* COFF structures and constants.  */
+
+/* COFF file header.  */
+
+struct external_filehdr
+{
+  unsigned char f_magic[2];	/* magic number			*/
+  unsigned char f_nscns[2];	/* number of sections		*/
+  unsigned char f_timdat[4];	/* time & date stamp		*/
+  unsigned char f_symptr[4];	/* file pointer to symtab	*/
+  unsigned char f_nsyms[4];	/* number of symtab entries	*/
+  unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
+  unsigned char f_flags[2];	/* flags			*/
+};
+
+/* Bits for filehdr f_flags field.  */
+
+#define F_EXEC			(0x0002)
+#define IMAGE_FILE_SYSTEM	(0x1000)
+#define IMAGE_FILE_DLL		(0x2000)
+
+/* COFF section header.  */
+
+struct external_scnhdr
+{
+  unsigned char s_name[8];	/* section name				*/
+  unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
+  unsigned char s_vaddr[4];	/* virtual address			*/
+  unsigned char s_size[4];	/* section size				*/
+  unsigned char s_scnptr[4];	/* file ptr to raw data for section 	*/
+  unsigned char s_relptr[4];	/* file ptr to relocation		*/
+  unsigned char s_lnnoptr[4];	/* file ptr to line numbers		*/
+  unsigned char s_nreloc[2];	/* number of relocation entries		*/
+  unsigned char s_nlnno[2];	/* number of line number entries	*/
+  unsigned char s_flags[4];	/* flags				*/
+};
+
+/* The length of the s_name field in struct external_scnhdr.  */
+
+#define SCNNMLEN (8)
+
+/* Bits for scnhdr s_flags field.  This includes some bits defined
+   only for PE.  This may need to be moved into coff_magic.  */
+
+#define STYP_DATA			(1 << 6)
+#define IMAGE_SCN_ALIGN_1BYTES		(1 << 20)
+#define IMAGE_SCN_MEM_DISCARDABLE	(1 << 25)
+#define IMAGE_SCN_MEM_SHARED		(1 << 28)
+#define IMAGE_SCN_MEM_READ		(1 << 30)
+
+/* COFF symbol table entry.  */
+
+#define E_SYMNMLEN	8	/* # characters in a symbol name	*/
+
+struct external_syment 
+{
+  union
+  {
+    unsigned char e_name[E_SYMNMLEN];
+
+    struct
+    {
+      unsigned char e_zeroes[4];
+      unsigned char e_offset[4];
+    } e;
+  } e;
+
+  unsigned char e_value[4];
+  unsigned char e_scnum[2];
+  unsigned char e_type[2];
+  unsigned char e_sclass[1];
+  unsigned char e_numaux[1];
+};
+
+/* Private data for an objfile_read.  */
+
+struct objfile_coff_read
+{
+  /* Magic number.  */
+  unsigned short magic;
+  /* Whether the file is big-endian.  */
+  unsigned char is_big_endian;
+  /* Number of sections.  */
+  unsigned short nscns;
+  /* File offset of symbol table.  */
+  off_t symptr;
+  /* Number of symbol table entries.  */
+  unsigned int nsyms;
+  /* Flags.  */
+  unsigned short flags;
+  /* Offset of section headers in file.  */
+  off_t scnhdr_offset;
+};
+
+/* Private data for an objfile_attributes.  */
+
+struct objfile_coff_attributes
+{
+  /* Magic number.  */
+  unsigned short magic;
+  /* Whether the file is big-endian.  */
+  unsigned char is_big_endian;
+  /* Flags.  */
+  unsigned short flags;
+};
+
+/* There is no magic number which indicates a COFF file as opposed to
+   any other sort of file.  Instead, each COFF file starts with a
+   two-byte magic number which also indicates the type of the target.
+   This struct holds a magic number as well as characteristics of that
+   COFF format.  */
+
+struct coff_magic_struct
+{
+  /* Magic number.  */
+  unsigned short magic;
+  /* Whether this magic number is for a big-endian file.  */
+  unsigned char is_big_endian;
+  /* Flag bits, in the f_flags fields, which indicates that this file
+     is not a relocatable object file.  There is no flag which
+     specifically indicates a relocatable object file, it is only
+     implied by the absence of these flags.  */
+  unsigned short non_object_flags;
+};
+
+/* This is a list of the COFF magic numbers which we recognize, namely
+   the ones used on Windows.  More can be added as needed.  */
+
+static const struct coff_magic_struct coff_magic[] =
+{
+  /* i386.  */
+  { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
+  /* x86_64.  */
+  { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
+};
+
+/* See if we have a COFF file.  */
+
+static void *
+objfile_coff_match (unsigned char header[OBJFILE_MATCH_HEADER_LEN],
+		    int descriptor, off_t offset,
+		    const char *segment_name ATTRIBUTE_UNUSED,
+		    const char **errmsg, int *err)
+{
+  size_t c;
+  unsigned short magic_big;
+  unsigned short magic_little;
+  unsigned short magic;
+  size_t i;
+  int is_big_endian;
+  unsigned short (*fetch_16) (const unsigned char *);
+  unsigned int (*fetch_32) (const unsigned char *);
+  unsigned char hdrbuf[sizeof (struct external_filehdr)];
+  unsigned char *hdr;
+  unsigned short flags;
+  struct objfile_coff_read *ocr;
+
+  c = sizeof (coff_magic) / sizeof (coff_magic[0]);
+  magic_big = objfile_fetch_big_16 (header);
+  magic_little = objfile_fetch_little_16 (header);
+  for (i = 0; i < c; ++i)
+    {
+      if (coff_magic[i].is_big_endian
+	  ? coff_magic[i].magic == magic_big
+	  : coff_magic[i].magic == magic_little)
+	break;
+    }
+  if (i >= c)
+    {
+      *errmsg = NULL;
+      *err = 0;
+      return NULL;
+    }
+  is_big_endian = coff_magic[i].is_big_endian;
+  
+  magic = is_big_endian ? magic_big : magic_little;
+  fetch_16 = (is_big_endian
+	      ? objfile_fetch_big_16
+	      : objfile_fetch_little_16);
+  fetch_32 = (is_big_endian
+	      ? objfile_fetch_big_32
+	      : objfile_fetch_little_32);
+
+  if (!objfile_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
+			      errmsg, err))
+    return NULL;
+
+  hdr = &hdrbuf[0];
+
+  flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
+  if ((flags & coff_magic[i].non_object_flags) != 0)
+    {
+      *errmsg = "not relocatable object file";
+      *err = 0;
+      return NULL;
+    }
+
+  ocr = XNEW (struct objfile_coff_read);
+  ocr->magic = magic;
+  ocr->is_big_endian = is_big_endian;
+  ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
+  ocr->symptr = fetch_32 (hdrbuf
+			  + offsetof (struct external_filehdr, f_symptr));
+  ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
+  ocr->flags = flags;
+  ocr->scnhdr_offset = (sizeof (struct external_filehdr)
+			+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
+						       f_opthdr)));
+
+  return (void *) ocr;
+}
+
+/* Read the string table in a COFF file.  */
+
+static char *
+objfile_coff_read_strtab (objfile_read *objfile, size_t *strtab_size,
+			  const char **errmsg, int *err)
+{
+  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
+  off_t strtab_offset;
+  unsigned char strsizebuf[4];
+  size_t strsize;
+  char *strtab;
+
+  strtab_offset = ocr->symptr + ocr->nsyms * sizeof (struct external_syment);
+  if (!objfile_internal_read (objfile->descriptor, strtab_offset,
+			      strsizebuf, 4, errmsg, err))
+    return NULL;
+  strsize = (ocr->is_big_endian
+	     ? objfile_fetch_big_32 (strsizebuf)
+	     : objfile_fetch_little_32 (strsizebuf));
+  strtab = XNEWVEC (char, strsize);
+  if (!objfile_internal_read (objfile->descriptor, strtab_offset,
+			      (unsigned char *) strtab, strsize, errmsg, err))
+    {
+      XDELETEVEC (strtab);
+      return NULL;
+    }
+  *strtab_size = strsize;
+  return strtab;
+}
+
+/* Find all sections in a COFF file.  */
+
+static const char *
+objfile_coff_find_sections (objfile_read *objfile,
+			    int (*pfn) (void *, const char *, off_t offset,
+					off_t length),
+			    void *data,
+			    int *err)
+{
+  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
+  size_t scnhdr_size;
+  unsigned char *scnbuf;
+  const char *errmsg;
+  unsigned int (*fetch_32) (const unsigned char *);
+  unsigned int nscns;
+  char *strtab;
+  size_t strtab_size;
+  unsigned int i;
+
+  scnhdr_size = sizeof (struct external_scnhdr);
+  scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
+  if (!objfile_internal_read (objfile->descriptor,
+			      objfile->offset + ocr->scnhdr_offset,
+			      scnbuf, scnhdr_size * ocr->nscns, &errmsg, err))
+    {
+      XDELETEVEC (scnbuf);
+      return errmsg;
+    }
+
+  fetch_32 = (ocr->is_big_endian
+	      ? objfile_fetch_big_32
+	      : objfile_fetch_little_32);
+
+  nscns = ocr->nscns;
+  strtab = NULL;
+  strtab_size = 0;
+  for (i = 0; i < nscns; ++i)
+    {
+      unsigned char *scnhdr;
+      unsigned char *scnname;
+      char namebuf[SCNNMLEN + 1];
+      char *name;
+      off_t scnptr;
+      unsigned int size;
+
+      scnhdr = scnbuf + i * scnhdr_size;
+      scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
+      memcpy (namebuf, scnname, SCNNMLEN);
+      namebuf[SCNNMLEN] = '\0';
+      name = &namebuf[0];
+      if (namebuf[0] == '/')
+	{
+	  size_t strindex;
+	  char *end;
+
+	  strindex = strtol (namebuf, &end, 10);
+	  if (*end == '\0')
+	    {
+	      /* The real section name is found in the string
+		 table.  */
+	      if (strtab == NULL)
+		{
+		  strtab = objfile_coff_read_strtab (objfile, &strtab_size,
+						     &errmsg, err);
+		  if (strtab == NULL)
+		    {
+		      XDELETEVEC (scnbuf);
+		      return errmsg;
+		    }
+		}
+
+	      if (strindex < 4 || strindex >= strtab_size)
+		{
+		  XDELETEVEC (strtab);
+		  XDELETEVEC (scnbuf);
+		  *err = 0;
+		  return "section string index out of range";
+		}
+
+	      name = strtab + strindex;
+	    }
+	}
+
+      scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
+      size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
+
+      if (!(*pfn) (data, name, scnptr, size))
+	break;
+    }
+
+  if (strtab != NULL)
+    XDELETEVEC (strtab);
+  XDELETEVEC (scnbuf);
+
+  return NULL;
+}
+
+/* Fetch the attributes for an objfile_read.  */
+
+static void *
+objfile_coff_fetch_attributes (objfile_read *objfile,
+			       const char **errmsg ATTRIBUTE_UNUSED,
+			       int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_coff_read *ocr = (struct objfile_coff_read *) objfile->data;
+  struct objfile_coff_attributes *ret;
+
+  ret = XNEW (struct objfile_coff_attributes);
+  ret->magic = ocr->magic;
+  ret->is_big_endian = ocr->is_big_endian;
+  ret->flags = ocr->flags;
+  return ret;
+}
+
+/* Release the private data for an objfile_read.  */
+
+static void
+objfile_coff_release_read (void *data)
+{
+  XDELETE (data);
+}
+
+/* Compare two attributes structures.  */
+
+static const char *
+objfile_coff_attributes_compare (void *data1, void *data2, int *err)
+{
+  struct objfile_coff_attributes *attrs1 =
+    (struct objfile_coff_attributes *) data1;
+  struct objfile_coff_attributes *attrs2 =
+    (struct objfile_coff_attributes *) data2;
+
+  if (attrs1->magic != attrs2->magic
+      || attrs1->is_big_endian != attrs2->is_big_endian)
+    {
+      *err = 0;
+      return "COFF object format mismatch";
+    }
+  return NULL;
+}
+
+/* Release the private data for an attributes structure.  */
+
+static void
+objfile_coff_release_attributes (void *data)
+{
+  XDELETE (data);
+}
+
+/* Prepare to write out a file.  */
+
+static void *
+objfile_coff_start_write (void *attributes_data,
+			  const char **errmsg ATTRIBUTE_UNUSED,
+			  int *err ATTRIBUTE_UNUSED)
+{
+  struct objfile_coff_attributes *attrs =
+    (struct objfile_coff_attributes *) attributes_data;
+  struct objfile_coff_attributes *ret;
+
+  /* We're just going to record the attributes, but we need to make a
+     copy because the user may delete them.  */
+  ret = XNEW (struct objfile_coff_attributes);
+  *ret = *attrs;
+  return ret;
+}
+
+/* Write out a COFF filehdr.  */
+
+static int
+objfile_coff_write_filehdr (objfile_write *objfile, int descriptor,
+			    unsigned int nscns, size_t strtab_offset,
+			    const char **errmsg, int *err)
+{
+  struct objfile_coff_attributes *attrs =
+    (struct objfile_coff_attributes *) objfile->data;
+  unsigned char hdrbuf[sizeof (struct external_filehdr)];
+  unsigned char *hdr;
+  void (*set_16) (unsigned char *, unsigned short);
+  void (*set_32) (unsigned char *, unsigned int);
+
+  hdr = &hdrbuf[0];
+
+  set_16 = (attrs->is_big_endian
+	    ? objfile_set_big_16
+	    : objfile_set_little_16);
+  set_32 = (attrs->is_big_endian
+	    ? objfile_set_big_32
+	    : objfile_set_little_32);
+
+  memset (hdr, 0, sizeof (struct external_filehdr));
+
+  /* We don't write out any symbols.  We'll see if that causes any
+     problems.  */
+
+  set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
+  set_16 (hdr + offsetof (struct external_filehdr, f_magic), nscns);
+  /* f_timdat left as zero.  */
+  set_32 (hdr + offsetof (struct external_filehdr, f_symptr), strtab_offset);
+  /* f_nsyms left as zero.  */
+  /* f_opthdr left as zero.  */
+  set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
+
+  return objfile_internal_write (descriptor, 0, hdrbuf,
+				 sizeof (struct external_filehdr),
+				 errmsg, err);
+}
+
+/* Write out a COFF section header.  */
+
+static int
+objfile_coff_write_scnhdr (objfile_write *objfile, int descriptor,
+			   const char *name, size_t *name_offset,
+			   off_t scnhdr_offset, size_t scnsize, off_t offset,
+			   const char **errmsg, int *err)
+{
+  struct objfile_coff_attributes *attrs =
+    (struct objfile_coff_attributes *) objfile->data;
+  void (*set_32) (unsigned char *, unsigned int);
+  unsigned char hdrbuf[sizeof (struct external_scnhdr)];
+  unsigned char *hdr;
+  size_t namelen;
+
+  set_32 = (attrs->is_big_endian
+	    ? objfile_set_big_32
+	    : objfile_set_little_32);
+
+  memset (hdrbuf, 0, sizeof hdrbuf);
+  hdr = &hdrbuf[0];
+
+  namelen = strlen (name);
+  if (namelen <= SCNNMLEN)
+    strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
+	     SCNNMLEN);
+  else
+    {
+      snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
+		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
+      *name_offset += namelen + 1;
+    }
+
+  /* s_paddr left as zero.  */
+  /* s_vaddr left as zero.  */
+  set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
+  set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
+  /* s_relptr left as zero.  */
+  /* s_lnnoptr left as zero.  */
+  /* s_nreloc left as zero.  */
+  /* s_nlnno left as zero.  */
+  set_32 (hdr + offsetof (struct external_scnhdr, s_flags),
+	  (STYP_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE
+	   | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ));
+
+  return objfile_internal_write (descriptor, scnhdr_offset, hdrbuf,
+				 sizeof (struct external_scnhdr),
+				 errmsg, err);
+}
+
+/* Write out a complete COFF file.  */
+
+static const char *
+objfile_coff_write_to_file (objfile_write *objfile, int descriptor, int *err)
+{
+  struct objfile_coff_attributes *attrs =
+    (struct objfile_coff_attributes *) objfile->data;
+  unsigned int nscns;
+  objfile_write_section *section;
+  off_t scnhdr_offset;
+  size_t offset;
+  size_t name_offset;
+  const char *errmsg;
+  unsigned char strsizebuf[4];
+
+  nscns = 0;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    ++nscns;
+
+  scnhdr_offset = sizeof (struct external_filehdr);
+  offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
+  name_offset = 4;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t mask;
+      size_t new_offset;
+      size_t scnsize;
+      struct objfile_write_section_buffer *buffer;
+
+      mask = (1U << section->align) - 1;
+      new_offset = offset & mask;
+      new_offset &= ~ mask;
+      while (new_offset > offset)
+	{
+	  unsigned char zeroes[16];
+	  size_t write;
+
+	  memset (zeroes, 0, sizeof zeroes);
+	  write = new_offset - offset;
+	  if (write > sizeof zeroes)
+	    write = sizeof zeroes;
+	  if (!objfile_internal_write (descriptor, offset, zeroes, write,
+				       &errmsg, err))
+	    return errmsg;
+	}
+
+      scnsize = 0;
+      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
+	{
+	  if (!objfile_internal_write (descriptor, offset + scnsize,
+				       (const unsigned char *) buffer->buffer,
+				       buffer->size, &errmsg, err))
+	    return errmsg;
+	  scnsize += buffer->size;
+	}
+
+      if (!objfile_coff_write_scnhdr (objfile, descriptor, section->name,
+				      &name_offset, scnhdr_offset,
+				      scnsize, offset, &errmsg, err))
+	return errmsg;
+
+      scnhdr_offset += sizeof (struct external_scnhdr);
+      offset += scnsize;
+    }
+
+  if (attrs->is_big_endian)
+    objfile_set_big_32 (strsizebuf, name_offset);
+  else
+    objfile_set_little_32 (strsizebuf, name_offset);
+  if (!objfile_internal_write (descriptor, offset, strsizebuf, 4, &errmsg, err))
+    return errmsg;
+
+  name_offset = 4;
+  for (section = objfile->sections; section != NULL; section = section->next)
+    {
+      size_t namelen;
+
+      namelen = strlen (section->name);
+      if (namelen > SCNNMLEN)
+	{
+	  if (!objfile_internal_write (descriptor, offset + name_offset,
+				       (const unsigned char *) section->name,
+				       namelen + 1, &errmsg, err))
+	    return errmsg;
+	  name_offset += namelen;
+	}
+    }
+
+  if (!objfile_coff_write_filehdr (objfile, descriptor, nscns, offset,
+				   &errmsg, err))
+    return errmsg;
+
+  return NULL;
+}
+
+/* Release the private data for an objfile_write structure.  */
+
+static void
+objfile_coff_release_write (void *data)
+{
+  XDELETE (data);
+}
+
+/* The COFF functions.  */
+
+const struct objfile_functions objfile_coff_functions =
+{
+  objfile_coff_match,
+  objfile_coff_find_sections,
+  objfile_coff_fetch_attributes,
+  objfile_coff_release_read,
+  objfile_coff_attributes_compare,
+  objfile_coff_release_attributes,
+  objfile_coff_start_write,
+  objfile_coff_write_to_file,
+  objfile_coff_release_write
+};
Index: gcc/lto/lto-elf.c
===================================================================
--- gcc/lto/lto-elf.c	(revision 166002)
+++ gcc/lto/lto-elf.c	(working copy)
@@ -1,817 +0,0 @@ 
-/* LTO routines for ELF object files.
-   Copyright 2009, 2010 Free Software Foundation, Inc.
-   Contributed by CodeSourcery, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include <gelf.h>
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "ggc.h"
-#include "lto-streamer.h"
-
-/* Cater to hosts with half-backed <elf.h> file like HP-UX.  */
-#ifndef EM_SPARC
-# define EM_SPARC 2
-#endif
-
-#ifndef EM_SPARC32PLUS
-# define EM_SPARC32PLUS 18
-#endif
-
-#ifndef ELFOSABI_NONE
-# define ELFOSABI_NONE 0
-#endif
-
-#ifndef ELFOSABI_LINUX
-# define ELFOSABI_LINUX 3
-#endif
-
-#ifndef SHN_XINDEX
-# define SHN_XINDEX 0xffff
-#endif
-
-
-/* Handle opening elf files on hosts, such as Windows, that may use 
-   text file handling that will break binary access.  */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-
-/* Initialize FILE, an LTO file object for FILENAME.  */
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* An ELF file.  */
-struct lto_elf_file 
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The libelf descriptor for the file.  */
-  Elf *elf;
-
-  /* Section number of string table used for section names.  */
-  size_t sec_strtab;
-
-  /* Writable file members.  */
-
-  /* The currently active section.  */
-  Elf_Scn *scn;
-
-  /* The output stream for section header names.  */
-  struct lto_output_stream *shstrtab_stream;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_elf_file lto_elf_file;
-
-/* Stores executable header attributes which must be shared by all ELF files.
-   This is used for validating input files and populating output files.  */
-static struct {
-  bool initialized;
-  /* 32 or 64 bits?  */
-  size_t bits;
-  unsigned char elf_ident[EI_NIDENT];
-  Elf64_Half elf_machine;
-} cached_file_attrs;
-
-
-/* Return the section header for SECTION.  The return value is never
-   NULL.  Call lto_elf_free_shdr to release the memory allocated.  */
-
-static Elf64_Shdr *
-lto_elf_get_shdr (Elf_Scn *section)
-{
-  Elf64_Shdr *shdr;
-
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      {
-	Elf32_Shdr *shdr32;
-
-	/* Read the 32-bit section header.  */
-	shdr32 = elf32_getshdr (section);
-	if (!shdr32)
-	  fatal_error ("could not read section header: %s", elf_errmsg (0));
-
-	/* Transform it into a 64-bit section header.  */
-	shdr = XNEW (Elf64_Shdr);
-	shdr->sh_name = shdr32->sh_name;
-	shdr->sh_type = shdr32->sh_type;
-	shdr->sh_flags = shdr32->sh_flags;
-	shdr->sh_addr = shdr32->sh_addr;
-	shdr->sh_offset = shdr32->sh_offset;
-	shdr->sh_size = shdr32->sh_size;
-	shdr->sh_link = shdr32->sh_link;
-	shdr->sh_info = shdr32->sh_info;
-	shdr->sh_addralign = shdr32->sh_addralign;
-	shdr->sh_entsize  = shdr32->sh_entsize;
-	break;
-      }
-      break;
-
-    case 64:
-      shdr = elf64_getshdr (section);
-      if (!shdr)
-	fatal_error ("could not read section header: %s", elf_errmsg (0));
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  return shdr;
-}
-
-/* Free SHDR, previously allocated by lto_elf_get_shdr.  */
-static void
-lto_elf_free_shdr (Elf64_Shdr *shdr)
-{
-  if (cached_file_attrs.bits != 64)
-    free (shdr);
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_elf_file *elf_file = (lto_elf_file *)lto_file;
-  htab_t section_hash_table;
-  Elf_Scn *section;
-  size_t base_offset;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  base_offset = elf_getbase (elf_file->elf);
-  /* We are reasonably sure that elf_getbase does not fail at this
-     point.  So assume that we run into the incompatibility with
-     the FreeBSD libelf implementation that has a non-working
-     elf_getbase for non-archive members in which case the offset
-     should be zero.  */
-  if (base_offset == (size_t)-1)
-    base_offset = 0;
-  for (section = elf_getscn (elf_file->elf, 0);
-       section;
-       section = elf_nextscn (elf_file->elf, section)) 
-    {
-      Elf64_Shdr *shdr;
-      const char *name;
-      size_t offset;
-      char *new_name;
-      void **slot;
-      struct lto_section_slot s_slot;
-
-      /* Get the name of this section.  */
-      shdr = lto_elf_get_shdr (section);
-      offset = shdr->sh_name;
-      name = elf_strptr (elf_file->elf, 
-			 elf_file->sec_strtab,
-			 offset);
-
-      /* Only put lto stuff into the symtab.  */
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX, 
-		   strlen (LTO_SECTION_NAME_PREFIX)) != 0)
-	{
-	  lto_elf_free_shdr (shdr);
-	  continue;
-	}
-
-      new_name = XNEWVEC (char, strlen (name) + 1);
-      strcpy (new_name, name);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-	{
-	  struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-	  new_slot->name = new_name;
-	  /* The offset into the file for this section.  */
-	  new_slot->start = base_offset + shdr->sh_offset;
-	  new_slot->len = shdr->sh_size;
-	  *slot = new_slot;
-	}
-      else
-	{
-	  error ("two or more sections for %s:", new_name);
-	  return NULL;
-	}
-
-      lto_elf_free_shdr (shdr);
-    }
-
-  return section_hash_table;
-}
-
-
-/* Initialize the section header of section SCN.  SH_NAME is the section name
-   as an index into the section header string table.  SH_TYPE is the section
-   type, an SHT_* macro from libelf headers.  */
-
-#define DEFINE_INIT_SHDR(BITS)					      \
-static void							      \
-init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type)	      \
-{								      \
-  Elf##BITS##_Shdr *shdr;					      \
-								      \
-  shdr = elf##BITS##_getshdr (scn);				      \
-  if (!shdr)							      \
-    {								      \
-      if (BITS == 32)						      \
-	fatal_error ("elf32_getshdr() failed: %s", elf_errmsg (-1));  \
-      else							      \
-	fatal_error ("elf64_getshdr() failed: %s", elf_errmsg (-1));  \
-    }								      \
-								      \
-  shdr->sh_name = sh_name;					      \
-  shdr->sh_type = sh_type;					      \
-  shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT;		      \
-  shdr->sh_flags = 0;						      \
-  shdr->sh_entsize = 0;						      \
-}
-
-DEFINE_INIT_SHDR (32)
-DEFINE_INIT_SHDR (64)
-
-static bool first_data_block;
-
-/* Begin a new ELF section named NAME with type TYPE in the current output
-   file.  TYPE is an SHT_* macro from the libelf headers.  */
-
-static void
-lto_elf_begin_section_with_type (const char *name, size_t type)
-{
-  lto_elf_file *file;
-  Elf_Scn *scn;
-  size_t sh_name;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_elf_file *) lto_get_current_out_file (),
-  gcc_assert (file);
-  gcc_assert (file->elf);
-  gcc_assert (!file->scn);
-
-  /* Create a new section.  */
-  scn = elf_newscn (file->elf);
-  if (!scn)
-    fatal_error ("could not create a new ELF section: %s", elf_errmsg (-1));
-  file->scn = scn;
-
-  /* Add a string table entry and record the offset.  */
-  gcc_assert (file->shstrtab_stream);
-  sh_name = file->shstrtab_stream->total_size;
-  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
-
-  /* Initialize the section header.  */
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      init_shdr32 (scn, sh_name, type);
-      break;
-
-    case 64:
-      init_shdr64 (scn, sh_name, type);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  first_data_block = true;
-}
-
-
-/* Begin a new ELF section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_elf_begin_section_with_type (name, SHT_PROGBITS);
-}
-
-
-/* Append DATA of length LEN to the current output section.  BASE is a pointer
-   to the output page containing DATA.  It is freed once the output file has
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_elf_file *file;
-  Elf_Data *elf_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_elf_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  elf_data = elf_newdata (file->scn);
-  if (!elf_data)
-    fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1));
-
-  if (first_data_block)
-    {
-      elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT;
-      first_data_block = false;
-    }
-  else
-    elf_data->d_align = 1;
-  elf_data->d_buf = CONST_CAST (void *, data);
-  elf_data->d_off = 0LL;
-  elf_data->d_size = len;
-  elf_data->d_type = ELF_T_BYTE;
-  elf_data->d_version = EV_CURRENT;
-
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_elf_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_elf_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* Return true if ELF_MACHINE is compatible with the cached value of the
-   architecture and possibly update the latter.  Return false otherwise.
-
-   Note: if you want to add more EM_* cases, you'll need to provide the
-   corresponding definitions at the beginning of the file.  */
-
-static bool
-is_compatible_architecture (Elf64_Half elf_machine)
-{
-  if (cached_file_attrs.elf_machine == elf_machine)
-    return true;
-
-  switch (cached_file_attrs.elf_machine)
-    {
-    case EM_SPARC:
-      if (elf_machine == EM_SPARC32PLUS)
-	{
-	  cached_file_attrs.elf_machine = elf_machine;
-	  return true;
-	}
-      break;
-
-    case EM_SPARC32PLUS:
-      if (elf_machine == EM_SPARC)
-	return true;
-      break;
-
-    default:
-      break;
-    }
-
-  return false;
-}
-
-
-/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
-   uninitialized, caches the architecture.  */
-
-#define DEFINE_VALIDATE_EHDR(BITS)				\
-static bool							\
-validate_ehdr##BITS (lto_elf_file *elf_file)			\
-{								\
-  Elf##BITS##_Ehdr *elf_header;					\
-								\
-  elf_header = elf##BITS##_getehdr (elf_file->elf);		\
-  if (!elf_header)						\
-    {								\
-      error ("could not read ELF header: %s", elf_errmsg (0));	\
-      return false;						\
-    }								\
-								\
-  if (elf_header->e_type != ET_REL)				\
-    {								\
-      error ("not a relocatable ELF object file");		\
-      return false;						\
-    }								\
-								\
-  if (!cached_file_attrs.initialized)				\
-    cached_file_attrs.elf_machine = elf_header->e_machine;	\
-  else if (!is_compatible_architecture (elf_header->e_machine))	\
-    {								\
-      error ("inconsistent file architecture detected");	\
-      return false;						\
-    }								\
-								\
-  return true;							\
-}
-
-DEFINE_VALIDATE_EHDR (32)
-DEFINE_VALIDATE_EHDR (64)
-
-
-#ifndef HAVE_ELF_GETSHDRSTRNDX
-/* elf_getshdrstrndx replacement for systems that lack it, but provide
-   either the gABI conformant or Solaris 2 variant of elf_getshstrndx
-   instead.  */
-
-static int
-elf_getshdrstrndx (Elf *elf, size_t *dst)
-{
-#ifdef HAVE_ELF_GETSHSTRNDX_GABI
-  return elf_getshstrndx (elf, dst);
-#else
-  return elf_getshstrndx (elf, dst) ? 0 : -1;
-#endif
-}
-#endif
-
-/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success or false on failure.  */
-
-static bool
-validate_file (lto_elf_file *elf_file)
-{
-  const char *elf_ident;
-
-  /* Some aspects of the libelf API are dependent on whether the
-     object file is a 32-bit or 64-bit file.  Determine which kind of
-     file this is now.  */
-  elf_ident = elf_getident (elf_file->elf, NULL);
-  if (!elf_ident)
-    {
-      error ("could not read ELF identification information: %s",
-	      elf_errmsg (0));
-      return false;
-    }
-
-  if (!cached_file_attrs.initialized)
-    {
-      switch (elf_ident[EI_CLASS])
-	{
-	case ELFCLASS32:
-	  cached_file_attrs.bits = 32;
-	  break;
-
-	case ELFCLASS64:
-	  cached_file_attrs.bits = 64;
-	  break;
-
-	default:
-	  error ("unsupported ELF file class");
-	  return false;
-	}
-
-      memcpy (cached_file_attrs.elf_ident, elf_ident,
-	      sizeof cached_file_attrs.elf_ident);
-    }
-  else
-    {
-      char elf_ident_buf[EI_NIDENT];
-
-      memcpy (elf_ident_buf, elf_ident, sizeof elf_ident_buf);
-
-      if (elf_ident_buf[EI_OSABI] != cached_file_attrs.elf_ident[EI_OSABI])
-	{
-	  /* Allow mixing ELFOSABI_NONE with ELFOSABI_LINUX, with the result
-	     ELFOSABI_LINUX.  */
-	  if (elf_ident_buf[EI_OSABI] == ELFOSABI_NONE
-	      && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_LINUX)
-	    elf_ident_buf[EI_OSABI] = cached_file_attrs.elf_ident[EI_OSABI];
-	  else if (elf_ident_buf[EI_OSABI] == ELFOSABI_LINUX
-		   && cached_file_attrs.elf_ident[EI_OSABI] == ELFOSABI_NONE)
-	    cached_file_attrs.elf_ident[EI_OSABI] = elf_ident_buf[EI_OSABI];
-	}
-
-      if (memcmp (elf_ident_buf, cached_file_attrs.elf_ident,
-		  sizeof cached_file_attrs.elf_ident))
-	{
-	  error ("incompatible ELF identification");
-	  return false;
-	}
-    }
-
-  /* Check that the input file is a relocatable object file with the correct
-     architecture.  */
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      if (!validate_ehdr32 (elf_file))
-	return false;
-      break;
-
-    case 64:
-      if (!validate_ehdr64 (elf_file))
-	return false;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  /* Read the string table used for section header names.  */
-  if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
-    {
-      error ("could not locate ELF string table: %s", elf_errmsg (0));
-      return false;
-    }
-
-  cached_file_attrs.initialized = true;
-  return true;
-}
-
-
-/* Helper functions used by init_ehdr.  Initialize ELF_FILE's executable
-   header using cached data from previously read files.  */
-
-#define DEFINE_INIT_EHDR(BITS)					      \
-static void							      \
-init_ehdr##BITS (lto_elf_file *elf_file)			      \
-{								      \
-  Elf##BITS##_Ehdr *ehdr;					      \
-								      \
-  gcc_assert (cached_file_attrs.bits);				      \
-								      \
-  ehdr = elf##BITS##_newehdr (elf_file->elf);			      \
-  if (!ehdr)							      \
-    {								      \
-      if (BITS == 32)						      \
-	fatal_error ("elf32_newehdr() failed: %s", elf_errmsg (-1));  \
-      else							      \
-	fatal_error ("elf64_newehdr() failed: %s", elf_errmsg (-1));  \
-    }								      \
-								      \
-  memcpy (ehdr->e_ident, cached_file_attrs.elf_ident,		      \
-	  sizeof cached_file_attrs.elf_ident);			      \
-  ehdr->e_type = ET_REL;					      \
-  ehdr->e_version = EV_CURRENT;					      \
-  ehdr->e_machine = cached_file_attrs.elf_machine;		      \
-}
-
-DEFINE_INIT_EHDR (32)
-DEFINE_INIT_EHDR (64)
-
-
-/* Initialize ELF_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_ehdr (lto_elf_file *elf_file)
-{
-  switch (cached_file_attrs.bits)
-    {
-    case 32:
-      init_ehdr32 (elf_file);
-      break;
-
-    case 64:
-      init_ehdr64 (elf_file);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Open ELF file FILENAME.  If WRITABLE is true, the file is opened for write
-   and, if necessary, created.  Otherwise, the file is opened for reading.
-   Returns the opened file.  */
-
-lto_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_elf_file *elf_file;
-  lto_file *result = NULL;
-  off_t offset;
-  long loffset;
-  off_t header_offset;
-  const char *offset_p;
-  char *fname;
-  int consumed;
-
-  offset_p = strrchr (filename, '@');
-  if (offset_p
-      && offset_p != filename
-      && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
-      && strlen (offset_p) == (unsigned int)consumed)
-    {
-      fname = (char *) xmalloc (offset_p - filename + 1);
-      memcpy (fname, filename, offset_p - filename);
-      fname[offset_p - filename] = '\0';
-      offset = (off_t)loffset;
-      /* elf_rand expects the offset to point to the ar header, not the
-         object itself. Subtract the size of the ar header (60 bytes).
-         We don't uses sizeof (struct ar_hd) to avoid including ar.h */
-      header_offset = offset - 60;
-    }
-  else
-    {
-      fname = xstrdup (filename);
-      offset = 0;
-      header_offset = 0;
-    }
-
-  /* Set up.  */
-  elf_file = XCNEW (lto_elf_file);
-  result = (lto_file *) elf_file;
-  lto_file_init (result, fname, offset);
-  elf_file->fd = -1;
-
-  /* Open the file.  */
-  elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT|O_BINARY 
-				       : O_RDONLY|O_BINARY, 0666);
-  if (elf_file->fd == -1)
-    {
-      error ("could not open file %s", fname);
-      goto fail;
-    }
-
-  /* Initialize the ELF library.  */
-  if (elf_version (EV_CURRENT) == EV_NONE)
-    {
-      error ("ELF library is older than that used when building GCC");
-      goto fail;
-    }
-
-  /* Open the ELF file descriptor.  */
-  elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ,
-			     NULL);
-  if (!elf_file->elf)
-    {
-      error ("could not open %s as an ELF file: %s", fname, elf_errmsg (0));
-      goto fail;
-    }
-
-  if (offset != 0)
-    {
-      Elf *e;
-      off_t t = elf_rand (elf_file->elf, header_offset);
-      if (t != header_offset)
-        {
-          error ("could not seek in archive");
-          goto fail;
-        }
-
-      e = elf_begin (elf_file->fd, ELF_C_READ, elf_file->elf);
-      if (e == NULL)
-        {
-          error("could not find archive member");
-          goto fail;
-        }
-      elf_end (elf_file->elf);
-      elf_file->elf = e;
-    }
-
-  if (writable)
-    {
-      init_ehdr (elf_file);
-      elf_file->shstrtab_stream = XCNEW (struct lto_output_stream);
-      /* Output an empty string to the section header table.  This becomes the
-	 name of the initial NULL section.  */
-      lto_output_1_stream (elf_file->shstrtab_stream, '\0');
-    }
-  else
-    if (!validate_file (elf_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* Close ELF file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's ELF data is written at this time, and
-   any cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_elf_file *elf_file = (lto_elf_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-
-  /* Write the ELF section header string table.  */
-  if (elf_file->shstrtab_stream)
-    {
-      size_t strtab;
-      GElf_Ehdr *ehdr_p, ehdr_buf;
-      lto_file *old_file = lto_set_current_out_file (file);
-
-      lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
-      ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf);
-      if (ehdr_p == NULL)
-	fatal_error ("gelf_getehdr() failed: %s", elf_errmsg (-1));
-      strtab = elf_ndxscn (elf_file->scn);
-      if (strtab < SHN_LORESERVE)
-	ehdr_p->e_shstrndx = strtab;
-      else
-	{
-	  GElf_Shdr *shdr_p, shdr_buf;
-	  Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0);
-	  if (scn_p == NULL)
-	    fatal_error ("elf_getscn() failed: %s", elf_errmsg (-1));
-	  shdr_p = gelf_getshdr (scn_p, &shdr_buf);
-	  if (shdr_p == NULL)
-	    fatal_error ("gelf_getshdr() failed: %s", elf_errmsg (-1));
-	  shdr_p->sh_link = strtab;
-	  if (gelf_update_shdr (scn_p, shdr_p) == 0)
-	    fatal_error ("gelf_update_shdr() failed: %s", elf_errmsg (-1));
-	  ehdr_p->e_shstrndx = SHN_XINDEX;
-	}
-      if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0)
-	fatal_error ("gelf_update_ehdr() failed: %s", elf_errmsg (-1));
-      lto_write_stream (elf_file->shstrtab_stream);
-      lto_obj_end_section ();
-
-      lto_set_current_out_file (old_file);
-      free (elf_file->shstrtab_stream);
-
-      if (elf_update (elf_file->elf, ELF_C_WRITE) < 0)
-	fatal_error ("elf_update() failed: %s", elf_errmsg (-1));
-    }
-
-  if (elf_file->elf)
-    elf_end (elf_file->elf);
-  if (elf_file->fd != -1)
-    close (elf_file->fd);
-
-  /* Free any ELF data buffers.  */
-  cur = elf_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  free (file);
-}
-
-
-/* The current output file.  */
-static lto_file *current_out_file;
-
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
Index: gcc/lto/lto-objfile.c
===================================================================
--- gcc/lto/lto-objfile.c	(revision 0)
+++ gcc/lto/lto-objfile.c	(revision 0)
@@ -0,0 +1,374 @@ 
+/* LTO routines to use objfiles.
+   Copyright 2010 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
+#include "lto.h"
+#include "tm.h"
+#include "lto-streamer.h"
+#include "libiberty.h"
+#include "objfile.h"
+
+/* Handle opening elf files on hosts, such as Windows, that may use
+   text file handling that will break binary access.  */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* Segment name for LTO sections.  This is only used for Mach-O.
+   FIXME: This needs to be kept in sync with darwin.c.  */
+
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* An LTO file wrapped around an objfile.  */
+
+struct lto_objfile
+{
+  /* The base information.  */
+  lto_file base;
+
+  /* The system file descriptor.  */
+  int fd;
+
+  /* The objfile if we are reading the file.  */
+  objfile_read *objfile_r;
+
+  /* The objfile if we are writing the file.  */
+  objfile_write *objfile_w;
+
+  /* The currently active section.  */
+  objfile_write_section *section;
+};
+
+/* Saved objfile attributes.  FIXME: Once set, this is never
+   cleared.  */
+
+static objfile_attributes *saved_attributes;
+
+/* Initialize FILE, an LTO file object for FILENAME.  */
+
+static void
+lto_file_init (lto_file *file, const char *filename, off_t offset)
+{
+  file->filename = filename;
+  file->offset = offset;
+}
+
+/* Open the file FILENAME.  It WRITABLE is true, the file is opened
+   for write and, if necessary, created.  Otherwise, the file is
+   opened for reading.  Returns the opened file.  */
+
+lto_file *
+lto_obj_file_open (const char *filename, bool writable)
+{
+  const char *offset_p;
+  long loffset;
+  int consumed;
+  char *fname;
+  off_t offset;
+  struct lto_objfile *lo;
+  const char *errmsg;
+  int err;
+
+  offset_p = strrchr (filename, '@');
+  if (offset_p != NULL
+      && offset_p != filename
+      && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
+      && strlen (offset_p) == (unsigned int) consumed)
+    {
+      fname = XNEWVEC (char, offset_p - filename + 1);
+      memcpy (fname, filename, offset_p - filename);
+      fname[offset_p - filename] = '\0';
+      offset = (off_t) loffset;
+    }
+  else
+    {
+      fname = xstrdup (filename);
+      offset = 0;
+    }
+
+  lo = XCNEW (struct lto_objfile);
+  lto_file_init ((lto_file *) lo, fname, offset);
+
+  lo->fd = open (fname,
+		 (writable
+		  ? O_WRONLY | O_CREAT | O_BINARY
+		  : O_RDONLY | O_BINARY),
+		 0666);
+  if (lo->fd == -1)
+    {
+      error ("open %s failed: %s", fname, xstrerror (errno));
+      goto fail;
+    }
+
+  if (!writable)
+    {
+      objfile_attributes *attrs;
+
+      lo->objfile_r = objfile_open_read (lo->fd, offset, LTO_SEGMENT_NAME,
+					 &errmsg, &err);
+      if (lo->objfile_r == NULL)
+	goto fail_errmsg;
+
+      attrs = objfile_fetch_attributes (lo->objfile_r, &errmsg, &err);
+      if (attrs == NULL)
+	goto fail_errmsg;
+
+      if (saved_attributes == NULL)
+	saved_attributes = attrs;
+      else
+	{
+	  errmsg = objfile_attributes_compare (saved_attributes, attrs, &err);
+	  if (errmsg != NULL)
+	    goto fail_errmsg;
+	}
+    }
+  else
+    {
+      gcc_assert (saved_attributes != NULL);
+      lo->objfile_w = objfile_start_write (saved_attributes, LTO_SEGMENT_NAME,
+					   &errmsg, &err);
+      if (lo->objfile_w == NULL)
+	goto fail_errmsg;
+    }
+
+  return &lo->base;
+
+ fail_errmsg:
+  if (err == 0)
+    error ("%s: %s", fname, errmsg);
+  else
+    error ("%s: %s: %s", fname, errmsg, xstrerror (err));
+					 
+ fail:
+  if (lo != NULL)
+    lto_obj_file_close ((lto_file *) lo);
+  return NULL;
+}
+
+/* Close FILE.  If FILE was opened for writing, it is written out
+   now.  */
+
+void
+lto_obj_file_close (lto_file *file)
+{
+  struct lto_objfile *lo = (struct lto_objfile *) file;
+
+  if (lo->objfile_r != NULL)
+    objfile_release_read (lo->objfile_r);
+  else if (lo->objfile_w != NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      gcc_assert (lo->base.offset == 0);
+
+      errmsg = objfile_write_to_file (lo->objfile_w, lo->fd, &err);
+      if (errmsg != NULL)
+	{
+	  if (err == 0)
+	    fatal_error ("%s", errmsg);
+	  else
+	    fatal_error ("%s: %s", errmsg, xstrerror (err));
+	}
+
+      objfile_release_write (lo->objfile_w);
+    }
+
+  if (lo->fd != -1)
+    {
+      if (close (lo->fd) < 0)
+	fatal_error ("close: %s", xstrerror (errno));
+    }
+}
+
+/* This is passed to lto_obj_add_section.  */
+
+struct lto_obj_add_section_data
+{
+  /* The hash table of sections.  */
+  htab_t section_hash_table;
+  /* The offset of this file.  */
+  off_t base_offset;
+};
+
+/* This is called for each section in the file.  */
+
+static int
+lto_obj_add_section (void *data, const char *name, off_t offset,
+		     off_t length)
+{
+  struct lto_obj_add_section_data *loasd =
+    (struct lto_obj_add_section_data *) data;
+  htab_t section_hash_table = (htab_t) loasd->section_hash_table;
+  char *new_name;
+  struct lto_section_slot s_slot;
+  void **slot;
+
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+	       strlen (LTO_SECTION_NAME_PREFIX)) != 0)
+    return 1;
+
+  new_name = xstrdup (name);
+  s_slot.name = new_name;
+  slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
+
+      new_slot->name = new_name;
+      new_slot->start = loasd->base_offset + offset;
+      new_slot->len = length;
+      *slot = new_slot;
+    }
+  else
+    {
+      error ("two or more sections for %s", new_name);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Build a hash table whose key is the section name and whose data is
+   the start and size of each section in the .o file.  */
+
+htab_t
+lto_obj_build_section_table (lto_file *lto_file)
+{
+  struct lto_objfile *lo = (struct lto_objfile *) lto_file;
+  htab_t section_hash_table;
+  struct lto_obj_add_section_data loasd;
+  const char *errmsg;
+  int err;
+
+  section_hash_table = lto_obj_create_section_hash_table ();
+
+  gcc_assert (lo->objfile_r != NULL && lo->objfile_w == NULL);
+  loasd.section_hash_table = section_hash_table;
+  loasd.base_offset = lo->base.offset;
+  errmsg = objfile_find_sections (lo->objfile_r, lto_obj_add_section,
+				  &loasd, &err);
+  if (errmsg != NULL)
+    {
+      if (err == 0)
+	error ("%s", errmsg);
+      else
+	error ("%s: %s", errmsg, xstrerror (err));
+      htab_delete (section_hash_table);
+      return NULL;
+    }
+
+  return section_hash_table;
+}
+
+/* The current output file.  */
+
+static lto_file *current_out_file;
+
+/* Set the current output file.  Return the old one.  */
+
+lto_file *
+lto_set_current_out_file (lto_file *file)
+{
+  lto_file *old_file;
+
+  old_file = current_out_file;
+  current_out_file = file;
+  return old_file;
+}
+
+/* Return the current output file.  */
+
+lto_file *
+lto_get_current_out_file (void)
+{
+  return current_out_file;
+}
+
+/* Begin writing a new section named NAME in the current output
+   file.  */
+
+void
+lto_obj_begin_section (const char *name)
+{
+  struct lto_objfile *lo;
+  int align;
+  const char *errmsg;
+  int err;
+
+  lo = (struct lto_objfile *) current_out_file;
+  gcc_assert (lo != NULL
+	      && lo->objfile_r == NULL
+	      && lo->objfile_w != NULL
+	      && lo->section == NULL);
+
+  align = exact_log2 (POINTER_SIZE / BITS_PER_UNIT);
+  lo->section = objfile_write_create_section (lo->objfile_w, name, align,
+					      &errmsg, &err);
+  if (lo->section == NULL)
+    {
+      if (err == 0)
+	fatal_error ("%s", errmsg);
+      else
+	fatal_error ("%s: %s", errmsg, xstrerror (errno));
+    }
+}
+
+/* Add data to a section.  BLOCK is a pointer to memory containing
+   DATA.  */
+
+void
+lto_obj_append_data (const void *data, size_t len, void *block)
+{
+  struct lto_objfile *lo;
+  const char *errmsg;
+  int err;
+
+  lo = (struct lto_objfile *) current_out_file;
+  gcc_assert (lo != NULL && lo->section != NULL);
+
+  errmsg = objfile_write_add_data (lo->objfile_w, lo->section, data, len, 1,
+				   &err);
+  if (errmsg != NULL)
+    {
+      if (err == 0)
+	fatal_error ("%s", errmsg);
+      else
+	fatal_error ("%s: %s", errmsg, xstrerror (errno));
+    }
+
+  free (block);
+}
+
+/* Stop writing to the current output section.  */
+
+void
+lto_obj_end_section (void)
+{
+  struct lto_objfile *lo;
+
+  lo = (struct lto_objfile *) current_out_file;
+  gcc_assert (lo != NULL && lo->section != NULL);
+  lo->section = NULL;
+}
Index: gcc/lto/lto-coff.c
===================================================================
--- gcc/lto/lto-coff.c	(revision 166002)
+++ gcc/lto/lto-coff.c	(working copy)
@@ -1,817 +0,0 @@ 
-/* LTO routines for COFF object files.
-   Copyright 2009, 2010 Free Software Foundation, Inc.
-   Contributed by Dave Korn.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "ggc.h"
-#include "lto-streamer.h"
-#include "lto/lto-coff.h"
-
-
-/* Rather than implementing a libcoff to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) COFF format object file reader/writer.  The generated files
-   will contain a COFF header, a number of COFF section headers, the 
-   section data itself, and a trailing string table for section names.  */
-
-/* Handle opening elf files on hosts, such as Windows, that may use 
-   text file handling that will break binary access.  */
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-/* Known header magics for validation, as an array.  */
-
-static const unsigned int coff_machine_array[] = COFF_KNOWN_MACHINES;
-
-/* Number of valid entries (no sentinel) in array.  */
-
-#define NUM_COFF_KNOWN_MACHINES	\
-	(sizeof (coff_machine_array) / sizeof (coff_machine_array[0]))
-
-/* Cached object file header.  */
-
-static Coff_header cached_coff_hdr;
-
-/* Flag to indicate if we have read and cached any header yet.  */
-
-static bool cached_coff_hdr_valid = false;
-
-/* The current output file.  */
-
-static lto_file *current_out_file;
-
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
-
-
-/* COFF section structure constructor.  */
-
-static lto_coff_section *
-coff_newsection (lto_coff_file *file, const char *name, size_t type)
-{
-  lto_coff_section *ptr, **chain_ptr_ptr;
-
-  ptr = XCNEW (lto_coff_section);
-  ptr->name = name;
-  ptr->type = type;
-
-  chain_ptr_ptr = &file->section_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-
-/* COFF section data block structure constructor.  */
-
-static lto_coff_data *
-coff_newdata (lto_coff_section *sec)
-{
-  lto_coff_data *ptr, **chain_ptr_ptr;
-
-  ptr = XCNEW (lto_coff_data);
-
-  chain_ptr_ptr = &sec->data_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-
-/* Initialize FILE, an LTO file object for FILENAME.  */
-
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_coff_file *coff_file = (lto_coff_file *)lto_file;
-  lto_coff_section *sec;
-  htab_t section_hash_table;
-  ssize_t strtab_size;
-  char *strtab;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  /* Seek to start of string table.  */
-  if (coff_file->strtab_offs != lseek (coff_file->fd,
-		coff_file->base.offset + coff_file->strtab_offs, SEEK_SET))
-    {
-      error ("altered or invalid COFF object file");
-      return section_hash_table;
-    }
-
-  strtab_size = coff_file->file_size - coff_file->strtab_offs;
-  strtab = XNEWVEC (char, strtab_size);
-  if (read (coff_file->fd, strtab, strtab_size) != strtab_size)
-    {
-      error ("invalid COFF object file string table");
-      return section_hash_table;
-    }
-
-  /* Scan sections looking at names.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, sec)
-    {
-      struct lto_section_slot s_slot;
-      void **slot;
-      char *new_name;
-      int stringoffset;
-      char *name = (char *) &sec->coffsec.Name[0];
-
-      /* Skip dummy string section if by any chance we see it.  */
-      if (sec->type == 1)
-	continue;
-
-      if (name[0] == '/')
-	{
-	  if (1 != sscanf (&name[1], "%d", &stringoffset)
-		|| stringoffset < 0 || stringoffset >= strtab_size)
-	    {
-	      error ("invalid COFF section name string");
-	      continue;
-	    }
-	  name = strtab + stringoffset;
-	}
-      else
-	{
-	  /* If we cared about the VirtualSize field, we couldn't
-	     crudely trash it like this to guarantee nul-termination
-	     of the Name field.  But we don't, so we do.  */
-	  name[8] = 0;
-	}
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-			strlen (LTO_SECTION_NAME_PREFIX)) != 0)
-	  continue;
-
-      new_name = XNEWVEC (char, strlen (name) + 1);
-      strcpy (new_name, name);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-	{
-	  struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-	  new_slot->name = new_name;
-	  /* The offset into the file for this section.  */
-	  new_slot->start = coff_file->base.offset
-			+ COFF_GET(&sec->coffsec,PointerToRawData);
-	  new_slot->len = COFF_GET(&sec->coffsec,SizeOfRawData);
-	  *slot = new_slot;
-	}
-      else
-	{
-	  error ("two or more sections for %s:", new_name);
-	  return NULL;
-	}
-    }
-
-  free (strtab);
-  return section_hash_table;
-}
-
-
-/* Begin a new COFF section named NAME with type TYPE in the current output
-   file.  TYPE is an SHT_* macro from the libelf headers.  */
-
-static void
-lto_coff_begin_section_with_type (const char *name, size_t type)
-{
-  lto_coff_file *file;
-  size_t sh_name;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_coff_file *) lto_get_current_out_file (),
-  gcc_assert (file);
-  gcc_assert (!file->scn);
-
-  /* Create a new section.  */
-  file->scn = coff_newsection (file, name, type);
-  if (!file->scn)
-    fatal_error ("could not create a new COFF section: %m");
-
-  /* Add a string table entry and record the offset.  */
-  gcc_assert (file->shstrtab_stream);
-  sh_name = file->shstrtab_stream->total_size;
-  lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
-
-  /* Initialize the section header.  */
-  file->scn->strtab_offs = sh_name;
-}
-
-
-/* Begin a new COFF section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_coff_begin_section_with_type (name, 0);
-}
-
-
-/* Append DATA of length LEN to the current output section.  BASE is a pointer
-   to the output page containing DATA.  It is freed once the output file has
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_coff_file *file;
-  lto_coff_data *coff_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_coff_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  coff_data = coff_newdata (file->scn);
-  if (!coff_data)
-    fatal_error ("could not append data to COFF section: %m");
-
-  coff_data->d_buf = CONST_CAST (void *, data);
-  coff_data->d_size = len;
-
-  /* Chain all data blocks (from all sections) on one singly-linked
-     list for freeing en masse after the file is closed.  */
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_coff_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_coff_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* Validate's COFF_FILE's executable header and, if cached_coff_hdr is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success or false on failure.  */
-
-static bool
-validate_file (lto_coff_file *coff_file)
-{
-  size_t n, secnum;
-  unsigned int numsections, secheaderssize, numsyms;
-  off_t sectionsstart, symbolsstart, stringsstart;
-  unsigned int mach, charact;
-
-  /* Read and sanity check the raw header.  */
-  n = read (coff_file->fd, &coff_file->coffhdr, sizeof (coff_file->coffhdr));
-  if (n != sizeof (coff_file->coffhdr))
-    {
-      error ("not a COFF object file");
-      return false;
-    }
-
-  mach = COFF_GET(&coff_file->coffhdr, Machine);
-  for (n = 0; n < NUM_COFF_KNOWN_MACHINES; n++)
-    if (mach == coff_machine_array[n])
-      break;
-  if (n == NUM_COFF_KNOWN_MACHINES)
-    {
-      error ("not a recognized COFF object file");
-      return false;
-    }
-
-  charact = COFF_GET(&coff_file->coffhdr, Characteristics);
-  if (COFF_NOT_CHARACTERISTICS & charact)
-    {
-      /* DLL, EXE or SYS file.  */
-      error ("not a relocatable COFF object file");
-      return false;
-    }
-
-  if (mach != IMAGE_FILE_MACHINE_AMD64
-      && COFF_CHARACTERISTICS != (COFF_CHARACTERISTICS & charact))
-    {
-      /* ECOFF/XCOFF support not implemented.  */
-      error ("not a 32-bit COFF object file");
-      return false;
-    }
-
-  /* It validated OK, so cached it if we don't already have one.  */
-  if (!cached_coff_hdr_valid)
-    {
-      cached_coff_hdr_valid = true;
-      memcpy (&cached_coff_hdr, &coff_file->coffhdr, sizeof (cached_coff_hdr));
-    }
-
-  if (mach != COFF_GET(&cached_coff_hdr, Machine))
-    {
-      error ("inconsistent file architecture detected");
-      return false;
-    }
-
-  /* Read section headers and string table? */
-
-  numsections = COFF_GET(&coff_file->coffhdr, NumberOfSections);
-  secheaderssize = numsections * sizeof (Coff_section);
-  sectionsstart = sizeof (Coff_header) + secheaderssize;
-  symbolsstart = COFF_GET(&coff_file->coffhdr, PointerToSymbolTable);
-  numsyms = COFF_GET(&coff_file->coffhdr, NumberOfSymbols);
-  stringsstart = (symbolsstart + COFF_SYMBOL_SIZE * numsyms);
-
-#define CVOFFSETTTED(x) (coff_file->base.offset + (x))
-
-  if (numsections <= 0 || symbolsstart <= 0 || numsyms <= 0
-	|| (CVOFFSETTTED(sectionsstart) >= coff_file->file_size)
-	|| (CVOFFSETTTED(symbolsstart) >= coff_file->file_size)
-	|| (CVOFFSETTTED(stringsstart) >= coff_file->file_size))
-    {
-      error ("not a valid COFF object file");
-      return false;
-    }
-
-#undef CVOFFSETTTED
-
-  /* Record start of string table.  */
-  coff_file->strtab_offs = stringsstart;
-
-  /* Validate section table entries.  */
-  for (secnum = 0; secnum < numsections; secnum++)
-    {
-      Coff_section coffsec;
-      lto_coff_section *ltosec;
-      off_t size_raw, offs_raw, offs_relocs, offs_lines;
-      off_t num_relocs, num_lines;
-
-      n = read (coff_file->fd, &coffsec, sizeof (coffsec));
-      if (n != sizeof (coffsec))
-	{
-	  error ("short/missing COFF section table");
-	  return false;
-	}
-
-      size_raw = COFF_GET(&coffsec, SizeOfRawData);
-      offs_raw = COFF_GET(&coffsec, PointerToRawData);
-      offs_relocs = COFF_GET(&coffsec, PointerToRelocations);
-      offs_lines = COFF_GET(&coffsec, PointerToLinenumbers);
-      num_relocs = COFF_GET(&coffsec, NumberOfRelocations);
-      num_lines = COFF_GET(&coffsec, NumberOfLinenumbers);
-
-      if (size_raw < 0 || num_relocs < 0 || num_lines < 0
-	|| (size_raw
-	  && ((COFF_GET(&coffsec, Characteristics)
-	      & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
-	    ? (offs_raw != 0)
-	    : (offs_raw < sectionsstart || offs_raw >= coff_file->file_size)))
-	|| (num_relocs
-	  && (offs_relocs < sectionsstart
-	    || offs_relocs >= coff_file->file_size))
-	|| (num_lines
-	  && (offs_lines < sectionsstart
-	    || offs_lines >= coff_file->file_size)))
-	{
-	  error ("invalid COFF section table");
-	  return false;
-	}
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-	 we build the hash table.  */
-      ltosec = coff_newsection (coff_file, NULL, 0);
-      memcpy (&ltosec->coffsec, &coffsec, sizeof (ltosec->coffsec));
-    }
-
-  return true;
-}
-
-/* Initialize COFF_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_coffhdr (lto_coff_file *coff_file)
-{
-  gcc_assert (cached_coff_hdr_valid);
-  memset (&coff_file->coffhdr, 0, sizeof (coff_file->coffhdr));
-  COFF_PUT(&coff_file->coffhdr, Machine, COFF_GET(&cached_coff_hdr, Machine));
-  COFF_PUT(&coff_file->coffhdr, Characteristics, COFF_GET(&cached_coff_hdr, Characteristics));
-}
-
-/* Open COFF file FILENAME.  If WRITABLE is true, the file is opened for write
-   and, if necessary, created.  Otherwise, the file is opened for reading.
-   Returns the opened file.  */
-
-lto_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_coff_file *coff_file;
-  lto_file *result = NULL;
-  off_t offset;
-  const char *offset_p;
-  char *fname;
-  struct stat statbuf;
-
-  offset_p = strchr (filename, '@');
-  if (!offset_p)
-    {
-      fname = xstrdup (filename);
-      offset = 0;
-    }
-  else
-    {
-      /* The file started with '@' is a file containing command line
-	 options.  Stop if it doesn't exist.  */
-      if (offset_p == filename)
-	fatal_error ("command line option file '%s' does not exist",
-		     filename);
-
-      fname = (char *) xmalloc (offset_p - filename + 1);
-      memcpy (fname, filename, offset_p - filename);
-      fname[offset_p - filename] = '\0';
-      offset_p += 3; /* skip the @0x */
-      offset = lto_parse_hex (offset_p);
-    }
-
-  /* Set up.  */
-  coff_file = XCNEW (lto_coff_file);
-  result = (lto_file *) coff_file;
-  lto_file_init (result, fname, offset);
-  coff_file->fd = -1;
-
-  /* Open the file.  */
-  coff_file->fd = open (fname,
-    O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
-  if (coff_file->fd == -1)
-    {
-      error ("could not open file %s", fname);
-      goto fail;
-    }
-
-  if (stat (fname, &statbuf) < 0)
-    {
-      error ("could not stat file %s", fname);
-      goto fail;
-    }
-
-  coff_file->file_size = statbuf.st_size;
-
-  if (offset != 0)
-    {
-      char ar_tail[12];
-      int size;
-
-      /* Surely not?  */
-      gcc_assert (!writable);
-
-      /* Seek to offset, or error.  */
-      if (lseek (coff_file->fd, offset, SEEK_SET) != (ssize_t) offset)
-	{
-	  error ("could not find archive member @0x%lx", (long) offset);
-	  goto fail;
-	}
-
-      /* Now seek back 12 chars and read the tail of the AR header to
-         find the length of the member file.  */
-      if (lseek (coff_file->fd, -12, SEEK_CUR) < 0
-	  || read (coff_file->fd, ar_tail, 12) != 12
-	  || lseek (coff_file->fd, 0, SEEK_CUR) != (ssize_t) offset
-	  || ar_tail[10] != '`' || ar_tail[11] != '\n')
-	{
-	  error ("could not find archive header @0x%lx", (long) offset);
-	  goto fail;
-	}
-
-      ar_tail[11] = 0;
-      if (sscanf (ar_tail, "%d", &size) != 1)
-	{
-	  error ("invalid archive header @0x%lx", (long) offset);
-	  goto fail;
-	}
-      coff_file->file_size = size;
-    }
-
-  if (writable)
-    {
-      init_coffhdr (coff_file);
-      coff_file->shstrtab_stream = XCNEW (struct lto_output_stream);
-    }
-  else
-    if (!validate_file (coff_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* Close COFF file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's COFF data is written at this time, and
-   any cached data buffers are freed.  Return TRUE if there was an error.  */
-
-static bool
-coff_write_object_file (lto_coff_file *coff_file)
-{
-  lto_coff_section *cursec, *stringsec;
-  lto_coff_data *data;
-  size_t fileoffset, numsections, totalsecsize, numsyms, stringssize;
-  bool write_err = false;
-  int secnum;
-
-  /* Infer whether this file was opened for reading or writing from the
-     presence or absense of an initialised stream for the string table;
-     do nothing if it was opened for reading.  */
-  if (!coff_file->shstrtab_stream)
-    return false;
-  else
-    {
-      /* Write the COFF string table into a dummy new section that
-	 we will not write a header for.  */
-      lto_file *old_file = lto_set_current_out_file (&coff_file->base);
-      /* This recursively feeds in the data to a new section.  */
-      lto_coff_begin_section_with_type (".strtab", 1);
-      lto_write_stream (coff_file->shstrtab_stream);
-      lto_obj_end_section ();
-      lto_set_current_out_file (old_file);
-      free (coff_file->shstrtab_stream);
-    }
-
-  /* Layout the file.  Count sections (not dummy string section) and calculate
-     data size for all of them.  */
-  numsections = 0;
-  totalsecsize = 0;
-  stringssize = 0;
-  stringsec = NULL;
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-      lto_coff_data *data;
-      size_t cursecsize;
-      cursecsize = 0;
-      COFF_FOR_ALL_DATA(cursec,data)
-	cursecsize += data->d_size;
-      if (cursec->type == 0)
-	{
-	  ++numsections;
-	  totalsecsize += COFF_ALIGN(cursecsize);
-#if COFF_ALIGNMENT > 1
-	  cursec->pad_needed = COFF_ALIGN(cursecsize) - cursecsize;
-#endif
-	}
-      else
-        {
-	  stringssize = cursecsize;
-	  stringsec = cursec;
-	}
-      COFF_PUT(&cursec->coffsec, SizeOfRawData, cursecsize);
-    }
-
-  /* There is a file symbol and a section symbol per section,
-     and each of these has a single auxiliary symbol following.  */
-  numsyms = 2 * (1 + numsections);
-
-  /* Great!  Now we have enough info to fill out the file header.  */
-  COFF_PUT(&coff_file->coffhdr, NumberOfSections, numsections);
-  COFF_PUT(&coff_file->coffhdr, NumberOfSymbols, numsyms);
-  COFF_PUT(&coff_file->coffhdr, PointerToSymbolTable, sizeof (Coff_header)
-		+ numsections * sizeof (Coff_section) + totalsecsize);
-  /* The remaining members were initialised to zero or copied from
-     a cached header, so we leave them alone here.  */
-
-  /* Now position all the sections, and fill out their headers.  */
-  fileoffset = sizeof (Coff_header) + numsections * sizeof (Coff_section);
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-      /* Skip dummy string section.  */
-      if (cursec->type == 1)
-	continue;
-      COFF_PUT(&cursec->coffsec, PointerToRawData, fileoffset);
-      fileoffset += COFF_ALIGN (COFF_GET(&cursec->coffsec, SizeOfRawData));
-      COFF_PUT(&cursec->coffsec, Characteristics, COFF_SECTION_CHARACTERISTICS);
-      snprintf ((char *)&cursec->coffsec.Name[0], 8, "/%d", cursec->strtab_offs + 4);
-    }
-
-  /* We can write the data now.  As there's no way to indicate an error return
-     from this hook, error handling is limited to not wasting our time doing
-     any more writes in the event that any one fails.  */
-
-  /* Write the COFF header.  */
-  write_err = (write (coff_file->fd, &coff_file->coffhdr,
-		sizeof (coff_file->coffhdr)) != sizeof (coff_file->coffhdr));
-
-  /* Write the COFF section headers.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    if (cursec->type == 1)	/* Skip dummy string section.  */
-	continue;
-    else if (!write_err)
-      write_err = (write (coff_file->fd, &cursec->coffsec,
-		sizeof (cursec->coffsec)) != sizeof (cursec->coffsec));
-    else
-      break;
-
-  /* Write the COFF sections.  */
-  COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-    {
-#if COFF_ALIGNMENT > 1
-      static const char padzeros[COFF_ALIGNMENT] = { 0 };
-#endif
-      /* Skip dummy string section.  */
-      if (cursec->type == 1)
-	continue;
-      COFF_FOR_ALL_DATA(cursec, data)
-	if (!write_err)
-	  write_err = (write (coff_file->fd, data->d_buf, data->d_size)
-		!= data->d_size);
-	else
-	  break;
-#if COFF_ALIGNMENT > 1
-      if (!write_err && cursec->pad_needed)
-	write_err = (write (coff_file->fd, padzeros, cursec->pad_needed)
-		!= cursec->pad_needed);
-#endif
-    }
-
-  /* Write the COFF symbol table.  */
-  if (!write_err)
-    {
-      union
-	{
-	  Coff_symbol sym;
-	  Coff_aux_sym_file file;
-	  Coff_aux_sym_section sec;
-	} symbols[2];
-      memset (&symbols[0], 0, sizeof (symbols));
-      strcpy ((char *) &symbols[0].sym.Name[0], ".file");
-      COFF_PUT(&symbols[0].sym, SectionNumber, IMAGE_SYM_DEBUG);
-      COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
-      symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_FILE;
-      symbols[0].sym.NumberOfAuxSymbols[0] = 1;
-      snprintf ((char *)symbols[1].file.FileName,
-		sizeof (symbols[1].file.FileName),
-		"%s", lbasename (coff_file->base.filename));
-      write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
-		!= (2 * COFF_SYMBOL_SIZE));
-
-      /* Set up constant parts for section sym loop.  */
-      memset (&symbols[0], 0, sizeof (symbols));
-      COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
-      symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_STATIC;
-      symbols[0].sym.NumberOfAuxSymbols[0] = 1;
-
-      secnum = 1;
-      if (!write_err)
-	COFF_FOR_ALL_SECTIONS(coff_file, cursec)
-	  {
-	    /* Skip dummy string section.  */
-	    if (cursec->type == 1)
-	      continue;
-	    /* Reuse section name string for section symbol name.  */
-	    COFF_PUT_NDXSZ(&symbols[0].sym, Name, 0, 0, 4);
-	    COFF_PUT_NDXSZ(&symbols[0].sym, Name, cursec->strtab_offs + 4, 4, 4);
-	    COFF_PUT(&symbols[0].sym, SectionNumber, secnum++);
-	    COFF_PUT(&symbols[1].sec, Length,
-			COFF_GET(&cursec->coffsec, SizeOfRawData));
-	    if (!write_err)
-	      write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
-			!= (2 * COFF_SYMBOL_SIZE));
-	    else
-	      break;
-	  }
-    }
-
-  /* Write the COFF string table.  */
-  if (!write_err)
-    {
-      unsigned char outlen[4];
-      COFF_PUT4(outlen, stringssize + 4);
-      if (!write_err)
-	write_err = (write (coff_file->fd, outlen, 4) != 4);
-      if (stringsec)
-	{
-	  COFF_FOR_ALL_DATA(stringsec, data)
-	    if (!write_err)
-	      write_err = (write (coff_file->fd, data->d_buf, data->d_size)
-			   != data->d_size);
-	    else
-	      break;
-	}
-    }
-
-  return write_err;
-}
-
-/* Close COFF file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's COFF data is written at this time, and
-   any cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_coff_file *coff_file = (lto_coff_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-  lto_coff_section *cursec, *nextsec;
-  bool write_err = false;
-
-  /* Write the COFF string table into a dummy new section that
-     we will not write a header for.  */
-  if (coff_file->shstrtab_stream)
-    coff_write_object_file (coff_file);
-
-  /* Close the file, we're done.  */
-  if (coff_file->fd != -1)
-    close (coff_file->fd);
-
-  /* Free any data buffers.  */
-  cur = coff_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  /* Free any sections and their data chains.  */
-  cursec = coff_file->section_chain;
-  while (cursec)
-    {
-      lto_coff_data *curdata, *nextdata;
-      nextsec = cursec->next;
-      curdata = cursec->data_chain;
-      while (curdata)
-	{
-	  nextdata = curdata->next;
-	  free (curdata);
-	  curdata = nextdata;
-	}
-      free (cursec);
-      cursec = nextsec;
-    }
-
-  free (file);
-
-  /* If there was an error, mention it.  */
-  if (write_err)
-    error ("I/O error writing COFF output file");
-}
-
Index: gcc/lto/lto-coff.h
===================================================================
--- gcc/lto/lto-coff.h	(revision 166002)
+++ gcc/lto/lto-coff.h	(working copy)
@@ -1,408 +0,0 @@ 
-/* LTO routines for COFF object files.
-   Copyright 2009 Free Software Foundation, Inc.
-   Contributed by Dave Korn.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#ifndef LTO_COFF_H
-#define LTO_COFF_H
-
-/* Rather than implementing a libcoff to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) COFF format object file reader/writer.  The generated files
-   will contain a COFF header, a number of COFF section headers, the 
-   section data itself, and a trailing string table for section names.  */
-
-/* Alignment of sections in a COFF object file.
-
-   The LTO writer uses zlib compression on the data that it streams into
-   LTO sections in the output object file.  Because these streams don't
-   have any embedded size information, the section in the object file must
-   be exactly sized to the data emitted; any trailing padding bytes will
-   be interpreted as partial and/or corrupt compressed data.
-
-   This is easy enough to do on COFF targets (with binutils 2.20.1 or
-   above) because we can specify 1-byte alignment for the LTO sections.
-   They are then emitted precisely-sized and byte-packed into the object
-   and the reader is happy when it parses them later.  This is currently
-   implemented in the x86/windows backed in i386_pe_asm_named_section()
-   in config/i386/winnt.c by detecting the LTO section name prefix, 
-
-   That would be sufficient, but for one thing.  At the start of the LTO
-   data is a header struct with (currently) a couple of version numbers and
-   some type info; see struct lto_header in lto-streamer.h.  If the sections
-   are byte-packed, this header will not necessarily be correctly-aligned
-   when it is read back into memory.
-
-   On x86 targets, which are currently the only LTO-COFF targets, misaligned
-   memory accesses aren't problematic (okay, inefficient, but not worth
-   worrying about two half-word memory reads per section in the context of
-   everything else the compiler has to do at the time!), but RISC targets may
-   fail on trying to access the header struct.  In this case, it will be
-   necessary to enable (preferably in a target-dependent fashion, but a few
-   bytes of padding are hardly an important issue if it comes down to it) the
-   COFF_ALIGNMENT macros below.
-
-   As currently implemented, this will emit padding to the necessary number
-   of bytes after each LTO section.  These bytes will constitute 'gaps' in
-   the object file structure, as they won't be covered by any section header.
-   This hasn't yet been tested, because no such RISC LTO-COFF target yet
-   exists.  If it causes problems further down the toolchain, it will be
-   necessary to adapt the code to emit additional section headers for these
-   padding bytes, but the odds are that it will "just work".
-
-  */
-
-#if 0
-#define COFF_ALIGNMENT	 (4)
-#define COFF_ALIGNMENTM1 (COFF_ALIGNMENT - 1)
-#define COFF_ALIGN(x)	 (((x) + COFF_ALIGNMENTM1) & ~COFF_ALIGNMENTM1)
-#else
-#define COFF_ALIGNMENT	 (1)
-#define COFF_ALIGN(x)	 (x)
-#endif
-
-/* COFF header machine codes.  */
-
-#define IMAGE_FILE_MACHINE_I386	(0x014c)
-#define IMAGE_FILE_MACHINE_AMD64 (0x8664)
-
-/* Known header magics for validation, as an array initialiser.  */
-
-#define COFF_KNOWN_MACHINES \
-  { IMAGE_FILE_MACHINE_I386, \
-    IMAGE_FILE_MACHINE_AMD64/*, ... add more here when working.  */ }
-
-/* COFF object file header, section and symbol flags and types.  These are
-   currently specific to PE-COFF, which is the only LTO-COFF format at the
-   time of writing.  Maintainers adding support for new COFF formats will
-   need to make these into target macros of some kind.  */
-
-/* COFF header characteristics.  */
-
-#define IMAGE_FILE_EXECUTABLE_IMAGE	(1 << 1)
-#define IMAGE_FILE_32BIT_MACHINE	(1 << 8)
-#define IMAGE_FILE_SYSTEM		(1 << 12)
-#define IMAGE_FILE_DLL			(1 << 13)
-
-/* Desired characteristics (for validation).  */
-
-#define COFF_CHARACTERISTICS \
-  (IMAGE_FILE_32BIT_MACHINE)
-
-/* Unwanted characteristics (for validation).  */
-
-#define COFF_NOT_CHARACTERISTICS \
-  (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL)
-
-/* Section flags.  LTO emits byte-aligned read-only loadable data sections.  */
-
-#define IMAGE_SCN_CNT_INITIALIZED_DATA	 (1 << 6)
-#define IMAGE_SCN_CNT_UNINITIALIZED_DATA (1 << 7)
-#define IMAGE_SCN_ALIGN_1BYTES		 (0x1 << 20)
-#define IMAGE_SCN_MEM_DISCARDABLE	 (1 << 25)
-#define	IMAGE_SCN_MEM_SHARED		 (1 << 28)
-#define IMAGE_SCN_MEM_READ		 (1 << 30)
-
-#define COFF_SECTION_CHARACTERISTICS \
-  (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | \
-  IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ)
-
-/* Symbol-related constants.  */
-
-#define IMAGE_SYM_DEBUG		(-2)
-#define IMAGE_SYM_TYPE_NULL	(0)
-#define IMAGE_SYM_DTYPE_NULL	(0)
-#define IMAGE_SYM_CLASS_STATIC	(3)
-#define IMAGE_SYM_CLASS_FILE	(103)
-
-#define IMAGE_SYM_TYPE \
-  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
-
-/* Size of a COFF symbol in bytes.  */
-
-#define COFF_SYMBOL_SIZE	(18)
-
-/* On-disk file structures.  */
-
-struct Coff_header
-{
-  unsigned char Machine[2];
-  unsigned char NumberOfSections[2];
-  unsigned char TimeDateStamp[4];
-  unsigned char PointerToSymbolTable[4];
-  unsigned char NumberOfSymbols[4];
-  unsigned char SizeOfOptionalHeader[2];
-  unsigned char Characteristics[2];
-};
-typedef struct Coff_header Coff_header;
-
-struct Coff_section
-{
-  unsigned char Name[8];
-  unsigned char VirtualSize[4];
-  unsigned char VirtualAddress[4];
-  unsigned char SizeOfRawData[4];
-  unsigned char PointerToRawData[4];
-  unsigned char PointerToRelocations[4];
-  unsigned char PointerToLinenumbers[4];
-  unsigned char NumberOfRelocations[2];
-  unsigned char NumberOfLinenumbers[2];
-  unsigned char Characteristics[4];
-};
-typedef struct Coff_section Coff_section;
-
-struct Coff_symbol
-{
-  unsigned char Name[8];
-  unsigned char Value[4];
-  unsigned char SectionNumber[2];
-  unsigned char Type[2];
-  unsigned char StorageClass[1];
-  unsigned char NumberOfAuxSymbols[1];
-};
-typedef struct Coff_symbol Coff_symbol;
-
-struct Coff_aux_sym_file
-{
-  unsigned char FileName[18];
-};
-typedef struct Coff_aux_sym_file Coff_aux_sym_file;
-
-struct Coff_aux_sym_section
-{
-  unsigned char Length[4];
-  unsigned char NumberOfRelocations[2];
-  unsigned char NumberOfLineNumbers[2];
-  unsigned char Checksum[4];
-  unsigned char Number[2];
-  unsigned char Selection[1];
-  unsigned char Unused[3];
-};
-typedef struct Coff_aux_sym_section Coff_aux_sym_section;
-
-/* Accessor macros for the above structures.  */
-
-#define COFF_GET(struc,memb) \
-  ((COFFENDIAN ? get_be : get_le) (&(struc)->memb[0], sizeof ((struc)->memb)))
-
-#define COFF_PUT(struc,memb,val) \
-  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[0], sizeof ((struc)->memb), val))
-
-#define COFF_PUT_NDXSZ(struc,memb,val,ndx,sz) \
-  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[ndx], sz, val))
-
-/* In-memory file structures.  */
-
-/* Forward declared structs.  */
-
-struct lto_coff_data;
-struct lto_coff_section;
-struct lto_coff_file;
-
-/* Section data in output files is made of these.  */
-
-struct lto_coff_data
-{
-  /* Pointer to data block.  */
-  void *d_buf;
-
-  /* Size of data block.  */
-  ssize_t d_size;
-
-  /* Next data block for this section.  */
-  struct lto_coff_data *next;
-};
-typedef struct lto_coff_data lto_coff_data;
-
-/* This struct tracks the data for a section.  */
-
-struct lto_coff_section
-{
-  /* Singly-linked list of section's data blocks.  */
-  lto_coff_data *data_chain;
-
-  /* Offset in string table of name.  */
-  size_t strtab_offs;
-
-  /* Section type: 0 = real, 1 = dummy.  */
-  size_t type;
-
-  /* Section name.  */
-  const char *name;
-
-#if COFF_ALIGNMENT > 1
-  /* Number of trailing padding bytes needed.  */
-  ssize_t pad_needed;
-#endif
-
-  /* Raw section header data.  */
-  Coff_section coffsec;
-
-  /* Next section for this file.  */
-  struct lto_coff_section *next;
-};
-typedef struct lto_coff_section lto_coff_section;
-
-/* A COFF file.  */
-
-struct lto_coff_file 
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* Common file members:  */
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The file's overall header.  */
-  Coff_header coffhdr;
-
-  /* All sections in a singly-linked list.  */
-  lto_coff_section *section_chain;
-
-  /* Readable file members:  */
-
-  /* File total size.  */
-  off_t file_size;
-
-  /* String table file offset, relative to base.offset.  */
-  off_t strtab_offs;
-
-  /* Writable file members:  */
-
-  /* The currently active section.  */
-  lto_coff_section *scn;
-
-  /* The output stream for section header names.  */
-  struct lto_output_stream *shstrtab_stream;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  Which has been
-     faithfully reproduced here.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_coff_file lto_coff_file;
-
-/* Data hunk iterator.  */
-
-#define COFF_FOR_ALL_DATA(sec,var) \
-  for (var = sec->data_chain; var; var = var->next)
-
-/* Section list iterator.  */
-
-#define COFF_FOR_ALL_SECTIONS(file,var) \
-  for (var = file->section_chain; var; var = var->next)
-
-/* Very simple endian-ness layer.  */
-
-#ifndef COFFENDIAN
-#define COFFENDIAN (BYTES_BIG_ENDIAN)
-#endif
-
-static inline unsigned int
-get_2_le (const unsigned char *ptr)
-{
-  return ptr[0] | (ptr[1] << 8);
-}
-
-static inline unsigned int
-get_4_le (const unsigned char *ptr)
-{
-  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-}
-
-static inline unsigned int
-get_2_be (const unsigned char *ptr)
-{
-  return ptr[1] | (ptr[0] << 8);
-}
-
-static inline unsigned int
-get_4_be (const unsigned char *ptr)
-{
-  return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
-}
-
-static inline unsigned int
-get_be (const unsigned char *ptr, size_t size)
-{
-  gcc_assert (size == 4 || size == 2);
-  return (size == 2) ? get_2_be (ptr) : get_4_be (ptr);
-}
-
-static inline unsigned int
-get_le (const unsigned char *ptr, size_t size)
-{
-  gcc_assert (size == 4 || size == 2);
-  return (size == 2) ? get_2_le (ptr) : get_4_le (ptr);
-}
-
-static inline void
-put_2_le (unsigned char *ptr, unsigned int data)
-{
-  ptr[0] = data & 0xff;
-  ptr[1] = (data >> 8) & 0xff;
-}
-
-static inline void
-put_4_le (unsigned char *ptr, unsigned int data)
-{
-  ptr[0] = data & 0xff;
-  ptr[1] = (data >> 8) & 0xff;
-  ptr[2] = (data >> 16) & 0xff;
-  ptr[3] = (data >> 24) & 0xff;
-}
-
-static inline void
-put_2_be (unsigned char *ptr, unsigned int data)
-{
-  ptr[1] = data & 0xff;
-  ptr[0] = (data >> 8) & 0xff;
-}
-
-static inline void
-put_4_be (unsigned char *ptr, unsigned int data)
-{
-  ptr[3] = data & 0xff;
-  ptr[2] = (data >> 8) & 0xff;
-  ptr[1] = (data >> 16) & 0xff;
-  ptr[0] = (data >> 24) & 0xff;
-}
-
-static inline void
-put_le (unsigned char *ptr, size_t size, unsigned int data)
-{
-  gcc_assert (size == 4 || size == 2);
-  (void) (size == 2 ? put_2_le : put_4_le) (ptr, data);
-}
-
-static inline void
-put_be (unsigned char *ptr, size_t size, unsigned int data)
-{
-  gcc_assert (size == 4 || size == 2);
-  (void) (size == 2 ? put_2_be : put_4_be) (ptr, data);
-}
-
-/* We use this for putting the string table size.  */
-
-#define COFF_PUT4(ptr, data) \
-  ((COFFENDIAN ? put_4_be : put_4_le) (ptr, data))
-
-
-#endif /* LTO_COFF_H */
Index: gcc/lto/Make-lang.in
===================================================================
--- gcc/lto/Make-lang.in	(revision 166002)
+++ gcc/lto/Make-lang.in	(working copy)
@@ -23,7 +23,7 @@ 
 # The name of the LTO compiler.
 LTO_EXE = lto1$(exeext)
 # The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o lto/lto.o lto/$(LTO_BINARY_READER).o attribs.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-objfile.o attribs.o
 LTO_H = lto/lto.h $(HASHTAB_H)
 LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
 LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H)
@@ -73,7 +73,7 @@  lto-warn = $(STRICT_WARN)
 
 $(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS)
 	+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
-		$(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) $(LTO_USE_LIBELF)
+		$(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS)
 
 # Dependencies
 lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
@@ -86,14 +86,9 @@  lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTE
 	langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
 	$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
 	$(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H)
-lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-	toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H)
-lto/lto-coff.o: lto/lto-coff.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-	toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
-	lto/lto-coff.h
-lto/lto-macho.o: lto/lto-macho.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-	toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
-	lto/lto-macho.h lto/lto-endian.h
+lto/lto-objfile.o: lto/lto-objfile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+	$(DIAGNOSTIC_CORE_H) $(TOPLEV_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
+	$(LIBIBERTY_H) $(OBJFILE_H)
 
 # LTO testing is done as part of C/C++/Fortran etc. testing.
 check-lto:
Index: gcc/lto/lto-macho.c
===================================================================
--- gcc/lto/lto-macho.c	(revision 166002)
+++ gcc/lto/lto-macho.c	(working copy)
@@ -1,948 +0,0 @@ 
-/* LTO routines for Mach-O object files.
-   Copyright 2010 Free Software Foundation, Inc.
-   Contributed by Steven Bosscher.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "lto-streamer.h"
-#include "lto/lto-endian.h"
-#include "lto/lto-macho.h"
-
-/* Rather than implementing a libmacho to match libelf, or attempting to
-   integrate libbfd into GCC, this file is a self-contained (and very
-   minimal) Mach-O format object file reader/writer.  The generated files
-   will contain a Mach-O header, a number of Mach-O load commands an
-   section headers, the  section data itself, and a trailing string table
-   for section names.  */
-
-/* This needs to be kept in sync with darwin.c.  Better yet, lto-macho.c
-   and lto-macho.h should be moved to config/, and likewise for lto-coff.*
-   and lto-elf.*.  */
-
-/* Segment name for LTO sections.  */
-#define LTO_SEGMENT_NAME "__GNU_LTO"
-
-/* Section name for LTO section names section.  */
-#define LTO_NAMES_SECTION "__section_names"
-
-/* Handle opening elf files on hosts, such as Windows, that may use 
-   text file handling that will break binary access.  */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-/* Cached object file header.  We use a header_64 for this, since all
-   the fields we need are in there, in the same position as header_32.  */
-mach_o_header_64 cached_mach_o_header;
-uint32_t cached_mach_o_magic;
-
-/* The current output file.  */
-static lto_file *current_out_file;
-
-
-/* Is this a 32-bits or 64-bits Mach-O object file?  */
-static int
-mach_o_word_size (void)
-{
-  gcc_assert (cached_mach_o_magic != 0);
-  return (cached_mach_o_magic == MACH_O_MH_MAGIC_64
-	  || cached_mach_o_magic == MACH_O_MH_CIGAM_64) ? 64 : 32;
-}
-
-/* Sets the current output file to FILE.  Returns the old output file or
-   NULL.  */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
-  lto_file *old_file = current_out_file;
-  current_out_file = file;
-  return old_file;
-}
-
-
-/* Returns the current output file.  */
-
-lto_file *
-lto_get_current_out_file (void)
-{
-  return current_out_file;
-}
-
-/* Mach-O section structure constructor.  */
-
-static lto_mach_o_section
-mach_o_new_section (lto_mach_o_file *mach_o_file, const char *name)
-{
-  lto_mach_o_section ptr;
-
-  /* FIXME We could allocate these things on an obstack.  */
-  ptr = XCNEW (struct lto_mach_o_section_d);
-  if (name)
-    {
-      if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-		   strlen(LTO_SECTION_NAME_PREFIX)) != 0)
-	sorry ("not implemented: Mach-O writer for non-LTO sections");
-      ptr->name = xstrdup (name);
-    }
-
-  VEC_safe_push (lto_mach_o_section, heap, mach_o_file->section_vec, ptr);
-
-  return ptr;
-}
-
-/* Mach-O section data block structure constructor.  */
-
-static lto_mach_o_data
-mach_o_new_data (lto_mach_o_section sec)
-{
-  lto_mach_o_data ptr, *chain_ptr_ptr;
-
-  /* FIXME We could allocate these things on an obstack.  */
-  ptr = XCNEW (struct lto_mach_o_data_d);
-
-  chain_ptr_ptr = &sec->data_chain;
-  while (*chain_ptr_ptr)
-    chain_ptr_ptr = &(*chain_ptr_ptr)->next;
-  *chain_ptr_ptr = ptr;
-
-  return ptr;
-}
-
-/* Initialize FILE, an LTO file object for FILENAME.  Offset is the
-   offset into FILE where the object is located (e.g. in an archive).  */
-
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
-  file->filename = filename;
-  file->offset = offset;
-}
-
-/* Build a hash table whose key is the section names and whose data is
-   the start and size of each section in the .o file.  */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file) 
-{
-  lto_mach_o_file *mach_o_file = (lto_mach_o_file *)lto_file;
-  lto_mach_o_section sec;
-  htab_t section_hash_table;
-  off_t strtab_offs;
-  ssize_t strtab_size;
-  char *strtab = NULL;
-  int i;
-
-  section_hash_table = lto_obj_create_section_hash_table ();
-
-  /* Seek the string table.  */
-  /* FIXME The segment name should be in darwin.h, but can we include it
-     here in this file?  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
-	continue;
-      if (strncmp (sec->u.section.sectname, "__section_names", 16) == 0)
-        break;
-    }
-  if (! sec)
-    {
-      error ("invalid Mach-O LTO object file: no __section_names section found");
-      goto done;
-    }
-  mach_o_file->section_names_section = sec;
-
-  if (mach_o_word_size () == 64)
-    {
-      strtab_offs = (off_t) get_uint32 (&sec->u.section_64.offset[0]);
-      strtab_size = (size_t) get_uint64 (&sec->u.section_64.size[0]);
-    }
-  else
-    {
-      strtab_offs = (off_t) get_uint32 (&sec->u.section_32.offset[0]);
-      strtab_size = (size_t) get_uint32 (&sec->u.section_32.size[0]);
-    }
-
-  /* Seek to start of string table.  */
-  if (strtab_offs != lseek (mach_o_file->fd,
-			    mach_o_file->base.offset + strtab_offs,
-			    SEEK_SET))
-    {
-      error ("altered or invalid Mach-O object file");
-      goto done;
-    }
-
-  strtab = XNEWVEC (char, strtab_size);
-  if (read (mach_o_file->fd, strtab, strtab_size) != strtab_size)
-    {
-      error ("invalid Mach-O LTO object file __section_names section");
-      goto done;
-    }
-
-  /* Scan sections looking at names.  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      struct lto_section_slot s_slot;
-      void **slot;
-      char *new_name;
-      unsigned long stringoffset;
-      char name[17];
-
-      /* Ignore non-LTO sections.  Also ignore the __section_names section
-	 which does not need renaming.  */
-      if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
-	continue;
-      if (sec == mach_o_file->section_names_section)
-        continue;
-
-      /* Try to extract the offset of the real name for this section from
-	 __section_names.  */
-      memcpy (&name[0], sec->u.section.sectname, 16);
-      name[16] = '\0';
-      if (name[0] != '_' || name[1] != '_'
-	  || sscanf (&name[2], "%08lX", &stringoffset) != 1
-	  || strtab_size < (ssize_t) stringoffset)
-	{
-	  error ("invalid Mach-O LTO section name string: %s", name);
-	  continue;
-	}
-
-      new_name = XNEWVEC (char, strlen (strtab + stringoffset) + 1);
-      strcpy (new_name, strtab + stringoffset);
-      s_slot.name = new_name;
-      slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
-      if (*slot == NULL)
-	{
-	  struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
-	  new_slot->name = new_name;
-	  if (mach_o_word_size() == 64)
-	    {
-	      new_slot->start =
-		(intptr_t) get_uint32 (&sec->u.section_64.offset[0]);
-	      new_slot->len =
-		(size_t) get_uint64 (&sec->u.section_64.size[0]);
-	    }
-	  else
-	    {
-	      new_slot->start =
-		(intptr_t) get_uint32 (&sec->u.section_32.offset[0]);
-	      new_slot->len =
-		(size_t) get_uint32 (&sec->u.section_32.size[0]);
-	    }
-
-	  *slot = new_slot;
-	}
-      else
-	{
-	  error ("two or more sections for %s:", new_name);
-	  goto done;
-	}
-    }
-
- done:
-  if (strtab)
-    free (strtab);
-  return section_hash_table;
-}
-
-
-/* Begin a new Mach-O section named NAME in the current output file.  */
-
-void
-lto_obj_begin_section (const char *name)
-{
-  lto_mach_o_file *file;
-
-  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
-	       strlen(LTO_SECTION_NAME_PREFIX)) != 0)
-    sorry ("not implemented: Mach-O writer for non-LTO sections");
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file (),
-  gcc_assert (file && file->writable && !file->scn);
-
-  /* Create a new section.  */
-  file->scn = mach_o_new_section (file, name);
-  if (!file->scn)
-    fatal_error ("could not create a new Mach-O section: %m");
-}
-
-
-/* Append DATA of length LEN to the current output section.  BASE is a pointer
-   to the output page containing DATA.  It is freed once the output file has
-   been written.  */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
-  lto_mach_o_file *file;
-  lto_mach_o_data mach_o_data;
-  struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
-  /* Grab the current output file and do some basic assertion checking.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  mach_o_data = mach_o_new_data (file->scn);
-  if (!mach_o_data)
-    fatal_error ("could not append data to Mach-O section: %m");
-
-  mach_o_data->d_buf = CONST_CAST (void *, data);
-  mach_o_data->d_size = len;
-
-  /* Chain all data blocks (from all sections) on one singly-linked
-     list for freeing en masse after the file is closed.  */
-  base->ptr = (char *)file->data;
-  file->data = base;
-}
-
-
-/* End the current output section.  This just does some assertion checking
-   and sets the current output file's scn member to NULL.  */
-
-void
-lto_obj_end_section (void)
-{
-  lto_mach_o_file *file;
-
-  /* Grab the current output file and validate some basic assertions.  */
-  file = (lto_mach_o_file *) lto_get_current_out_file ();
-  gcc_assert (file);
-  gcc_assert (file->scn);
-
-  file->scn = NULL;
-}
-
-
-/* Read a Mach-O header from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the file.
-   If cached_mach_o_header is uninitialized, caches the results.
-   On succes, returns true and moves file pointer to the start of the
-   load commands.  On failure, returns false.  */
-
-static bool
-validate_mach_o_header (lto_mach_o_file *mach_o_file)
-{
-  ssize_t i, n;
-  unsigned char magic[4];
-  uint32_t cputype;
-  off_t startpos;
-
-  /* Known header magics for validation, as an array.  */
-  static const unsigned int mach_o_known_formats[] = {
-    MACH_O_MH_MAGIC,
-    MACH_O_MH_CIGAM,
-    MACH_O_MH_MAGIC_64,
-    MACH_O_MH_CIGAM_64,
-  };
-#define MACH_O_NUM_KNOWN_FORMATS \
-  ((ssize_t) ARRAY_SIZE (mach_o_known_formats))
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-  if (read (mach_o_file->fd, &magic, sizeof (magic)) != 4
-      || lseek (mach_o_file->fd, -4, SEEK_CUR) != startpos)
-    {
-      error ("cannot read file %s", mach_o_file->base.filename);
-      return false;
-    }
-
-  for (i = 0; i < MACH_O_NUM_KNOWN_FORMATS; ++i)
-    if (get_uint32 (&magic[0]) == mach_o_known_formats[i])
-      break;
-  if (i == MACH_O_NUM_KNOWN_FORMATS)
-    goto not_for_target;
-
-  /* Check the endian-ness.  */
-  if (BYTES_BIG_ENDIAN && magic[0] != 0xfe)
-    goto not_for_target;
-
-  /* Set or check cached magic number.  */
-  if (cached_mach_o_magic == 0)
-    cached_mach_o_magic = get_uint32 (&magic[0]);
-  else if (cached_mach_o_magic != get_uint32 (&magic[0]))
-    goto not_for_target;
- 
-  n = mach_o_word_size () == 64
-      ? sizeof (mach_o_header_64) : sizeof (mach_o_header_32);
-  if (read (mach_o_file->fd, &mach_o_file->u.header, n) != n)
-    goto not_for_target;
-
-  /* Is this a supported CPU?  */
-  /* ??? Would be nice to validate the exact target architecture.  */
-  cputype = get_uint32 (&mach_o_file->u.header.cputype[0]);
-  if (cputype == MACH_O_CPU_TYPE_I386
-      || cputype == MACH_O_CPU_TYPE_POWERPC)
-    {
-      if (mach_o_word_size () != 32)
-        goto not_for_target;
-    }
-  else if (cputype == MACH_O_CPU_TYPE_X86_64
-	   || cputype == MACH_O_CPU_TYPE_POWERPC_64)
-    {
-      if (mach_o_word_size () != 64)
-        goto not_for_target;
-    }
-
-  /* Is this an MH_OBJECT file?  */
-  if (get_uint32 (&mach_o_file->u.header.filetype[0]) != MACH_O_MH_OBJECT)
-    error ("Mach-O file %s is not an MH_OBJECT file",
-	   mach_o_file->base.filename);
-
-  /* Save the header for future use.  */
-  memcpy (&cached_mach_o_header, &mach_o_file->u.header,
-	  sizeof (cached_mach_o_header));
-
-  return true;
-
- not_for_target:
-  error ("file %s is not a Mach-O object file for target",
-	 mach_o_file->base.filename);
-  return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT command (32 bits) from MACH_O_FILE and
-   validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_segment_command_32 (lto_mach_o_file *mach_o_file)
-{
-  mach_o_segment_command_32 seg_cmd_32;
-  unsigned int i;
-  ssize_t n;
-  off_t startpos;
-
-  /* Fields we're interested in.  */
-  uint32_t cmd;
-  uint32_t cmdsize;
-  uint32_t nsects;
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
-  n = sizeof (mach_o_segment_command_32);
-  if (read (mach_o_file->fd, (void *) &seg_cmd_32, n) != n)
-    goto fail;
-
-  cmd = get_uint32 (&seg_cmd_32.cmd[0]);
-  cmdsize = get_uint32 (&seg_cmd_32.cmdsize[0]);
-  nsects = get_uint32 (&seg_cmd_32.nsects[0]);
-  gcc_assert (cmd == MACH_O_LC_SEGMENT);
-
-  /* Validate section table entries.  */
-  for (i = 0; i < nsects; i++)
-    {
-      mach_o_section_32 sec_32;
-      lto_mach_o_section ltosec;
-
-      n = sizeof (mach_o_section_32);
-      if (read (mach_o_file->fd, &sec_32, n) != n)
-	goto fail;
-
-      /* ??? Perform some checks.  */
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-	 we build the hash table.  */
-      ltosec = mach_o_new_section (mach_o_file, NULL);
-      memcpy (&ltosec->u.section_32, &sec_32, sizeof (sec_32));
-    }
-
-  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
-    goto fail;
-
-  return true;
-
- fail:
-  error ("could not read LC_SEGMENT command in Mach-O file %s",
-	 mach_o_file->base.filename);
-  return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT_64 command from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_segment_command_64 (lto_mach_o_file *mach_o_file)
-{
-  mach_o_segment_command_64 seg_cmd_64;
-  unsigned int i;
-  ssize_t n;
-  off_t startpos;
-
-  /* Fields we're interested in.  */
-  uint32_t cmd;
-  uint32_t cmdsize;
-  uint32_t nsects;
-
-  startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
-  n = sizeof (mach_o_segment_command_64);
-  if (read (mach_o_file->fd, (void *) &seg_cmd_64, n) != n)
-    goto fail;
-
-  cmd = get_uint32 (&seg_cmd_64.cmd[0]);
-  cmdsize = get_uint32 (&seg_cmd_64.cmdsize[0]);
-  nsects = get_uint32 (&seg_cmd_64.nsects[0]);
-  gcc_assert (cmd == MACH_O_LC_SEGMENT_64);
-
-  /* Validate section table entries.  */
-  for (i = 0; i < nsects; i++)
-    {
-      mach_o_section_64 sec_64;
-      lto_mach_o_section ltosec;
-
-      n = sizeof (mach_o_section_64);
-      if (read (mach_o_file->fd, &sec_64, n) != n)
-	goto fail;
-
-      /* ??? Perform some checks.  */
-
-      /* Looks ok, so record its details.  We don't read the 
-         string table or set up names yet; we'll do that when
-	 we build the hash table.  */
-      ltosec = mach_o_new_section (mach_o_file, NULL);
-      memcpy (&ltosec->u.section_64, &sec_64, sizeof (sec_64));
-    }
-
-  if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
-    goto fail;
-
-  return true;
-
- fail:
-  error ("could not read LC_SEGMENT_64 command in Mach-O file %s",
-	 mach_o_file->base.filename);
-  return false;
-}
-
-/* Read a Mach-O load commands from MACH_O_FILE and validate it.
-   The file descriptor in MACH_O_FILE points at the start of the load
-   command.  On sucess, returns true and advances the file pointer
-   past the end of the load command.  On failure, returns false.  */
-
-static bool
-validate_mach_o_load_command (lto_mach_o_file *mach_o_file)
-{
-  mach_o_load_command load_command;
-  uint32_t cmd;
-  uint32_t cmdsize;
-  ssize_t n;
-
-  n = sizeof (load_command);
-  if (read (mach_o_file->fd, &load_command, n) != n)
-    {
-      error ("could not read load commands in Mach-O file %s",
-	     mach_o_file->base.filename);
-      return false;
-    }
-  lseek (mach_o_file->fd, -1 * (off_t) sizeof (load_command), SEEK_CUR);
-
-  cmd = get_uint32 (&load_command.cmd[0]);
-  cmdsize = get_uint32 (&load_command.cmdsize[0]);
-  switch (cmd)
-    {
-    case MACH_O_LC_SEGMENT:
-      return validate_mach_o_segment_command_32 (mach_o_file);
-    case MACH_O_LC_SEGMENT_64:
-      return validate_mach_o_segment_command_64 (mach_o_file);
-
-    default:
-      /* Just skip over it.  */
-      lseek (mach_o_file->fd, cmdsize, SEEK_CUR);
-      return true;
-    }
-}
-
-/* Validate's MACH_O_FILE's executable header and, if cached_mach_o_header is
-   uninitialized, caches the results.  Also records the section header string
-   table's section index.  Returns true on success, false on failure.  */
-
-static bool
-validate_file (lto_mach_o_file *mach_o_file)
-{
-  uint32_t i, ncmds;
-
-  /* Read and sanity check the raw header.  */
-  if (! validate_mach_o_header (mach_o_file))
-    return false;
-
-  ncmds = get_uint32 (&mach_o_file->u.header.ncmds[0]);
-  for (i = 0; i < ncmds; ++i)
-    if (! validate_mach_o_load_command (mach_o_file))
-      return false;
-
-  return true;
-}
-
-/* Initialize MACH_O_FILE's executable header using cached data from previously
-   read files.  */
-
-static void
-init_mach_o_header (lto_mach_o_file *mach_o_file)
-{
-  gcc_assert (cached_mach_o_magic != 0);
-  memcpy (&mach_o_file->u.header,
-	  &cached_mach_o_header,
-	  sizeof (mach_o_file->u.header));
-  put_uint32 (&mach_o_file->u.header.ncmds[0], 0);
-  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], 0);
-}
-
-/* Open Mach-O file FILENAME.  If WRITABLE is true, the file is opened for write
-   and, if necessary, created.  Otherwise, the file is opened for reading.
-   Returns the opened file.  */
-
-lto_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
-  lto_mach_o_file *mach_o_file;
-  lto_file *result = NULL;
-  off_t offset;
-  const char *offset_p;
-  char *fname;
-  struct stat statbuf;
-
-  offset_p = strchr (filename, '@');
-  if (!offset_p)
-    {
-      fname = xstrdup (filename);
-      offset = 0;
-    }
-  else
-    {
-      /* The file started with '@' is a file containing command line
-	 options.  Stop if it doesn't exist.  */
-      if (offset_p == filename)
-	fatal_error ("command line option file '%s' does not exist",
-		     filename);
-
-      fname = (char *) xmalloc (offset_p - filename + 1);
-      memcpy (fname, filename, offset_p - filename);
-      fname[offset_p - filename] = '\0';
-      offset_p += 3; /* skip the @0x */
-      offset = lto_parse_hex (offset_p);
-    }
-
-  /* Set up.  */
-  mach_o_file = XCNEW (lto_mach_o_file);
-  result = (lto_file *) mach_o_file;
-  lto_file_init (result, fname, offset);
-  mach_o_file->fd = -1;
-  mach_o_file->writable = writable;
-
-  /* Open the file.  */
-  mach_o_file->fd = open (fname,
-    O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
-  if (mach_o_file->fd == -1)
-    {
-      error ("could not open file %s", fname);
-      goto fail;
-    }
-
-  if (stat (fname, &statbuf) < 0)
-    {
-      error ("could not stat file %s", fname);
-      goto fail;
-    }
-
-  mach_o_file->file_size = statbuf.st_size;
-
-  /* If the object is in an archive, get it out.  */
-  if (offset != 0)
-    {
-      char ar_tail[12];
-      int size;
-
-      /* Surely not?  */
-      gcc_assert (!writable);
-
-      /* Seek to offset, or error.  */
-      if (lseek (mach_o_file->fd, offset, SEEK_SET) != (ssize_t) offset)
-	{
-	  error ("could not find archive member @0x%lx", (long) offset);
-	  goto fail;
-	}
-
-      /* Now seek back 12 chars and read the tail of the AR header to
-         find the length of the member file.  */
-      if (lseek (mach_o_file->fd, -12, SEEK_CUR) < 0
-	  || read (mach_o_file->fd, ar_tail, 12) != 12
-	  || lseek (mach_o_file->fd, 0, SEEK_CUR) != (ssize_t) offset
-	  || ar_tail[10] != '`' || ar_tail[11] != '\n')
-	{
-	  error ("could not find archive header @0x%lx", (long) offset);
-	  goto fail;
-	}
-
-      ar_tail[11] = 0;
-      if (sscanf (ar_tail, "%d", &size) != 1)
-	{
-	  error ("invalid archive header @0x%lx", (long) offset);
-	  goto fail;
-	}
-      mach_o_file->file_size = size;
-    }
-
-  if (writable)
-    {
-      init_mach_o_header (mach_o_file);
-    }
-  else
-    if (! validate_file (mach_o_file))
-      goto fail;
-
-  return result;
-
- fail:
-  if (result)
-    lto_obj_file_close (result);
-  return NULL;
-}
-
-
-/* Write the data in MACH_O_FILE to a real Mach-O binary object.
-   We write a header, a segment load command, and section data.  */
-
-static bool
-mach_o_write_object_file (lto_mach_o_file *mach_o_file)
-{
-  lto_mach_o_section sec, snsec;
-  lto_mach_o_data snsec_data;
-  ssize_t hdrsize, cmdsize, secsize;
-  size_t num_sections, snsec_size, total_sec_size;
-  unsigned int sec_offs, strtab_offs;
-  int i;
-  bool write_err = false;
-
-  /* The number of sections we will write is the number of sections added by
-     the streamer, plus 1 for the section names section.  */
-  num_sections = VEC_length (lto_mach_o_section, mach_o_file->section_vec) + 1;
-
-  /* Calculate the size of the basic data structures on disk.  */
-  if (mach_o_word_size () == 64)
-    {
-      hdrsize = sizeof (mach_o_header_64);
-      secsize = sizeof (mach_o_section_64);
-      cmdsize = sizeof (mach_o_segment_command_64) + num_sections * secsize;
-    }
-  else
-    {
-      hdrsize = sizeof (mach_o_header_32);
-      secsize = sizeof (mach_o_section_32);
-      cmdsize = sizeof (mach_o_segment_command_32) + num_sections * secsize;
-    }
- 
-  /* Allocate the section names section.  */
-  snsec_size = 0;
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    snsec_size += strlen (sec->name) + 1;
-  snsec = mach_o_new_section (mach_o_file, NULL);
-  snsec->name = LTO_NAMES_SECTION;
-  snsec_data = mach_o_new_data (snsec);
-  snsec_data->d_buf = XCNEWVEC (char, snsec_size);
-  snsec_data->d_size = snsec_size;
-
-  /* Position all the sections, and fill out their headers.  */
-  sec_offs = hdrsize + cmdsize;
-  strtab_offs = 0;
-  total_sec_size = 0;
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data data;
-      size_t data_size;
-      /* Put the section and segment names.  Add the section name to the
-         section names section (unless, of course, this *is* the section
-	 names section).  */
-      if (sec == snsec)
-	snprintf (sec->u.section.sectname, 16, "%s", LTO_NAMES_SECTION);
-      else
-	{
-	  sprintf (sec->u.section.sectname, "__%08X", strtab_offs);
-	  memcpy ((char *) snsec_data->d_buf + strtab_offs, sec->name, strlen (sec->name));
-	}
-      memcpy (&sec->u.section.segname[0],
-	      LTO_SEGMENT_NAME, strlen (LTO_SEGMENT_NAME));
-
-      /* Add layout and attributes.  */
-      for (data = sec->data_chain, data_size = 0; data; data = data->next)
-	data_size += data->d_size;
-      if (mach_o_word_size () == 64)
-	{
-	  put_uint64 (&sec->u.section_64.addr[0], total_sec_size); 
-	  put_uint64 (&sec->u.section_64.size[0], data_size); 
-	  put_uint32 (&sec->u.section_64.offset[0], sec_offs); 
-	  put_uint32 (&sec->u.section_64.flags[0], MACH_O_S_ATTR_DEBUG);
-	}
-      else
-	{
-	  put_uint32 (&sec->u.section_64.addr[0], total_sec_size); 
-	  put_uint32 (&sec->u.section_32.size[0], data_size); 
-	  put_uint32 (&sec->u.section_32.offset[0], sec_offs); 
-	  put_uint32 (&sec->u.section_32.flags[0], MACH_O_S_ATTR_DEBUG);
-	}
-
-      sec_offs += data_size;
-      total_sec_size += data_size;
-      strtab_offs += strlen (sec->name) + 1;
-    }
-
-  /* We can write the data now.  As there's no way to indicate an error return
-     from this hook, error handling is limited to not wasting our time doing
-     any more writes in the event that any one fails.  */
-
-  /* Write the header.  */
-  put_uint32 (&mach_o_file->u.header.ncmds[0], 1);
-  put_uint32 (&mach_o_file->u.header.sizeofcmds[0], cmdsize);
-  write_err = (write (mach_o_file->fd,
-		      &mach_o_file->u.header, hdrsize) != hdrsize);
-  /* Write the segment load command.  */
-  if (mach_o_word_size () == 64)
-    {
-      mach_o_segment_command_64 lc;
-      ssize_t lc_size = sizeof (lc);
-      memset (&lc, 0, lc_size);
-      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT_64);
-      put_uint32 (&lc.cmdsize[0], cmdsize);
-      put_uint64 (&lc.fileoff[0], hdrsize + cmdsize);
-      put_uint64 (&lc.filesize[0], total_sec_size);
-      put_uint32 (&lc.nsects[0], num_sections);
-      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
-    }
-  else
-    {
-      mach_o_segment_command_32 lc;
-      ssize_t lc_size = sizeof (lc);
-      memset (&lc, 0, lc_size);
-      put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT);
-      put_uint32 (&lc.cmdsize[0], cmdsize);
-      put_uint32 (&lc.fileoff[0], hdrsize + cmdsize);
-      put_uint32 (&lc.filesize[0], total_sec_size);
-      put_uint32 (&lc.nsects[0], num_sections);
-      write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
-    }
-  for (i = 0;
-       !write_err
-       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    write_err = (write (mach_o_file->fd,
-			&sec->u.section, secsize) != secsize);
-
-  gcc_assert (lseek (mach_o_file->fd, 0, SEEK_CUR) == hdrsize + cmdsize);
-
-  /* Write the section data.  */
-  for (i = 0;
-       !write_err
-       && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data data;
-
-      for (data = sec->data_chain; data; data = data->next)
-	{
-	  if (!write_err)
-	    write_err = (write (mach_o_file->fd, data->d_buf, data->d_size)
-			 != data->d_size);
-	  else
-	    break;
-	}
-    }
-
-  return !write_err;
-}
-
-/* Close Mach-O file FILE and clean up any associated data structures.  If FILE
-   was opened for writing, the file's Mach-O data is written at this time.  Any
-   cached data buffers are freed.  */
-
-void
-lto_obj_file_close (lto_file *file)
-{
-  lto_mach_o_file *mach_o_file = (lto_mach_o_file *) file;
-  struct lto_char_ptr_base *cur, *tmp;
-  lto_mach_o_section sec;
-  bool write_err = false;
-  int i;
-
-  /* If this file is open for writing, write a Mach-O object file.  */
-  if (mach_o_file->writable)
-    {
-      if (! mach_o_write_object_file (mach_o_file))
-        fatal_error ("cannot write Mach-O object file");
-    }
-
-  /* Close the file, we're done.  */
-  if (mach_o_file->fd != -1)
-    close (mach_o_file->fd);
-
-  /* Free any data buffers.  */
-  cur = mach_o_file->data;
-  while (cur)
-    {
-      tmp = cur;
-      cur = (struct lto_char_ptr_base *) cur->ptr;
-      free (tmp);
-    }
-
-  /* Free any sections and their data chains.  */
-  for (i = 0;
-       VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
-       i++)
-    {
-      lto_mach_o_data curdata, nextdata;
-      curdata = sec->data_chain;
-      while (curdata)
-	{
-	  nextdata = curdata->next;
-	  free (curdata);
-	  curdata = nextdata;
-	}
-      free (sec);
-    }
-  VEC_free (lto_mach_o_section, heap, mach_o_file->section_vec);
-
-  free (file);
-
-  /* If there was an error, mention it.  */
-  if (write_err)
-    error ("I/O error writing Mach-O output file");
-}
-
Index: gcc/lto/lto-macho.h
===================================================================
--- gcc/lto/lto-macho.h	(revision 166002)
+++ gcc/lto/lto-macho.h	(working copy)
@@ -1,251 +0,0 @@ 
-/* LTO routines for Mach-O object files.
-   Copyright 2010 Free Software Foundation, Inc.
-   Contributed by Steven Bosscher.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#ifndef LTO_MACH_O_H
-#define LTO_MACH_O_H
-
-/* On-disk file structures.  */
-
-/* Mach-O header (32 bits version).  */
-struct mach_o_header_32
-{
-  unsigned char magic[4];	/* Magic number.  */
-  unsigned char cputype[4];	/* CPU that this object is for.  */
-  unsigned char cpusubtype[4];	/* CPU subtype.  */
-  unsigned char filetype[4];	/* Type of file.  */
-  unsigned char ncmds[4];	/* Number of load commands.  */
-  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
-  unsigned char flags[4];	/* Flags for special featues.  */
-};
-typedef struct mach_o_header_32 mach_o_header_32;
-
-/* Mach-O header (64 bits version).  */
-struct mach_o_header_64
-{
-  unsigned char magic[4];	/* Magic number.  */
-  unsigned char cputype[4];	/* CPU that this object is for.  */
-  unsigned char cpusubtype[4];	/* CPU subtype.  */
-  unsigned char filetype[4];	/* Type of file.  */
-  unsigned char ncmds[4];	/* Number of load commands.  */
-  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
-  unsigned char flags[4];	/* Flags for special featues.  */
-  unsigned char reserved[4];	/* Reserved.  Duh.  */
-};
-typedef struct mach_o_header_64 mach_o_header_64;
-
-/* Magic number.  */
-#define MACH_O_MH_MAGIC			0xfeedface
-#define MACH_O_MH_CIGAM			0xcefaedfe
-#define MACH_O_MH_MAGIC_64		0xfeedfacf
-#define MACH_O_MH_CIGAM_64		0xcffaedfe
-
-/* Supported CPU types.  */
-#define MACH_O_CPU_TYPE_I386		7
-#define MACH_O_CPU_TYPE_X86_64		7 + 0x1000000
-#define MACH_O_CPU_TYPE_POWERPC		18
-#define MACH_O_CPU_TYPE_POWERPC_64	18 + 0x1000000
-
-/* Supported file types.  */
-#define MACH_O_MH_OBJECT		0x01
-
-/* Mach-O load command data structure.  */
-struct mach_o_load_command
-{
-  unsigned char cmd[4];		/* The type of load command.  */
-  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
-};
-typedef struct mach_o_load_command mach_o_load_command;
-
-/* Supported load commands.  We support only the segment load commands.  */
-#define MACH_O_LC_SEGMENT		0x01
-#define MACH_O_LC_SEGMENT_64		0x19
-
-/* LC_SEGMENT load command.  */
-struct mach_o_segment_command_32
-{
-  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT).  */
-  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
-  unsigned char segname[16];	/* Name of this segment.  */
-  unsigned char vmaddr[4];	/* Virtual memory address of this segment.  */
-  unsigned char vmsize[4];	/* Size there, in bytes.  */
-  unsigned char fileoff[4];	/* Offset in bytes of the data to be mapped.  */
-  unsigned char filesize[4];	/* Size in bytes on disk.  */
-  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
-  unsigned char initprot[4];	/* Initial vmem protection.  */
-  unsigned char nsects[4];	/* Number of sections in this segment.  */
-  unsigned char flags[4];	/* Flags that affect the loading.  */
-};
-typedef struct mach_o_segment_command_32 mach_o_segment_command_32;
-
-/* LC_SEGMENT_64 load command.  Only nsects matters for us, really.  */
-struct mach_o_segment_command_64
-{
-  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT_64).  */
-  unsigned char cmdsize[4];	/* Size in bytes of load command data structure.  */
-  unsigned char segname[16];	/* Name of this segment.  */
-  unsigned char vmaddr[8];	/* Virtual memory address of this segment.  */
-  unsigned char vmsize[8];	/* Size there, in bytes.  */
-  unsigned char fileoff[8];	/* Offset in bytes of the data to be mapped.  */
-  unsigned char filesize[8];	/* Size in bytes on disk.  */
-  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
-  unsigned char initprot[4];	/* Initial vmem protection.  */
-  unsigned char nsects[4];	/* Number of sections in this segment.  */
-  unsigned char flags[4];	/* Flags that affect the loading.  */
-};
-typedef struct mach_o_segment_command_64 mach_o_segment_command_64;
-
-/* A Mach-O 32-bits section.  */
-struct mach_o_section_32
-{
-  unsigned char sectname[16];	/* Section name.  */
-  unsigned char segname[16];	/* Segment that the section belongs to.  */
-  unsigned char addr[4];	/* Address of this section in memory.  */
-  unsigned char size[4];	/* Size in bytes of this section.  */
-  unsigned char offset[4];	/* File offset of this section.  */
-  unsigned char align[4];	/* log2 of this section's alignment.  */
-  unsigned char reloff[4];	/* File offset of this section's relocs.  */
-  unsigned char nreloc[4];	/* Number of relocs for this section.  */
-  unsigned char flags[4];	/* Section flags/attributes.  */
-  unsigned char reserved1[4];
-  unsigned char reserved2[4];
-};
-typedef struct mach_o_section_32 mach_o_section_32;
-
-/* A Mach-O 64-bits section.  */
-struct mach_o_section_64
-{
-  unsigned char sectname[16];	/* Section name.  */
-  unsigned char segname[16];	/* Segment that the section belongs to.  */
-  unsigned char addr[8];	/* Address of this section in memory.  */
-  unsigned char size[8];	/* Size in bytes of this section.  */
-  unsigned char offset[4];	/* File offset of this section.  */
-  unsigned char align[4];	/* log2 of this section's alignment.  */
-  unsigned char reloff[4];	/* File offset of this section's relocs.  */
-  unsigned char nreloc[4];	/* Number of relocs for this section.  */
-  unsigned char flags[4];	/* Section flags/attributes.  */
-  unsigned char reserved1[4];
-  unsigned char reserved2[4];
-  unsigned char reserved3[4];
-};
-typedef struct mach_o_section_64 mach_o_section_64;
-
-/* Flags for Mach-O sections.  LTO sections are marked with S_ATTR_DEBUG
-   to instruct the linker to ignore the sections.  */
-#define MACH_O_S_ATTR_DEBUG			0x02000000
-
-/* In-memory file structures.  */
-
-/* Section data in output files is made of these.  */
-struct lto_mach_o_data_d
-{
-  /* Pointer to data block.  */
-  void *d_buf;
-
-  /* Size of data block.  */
-  ssize_t d_size;
-
-  /* Next data block for this section.  */
-  struct lto_mach_o_data_d *next;
-};
-typedef struct lto_mach_o_data_d *lto_mach_o_data;
-
-/* This struct tracks the data for a section.  */
-struct lto_mach_o_section_d
-{
-  /* Singly-linked list of section's data blocks.  */
-  lto_mach_o_data data_chain;
-
-  /* Offset in string table of the section name.  */
-  size_t strtab_offs;
-
-  /* Section name.  */
-  const char *name;
-
-  /* Number of trailing padding bytes needed.  */
-  ssize_t pad_needed;
-
-  /* Raw section header data.  */
-  size_t section_size;
-  union {
-    struct {
-      char sectname[16];
-      char segname[16];
-    } section;
-    mach_o_section_32 section_32;
-    mach_o_section_64 section_64;
-  } u;
-
-  /* Next section for this file.  */
-  struct lto_mach_o_section_d *next;
-};
-typedef struct lto_mach_o_section_d *lto_mach_o_section;
-DEF_VEC_P (lto_mach_o_section);
-DEF_VEC_ALLOC_P (lto_mach_o_section, heap);
-
-/* A Mach-O file.  */
-struct lto_mach_o_file_d
-{
-  /* The base information.  */
-  lto_file base;
-
-  /* Common file members:  */
-
-  /* The system file descriptor for the file.  */
-  int fd;
-
-  /* The file's overall header.  */
-  union {
-    /* We make use here of the fact that section_32 and section_64
-       have the same layout (except for section_64.reserved3).  We
-       read the struct of proper size, but only address the first
-       member of this union.  */
-    mach_o_header_64 header;
-    mach_o_header_32 header_32;
-    mach_o_header_64 header_64;
-  } u;
-
-  /* All sections in a varray.  */
-  VEC(lto_mach_o_section, heap) *section_vec;
-
-  /* Readable file members:  */
-
-  /* File total size.  */
-  off_t file_size;
-
-  /* True if this file is open for writing.  */
-  bool writable;
-
-  /* Section containing the __section_names section.  */
-  lto_mach_o_section section_names_section;
-
-  /* Writable file members:  */
-
-  /* The currently active section.  */
-  lto_mach_o_section scn;
-
-  /* Linked list of data which must be freed *after* the file has been
-     closed.  This is an annoying limitation of libelf.  Which has been
-     faithfully reproduced here.  */
-  struct lto_char_ptr_base *data;
-};
-typedef struct lto_mach_o_file_d lto_mach_o_file;
-
-#endif /* LTO_MACH_O_H */
-
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 166002)
+++ gcc/configure.ac	(working copy)
@@ -975,22 +975,6 @@  AC_CHECK_FUNCS(times clock kill getrlimi
 	gettimeofday mbstowcs wcswidth mmap mincore setlocale \
 	gcc_UNLOCKED_FUNCS)
 
-save_CPPFLAGS="$CPPFLAGS"
-save_LIBS="$LIBS"
-LIBS="$LIBS $LIBELFLIBS"
-AC_CHECK_FUNCS(elf_getshdrstrndx,,
-  [AC_CHECK_FUNCS(elf_getshstrndx,
-    [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
-#include <libelf.h>
-int main()
-{
-  return elf_getshstrndx (NULL, 0) == 0;
-}]])], AC_DEFINE(HAVE_ELF_GETSHSTRNDX_GABI, 1,
-        [Define if elf_getshstrndx has gABI conformant return values.]))])]
-  )
-LIBS="$save_LIBS"
-CPPFLAGS="$save_CPPFLAGS"
-
 if test x$ac_cv_func_mbstowcs = xyes; then
   AC_CACHE_CHECK(whether mbstowcs works, gcc_cv_func_mbstowcs_works,
 [    AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
@@ -4461,17 +4445,6 @@  changequote([,])dnl
 		    AC_DEFINE(ENABLE_LTO, 1, [Define to enable LTO support.])
 		    enable_lto=yes
 		    AC_SUBST(enable_lto)
-		    # LTO needs to speak the platform's object file format, and has a
-		    # number of implementations of the required binary file access APIs.
-		    # ELF is the most common, and default.  We only link libelf if ELF
-		    # is indeed the selected format.
-		    LTO_BINARY_READER=${lto_binary_reader}
-		    LTO_USE_LIBELF=-lelf
-		    if test "x$lto_binary_reader" != "xlto-elf" ; then
-		      LTO_USE_LIBELF=
-		    fi
-		    AC_SUBST(LTO_BINARY_READER)
-		    AC_SUBST(LTO_USE_LIBELF)
 		    ;;
 		*) ;;
 	esac
@@ -4644,12 +4617,6 @@  if test "x${CLOOGLIBS}" != "x" ; then 
    AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.])
 fi
 
-AC_ARG_VAR(LIBELFLIBS,[How to link libelf])
-AC_ARG_VAR(LIBELFINC,[How to find libelf include files])
-if test "x${LIBELFLIBS}" != "x" ; then 
-   AC_DEFINE(HAVE_libelf, 1, [Define if libelf is in use.])
-fi
-
 # Check for plugin support
 AC_ARG_ENABLE(plugin,
 [  --enable-plugin         enable plugin support],
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 166002)
+++ gcc/config.gcc	(working copy)
@@ -219,8 +219,6 @@  default_gnu_indirect_function=no
 target_gtfiles=
 need_64bit_hwint=
 need_64bit_isa=
-# Selects the object file format reader/writer used by LTO.
-lto_binary_reader=lto-elf
 
 # Don't carry these over build->host->target.  Please.
 xm_file=
@@ -1159,14 +1157,12 @@  i[34567]86-*-darwin*)
 	with_cpu=${with_cpu:-generic}
 	tmake_file="${tmake_file} t-slibgcc-darwin i386/t-crtpc i386/t-crtfm"
 	extra_options="${extra_options} i386/darwin.opt"
-	lto_binary_reader=lto-macho
 	;;
 x86_64-*-darwin*)
 	with_cpu=${with_cpu:-generic}
 	tmake_file="${tmake_file} ${cpu_type}/t-darwin64 t-slibgcc-darwin i386/t-crtpc i386/t-crtfm"
 	tm_file="${tm_file} ${cpu_type}/darwin64.h"
 	extra_options="${extra_options} i386/darwin.opt"
-	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"
@@ -1421,7 +1417,6 @@  i[34567]86-*-pe | i[34567]86-*-cygwin*)
 		thread_file='posix'
 	fi
 	use_gcc_stdint=wrap
-	lto_binary_reader=lto-coff
 	;;
 i[34567]86-*-mingw* | x86_64-*-mingw*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/mingw32.h"
@@ -1494,7 +1489,6 @@  i[34567]86-*-mingw* | x86_64-*-mingw*)
 	cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	use_gcc_stdint=wrap
-	lto_binary_reader=lto-coff
 	case ${enable_threads} in
 	  "" | yes | win32)	  thread_file='win32'
 	  tmake_file="${tmake_file} i386/t-gthr-win32"
@@ -2004,7 +1998,6 @@  powerpc-*-darwin*)
 	    ;;
 	esac
 	tmake_file="${tmake_file} t-slibgcc-darwin"
-	lto_binary_reader=lto-macho
 	extra_headers=altivec.h
 	;;
 powerpc64-*-darwin*)
@@ -2012,7 +2005,6 @@  powerpc64-*-darwin*)
 	extra_parts="crt2.o"
 	tmake_file="${tmake_file} ${cpu_type}/t-darwin64 t-slibgcc-darwin"
 	tm_file="${tm_file} ${cpu_type}/darwin8.h ${cpu_type}/darwin64.h"
-	lto_binary_reader=lto-macho
 	extra_headers=altivec.h
 	;;
 powerpc*-*-freebsd*)
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 166002)
+++ gcc/Makefile.in	(working copy)
@@ -319,17 +319,9 @@  PPLINC = @PPLINC@
 CLOOGLIBS = @CLOOGLIBS@
 CLOOGINC = @CLOOGINC@
 
-# How to find libelf
-LIBELFLIBS = @LIBELFLIBS@
-LIBELFINC = @LIBELFINC@
-
 # Set to 'yes' if the LTO front end is enabled.
 enable_lto = @enable_lto@
 
-# Set according to LTO object file format.
-LTO_BINARY_READER = @LTO_BINARY_READER@
-LTO_USE_LIBELF = @LTO_USE_LIBELF@
-
 # Compiler and flags needed for plugin support
 ifneq ($(ENABLE_BUILD_WITH_CXX),yes)
 PLUGINCC = @CC@
@@ -1032,7 +1024,7 @@  BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
 LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(HOST_LIBS)
 BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \
-	$(ZLIB) $(LIBELFLIBS)
+	$(ZLIB)
 # Any system libraries needed just for GNAT.
 SYSLIBS = @GNAT_LIBEXC@
 
@@ -1063,7 +1055,7 @@  BUILD_ERRORS = build/errors.o
 INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
 	   -I$(srcdir)/../include @INCINTL@ \
 	   $(CPPINC) $(GMPINC) $(DECNUMINC) \
-	   $(PPLINC) $(CLOOGINC) $(LIBELFINC)
+	   $(PPLINC) $(CLOOGINC)
 
 .c.o:
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
Index: configure.ac
===================================================================
--- configure.ac	(revision 166002)
+++ configure.ac	(working copy)
@@ -1647,174 +1647,7 @@  AC_SUBST(clooginc)
 AC_ARG_ENABLE(lto,
 [  --enable-lto            enable link time optimization support],
 enable_lto=$enableval,
-enable_lto=yes; default_enable_lto=yes)
-
-
-ACX_ELF_TARGET_IFELSE([if test x"$enable_lto" = x"yes" ; then
-  # Make sure that libelf.h and gelf.h are available.
-  AC_ARG_WITH(libelf, [  --with-libelf=PATH       Specify prefix directory for the installed libelf package
-                          Equivalent to --with-libelf-include=PATH/include
-                          plus --with-libelf-lib=PATH/lib])
-
-  AC_ARG_WITH(libelf_include, [  --with-libelf-include=PATH Specify directory for installed libelf include files])
-
-  AC_ARG_WITH(libelf_lib, [  --with-libelf-lib=PATH   Specify the directory for the installed libelf library])
-
-  saved_CFLAGS="$CFLAGS"
-  saved_CPPFLAGS="$CPPFLAGS"
-  saved_LIBS="$LIBS"
-
-  case $with_libelf in 
-    "")
-      libelflibs="-lelf"
-      libelfinc="-I/usr/include/libelf"
-      ;;
-    *)
-      libelflibs="-L$with_libelf/lib -lelf"
-      libelfinc="-I$with_libelf/include -I$with_libelf/include/libelf"
-      LIBS="$libelflibs $LIBS"
-      ;;
-  esac
-
-  if test "x$with_libelf_include" != x; then
-    libelfinc="-I$with_libelf_include"
-  fi
-
-  if test "x$with_libelf_lib" != x; then
-    libelflibs="-L$with_libelf_lib -lelf"
-    LIBS="$libelflibs $LIBS"
-  fi
-
-  if test "x$with_libelf$with_libelf_include$with_libelf_lib" = x \
-     && test -d ${srcdir}/libelf; then
-    libelflibs='-L$$r/$(HOST_SUBDIR)/libelf/lib -lelf '
-    libelfinc='-D__LIBELF_INTERNAL__ -I$$r/$(HOST_SUBDIR)/libelf/lib -I$$s/libelf/lib'
-    LIBS="$libelflibs $LIBS"
-
- else
-
-  CFLAGS="$CFLAGS $libelfinc"
-  CPPFLAGS="$CPPFLAGS $libelfinc"
-  LIBS="$LIBS $libelflibs"
-
-  AC_CHECK_HEADERS(libelf.h, [have_libelf_h=yes])
-  AC_CHECK_HEADERS(gelf.h, [have_gelf_h=yes])
-
-  AC_CHECK_HEADERS(libelf/libelf.h, [have_libelf_libelf_h=yes])
-  AC_CHECK_HEADERS(libelf/gelf.h, [have_libelf_gelf_h=yes])
-
-  # If we couldn't find libelf.h and the user forced it, emit an error.
-  if test x"$have_libelf_h" != x"yes" \
-     && test x"$have_libelf_libelf_h" != x"yes" ; then
-    if test x"$default_enable_lto" != x"yes" ; then
-      AC_MSG_ERROR([LTO support requires libelf.h or libelf/libelf.h.])
-    else
-      enable_lto=no
-      libelflibs=
-      libelfinc=
-    fi
-  fi
-
-  # If we couldn't find gelf.h and the user forced it, emit an error.
-  if test x"$have_gelf_h" != x"yes" \
-     && test x"$have_libelf_gelf_h" != x"yes" ; then
-    if test x"$default_enable_lto" != x"yes" ; then
-      AC_MSG_ERROR([LTO support requires gelf.h or libelf/gelf.h.])
-    else
-      enable_lto=no
-      libelflibs=
-      libelfinc=
-    fi
-  fi
-
-  # Check that the detected libelf has the functions we need.  We cannot
-  # rely on just detecting the headers since they do not include 
-  # versioning information.  Add functions, if needed.
-  if test x"$enable_lto" = x"yes" ; then
-    AC_MSG_CHECKING([for the correct version of libelf])
-    AC_TRY_LINK(
-      [#include <libelf.h>],[
-      elf_errmsg (0);
-      elf_getscn (0, 0);
-      elf_nextscn (0, 0);
-      elf_strptr (0, 0, 0);
-      elf_getident (0, 0);
-      elf_begin (0, 0, 0);
-      elf_ndxscn (0);
-      elf_end (0);
-      ],
-      [AC_MSG_RESULT([yes]);],
-      [AC_MSG_RESULT([no]); enable_lto=no; libelflibs= ; libelfinc= ]
-    )
-
-    # Check for elf_getshdrstrndx or elf_getshstrndx.  The latter's flavor
-    # is determined in gcc/configure.ac.
-    if test x"$enable_lto" = x"yes" ; then
-      AC_MSG_CHECKING([for elf_getshdrstrndx])
-      AC_TRY_LINK(
-        [#include <libelf.h>],[
-	elf_getshdrstrndx (0, 0);
-        ],
-        [AC_MSG_RESULT([yes]);],
-        [AC_MSG_RESULT([no]);
-	 AC_MSG_CHECKING([for elf_getshstrndx])
-         AC_TRY_LINK(
-           [#include <libelf.h>],[
-	   elf_getshstrndx (0, 0);
-           ],
-           [AC_MSG_RESULT([yes]);],
-           [AC_MSG_RESULT([no]); enable_lto=no; libelflibs= ; libelfinc= ]
-         )]
-      )
-    fi
-
-    # If we couldn't enable LTO and the user forced it, emit an error.
-    if test x"$enable_lto" = x"no" \
-       && test x"$default_enable_lto" != x"yes" ; then
-      AC_MSG_ERROR([To enable LTO, GCC requires libelf v0.8.12+.
-Try the --with-libelf, --with-libelf-include and --with-libelf-lib options
-to specify its location.])
-    fi
-  fi
-
-  CFLAGS="$saved_CFLAGS"
-  CPPFLAGS="$saved_CPPFLAGS"
-  LIBS="$saved_LIBS"
-
- fi
-
-  # Flags needed for libelf.
-  AC_SUBST(libelflibs)
-  AC_SUBST(libelfinc)
-  # ELF platforms build the lto-plugin when GOLD is in use.
-  build_lto_plugin=${ENABLE_GOLD}
-fi],[if test x"$default_enable_lto" = x"yes" ; then
-    case $target in
-      *-apple-darwin* | *-cygwin* | *-mingw*) ;;
-      # On other non-ELF platforms, LTO must be explicitly enabled.
-      *) enable_lto=no ;;
-    esac
-  else
-  # Apart from ELF platforms, only Windows and Darwin support LTO so far.
-  # It would also be nice to check the binutils support, but we don't
-  # have gcc_GAS_CHECK_FEATURE available here.  For now, we'll just
-  # warn during gcc/ subconfigure; unless you're bootstrapping with
-  # -flto it won't be needed until after installation anyway.
-    case $target in
-      *-cygwin* | *-mingw* | *-apple-darwin*) ;;
-      *) if test x"$enable_lto" = x"yes"; then
-	AC_MSG_ERROR([LTO support is not enabled for this target.])
-        fi
-      ;;
-    esac
-  fi
-  # Among non-ELF, only Windows platforms support the lto-plugin so far.
-  case $target in
-    *-cygwin* | *-mingw*) build_lto_plugin=yes ;;
-    *) ;;
-  esac
-  default_enable_lto=no])
-
+enable_lto=yes)
 
 # By default, C is the only stage 1 language.
 stage1_languages=,c,
Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi	(revision 166002)
+++ gcc/doc/install.texi	(working copy)
@@ -355,17 +355,6 @@  not installed in your default library se
 
 Necessary to build libgcj, the GCJ runtime.
 
-@item libelf version 0.8.12 (or later)
-
-Necessary to build link-time optimization (LTO) support.  It can be
-downloaded from @uref{http://www.mr511.de/software/libelf-0.8.12.tar.gz},
-though it is commonly available in several systems.  The version in
-IRIX 6.5 doesn't work since it lacks @file{gelf.h}.  The version in
-Solaris 2 does work.
-
-The @option{--with-libelf} configure option should be used if libelf is
-not installed in your default library search patch.
-
 @end table
 
 @heading Tools/packages necessary for modifying GCC
@@ -1650,20 +1639,9 @@  default for a native toolchain with an a
 GLIBC 2.11 or above, otherwise disabled.
 
 @item --enable-lto
+@itemx --disable-lto
 Enable support for link-time optimization (LTO).  This is enabled by
-default if a working libelf implementation is found (see
-@option{--with-libelf}).
-
-@item --with-libelf=@var{pathname}
-@itemx --with-libelf-include=@var{pathname}
-@itemx --with-libelf-lib=@var{pathname}
-If you do not have libelf installed in a standard location and you
-want to enable support for link-time optimization (LTO), you can
-explicitly specify the directory where libelf is installed
-(@samp{--with-libelf=@var{libelfinstalldir}}).  The
-@option{--with-libelf=@var{libelfinstalldir}} option is shorthand for
-@option{--with-libelf-include=@var{libelfinstalldir}/include}
-@option{--with-libelf-lib=@var{libelfinstalldir}/lib}.
+default, and may be disabled using @option{--disable-lto}.
 
 @item --enable-gold
 Enable support for using @command{gold} as the linker.  If gold support is