From patchwork Mon Nov 1 22:27:42 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: 69852 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 533CAB70AF for ; Tue, 2 Nov 2010 09:30:14 +1100 (EST) Received: (qmail 1661 invoked by alias); 1 Nov 2010 22:30:04 -0000 Received: (qmail 1399 invoked by uid 22791); 1 Nov 2010 22:29:06 -0000 X-SWARE-Spam-Status: No, hits=-2.4 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_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; Mon, 01 Nov 2010 22:28:05 +0000 Received: from hpaq2.eem.corp.google.com (hpaq2.eem.corp.google.com [172.25.149.2]) by smtp-out.google.com with ESMTP id oA1MS0uC002050 for ; Mon, 1 Nov 2010 15:28:00 -0700 Received: from pwi1 (pwi1.prod.google.com [10.241.219.1]) by hpaq2.eem.corp.google.com with ESMTP id oA1MRf8q022251 for ; Mon, 1 Nov 2010 15:27:57 -0700 Received: by pwi1 with SMTP id 1so1544931pwi.28 for ; Mon, 01 Nov 2010 15:27:57 -0700 (PDT) Received: by 10.142.49.8 with SMTP id w8mr4958485wfw.209.1288650477123; Mon, 01 Nov 2010 15:27:57 -0700 (PDT) Received: from coign.google.com ([216.239.45.130]) by mx.google.com with ESMTPS id q13sm9607961wfc.5.2010.11.01.15.27.44 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 01 Nov 2010 15:27:54 -0700 (PDT) From: Ian Lance Taylor To: Tom Tromey Cc: 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: Mon, 01 Nov 2010 15:27:42 -0700 In-Reply-To: (Tom Tromey's message of "Mon, 01 Nov 2010 10:45:02 -0600") 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 Tom Tromey writes: > GDB already uses the name "objfile" for one of its modules. > I don't think we have any name clashes with this patch right now, but I > would prefer to avoid the eventual confusion. > So, if this is in libiberty, could it please have a different name? OK, I renamed objfile to simple_object. This is the current patch, incorporating all suggestions so far. There are still reportedly problems with the Mach-O code. Ian ChangeLog: 2010-11-01 Ian Lance Taylor * configure.ac: Don't set default_enable_lto. Remove libelf tests. * configure: Rebuild. include/ChangeLog: 2010-11-01 Ian Lance Taylor * simple-object.h: New file. libiberty/ChangeLog: 2010-11-01 Ian Lance Taylor * simple-object.c: New file. * simple-object-common.h: New file. * simple-object-elf.c: New file. * simple-object-mach-o.c: New file. * simple-object-coff.c: New file. * simple-object.txh: New file. * configure.ac: Add AC_TYPE_SSIZE_T. * Makefile.in: Rebuild dependencies. (CFILES): Add simple-object.c, simple-object-coff, simple-object-elf.c, and simple-object-mach-o.c. (REQUIRED_OFILES): Add corresponding object files. * configure: Rebuild. * config.in: Rebuild. * functions.texi: Rebuild. gcc/ChangeLog: 2010-11-01 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-11-01 Ian Lance Taylor * lto-object.c: New file. * lto-elf.c: Remove file. * lto-macho.c: Remove file. * lto-macho.h: Remove file. * lto-coff.c: Remove file. * lto-coff.h: Remove file. * Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to lto/lto-object.o. ($(LTO_EXE)): Remove $(LTO_USE_LIBELF) (lto/lto-objfile.o): New target. (lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets. (lto/lto.o): Remove $(LIBIBERTY_H). Index: include/simple-object.h =================================================================== --- include/simple-object.h (revision 0) +++ include/simple-object.h (revision 0) @@ -0,0 +1,203 @@ +/* simple-object.h -- simple routines to read and write 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 SIMPLE_OBJECT_H +#define SIMPLE_OBJECT_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 simple_object_read * is used to read an existing object + file. */ + +typedef struct simple_object_read_struct simple_object_read; + +/* Create an simple_object_read 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 + simple_object_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 simple_object_read * +simple_object_start_read (int descriptor, off_t offset, + const char *segment_name, const char **errmsg, + int *err); + +/* Call PFN for each section in SIMPLE_OBJECT, 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 simple_object_start_read. The DATA argument + to simple_object_find_sections is passed on to PFN. If PFN returns + 0, the loop is stopped and simple_object_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 * +simple_object_find_sections (simple_object_read *simple_object, + int (*pfn) (void *data, const char *, + off_t offset, off_t length), + void *data, + int *err); + +/* Look for the section NAME in SIMPLE_OBJECT. This returns + information for the first section NAME in SIMPLE_OBJECT. Note that + calling this multiple times is inefficient; use + simple_object_find_sections instead. + + 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 + simple_object_start_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 +simple_object_find_section (simple_object_read *simple_object, + const char *name, off_t *offset, off_t *length, + const char **errmsg, int *err); + +/* Release all resources associated with SIMPLE_OBJECT. This does not + close the file descriptor. */ + +extern void +simple_object_release_read (simple_object_read *); + +/* The type simple_object_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 simple_object_attributes_struct simple_object_attributes; + +/* Fetch the attributes of SIMPLE_OBJECT. This information will + persist until simple_object_attributes_release is called, even if + SIMPLE_OBJECT 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 simple_object_attributes * +simple_object_fetch_attributes (simple_object_read *simple_object, + 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 * +simple_object_attributes_compare (simple_object_attributes *attrs1, + simple_object_attributes *attrs2, + int *err); + +/* Release all resources associated with ATTRS. */ + +extern void +simple_object_release_attributes (simple_object_attributes *attrs); + +/* The type simple_object_write is used to create a new object file. */ + +typedef struct simple_object_write_struct simple_object_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 simple_object_write * +simple_object_start_write (simple_object_attributes *attrs, + const char *segment_name, + const char **errmsg, int *err); + +/* The type simple_object_write_section is a handle for a section + which is being written. */ + +typedef struct simple_object_write_section_struct simple_object_write_section; + +/* Add a section to SIMPLE_OBJECT. 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 simple_object_write_section * +simple_object_write_create_section (simple_object_write *simple_object, + const char *name, unsigned int align, + const char **errmsg, int *err); + +/* Add data BUFFER/SIZE to SECTION in SIMPLE_OBJECT. If COPY is + non-zero, the data will be copied into memory if necessary. If + COPY is zero, BUFFER must persist until SIMPLE_OBJECT 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 * +simple_object_write_add_data (simple_object_write *simple_object, + simple_object_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 * +simple_object_write_to_file (simple_object_write *simple_object, + int descriptor, int *err); + +/* Release all resources associated with SIMPLE_OBJECT, including any + simple_object_write_section's that may have been created. */ + +extern void +simple_object_release_write (simple_object_write *); + +#ifdef __cplusplus +} +#endif + +#endif Index: libiberty/simple-object-elf.c =================================================================== --- libiberty/simple-object-elf.c (revision 0) +++ libiberty/simple-object-elf.c (revision 0) @@ -0,0 +1,916 @@ +/* simple-object-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 "simple-object.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 "simple-object-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 = +{ + simple_object_fetch_big_16, + simple_object_fetch_big_32, + simple_object_fetch_big_32_ulong, + simple_object_set_big_16, + simple_object_set_big_32, + simple_object_set_big_32_ulong +}; + +static const struct elf_type_functions elf_little_32_functions = +{ + simple_object_fetch_little_16, + simple_object_fetch_little_32, + simple_object_fetch_little_32_ulong, + simple_object_set_little_16, + simple_object_set_little_32, + simple_object_set_little_32_ulong +}; + +#ifdef UNSIGNED_64BIT_TYPE + +static const struct elf_type_functions elf_big_64_functions = +{ + simple_object_fetch_big_16, + simple_object_fetch_big_32, + simple_object_fetch_big_64, + simple_object_set_big_16, + simple_object_set_big_32, + simple_object_set_big_64 +}; + +static const struct elf_type_functions elf_little_64_functions = +{ + simple_object_fetch_little_16, + simple_object_fetch_little_32, + simple_object_fetch_little_64, + simple_object_set_little_16, + simple_object_set_little_32, + simple_object_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 simple_object_read. */ + +struct simple_object_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 simple_object_attributes. */ + +struct simple_object_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 * +simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_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 simple_object_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 (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr, + errmsg, err)) + return NULL; + + eor = XNEW (struct simple_object_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 (!simple_object_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 * +simple_object_elf_find_sections (simple_object_read *sobj, + int (*pfn) (void *, const char *, + off_t offset, off_t length), + void *data, + int *err) +{ + struct simple_object_elf_read *eor = + (struct simple_object_elf_read *) sobj->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 (!simple_object_internal_read (sobj->descriptor, + sobj->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 (!simple_object_internal_read (sobj->descriptor, + sobj->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 simple_object_read. */ + +static void * +simple_object_elf_fetch_attributes (simple_object_read *sobj, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_elf_read *eor = + (struct simple_object_elf_read *) sobj->data; + struct simple_object_elf_attributes *ret; + + ret = XNEW (struct simple_object_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 simple_object_read. */ + +static void +simple_object_elf_release_read (void *data) +{ + XDELETE (data); +} + +/* Compare two attributes structures. */ + +static const char * +simple_object_elf_attributes_compare (void *data1, void *data2, int *err) +{ + struct simple_object_elf_attributes *attrs1 = + (struct simple_object_elf_attributes *) data1; + struct simple_object_elf_attributes *attrs2 = + (struct simple_object_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 +simple_object_elf_release_attributes (void *data) +{ + XDELETE (data); +} + +/* Prepare to write out a file. */ + +static void * +simple_object_elf_start_write (void *attributes_data, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_elf_attributes *attrs = + (struct simple_object_elf_attributes *) attributes_data; + struct simple_object_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 simple_object_elf_attributes); + *ret = *attrs; + return ret; +} + +/* Write out an ELF ehdr. */ + +static int +simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, + const char **errmsg, int *err) +{ + struct simple_object_elf_attributes *attrs = + (struct simple_object_elf_attributes *) sobj->data; + const struct elf_type_functions* fns; + unsigned char cl; + size_t ehdr_size; + unsigned char buf[sizeof (Elf64_External_Ehdr)]; + simple_object_write_section *section; + unsigned int shnum; + + fns = attrs->type_functions; + cl = attrs->ei_class; + + shnum = 0; + for (section = sobj->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, sizeof (Elf64_External_Ehdr)); + + 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 simple_object_internal_write (descriptor, 0, buf, ehdr_size, + errmsg, err); +} + +/* Write out an ELF shdr. */ + +static int +simple_object_elf_write_shdr (simple_object_write *sobj, 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 simple_object_elf_attributes *attrs = + (struct simple_object_elf_attributes *) sobj->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, sizeof (Elf64_External_Shdr)); + + 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 simple_object_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 * +simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, + int *err) +{ + struct simple_object_elf_attributes *attrs = + (struct simple_object_elf_attributes *) sobj->data; + unsigned char cl; + size_t ehdr_size; + size_t shdr_size; + const char *errmsg; + simple_object_write_section *section; + unsigned int shnum; + size_t shdr_offset; + size_t sh_offset; + size_t sh_name; + unsigned char zero; + + if (!simple_object_elf_write_ehdr (sobj, 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 = sobj->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 (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, + 0, 0, 0, 0, 0, 0, &errmsg, err)) + return errmsg; + + shdr_offset += shdr_size; + + sh_name = 1; + for (section = sobj->sections; section != NULL; section = section->next) + { + size_t mask; + size_t new_sh_offset; + size_t sh_size; + struct simple_object_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 (!simple_object_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 (!simple_object_internal_write (descriptor, sh_offset + sh_size, + ((const unsigned char *) + buffer->buffer), + buffer->size, &errmsg, err)) + return errmsg; + sh_size += buffer->size; + } + + if (!simple_object_elf_write_shdr (sobj, 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 (!simple_object_elf_write_shdr (sobj, 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 (!simple_object_internal_write (descriptor, sh_offset, &zero, 1, + &errmsg, err)) + return errmsg; + ++sh_offset; + + for (section = sobj->sections; section != NULL; section = section->next) + { + size_t len; + + len = strlen (section->name) + 1; + if (!simple_object_internal_write (descriptor, sh_offset, + (const unsigned char *) section->name, + len, &errmsg, err)) + return errmsg; + sh_offset += len; + } + + if (!simple_object_internal_write (descriptor, sh_offset, + (const unsigned char *) ".shstrtab", + strlen (".shstrtab") + 1, &errmsg, err)) + return errmsg; + + return NULL; +} + +/* Release the private data for an simple_object_write structure. */ + +static void +simple_object_elf_release_write (void *data) +{ + XDELETE (data); +} + +/* The ELF functions. */ + +const struct simple_object_functions simple_object_elf_functions = +{ + simple_object_elf_match, + simple_object_elf_find_sections, + simple_object_elf_fetch_attributes, + simple_object_elf_release_read, + simple_object_elf_attributes_compare, + simple_object_elf_release_attributes, + simple_object_elf_start_write, + simple_object_elf_write_to_file, + simple_object_elf_release_write +}; Index: libiberty/configure.ac =================================================================== --- libiberty/configure.ac (revision 166080) +++ 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/simple-object-mach-o.c =================================================================== --- libiberty/simple-object-mach-o.c (revision 0) +++ libiberty/simple-object-mach-o.c (revision 0) @@ -0,0 +1,1026 @@ +/* simple-object-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 "simple-object.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 "simple-object-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 simple_object_read. */ + +struct simple_object_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 simple_object_attributes. */ + +struct simple_object_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 * +simple_object_mach_o_match ( + unsigned char header[SIMPLE_OBJECT_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 simple_object_mach_o_read *omr; + unsigned char buf[sizeof (struct mach_o_header_64)]; + unsigned char *b; + + magic = simple_object_fetch_big_32 (header); + if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) + is_big_endian = 1; + else + { + magic = simple_object_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 + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + + if (!simple_object_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 simple_object_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 +simple_object_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 + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + + fetch_64 = NULL; +#ifdef UNSIGNED_64BIT_TYPE + fetch_64 = (is_big_endian + ? simple_object_fetch_big_64 + : simple_object_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 +simple_object_mach_o_segment (simple_object_read *sobj, 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 simple_object_mach_o_read *omr = + (struct simple_object_mach_o_read *) sobj->data; + unsigned int (*fetch_32) (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 + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + + 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 (!simple_object_internal_read (sobj->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; + + simple_object_mach_o_section_info (omr->is_big_endian, is_32, + secdata + strtab_index * sechdrsize, + &strtab_offset, &strtab_size); + strtab = XNEWVEC (char, strtab_size); + if (!simple_object_internal_read (sobj->descriptor, + sobj->offset + 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 (namebuf, 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; + } + } + + simple_object_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 * +simple_object_mach_o_find_sections (simple_object_read *sobj, + int (*pfn) (void *, const char *, + off_t offset, off_t length), + void *data, + int *err) +{ + struct simple_object_mach_o_read *omr = + (struct simple_object_mach_o_read *) sobj->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 + ? simple_object_fetch_big_32 + : simple_object_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 (!simple_object_internal_read (sobj->descriptor, + sobj->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 (!simple_object_internal_read (sobj->descriptor, + sobj->offset + 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 = simple_object_mach_o_segment (sobj, 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 simple_object_read. */ + +static void * +simple_object_mach_o_fetch_attributes (simple_object_read *sobj, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_mach_o_read *omr = + (struct simple_object_mach_o_read *) sobj->data; + struct simple_object_mach_o_attributes *ret; + + ret = XNEW (struct simple_object_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 simple_object_read. */ + +static void +simple_object_mach_o_release_read (void *data) +{ + struct simple_object_mach_o_read *omr = + (struct simple_object_mach_o_read *) data; + + free (omr->segment_name); + XDELETE (omr); +} + +/* Compare two attributes structures. */ + +static const char * +simple_object_mach_o_attributes_compare (void *data1, void *data2, int *err) +{ + struct simple_object_mach_o_attributes *attrs1 = + (struct simple_object_mach_o_attributes *) data1; + struct simple_object_mach_o_attributes *attrs2 = + (struct simple_object_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 +simple_object_mach_o_release_attributes (void *data) +{ + XDELETE (data); +} + +/* Prepare to write out a file. */ + +static void * +simple_object_mach_o_start_write (void *attributes_data, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_mach_o_attributes *attrs = + (struct simple_object_mach_o_attributes *) attributes_data; + struct simple_object_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 simple_object_mach_o_attributes); + *ret = *attrs; + return ret; +} + +/* Write out the header of a Mach-O file. */ + +static int +simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor, + size_t nsects, const char **errmsg, + int *err) +{ + struct simple_object_mach_o_attributes *attrs = + (struct simple_object_mach_o_attributes *) sobj->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 + ? simple_object_set_big_32 + : simple_object_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 simple_object_internal_write (descriptor, 0, hdrbuf, wrsize, + errmsg, err); +} + +/* Write a Mach-O section header. */ + +static int +simple_object_mach_o_write_section_header (simple_object_write *sobj, + 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 simple_object_mach_o_attributes *attrs = + (struct simple_object_mach_o_attributes *) sobj->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 + ? simple_object_set_big_32 + : simple_object_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), + sobj->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 + ? simple_object_set_big_64 + : simple_object_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), + sobj->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 simple_object_internal_write (descriptor, sechdr_offset, hdr, + sechdrsize, errmsg, err); +} + +/* Write out the single segment and the sections of a Mach-O file. */ + +static int +simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, + size_t nsects, const char **errmsg, + int *err) +{ + struct simple_object_mach_o_attributes *attrs = + (struct simple_object_mach_o_attributes *) sobj->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; + simple_object_write_section *section; + unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; + unsigned char *hdr; + + set_32 = (attrs->is_big_endian + ? simple_object_set_big_32 + : simple_object_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 = sobj->sections; section != NULL; section = section->next) + { + size_t mask; + size_t new_offset; + size_t secsize; + struct simple_object_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 (!simple_object_internal_write (descriptor, offset, zeroes, write, + errmsg, err)) + return 0; + offset += write; + } + + secsize = 0; + for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) + { + if (!simple_object_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 (!simple_object_mach_o_write_section_header (sobj, 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 (!simple_object_mach_o_write_section_header (sobj, descriptor, + sechdr_offset, + GNU_SECTION_NAMES, secaddr, + name_offset, offset, 0, + errmsg, err)) + return 0; + + for (section = sobj->sections; section != NULL; section = section->next) + { + size_t namelen; + + namelen = strlen (section->name) + 1; + if (!simple_object_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)), + sobj->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 + ? simple_object_set_big_64 + : simple_object_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)), + sobj->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 simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, + errmsg, err); +} + +/* Write out a complete Mach-O file. */ + +static const char * +simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, + int *err) +{ + size_t nsects; + simple_object_write_section *section; + const char *errmsg; + + /* Start at 1 for symbol_names section. */ + nsects = 1; + for (section = sobj->sections; section != NULL; section = section->next) + ++nsects; + + if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, + &errmsg, err)) + return errmsg; + + if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects, + &errmsg, err)) + return errmsg; + + return NULL; +} + +/* Release the private data for an simple_object_write structure. */ + +static void +simple_object_mach_o_release_write (void *data) +{ + XDELETE (data); +} + +/* The Mach-O functions. */ + +const struct simple_object_functions simple_object_mach_o_functions = +{ + simple_object_mach_o_match, + simple_object_mach_o_find_sections, + simple_object_mach_o_fetch_attributes, + simple_object_mach_o_release_read, + simple_object_mach_o_attributes_compare, + simple_object_mach_o_release_attributes, + simple_object_mach_o_start_write, + simple_object_mach_o_write_to_file, + simple_object_mach_o_release_write +}; Index: libiberty/simple-object-coff.c =================================================================== --- libiberty/simple-object-coff.c (revision 0) +++ libiberty/simple-object-coff.c (revision 0) @@ -0,0 +1,804 @@ +/* simple-object-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 "simple-object.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 "simple-object-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_MEM_DISCARDABLE (1 << 25) +#define IMAGE_SCN_MEM_SHARED (1 << 28) +#define IMAGE_SCN_MEM_READ (1 << 30) + +#define IMAGE_SCN_ALIGN_POWER_BIT_POS 20 +#define IMAGE_SCN_ALIGN_POWER_CONST(val) \ + (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS) + +/* COFF symbol table entry. */ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ + +struct external_syment +{ + union + { + unsigned char e_name[E_SYMNMLEN]; + + struct + { + unsigned char e_zeroes[4]; + unsigned char e_offset[4]; + } e; + } e; + + unsigned char e_value[4]; + unsigned char e_scnum[2]; + unsigned char e_type[2]; + unsigned char e_sclass[1]; + unsigned char e_numaux[1]; +}; + +/* Length allowed for filename in aux sym format 4. */ + +#define E_FILNMLEN 18 + +/* Omits x_sym and other unused variants. */ + +union external_auxent +{ + /* Aux sym format 4: file. */ + union + { + char x_fname[E_FILNMLEN]; + struct + { + unsigned char x_zeroes[4]; + unsigned char x_offset[4]; + } x_n; + } x_file; + /* Aux sym format 5: section. */ + struct + { + unsigned char x_scnlen[4]; /* section length */ + unsigned char x_nreloc[2]; /* # relocation entries */ + unsigned char x_nlinno[2]; /* # line numbers */ + unsigned char x_checksum[4]; /* section COMDAT checksum */ + unsigned char x_associated[2]; /* COMDAT assoc section index */ + unsigned char x_comdat[1]; /* COMDAT selection number */ + } x_scn; +}; + +/* Symbol-related constants. */ + +#define IMAGE_SYM_DEBUG (-2) +#define IMAGE_SYM_TYPE_NULL (0) +#define IMAGE_SYM_DTYPE_NULL (0) +#define IMAGE_SYM_CLASS_STATIC (3) +#define IMAGE_SYM_CLASS_FILE (103) + +#define IMAGE_SYM_TYPE \ + ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL) + +/* Private data for an simple_object_read. */ + +struct simple_object_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 simple_object_attributes. */ + +struct simple_object_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 * +simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + int descriptor, off_t offset, + const char *segment_name ATTRIBUTE_UNUSED, + const char **errmsg, int *err) +{ + size_t c; + unsigned short magic_big; + unsigned short magic_little; + unsigned short magic; + size_t i; + int is_big_endian; + unsigned short (*fetch_16) (const unsigned char *); + unsigned int (*fetch_32) (const unsigned char *); + unsigned char hdrbuf[sizeof (struct external_filehdr)]; + unsigned short flags; + struct simple_object_coff_read *ocr; + + c = sizeof (coff_magic) / sizeof (coff_magic[0]); + magic_big = simple_object_fetch_big_16 (header); + magic_little = simple_object_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 + ? simple_object_fetch_big_16 + : simple_object_fetch_little_16); + fetch_32 = (is_big_endian + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + + if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf, + errmsg, err)) + return NULL; + + flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags)); + if ((flags & coff_magic[i].non_object_flags) != 0) + { + *errmsg = "not relocatable object file"; + *err = 0; + return NULL; + } + + ocr = XNEW (struct simple_object_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 * +simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size, + const char **errmsg, int *err) +{ + struct simple_object_coff_read *ocr = + (struct simple_object_coff_read *) sobj->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 (!simple_object_internal_read (sobj->descriptor, strtab_offset, + strsizebuf, 4, errmsg, err)) + return NULL; + strsize = (ocr->is_big_endian + ? simple_object_fetch_big_32 (strsizebuf) + : simple_object_fetch_little_32 (strsizebuf)); + strtab = XNEWVEC (char, strsize); + if (!simple_object_internal_read (sobj->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 * +simple_object_coff_find_sections (simple_object_read *sobj, + int (*pfn) (void *, const char *, + off_t offset, off_t length), + void *data, + int *err) +{ + struct simple_object_coff_read *ocr = + (struct simple_object_coff_read *) sobj->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 (!simple_object_internal_read (sobj->descriptor, + sobj->offset + ocr->scnhdr_offset, + scnbuf, scnhdr_size * ocr->nscns, &errmsg, + err)) + { + XDELETEVEC (scnbuf); + return errmsg; + } + + fetch_32 = (ocr->is_big_endian + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + + nscns = ocr->nscns; + strtab = NULL; + strtab_size = 0; + for (i = 0; i < nscns; ++i) + { + unsigned char *scnhdr; + unsigned char *scnname; + char namebuf[SCNNMLEN + 1]; + char *name; + off_t scnptr; + unsigned int size; + + scnhdr = scnbuf + i * scnhdr_size; + scnname = scnhdr + offsetof (struct external_scnhdr, s_name); + memcpy (namebuf, scnname, SCNNMLEN); + namebuf[SCNNMLEN] = '\0'; + name = &namebuf[0]; + if (namebuf[0] == '/') + { + size_t strindex; + char *end; + + strindex = strtol (namebuf + 1, &end, 10); + if (*end == '\0') + { + /* The real section name is found in the string + table. */ + if (strtab == NULL) + { + strtab = simple_object_coff_read_strtab (sobj, + &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 simple_object_read. */ + +static void * +simple_object_coff_fetch_attributes (simple_object_read *sobj, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_coff_read *ocr = + (struct simple_object_coff_read *) sobj->data; + struct simple_object_coff_attributes *ret; + + ret = XNEW (struct simple_object_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 simple_object_read. */ + +static void +simple_object_coff_release_read (void *data) +{ + XDELETE (data); +} + +/* Compare two attributes structures. */ + +static const char * +simple_object_coff_attributes_compare (void *data1, void *data2, int *err) +{ + struct simple_object_coff_attributes *attrs1 = + (struct simple_object_coff_attributes *) data1; + struct simple_object_coff_attributes *attrs2 = + (struct simple_object_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 +simple_object_coff_release_attributes (void *data) +{ + XDELETE (data); +} + +/* Prepare to write out a file. */ + +static void * +simple_object_coff_start_write (void *attributes_data, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_coff_attributes *attrs = + (struct simple_object_coff_attributes *) attributes_data; + struct simple_object_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 simple_object_coff_attributes); + *ret = *attrs; + return ret; +} + +/* Write out a COFF filehdr. */ + +static int +simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor, + unsigned int nscns, size_t symtab_offset, + unsigned int nsyms, const char **errmsg, + int *err) +{ + struct simple_object_coff_attributes *attrs = + (struct simple_object_coff_attributes *) sobj->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 + ? simple_object_set_big_16 + : simple_object_set_little_16); + set_32 = (attrs->is_big_endian + ? simple_object_set_big_32 + : simple_object_set_little_32); + + memset (hdr, 0, sizeof (struct external_filehdr)); + + set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); + set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); + /* f_timdat left as zero. */ + set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset); + set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms); + /* f_opthdr left as zero. */ + set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags); + + return simple_object_internal_write (descriptor, 0, hdrbuf, + sizeof (struct external_filehdr), + errmsg, err); +} + +/* Write out a COFF section header. */ + +static int +simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor, + const char *name, size_t *name_offset, + off_t scnhdr_offset, size_t scnsize, + off_t offset, unsigned int align, + const char **errmsg, int *err) +{ + struct simple_object_coff_attributes *attrs = + (struct simple_object_coff_attributes *) sobj->data; + void (*set_32) (unsigned char *, unsigned int); + unsigned char hdrbuf[sizeof (struct external_scnhdr)]; + unsigned char *hdr; + size_t namelen; + unsigned int flags; + + set_32 = (attrs->is_big_endian + ? simple_object_set_big_32 + : simple_object_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. */ + flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED + | IMAGE_SCN_MEM_READ); + /* PE can represent alignment up to 13. */ + if (align > 13) + align = 13; + flags |= IMAGE_SCN_ALIGN_POWER_CONST(align); + set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags); + + return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, + sizeof (struct external_scnhdr), + errmsg, err); +} + +/* Write out a complete COFF file. */ + +static const char * +simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, + int *err) +{ + struct simple_object_coff_attributes *attrs = + (struct simple_object_coff_attributes *) sobj->data; + unsigned int nscns, secnum; + simple_object_write_section *section; + off_t scnhdr_offset; + size_t symtab_offset; + off_t secsym_offset; + unsigned int nsyms; + size_t offset; + size_t name_offset; + const char *errmsg; + unsigned char strsizebuf[4]; + /* The interface doesn't give us access to the name of the input file + yet. We want to use its basename for the FILE symbol. This is + what 'gas' uses when told to assemble from stdin. */ + const char *source_filename = "fake"; + size_t sflen; + union + { + struct external_syment sym; + union external_auxent aux; + } syms[2]; + void (*set_16) (unsigned char *, unsigned short); + void (*set_32) (unsigned char *, unsigned int); + + set_16 = (attrs->is_big_endian + ? simple_object_set_big_16 + : simple_object_set_little_16); + set_32 = (attrs->is_big_endian + ? simple_object_set_big_32 + : simple_object_set_little_32); + + nscns = 0; + for (section = sobj->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 = sobj->sections; section != NULL; section = section->next) + { + size_t mask; + size_t new_offset; + size_t scnsize; + struct simple_object_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 (!simple_object_internal_write (descriptor, offset, zeroes, write, + &errmsg, err)) + return errmsg; + } + + scnsize = 0; + for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) + { + if (!simple_object_internal_write (descriptor, offset + scnsize, + ((const unsigned char *) + buffer->buffer), + buffer->size, &errmsg, err)) + return errmsg; + scnsize += buffer->size; + } + + if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name, + &name_offset, scnhdr_offset, + scnsize, offset, section->align, + &errmsg, err)) + return errmsg; + + scnhdr_offset += sizeof (struct external_scnhdr); + offset += scnsize; + } + + /* Symbol table is always half-word aligned. */ + offset += (offset & 1); + /* There is a file symbol and a section symbol per section, + and each of these has a single auxiliary symbol following. */ + nsyms = 2 * (nscns + 1); + symtab_offset = offset; + /* Advance across space reserved for symbol table to locate + start of string table. */ + offset += nsyms * sizeof (struct external_syment); + + /* Write out file symbol. */ + memset (&syms[0], 0, sizeof (syms)); + strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); + set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); + set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); + syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; + syms[0].sym.e_numaux[0] = 1; + /* The name need not be nul-terminated if it fits into the x_fname field + directly, but must be if it has to be placed into the string table. */ + sflen = strlen (source_filename); + if (sflen <= E_FILNMLEN) + memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); + else + { + set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); + if (!simple_object_internal_write (descriptor, offset + name_offset, + ((const unsigned char *) + source_filename), + sflen + 1, &errmsg, err)) + return errmsg; + name_offset += strlen (source_filename) + 1; + } + if (!simple_object_internal_write (descriptor, symtab_offset, + (const unsigned char *) &syms[0], + sizeof (syms), &errmsg, err)) + return errmsg; + + /* Write the string table length, followed by the strings and section + symbols in step with each other. */ + set_32 (strsizebuf, name_offset); + if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, + &errmsg, err)) + return errmsg; + + name_offset = 4; + secsym_offset = symtab_offset + sizeof (syms); + memset (&syms[0], 0, sizeof (syms)); + set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); + syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; + syms[0].sym.e_numaux[0] = 1; + secnum = 1; + + for (section = sobj->sections; section != NULL; section = section->next) + { + size_t namelen; + size_t scnsize; + struct simple_object_write_section_buffer *buffer; + + namelen = strlen (section->name); + set_16 (&syms[0].sym.e_scnum[0], secnum++); + scnsize = 0; + for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) + scnsize += buffer->size; + set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); + if (namelen > SCNNMLEN) + { + set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); + set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); + if (!simple_object_internal_write (descriptor, offset + name_offset, + ((const unsigned char *) + section->name), + namelen + 1, &errmsg, err)) + return errmsg; + name_offset += namelen + 1; + } + else + { + memcpy (&syms[0].sym.e.e_name[0], section->name, + strlen (section->name)); + memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, + E_SYMNMLEN - strlen (section->name)); + } + + if (!simple_object_internal_write (descriptor, secsym_offset, + (const unsigned char *) &syms[0], + sizeof (syms), &errmsg, err)) + return errmsg; + secsym_offset += sizeof (syms); + } + + if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, + symtab_offset, nsyms, &errmsg, err)) + return errmsg; + + return NULL; +} + +/* Release the private data for an simple_object_write structure. */ + +static void +simple_object_coff_release_write (void *data) +{ + XDELETE (data); +} + +/* The COFF functions. */ + +const struct simple_object_functions simple_object_coff_functions = +{ + simple_object_coff_match, + simple_object_coff_find_sections, + simple_object_coff_fetch_attributes, + simple_object_coff_release_read, + simple_object_coff_attributes_compare, + simple_object_coff_release_attributes, + simple_object_coff_start_write, + simple_object_coff_write_to_file, + simple_object_coff_release_write +}; Index: libiberty/Makefile.in =================================================================== --- libiberty/Makefile.in (revision 166080) +++ libiberty/Makefile.in (working copy) @@ -2,8 +2,8 @@ # Originally written by K. Richard Pixley . # # Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software -# Foundation +# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# Free Software Foundation # # This file is part of the libiberty library. # Libiberty is free software; you can redistribute it and/or @@ -145,6 +145,8 @@ CFILES = alloca.c argv.c asprintf.c atex physmem.c putenv.c \ random.c regex.c rename.c rindex.c \ safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c \ + simple-object.c simple-object-coff.c simple-object-elf.c \ + simple-object-mach-o.c \ snprintf.c sort.c \ spaces.c splay-tree.c stpcpy.c stpncpy.c strcasecmp.c \ strchr.c strdup.c strerror.c strncasecmp.c strncmp.c \ @@ -172,11 +174,15 @@ 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) \ + ./obstack.$(objext) \ ./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \ ./pex-common.$(objext) ./pex-one.$(objext) \ ./@pexecute@.$(objext) \ - ./safe-ctype.$(objext) ./sort.$(objext) ./spaces.$(objext) \ + ./safe-ctype.$(objext) \ + ./simple-object.$(objext) ./simple-object-coff.$(objext) \ + ./simple-object-elf.$(objext) ./simple-object-mach-o.$(objext) \ + ./sort.$(objext) ./spaces.$(objext) \ ./splay-tree.$(objext) ./strerror.$(objext) \ ./strsignal.$(objext) ./unlink-if-ordinary.$(objext) \ ./xatexit.$(objext) ./xexit.$(objext) ./xmalloc.$(objext) \ @@ -312,7 +318,7 @@ TEXISRC = \ # Additional files that have texi snippets that need to be collected # and sorted. Some are here because the sources are imported from # elsewhere. Others represent headers in ../include. -TEXIFILES = fnmatch.txh pexecute.txh +TEXIFILES = fnmatch.txh pexecute.txh simple-object.txh libiberty.info : $(srcdir)/libiberty.texi $(TEXISRC) $(MAKEINFO) -I$(srcdir) $(srcdir)/libiberty.texi @@ -965,6 +971,38 @@ $(CONFIGURED_OFILES): stamp-picdir else true; fi $(COMPILE.c) $(srcdir)/sigsetmask.c $(OUTPUT_OPTION) +./simple-object-coff.$(objext): $(srcdir)/simple-object-coff.c config.h \ + $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-coff.c -o pic/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/simple-object-coff.c $(OUTPUT_OPTION) + +./simple-object-elf.$(objext): $(srcdir)/simple-object-elf.c config.h \ + $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-elf.c -o pic/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/simple-object-elf.c $(OUTPUT_OPTION) + +./simple-object-mach-o.$(objext): $(srcdir)/simple-object-mach-o.c config.h \ + $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-mach-o.c -o pic/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/simple-object-mach-o.c $(OUTPUT_OPTION) + +./simple-object.$(objext): $(srcdir)/simple-object.c config.h \ + $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object.c -o pic/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/simple-object.c $(OUTPUT_OPTION) + ./snprintf.$(objext): $(srcdir)/snprintf.c $(INCDIR)/ansidecl.h if [ x"$(PICFLAG)" != x ]; then \ $(COMPILE.c) $(PICFLAG) $(srcdir)/snprintf.c -o pic/$@; \ Index: libiberty/simple-object-common.h =================================================================== --- libiberty/simple-object-common.h (revision 0) +++ libiberty/simple-object-common.h (revision 0) @@ -0,0 +1,354 @@ +/* simple-object-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 simple_object_functions; + +/* An object file opened for reading. */ + +struct simple_object_read_struct +{ + /* The file descriptor. */ + int descriptor; + /* The offset within the file. */ + off_t offset; + /* The functions which do the actual work. */ + const struct simple_object_functions *functions; + /* Private data for the object file format. */ + void *data; +}; + +/* Object file attributes. */ + +struct simple_object_attributes_struct +{ + /* The functions which do the actual work. */ + const struct simple_object_functions *functions; + /* Private data for the object file format. */ + void *data; +}; + +/* An object file being created. */ + +struct simple_object_write_struct +{ + /* The functions which do the actual work. */ + const struct simple_object_functions *functions; + /* The segment_name argument from the user. */ + char *segment_name; + /* The start of the list of sections. */ + simple_object_write_section *sections; + /* The last entry in the list of sections. */ + simple_object_write_section *last_section; + /* Private data for the object file format. */ + void *data; +}; + +/* A section in an object file being created. */ + +struct simple_object_write_section_struct +{ + /* Next in the list of sections attached to an + simple_object_write. */ + simple_object_write_section *next; + /* The name of this section. */ + char *name; + /* The required alignment. */ + unsigned int align; + /* The first data attached to this section. */ + struct simple_object_write_section_buffer *buffers; + /* The last data attached to this section. */ + struct simple_object_write_section_buffer *last_buffer; +}; + +/* Data attached to a section. */ + +struct simple_object_write_section_buffer +{ + /* The next data for this section. */ + struct simple_object_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 SIMPLE_OBJECT_MATCH_HEADER_LEN (16) + +/* Format-specific object file functions. */ + +struct simple_object_functions +{ + /* If this file matches these functions, return a new value for the + private data for an simple_object_read. HEADER is the first 16 + bytes of the file. DESCRIPTOR, OFFSET, SEGMENT_NAME, ERRMSG, and + ERR are as for simple_object_open_read. If this file does not + match, this function should return NULL with *ERRMSG set to + NULL. */ + void *(*match) (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + int descriptor, off_t offset, const char *segment_name, + const char **errmsg, int *err); + + /* Implement simple_object_find_sections. */ + const char *(*find_sections) (simple_object_read *, + int (*pfn) (void *, const char *, + off_t offset, off_t length), + void *data, + int *err); + + /* Return the private data for the attributes for SOBJ. */ + void *(*fetch_attributes) (simple_object_read *sobj, const char **errmsg, + int *err); + + /* Release the private data for an simple_object_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 simple_object_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) (simple_object_write *sobj, int descriptor, + int *err); + + /* Release the private data for an simple_object_write. */ + void (*release_write) (void *); +}; + +/* The known object file formats. */ + +extern const struct simple_object_functions simple_object_coff_functions; +extern const struct simple_object_functions simple_object_elf_functions; +extern const struct simple_object_functions simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_fetch_big_32_ulong (const unsigned char *buf) +{ + return (ulong_type) simple_object_fetch_big_32 (buf); +} + +/* Fetch a little-endian 32-bit value as a ulong_type. */ + +static inline ulong_type +simple_object_fetch_little_32_ulong (const unsigned char *buf) +{ + return (ulong_type) simple_object_fetch_little_32 (buf); +} + +#ifdef UNSIGNED_64BIT_TYPE + +/* Fetch a big-endian 64-bit value. */ + +static inline ulong_type +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_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 +simple_object_set_big_32_ulong (unsigned char *buf, ulong_type val) +{ + simple_object_set_big_32 (buf, val); +} + +/* Store a little-endian 32-bit value coming in as a ulong_type. */ + +static inline void +simple_object_set_little_32_ulong (unsigned char *buf, ulong_type val) +{ + simple_object_set_little_32 (buf, val); +} + +#ifdef UNSIGNED_64BIT_TYPE + +/* Store a big-endian 64-bit value. */ + +static inline void +simple_object_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 +simple_object_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; +} + Index: libiberty/simple-object.txh =================================================================== --- libiberty/simple-object.txh (revision 0) +++ libiberty/simple-object.txh (revision 0) @@ -0,0 +1,168 @@ +@c -*- mode: texinfo -*- +@deftypefn Extension {simple_object_read *} simple_object_open_read (int @var{descriptor}, off_t @var{offset}, const char *{segment_name}, const char **@var{errmsg}, int *@var{err}) + +Opens an object file for reading. Creates and returns an +@code{simple_object_read} pointer which may be passed to other +functions to extract data from the object file. + +@var{descriptor} holds a file descriptor which permits reading. + +@var{offset} is the offset into the file; this will be @code{0} in the +normal case, but may be a different value when reading an object file +in an archive file. + +@var{segment_name} is only used with the Mach-O file format used on +Darwin aka Mac OS X. It is required on that platform, and means to +only look at sections within the segment with that name. The +parameter is ignored on other systems. + +If an error occurs, this functions returns @code{NULL} and sets +@code{*@var{errmsg}} to an error string and sets @code{*@var{err}} to +an errno value or @code{0} if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {const char *} simple_object_find_sections (simple_object_read *@var{simple_object}, int (*@var{pfn}) (void *@var{data}, const char *@var{name}, off_t @var{offset}, off_t @var{length}), void *@var{data}, int *@var{err}) + +This function calls @var{pfn} for each section in @var{simple_object}. +It calls @var{pfn} with the section name, the offset within the file +of the section contents, and the length of the section contents. The +offset within the file is relative to the offset passed to +@code{simple_object_open_read}. The @var{data} argument to this +function is passed along to @var{pfn}. + +If @var{pfn} returns @code{0}, the loop over the sections stops and +@code{simple_object_find_sections} returns. If @var{pfn} returns some +other value, the loop continues. + +On success @code{simple_object_find_sections} returns. On error it +returns an error string, and sets @code{*@var{err}} to an errno value +or @code{0} if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {int} simple_object_find_section (simple_object_read *@var{simple_object} off_t *@var{offset}, off_t *@var{length}, const char **@var{errmsg}, int *@var{err}) + +Look for the section @var{name} in @var{simple_object}. This returns +information for the first section with that name. + +If found, return 1 and set @code{*@var{offset}} to the offset in the +file of the section contents and set @code{*@var{length}} to the +length of the section contents. The value in @code{*@var{offset}} +will be relative to the offset passed to +@code{simple_object_open_read}. + +If the section is not found, and no error occurs, +@code{simple_object_find_section} returns @code{0} and set +@code{*@var{errmsg}} to @code{NULL}. + +If an error occurs, @code{simple_object_find_section} returns +@code{0}, sets @code{*@var{errmsg}} to an error message, and sets +@code{*@var{err}} to an errno value or @code{0} if there is no +relevant errno. + +@end deftypefn + +@deftypefn Extension {void} simple_object_release_read (simple_object_read *@var{simple_object}) + +Release all resources associated with @var{simple_object}. This does +not close the file descriptor. + +@end deftypefn + +@deftypefn Extension {simple_object_attributes *} simple_object_fetch_attributes (simple_object_read *@var{simple_object}, const char **@var{errmsg}, int *@var{err}) + +Fetch the attributes of @var{simple_object}. The attributes are +internal information such as the format of the object file, or the +architecture it was compiled for. This information will persist until +@code{simple_object_attributes_release} is called, even if +@var{simple_object} itself is released. + +On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an +error message, and sets @code{*@var{err}} to an errno value or +@code{0} if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {const char *} simple_object_attributes_compare (simple_object_attributes *@var{attrs1}, simple_object_attributes *@var{attrs2}, int *@var{err}) + +Compare @var{attrs1} and @var{attrs2}. If they could be linked +together without error, return @code{NULL}. Otherwise, return an +error message and set @code{*@var{err}} to an errno value or @code{0} +if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {void} simple_object_release_attributes (simple_object_attributes *@var{attrs}) + +Release all resources associated with @var{attrs}. + +@end deftypefn + +@deftypefn Extension {simple_object_write *} simple_object_start_write (simple_object_attributes @var{attrs}, const char *@var{segment_name}, const char **@var{errmsg}, int *@var{err}) + +Start creating a new object file using the object file format +described in @var{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. + +@var{segment_name} is only used with Mach-O as found on Darwin aka Mac +OS X. The parameter is required on that target. It means that all +sections are created within the named segment. It is ignored for +other object file formats. + +On error @code{simple_object_start_write} returns @code{NULL}, sets +@code{*@var{ERRMSG}} to an error message, and sets @code{*@var{err}} +to an errno value or @code{0} if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {simple_object_write_section *} simple_object_write_create_section (simple_object_write *@var{simple_object}, const char *@var{name}, unsigned int @var{align}, const char **@var{errmsg}, int *@var{err}) + +Add a section to @var{simple_object}. @var{name} is the name of the +new section. @var{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. The section is not written to the +file until @code{simple_object_write_to_file} is called. + +On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an +error message, and sets @code{*@var{err}} to an errno value or +@code{0} if there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {const char *} simple_object_write_add_data (simple_object_write *@var{simple_object}, simple_object_write_section *@var{section}, const void *@var{buffer}, size_t @var{size}, int @var{copy}, int *@var{err}) + +Add data @var{buffer}/@var{size} to @var{section} in +@var{simple_object}. If @var{copy} is non-zero, the data will be +copied into memory if necessary. If @var{copy} is zero, @var{buffer} +must persist until @code{simple_object_write_to_file} is called. is +released. + +On success this returns @code{NULL}. On error this returns an error +message, and sets @code{*@var{err}} to an errno value or 0 if there is +no relevant erro. + +@end deftypefn + +@deftypefn Extension {const char *} simple_object_write_to_file (simple_object_write *@var{simple_object}, int @var{descriptor}, int *@var{err}) + +Write the complete object file to @var{descriptor}, an open file +descriptor. This writes out all the data accumulated by calls to +@code{simple_object_write_create_section} and +@var{simple_object_write_add_data}. + +This returns @code{NULL} on success. On error this returns an error +message and sets @code{*@var{err}} to an errno value or @code{0} if +there is no relevant errno. + +@end deftypefn + +@deftypefn Extension {void} simple_object_release_write (simple_object_write *@var{simple_object}) + +Release all resources associated with @var{simple_object}. + +@end deftypefn Index: libiberty/simple-object.c =================================================================== --- libiberty/simple-object.c (revision 0) +++ libiberty/simple-object.c (revision 0) @@ -0,0 +1,423 @@ +/* simple-object.c -- simple routines to read and write 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 "simple-object.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 "simple-object-common.h" + +/* The known object file formats. */ + +static const struct simple_object_functions * const format_functions[] = +{ + &simple_object_elf_functions, + &simple_object_mach_o_functions, + &simple_object_coff_functions +}; + +/* Read data from a file using the simple_object error reporting + conventions. */ + +int +simple_object_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 simple_object error reporting + conventions. */ + +int +simple_object_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. */ + +simple_object_read * +simple_object_start_read (int descriptor, off_t offset, + const char *segment_name, const char **errmsg, + int *err) +{ + unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN]; + size_t len, i; + + if (!simple_object_internal_read (descriptor, offset, header, + SIMPLE_OBJECT_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) + { + simple_object_read *ret; + + ret = XNEW (simple_object_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 * +simple_object_find_sections (simple_object_read *sobj, + int (*pfn) (void *, const char *, off_t, off_t), + void *data, + int *err) +{ + return sobj->functions->find_sections (sobj, 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 +simple_object_find_section (simple_object_read *sobj, 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 = simple_object_find_sections (sobj, find_one_section, + (void *) &fosd, err); + if (*errmsg != NULL) + return 0; + if (!fosd.found) + return 0; + return 1; +} + +/* Fetch attributes. */ + +simple_object_attributes * +simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg, + int *err) +{ + void *data; + simple_object_attributes *ret; + + data = sobj->functions->fetch_attributes (sobj, errmsg, err); + if (data == NULL) + return NULL; + ret = XNEW (simple_object_attributes); + ret->functions = sobj->functions; + ret->data = data; + return ret; +} + +/* Release an simple_object_read. */ + +void +simple_object_release_read (simple_object_read *sobj) +{ + sobj->functions->release_read (sobj->data); + XDELETE (sobj); +} + +/* Compare attributes. */ + +const char * +simple_object_attributes_compare (simple_object_attributes *attrs1, + simple_object_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 +simple_object_release_attributes (simple_object_attributes *attrs) +{ + attrs->functions->release_attributes (attrs->data); + XDELETE (attrs); +} + +/* Start creating an object file. */ + +simple_object_write * +simple_object_start_write (simple_object_attributes *attrs, + const char *segment_name, const char **errmsg, + int *err) +{ + void *data; + simple_object_write *ret; + + data = attrs->functions->start_write (attrs->data, errmsg, err); + if (data == NULL) + return NULL; + ret = XNEW (simple_object_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. */ + +simple_object_write_section * +simple_object_write_create_section (simple_object_write *sobj, const char *name, + unsigned int align, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + simple_object_write_section *ret; + + ret = XNEW (simple_object_write_section); + ret->next = NULL; + ret->name = xstrdup (name); + ret->align = align; + ret->buffers = NULL; + ret->last_buffer = NULL; + + if (sobj->last_section == NULL) + { + sobj->sections = ret; + sobj->last_section = ret; + } + else + { + sobj->last_section->next = ret; + sobj->last_section = ret; + } + + return ret; +} + +/* Add data to a section. */ + +const char * +simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, + simple_object_write_section *section, + const void *buffer, + size_t size, int copy, + int *err ATTRIBUTE_UNUSED) +{ + struct simple_object_write_section_buffer *wsb; + + wsb = XNEW (struct simple_object_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 * +simple_object_write_to_file (simple_object_write *sobj, int descriptor, + int *err) +{ + return sobj->functions->write_to_file (sobj, descriptor, err); +} + +/* Release an simple_object_write. */ + +void +simple_object_release_write (simple_object_write *sobj) +{ + simple_object_write_section *section; + + free (sobj->segment_name); + + section = sobj->sections; + while (section != NULL) + { + struct simple_object_write_section_buffer *buffer; + simple_object_write_section *next_section; + + buffer = section->buffers; + while (buffer != NULL) + { + struct simple_object_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; + } + + sobj->functions->release_write (sobj->data); + XDELETE (sobj); +} Index: gcc/lto/lto-object.c =================================================================== --- gcc/lto/lto-object.c (revision 0) +++ gcc/lto/lto-object.c (revision 0) @@ -0,0 +1,376 @@ +/* LTO routines to use object files. + Copyright 2010 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "diagnostic-core.h" +#include "toplev.h" +#include "lto.h" +#include "tm.h" +#include "lto-streamer.h" +#include "libiberty.h" +#include "simple-object.h" + +/* Handle opening elf files on hosts, such as Windows, that may use + text file handling that will break binary access. */ +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* Segment name for LTO sections. This is only used for Mach-O. + FIXME: This needs to be kept in sync with darwin.c. */ + +#define LTO_SEGMENT_NAME "__GNU_LTO" + +/* An LTO file wrapped around an simple_object. */ + +struct lto_simple_object +{ + /* The base information. */ + lto_file base; + + /* The system file descriptor. */ + int fd; + + /* The simple_object if we are reading the file. */ + simple_object_read *sobj_r; + + /* The simple_object if we are writing the file. */ + simple_object_write *sobj_w; + + /* The currently active section. */ + simple_object_write_section *section; +}; + +/* Saved simple_object attributes. FIXME: Once set, this is never + cleared. */ + +static simple_object_attributes *saved_attributes; + +/* Initialize FILE, an LTO file object for FILENAME. */ + +static void +lto_file_init (lto_file *file, const char *filename, off_t offset) +{ + file->filename = filename; + file->offset = offset; +} + +/* Open the file FILENAME. It WRITABLE is true, the file is opened + for write and, if necessary, created. Otherwise, the file is + opened for reading. Returns the opened file. */ + +lto_file * +lto_obj_file_open (const char *filename, bool writable) +{ + const char *offset_p; + long loffset; + int consumed; + char *fname; + off_t offset; + struct lto_simple_object *lo; + const char *errmsg; + int err; + + offset_p = strrchr (filename, '@'); + if (offset_p != NULL + && offset_p != filename + && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1 + && strlen (offset_p) == (unsigned int) consumed) + { + fname = XNEWVEC (char, offset_p - filename + 1); + memcpy (fname, filename, offset_p - filename); + fname[offset_p - filename] = '\0'; + offset = (off_t) loffset; + } + else + { + fname = xstrdup (filename); + offset = 0; + } + + lo = XCNEW (struct lto_simple_object); + lto_file_init ((lto_file *) lo, fname, offset); + + lo->fd = open (fname, + (writable + ? O_WRONLY | O_CREAT | O_BINARY + : O_RDONLY | O_BINARY), + 0666); + if (lo->fd == -1) + { + error ("open %s failed: %s", fname, xstrerror (errno)); + goto fail; + } + + if (!writable) + { + simple_object_attributes *attrs; + + lo->sobj_r = simple_object_start_read (lo->fd, offset, LTO_SEGMENT_NAME, + &errmsg, &err); + if (lo->sobj_r == NULL) + goto fail_errmsg; + + attrs = simple_object_fetch_attributes (lo->sobj_r, &errmsg, &err); + if (attrs == NULL) + goto fail_errmsg; + + if (saved_attributes == NULL) + saved_attributes = attrs; + else + { + errmsg = simple_object_attributes_compare (saved_attributes, attrs, + &err); + if (errmsg != NULL) + goto fail_errmsg; + } + } + else + { + gcc_assert (saved_attributes != NULL); + lo->sobj_w = simple_object_start_write (saved_attributes, + LTO_SEGMENT_NAME, + &errmsg, &err); + if (lo->sobj_w == NULL) + goto fail_errmsg; + } + + return &lo->base; + + fail_errmsg: + if (err == 0) + error ("%s: %s", fname, errmsg); + else + error ("%s: %s: %s", fname, errmsg, xstrerror (err)); + + fail: + if (lo != NULL) + lto_obj_file_close ((lto_file *) lo); + return NULL; +} + +/* Close FILE. If FILE was opened for writing, it is written out + now. */ + +void +lto_obj_file_close (lto_file *file) +{ + struct lto_simple_object *lo = (struct lto_simple_object *) file; + + if (lo->sobj_r != NULL) + simple_object_release_read (lo->sobj_r); + else if (lo->sobj_w != NULL) + { + const char *errmsg; + int err; + + gcc_assert (lo->base.offset == 0); + + errmsg = simple_object_write_to_file (lo->sobj_w, lo->fd, &err); + if (errmsg != NULL) + { + if (err == 0) + fatal_error ("%s", errmsg); + else + fatal_error ("%s: %s", errmsg, xstrerror (err)); + } + + simple_object_release_write (lo->sobj_w); + } + + if (lo->fd != -1) + { + if (close (lo->fd) < 0) + fatal_error ("close: %s", xstrerror (errno)); + } +} + +/* This is passed to lto_obj_add_section. */ + +struct lto_obj_add_section_data +{ + /* The hash table of sections. */ + htab_t section_hash_table; + /* The offset of this file. */ + off_t base_offset; +}; + +/* This is called for each section in the file. */ + +static int +lto_obj_add_section (void *data, const char *name, off_t offset, + off_t length) +{ + struct lto_obj_add_section_data *loasd = + (struct lto_obj_add_section_data *) data; + htab_t section_hash_table = (htab_t) loasd->section_hash_table; + char *new_name; + struct lto_section_slot s_slot; + void **slot; + + if (strncmp (name, LTO_SECTION_NAME_PREFIX, + strlen (LTO_SECTION_NAME_PREFIX)) != 0) + return 1; + + new_name = xstrdup (name); + s_slot.name = new_name; + slot = htab_find_slot (section_hash_table, &s_slot, INSERT); + if (*slot == NULL) + { + struct lto_section_slot *new_slot = XNEW (struct lto_section_slot); + + new_slot->name = new_name; + new_slot->start = loasd->base_offset + offset; + new_slot->len = length; + *slot = new_slot; + } + else + { + error ("two or more sections for %s", new_name); + return 0; + } + + return 1; +} + +/* Build a hash table whose key is the section name and whose data is + the start and size of each section in the .o file. */ + +htab_t +lto_obj_build_section_table (lto_file *lto_file) +{ + struct lto_simple_object *lo = (struct lto_simple_object *) lto_file; + htab_t section_hash_table; + struct lto_obj_add_section_data loasd; + const char *errmsg; + int err; + + section_hash_table = lto_obj_create_section_hash_table (); + + gcc_assert (lo->sobj_r != NULL && lo->sobj_w == NULL); + loasd.section_hash_table = section_hash_table; + loasd.base_offset = lo->base.offset; + errmsg = simple_object_find_sections (lo->sobj_r, lto_obj_add_section, + &loasd, &err); + if (errmsg != NULL) + { + if (err == 0) + error ("%s", errmsg); + else + error ("%s: %s", errmsg, xstrerror (err)); + htab_delete (section_hash_table); + return NULL; + } + + return section_hash_table; +} + +/* The current output file. */ + +static lto_file *current_out_file; + +/* Set the current output file. Return the old one. */ + +lto_file * +lto_set_current_out_file (lto_file *file) +{ + lto_file *old_file; + + old_file = current_out_file; + current_out_file = file; + return old_file; +} + +/* Return the current output file. */ + +lto_file * +lto_get_current_out_file (void) +{ + return current_out_file; +} + +/* Begin writing a new section named NAME in the current output + file. */ + +void +lto_obj_begin_section (const char *name) +{ + struct lto_simple_object *lo; + int align; + const char *errmsg; + int err; + + lo = (struct lto_simple_object *) current_out_file; + gcc_assert (lo != NULL + && lo->sobj_r == NULL + && lo->sobj_w != NULL + && lo->section == NULL); + + align = exact_log2 (POINTER_SIZE / BITS_PER_UNIT); + lo->section = simple_object_write_create_section (lo->sobj_w, name, align, + &errmsg, &err); + if (lo->section == NULL) + { + if (err == 0) + fatal_error ("%s", errmsg); + else + fatal_error ("%s: %s", errmsg, xstrerror (errno)); + } +} + +/* Add data to a section. BLOCK is a pointer to memory containing + DATA. */ + +void +lto_obj_append_data (const void *data, size_t len, void *block) +{ + struct lto_simple_object *lo; + const char *errmsg; + int err; + + lo = (struct lto_simple_object *) current_out_file; + gcc_assert (lo != NULL && lo->section != NULL); + + errmsg = simple_object_write_add_data (lo->sobj_w, lo->section, data, len, + 1, &err); + if (errmsg != NULL) + { + if (err == 0) + fatal_error ("%s", errmsg); + else + fatal_error ("%s: %s", errmsg, xstrerror (errno)); + } + + free (block); +} + +/* Stop writing to the current output section. */ + +void +lto_obj_end_section (void) +{ + struct lto_simple_object *lo; + + lo = (struct lto_simple_object *) current_out_file; + gcc_assert (lo != NULL && lo->section != NULL); + lo->section = NULL; +} Index: gcc/lto/lto-elf.c =================================================================== --- gcc/lto/lto-elf.c (revision 166080) +++ 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-coff.c =================================================================== --- gcc/lto/lto-coff.c (revision 166080) +++ 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 166080) +++ 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 166080) +++ 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-object.o attribs.o LTO_H = lto/lto.h $(HASHTAB_H) LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H) @@ -73,7 +73,7 @@ lto-warn = $(STRICT_WARN) $(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) $(LTO_USE_LIBELF) + $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) # Dependencies lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \ @@ -81,19 +81,14 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_ $(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \ $(EXPR_H) lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \ - toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) $(LIBIBERTY_H) \ + toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \ $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \ langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \ $(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \ $(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) -lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \ - toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) -lto/lto-coff.o: lto/lto-coff.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \ - toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \ - lto/lto-coff.h -lto/lto-macho.o: lto/lto-macho.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \ - toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \ - lto/lto-macho.h lto/lto-endian.h +lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(DIAGNOSTIC_CORE_H) $(TOPLEV_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \ + ../include/simple-object.h # LTO testing is done as part of C/C++/Fortran etc. testing. check-lto: Index: gcc/lto/lto-macho.c =================================================================== --- gcc/lto/lto-macho.c (revision 166080) +++ 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 166080) +++ 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 166080) +++ 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 166080) +++ 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 166080) +++ 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 166080) +++ 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 166080) +++ 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