From patchwork Fri Oct 29 01:31:33 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 69535 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 5117BB6F10 for ; Fri, 29 Oct 2010 12:33:46 +1100 (EST) Received: (qmail 9294 invoked by alias); 29 Oct 2010 01:33:24 -0000 Received: (qmail 8426 invoked by uid 22791); 29 Oct 2010 01:32:56 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KAM_STOCKGEN, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_BJ, TW_CC, TW_CN, TW_CP, TW_DX, TW_FN, TW_NL, TW_XF, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.35) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 29 Oct 2010 01:32:00 +0000 Received: from hpaq7.eem.corp.google.com (hpaq7.eem.corp.google.com [172.25.149.7]) by smtp-out.google.com with ESMTP id o9T1VtiK027473 for ; Thu, 28 Oct 2010 18:31:56 -0700 Received: from gxk8 (gxk8.prod.google.com [10.202.11.8]) by hpaq7.eem.corp.google.com with ESMTP id o9T1VrZ7000513 for ; Thu, 28 Oct 2010 18:31:53 -0700 Received: by gxk8 with SMTP id 8so1723219gxk.39 for ; Thu, 28 Oct 2010 18:31:53 -0700 (PDT) Received: by 10.101.165.31 with SMTP id s31mr4466178ano.158.1288315912414; Thu, 28 Oct 2010 18:31:52 -0700 (PDT) Received: from coign.google.com (adsl-71-133-8-30.dsl.pltn13.pacbell.net [71.133.8.30]) by mx.google.com with ESMTPS id b25sm1831550anb.23.2010.10.28.18.31.39 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 28 Oct 2010 18:31:49 -0700 (PDT) From: Ian Lance Taylor To: Dave Korn Cc: Andi Kleen , Andrew Pinski , Mark Mitchell , gcc@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: Re: Discussion about merging Go frontend References: <4CC45302.9000702@gmail.com> <4CC59F1E.7040505@codesourcery.com> <87pquy3yh5.fsf@basil.nowhere.org> <4CC60C5E.6050605@gmail.com> Date: Thu, 28 Oct 2010 18:31:33 -0700 In-Reply-To: <4CC60C5E.6050605@gmail.com> (Dave Korn's message of "Tue, 26 Oct 2010 00:01:50 +0100") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Dave Korn 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 * objfile.h: New file. libiberty/ChangeLog: 2010-10-28 Ian Lance Taylor * 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 * 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 * 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 * configure.ac: Don't set default_enable_lto. Remove libelf tests. * configure: Rebuild. 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 +#include + +#ifdef HAVE_UNISTD_H +#include +#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 + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#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 + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#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 +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#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 +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "diagnostic-core.h" -#include "toplev.h" -#include -#include "lto.h" -#include "tm.h" -#include "libiberty.h" -#include "ggc.h" -#include "lto-streamer.h" - -/* Cater to hosts with half-backed 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 +. */ + +#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 -. */ - -#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 (<osec->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 -. */ - -#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 -. */ - -#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 (<osec->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 (<osec->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 -. */ - -#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 -#include -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 @@ -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 ],[ - 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 ],[ - elf_getshdrstrndx (0, 0); - ], - [AC_MSG_RESULT([yes]);], - [AC_MSG_RESULT([no]); - AC_MSG_CHECKING([for elf_getshstrndx]) - AC_TRY_LINK( - [#include ],[ - 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