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