summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2010-11-02 14:48:34 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2010-11-02 14:48:34 +0000
commite09108e1433d0e7f9e4515982b59f388ed31fb66 (patch)
tree87d5de3939e75d56c2757de45586be08850b3046
parentebb6c20c677930f98bb34e59b10c10ff3c977659 (diff)
downloadgcc-e09108e1433d0e7f9e4515982b59f388ed31fb66.tar.gz
* lto-object.c: New file.
* lto-elf.c: Remove file. * lto-macho.c: Remove file. * lto-macho.h: Remove file. * lto-coff.c: Remove file. * lto-coff.h: Remove file. * Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to lto/lto-object.o. ($(LTO_EXE)): Remove $(LTO_USE_LIBELF) (lto/lto-objfile.o): New target. (lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets. (lto/lto.o): Remove $(LIBIBERTY_H). git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166187 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/lto/ChangeLog15
-rw-r--r--gcc/lto/Make-lang.in17
-rw-r--r--gcc/lto/lto-coff.c817
-rw-r--r--gcc/lto/lto-coff.h408
-rw-r--r--gcc/lto/lto-elf.c817
-rw-r--r--gcc/lto/lto-macho.c948
-rw-r--r--gcc/lto/lto-macho.h251
-rw-r--r--gcc/lto/lto-object.c376
8 files changed, 397 insertions, 3252 deletions
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index e718fdbf458..c963d6f4bc3 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,18 @@
+2010-11-02 Ian Lance Taylor <iant@google.com>
+
+ * lto-object.c: New file.
+ * lto-elf.c: Remove file.
+ * lto-macho.c: Remove file.
+ * lto-macho.h: Remove file.
+ * lto-coff.c: Remove file.
+ * lto-coff.h: Remove file.
+ * Make-lang.in (LTO_OBJS): Change lto/$(LTO_BINARY_READER).o to
+ lto/lto-object.o.
+ ($(LTO_EXE)): Remove $(LTO_USE_LIBELF)
+ (lto/lto-objfile.o): New target.
+ (lto/lto-elf.o, lto/lto-coff.o, lto/lto-macho.o): Remove targets.
+ (lto/lto.o): Remove $(LIBIBERTY_H).
+
2010-10-22 Jan Hubicka <jh@suse.cz>
* lto.c (add_cgraph_node_to_partition,
diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
index 2dc64095d99..0c6386525c2 100644
--- a/gcc/lto/Make-lang.in
+++ b/gcc/lto/Make-lang.in
@@ -23,7 +23,7 @@
# The name of the LTO compiler.
LTO_EXE = lto1$(exeext)
# The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o lto/lto.o lto/$(LTO_BINARY_READER).o attribs.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-object.o attribs.o
LTO_H = lto/lto.h $(HASHTAB_H)
LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H)
@@ -73,7 +73,7 @@ lto-warn = $(STRICT_WARN)
$(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
- $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) $(LTO_USE_LIBELF)
+ $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS)
# Dependencies
lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
@@ -81,19 +81,14 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
$(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
$(EXPR_H)
lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \
- toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) $(LIBIBERTY_H) \
+ toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
$(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \
langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
$(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H)
-lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
- toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H)
-lto/lto-coff.o: lto/lto-coff.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
- toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
- lto/lto-coff.h
-lto/lto-macho.o: lto/lto-macho.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
- toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) \
- lto/lto-macho.h lto/lto-endian.h
+lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(DIAGNOSTIC_CORE_H) $(TOPLEV_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
+ ../include/simple-object.h
# LTO testing is done as part of C/C++/Fortran etc. testing.
check-lto:
diff --git a/gcc/lto/lto-coff.c b/gcc/lto/lto-coff.c
deleted file mode 100644
index f5aaff8bcaa..00000000000
--- a/gcc/lto/lto-coff.c
+++ /dev/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 (&ltosec->coffsec, &coffsec, sizeof (ltosec->coffsec));
- }
-
- return true;
-}
-
-/* Initialize COFF_FILE's executable header using cached data from previously
- read files. */
-
-static void
-init_coffhdr (lto_coff_file *coff_file)
-{
- gcc_assert (cached_coff_hdr_valid);
- memset (&coff_file->coffhdr, 0, sizeof (coff_file->coffhdr));
- COFF_PUT(&coff_file->coffhdr, Machine, COFF_GET(&cached_coff_hdr, Machine));
- COFF_PUT(&coff_file->coffhdr, Characteristics, COFF_GET(&cached_coff_hdr, Characteristics));
-}
-
-/* Open COFF file FILENAME. If WRITABLE is true, the file is opened for write
- and, if necessary, created. Otherwise, the file is opened for reading.
- Returns the opened file. */
-
-lto_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
- lto_coff_file *coff_file;
- lto_file *result = NULL;
- off_t offset;
- const char *offset_p;
- char *fname;
- struct stat statbuf;
-
- offset_p = strchr (filename, '@');
- if (!offset_p)
- {
- fname = xstrdup (filename);
- offset = 0;
- }
- else
- {
- /* The file started with '@' is a file containing command line
- options. Stop if it doesn't exist. */
- if (offset_p == filename)
- fatal_error ("command line option file '%s' does not exist",
- filename);
-
- fname = (char *) xmalloc (offset_p - filename + 1);
- memcpy (fname, filename, offset_p - filename);
- fname[offset_p - filename] = '\0';
- offset_p += 3; /* skip the @0x */
- offset = lto_parse_hex (offset_p);
- }
-
- /* Set up. */
- coff_file = XCNEW (lto_coff_file);
- result = (lto_file *) coff_file;
- lto_file_init (result, fname, offset);
- coff_file->fd = -1;
-
- /* Open the file. */
- coff_file->fd = open (fname,
- O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
- if (coff_file->fd == -1)
- {
- error ("could not open file %s", fname);
- goto fail;
- }
-
- if (stat (fname, &statbuf) < 0)
- {
- error ("could not stat file %s", fname);
- goto fail;
- }
-
- coff_file->file_size = statbuf.st_size;
-
- if (offset != 0)
- {
- char ar_tail[12];
- int size;
-
- /* Surely not? */
- gcc_assert (!writable);
-
- /* Seek to offset, or error. */
- if (lseek (coff_file->fd, offset, SEEK_SET) != (ssize_t) offset)
- {
- error ("could not find archive member @0x%lx", (long) offset);
- goto fail;
- }
-
- /* Now seek back 12 chars and read the tail of the AR header to
- find the length of the member file. */
- if (lseek (coff_file->fd, -12, SEEK_CUR) < 0
- || read (coff_file->fd, ar_tail, 12) != 12
- || lseek (coff_file->fd, 0, SEEK_CUR) != (ssize_t) offset
- || ar_tail[10] != '`' || ar_tail[11] != '\n')
- {
- error ("could not find archive header @0x%lx", (long) offset);
- goto fail;
- }
-
- ar_tail[11] = 0;
- if (sscanf (ar_tail, "%d", &size) != 1)
- {
- error ("invalid archive header @0x%lx", (long) offset);
- goto fail;
- }
- coff_file->file_size = size;
- }
-
- if (writable)
- {
- init_coffhdr (coff_file);
- coff_file->shstrtab_stream = XCNEW (struct lto_output_stream);
- }
- else
- if (!validate_file (coff_file))
- goto fail;
-
- return result;
-
- fail:
- if (result)
- lto_obj_file_close (result);
- return NULL;
-}
-
-
-/* Close COFF file FILE and clean up any associated data structures. If FILE
- was opened for writing, the file's COFF data is written at this time, and
- any cached data buffers are freed. Return TRUE if there was an error. */
-
-static bool
-coff_write_object_file (lto_coff_file *coff_file)
-{
- lto_coff_section *cursec, *stringsec;
- lto_coff_data *data;
- size_t fileoffset, numsections, totalsecsize, numsyms, stringssize;
- bool write_err = false;
- int secnum;
-
- /* Infer whether this file was opened for reading or writing from the
- presence or absense of an initialised stream for the string table;
- do nothing if it was opened for reading. */
- if (!coff_file->shstrtab_stream)
- return false;
- else
- {
- /* Write the COFF string table into a dummy new section that
- we will not write a header for. */
- lto_file *old_file = lto_set_current_out_file (&coff_file->base);
- /* This recursively feeds in the data to a new section. */
- lto_coff_begin_section_with_type (".strtab", 1);
- lto_write_stream (coff_file->shstrtab_stream);
- lto_obj_end_section ();
- lto_set_current_out_file (old_file);
- free (coff_file->shstrtab_stream);
- }
-
- /* Layout the file. Count sections (not dummy string section) and calculate
- data size for all of them. */
- numsections = 0;
- totalsecsize = 0;
- stringssize = 0;
- stringsec = NULL;
- COFF_FOR_ALL_SECTIONS(coff_file, cursec)
- {
- lto_coff_data *data;
- size_t cursecsize;
- cursecsize = 0;
- COFF_FOR_ALL_DATA(cursec,data)
- cursecsize += data->d_size;
- if (cursec->type == 0)
- {
- ++numsections;
- totalsecsize += COFF_ALIGN(cursecsize);
-#if COFF_ALIGNMENT > 1
- cursec->pad_needed = COFF_ALIGN(cursecsize) - cursecsize;
-#endif
- }
- else
- {
- stringssize = cursecsize;
- stringsec = cursec;
- }
- COFF_PUT(&cursec->coffsec, SizeOfRawData, cursecsize);
- }
-
- /* There is a file symbol and a section symbol per section,
- and each of these has a single auxiliary symbol following. */
- numsyms = 2 * (1 + numsections);
-
- /* Great! Now we have enough info to fill out the file header. */
- COFF_PUT(&coff_file->coffhdr, NumberOfSections, numsections);
- COFF_PUT(&coff_file->coffhdr, NumberOfSymbols, numsyms);
- COFF_PUT(&coff_file->coffhdr, PointerToSymbolTable, sizeof (Coff_header)
- + numsections * sizeof (Coff_section) + totalsecsize);
- /* The remaining members were initialised to zero or copied from
- a cached header, so we leave them alone here. */
-
- /* Now position all the sections, and fill out their headers. */
- fileoffset = sizeof (Coff_header) + numsections * sizeof (Coff_section);
- COFF_FOR_ALL_SECTIONS(coff_file, cursec)
- {
- /* Skip dummy string section. */
- if (cursec->type == 1)
- continue;
- COFF_PUT(&cursec->coffsec, PointerToRawData, fileoffset);
- fileoffset += COFF_ALIGN (COFF_GET(&cursec->coffsec, SizeOfRawData));
- COFF_PUT(&cursec->coffsec, Characteristics, COFF_SECTION_CHARACTERISTICS);
- snprintf ((char *)&cursec->coffsec.Name[0], 8, "/%d", cursec->strtab_offs + 4);
- }
-
- /* We can write the data now. As there's no way to indicate an error return
- from this hook, error handling is limited to not wasting our time doing
- any more writes in the event that any one fails. */
-
- /* Write the COFF header. */
- write_err = (write (coff_file->fd, &coff_file->coffhdr,
- sizeof (coff_file->coffhdr)) != sizeof (coff_file->coffhdr));
-
- /* Write the COFF section headers. */
- COFF_FOR_ALL_SECTIONS(coff_file, cursec)
- if (cursec->type == 1) /* Skip dummy string section. */
- continue;
- else if (!write_err)
- write_err = (write (coff_file->fd, &cursec->coffsec,
- sizeof (cursec->coffsec)) != sizeof (cursec->coffsec));
- else
- break;
-
- /* Write the COFF sections. */
- COFF_FOR_ALL_SECTIONS(coff_file, cursec)
- {
-#if COFF_ALIGNMENT > 1
- static const char padzeros[COFF_ALIGNMENT] = { 0 };
-#endif
- /* Skip dummy string section. */
- if (cursec->type == 1)
- continue;
- COFF_FOR_ALL_DATA(cursec, data)
- if (!write_err)
- write_err = (write (coff_file->fd, data->d_buf, data->d_size)
- != data->d_size);
- else
- break;
-#if COFF_ALIGNMENT > 1
- if (!write_err && cursec->pad_needed)
- write_err = (write (coff_file->fd, padzeros, cursec->pad_needed)
- != cursec->pad_needed);
-#endif
- }
-
- /* Write the COFF symbol table. */
- if (!write_err)
- {
- union
- {
- Coff_symbol sym;
- Coff_aux_sym_file file;
- Coff_aux_sym_section sec;
- } symbols[2];
- memset (&symbols[0], 0, sizeof (symbols));
- strcpy ((char *) &symbols[0].sym.Name[0], ".file");
- COFF_PUT(&symbols[0].sym, SectionNumber, IMAGE_SYM_DEBUG);
- COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
- symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_FILE;
- symbols[0].sym.NumberOfAuxSymbols[0] = 1;
- snprintf ((char *)symbols[1].file.FileName,
- sizeof (symbols[1].file.FileName),
- "%s", lbasename (coff_file->base.filename));
- write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
- != (2 * COFF_SYMBOL_SIZE));
-
- /* Set up constant parts for section sym loop. */
- memset (&symbols[0], 0, sizeof (symbols));
- COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
- symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_STATIC;
- symbols[0].sym.NumberOfAuxSymbols[0] = 1;
-
- secnum = 1;
- if (!write_err)
- COFF_FOR_ALL_SECTIONS(coff_file, cursec)
- {
- /* Skip dummy string section. */
- if (cursec->type == 1)
- continue;
- /* Reuse section name string for section symbol name. */
- COFF_PUT_NDXSZ(&symbols[0].sym, Name, 0, 0, 4);
- COFF_PUT_NDXSZ(&symbols[0].sym, Name, cursec->strtab_offs + 4, 4, 4);
- COFF_PUT(&symbols[0].sym, SectionNumber, secnum++);
- COFF_PUT(&symbols[1].sec, Length,
- COFF_GET(&cursec->coffsec, SizeOfRawData));
- if (!write_err)
- write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
- != (2 * COFF_SYMBOL_SIZE));
- else
- break;
- }
- }
-
- /* Write the COFF string table. */
- if (!write_err)
- {
- unsigned char outlen[4];
- COFF_PUT4(outlen, stringssize + 4);
- if (!write_err)
- write_err = (write (coff_file->fd, outlen, 4) != 4);
- if (stringsec)
- {
- COFF_FOR_ALL_DATA(stringsec, data)
- if (!write_err)
- write_err = (write (coff_file->fd, data->d_buf, data->d_size)
- != data->d_size);
- else
- break;
- }
- }
-
- return write_err;
-}
-
-/* Close COFF file FILE and clean up any associated data structures. If FILE
- was opened for writing, the file's COFF data is written at this time, and
- any cached data buffers are freed. */
-
-void
-lto_obj_file_close (lto_file *file)
-{
- lto_coff_file *coff_file = (lto_coff_file *) file;
- struct lto_char_ptr_base *cur, *tmp;
- lto_coff_section *cursec, *nextsec;
- bool write_err = false;
-
- /* Write the COFF string table into a dummy new section that
- we will not write a header for. */
- if (coff_file->shstrtab_stream)
- coff_write_object_file (coff_file);
-
- /* Close the file, we're done. */
- if (coff_file->fd != -1)
- close (coff_file->fd);
-
- /* Free any data buffers. */
- cur = coff_file->data;
- while (cur)
- {
- tmp = cur;
- cur = (struct lto_char_ptr_base *) cur->ptr;
- free (tmp);
- }
-
- /* Free any sections and their data chains. */
- cursec = coff_file->section_chain;
- while (cursec)
- {
- lto_coff_data *curdata, *nextdata;
- nextsec = cursec->next;
- curdata = cursec->data_chain;
- while (curdata)
- {
- nextdata = curdata->next;
- free (curdata);
- curdata = nextdata;
- }
- free (cursec);
- cursec = nextsec;
- }
-
- free (file);
-
- /* If there was an error, mention it. */
- if (write_err)
- error ("I/O error writing COFF output file");
-}
-
diff --git a/gcc/lto/lto-coff.h b/gcc/lto/lto-coff.h
deleted file mode 100644
index bdc9fa52222..00000000000
--- a/gcc/lto/lto-coff.h
+++ /dev/null
@@ -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 */
diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c
deleted file mode 100644
index 6268a9c0bf9..00000000000
--- a/gcc/lto/lto-elf.c
+++ /dev/null
@@ -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;
-}
diff --git a/gcc/lto/lto-macho.c b/gcc/lto/lto-macho.c
deleted file mode 100644
index 9f89e8e9bb3..00000000000
--- a/gcc/lto/lto-macho.c
+++ /dev/null
@@ -1,948 +0,0 @@
-/* LTO routines for Mach-O object files.
- Copyright 2010 Free Software Foundation, Inc.
- Contributed by Steven Bosscher.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
-#include "lto.h"
-#include "tm.h"
-#include "libiberty.h"
-#include "lto-streamer.h"
-#include "lto/lto-endian.h"
-#include "lto/lto-macho.h"
-
-/* Rather than implementing a libmacho to match libelf, or attempting to
- integrate libbfd into GCC, this file is a self-contained (and very
- minimal) Mach-O format object file reader/writer. The generated files
- will contain a Mach-O header, a number of Mach-O load commands an
- section headers, the section data itself, and a trailing string table
- for section names. */
-
-/* This needs to be kept in sync with darwin.c. Better yet, lto-macho.c
- and lto-macho.h should be moved to config/, and likewise for lto-coff.*
- and lto-elf.*. */
-
-/* Segment name for LTO sections. */
-#define LTO_SEGMENT_NAME "__GNU_LTO"
-
-/* Section name for LTO section names section. */
-#define LTO_NAMES_SECTION "__section_names"
-
-/* Handle opening elf files on hosts, such as Windows, that may use
- text file handling that will break binary access. */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-/* Cached object file header. We use a header_64 for this, since all
- the fields we need are in there, in the same position as header_32. */
-mach_o_header_64 cached_mach_o_header;
-uint32_t cached_mach_o_magic;
-
-/* The current output file. */
-static lto_file *current_out_file;
-
-
-/* Is this a 32-bits or 64-bits Mach-O object file? */
-static int
-mach_o_word_size (void)
-{
- gcc_assert (cached_mach_o_magic != 0);
- return (cached_mach_o_magic == MACH_O_MH_MAGIC_64
- || cached_mach_o_magic == MACH_O_MH_CIGAM_64) ? 64 : 32;
-}
-
-/* Sets the current output file to FILE. Returns the old output file or
- NULL. */
-
-lto_file *
-lto_set_current_out_file (lto_file *file)
-{
- lto_file *old_file = current_out_file;
- current_out_file = file;
- return old_file;
-}
-
-
-/* Returns the current output file. */
-
-lto_file *
-lto_get_current_out_file (void)
-{
- return current_out_file;
-}
-
-/* Mach-O section structure constructor. */
-
-static lto_mach_o_section
-mach_o_new_section (lto_mach_o_file *mach_o_file, const char *name)
-{
- lto_mach_o_section ptr;
-
- /* FIXME We could allocate these things on an obstack. */
- ptr = XCNEW (struct lto_mach_o_section_d);
- if (name)
- {
- if (strncmp (name, LTO_SECTION_NAME_PREFIX,
- strlen(LTO_SECTION_NAME_PREFIX)) != 0)
- sorry ("not implemented: Mach-O writer for non-LTO sections");
- ptr->name = xstrdup (name);
- }
-
- VEC_safe_push (lto_mach_o_section, heap, mach_o_file->section_vec, ptr);
-
- return ptr;
-}
-
-/* Mach-O section data block structure constructor. */
-
-static lto_mach_o_data
-mach_o_new_data (lto_mach_o_section sec)
-{
- lto_mach_o_data ptr, *chain_ptr_ptr;
-
- /* FIXME We could allocate these things on an obstack. */
- ptr = XCNEW (struct lto_mach_o_data_d);
-
- chain_ptr_ptr = &sec->data_chain;
- while (*chain_ptr_ptr)
- chain_ptr_ptr = &(*chain_ptr_ptr)->next;
- *chain_ptr_ptr = ptr;
-
- return ptr;
-}
-
-/* Initialize FILE, an LTO file object for FILENAME. Offset is the
- offset into FILE where the object is located (e.g. in an archive). */
-
-static void
-lto_file_init (lto_file *file, const char *filename, off_t offset)
-{
- file->filename = filename;
- file->offset = offset;
-}
-
-/* Build a hash table whose key is the section names and whose data is
- the start and size of each section in the .o file. */
-
-htab_t
-lto_obj_build_section_table (lto_file *lto_file)
-{
- lto_mach_o_file *mach_o_file = (lto_mach_o_file *)lto_file;
- lto_mach_o_section sec;
- htab_t section_hash_table;
- off_t strtab_offs;
- ssize_t strtab_size;
- char *strtab = NULL;
- int i;
-
- section_hash_table = lto_obj_create_section_hash_table ();
-
- /* Seek the string table. */
- /* FIXME The segment name should be in darwin.h, but can we include it
- here in this file? */
- for (i = 0;
- VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- {
- if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
- continue;
- if (strncmp (sec->u.section.sectname, "__section_names", 16) == 0)
- break;
- }
- if (! sec)
- {
- error ("invalid Mach-O LTO object file: no __section_names section found");
- goto done;
- }
- mach_o_file->section_names_section = sec;
-
- if (mach_o_word_size () == 64)
- {
- strtab_offs = (off_t) get_uint32 (&sec->u.section_64.offset[0]);
- strtab_size = (size_t) get_uint64 (&sec->u.section_64.size[0]);
- }
- else
- {
- strtab_offs = (off_t) get_uint32 (&sec->u.section_32.offset[0]);
- strtab_size = (size_t) get_uint32 (&sec->u.section_32.size[0]);
- }
-
- /* Seek to start of string table. */
- if (strtab_offs != lseek (mach_o_file->fd,
- mach_o_file->base.offset + strtab_offs,
- SEEK_SET))
- {
- error ("altered or invalid Mach-O object file");
- goto done;
- }
-
- strtab = XNEWVEC (char, strtab_size);
- if (read (mach_o_file->fd, strtab, strtab_size) != strtab_size)
- {
- error ("invalid Mach-O LTO object file __section_names section");
- goto done;
- }
-
- /* Scan sections looking at names. */
- for (i = 0;
- VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- {
- struct lto_section_slot s_slot;
- void **slot;
- char *new_name;
- unsigned long stringoffset;
- char name[17];
-
- /* Ignore non-LTO sections. Also ignore the __section_names section
- which does not need renaming. */
- if (strncmp (sec->u.section.segname, "__GNU_LTO", 16) != 0)
- continue;
- if (sec == mach_o_file->section_names_section)
- continue;
-
- /* Try to extract the offset of the real name for this section from
- __section_names. */
- memcpy (&name[0], sec->u.section.sectname, 16);
- name[16] = '\0';
- if (name[0] != '_' || name[1] != '_'
- || sscanf (&name[2], "%08lX", &stringoffset) != 1
- || strtab_size < (ssize_t) stringoffset)
- {
- error ("invalid Mach-O LTO section name string: %s", name);
- continue;
- }
-
- new_name = XNEWVEC (char, strlen (strtab + stringoffset) + 1);
- strcpy (new_name, strtab + stringoffset);
- s_slot.name = new_name;
- slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
- if (*slot == NULL)
- {
- struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
-
- new_slot->name = new_name;
- if (mach_o_word_size() == 64)
- {
- new_slot->start =
- (intptr_t) get_uint32 (&sec->u.section_64.offset[0]);
- new_slot->len =
- (size_t) get_uint64 (&sec->u.section_64.size[0]);
- }
- else
- {
- new_slot->start =
- (intptr_t) get_uint32 (&sec->u.section_32.offset[0]);
- new_slot->len =
- (size_t) get_uint32 (&sec->u.section_32.size[0]);
- }
-
- *slot = new_slot;
- }
- else
- {
- error ("two or more sections for %s:", new_name);
- goto done;
- }
- }
-
- done:
- if (strtab)
- free (strtab);
- return section_hash_table;
-}
-
-
-/* Begin a new Mach-O section named NAME in the current output file. */
-
-void
-lto_obj_begin_section (const char *name)
-{
- lto_mach_o_file *file;
-
- if (strncmp (name, LTO_SECTION_NAME_PREFIX,
- strlen(LTO_SECTION_NAME_PREFIX)) != 0)
- sorry ("not implemented: Mach-O writer for non-LTO sections");
-
- /* Grab the current output file and do some basic assertion checking. */
- file = (lto_mach_o_file *) lto_get_current_out_file (),
- gcc_assert (file && file->writable && !file->scn);
-
- /* Create a new section. */
- file->scn = mach_o_new_section (file, name);
- if (!file->scn)
- fatal_error ("could not create a new Mach-O section: %m");
-}
-
-
-/* Append DATA of length LEN to the current output section. BASE is a pointer
- to the output page containing DATA. It is freed once the output file has
- been written. */
-
-void
-lto_obj_append_data (const void *data, size_t len, void *block)
-{
- lto_mach_o_file *file;
- lto_mach_o_data mach_o_data;
- struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
-
- /* Grab the current output file and do some basic assertion checking. */
- file = (lto_mach_o_file *) lto_get_current_out_file ();
- gcc_assert (file);
- gcc_assert (file->scn);
-
- mach_o_data = mach_o_new_data (file->scn);
- if (!mach_o_data)
- fatal_error ("could not append data to Mach-O section: %m");
-
- mach_o_data->d_buf = CONST_CAST (void *, data);
- mach_o_data->d_size = len;
-
- /* Chain all data blocks (from all sections) on one singly-linked
- list for freeing en masse after the file is closed. */
- base->ptr = (char *)file->data;
- file->data = base;
-}
-
-
-/* End the current output section. This just does some assertion checking
- and sets the current output file's scn member to NULL. */
-
-void
-lto_obj_end_section (void)
-{
- lto_mach_o_file *file;
-
- /* Grab the current output file and validate some basic assertions. */
- file = (lto_mach_o_file *) lto_get_current_out_file ();
- gcc_assert (file);
- gcc_assert (file->scn);
-
- file->scn = NULL;
-}
-
-
-/* Read a Mach-O header from MACH_O_FILE and validate it.
- The file descriptor in MACH_O_FILE points at the start of the file.
- If cached_mach_o_header is uninitialized, caches the results.
- On succes, returns true and moves file pointer to the start of the
- load commands. On failure, returns false. */
-
-static bool
-validate_mach_o_header (lto_mach_o_file *mach_o_file)
-{
- ssize_t i, n;
- unsigned char magic[4];
- uint32_t cputype;
- off_t startpos;
-
- /* Known header magics for validation, as an array. */
- static const unsigned int mach_o_known_formats[] = {
- MACH_O_MH_MAGIC,
- MACH_O_MH_CIGAM,
- MACH_O_MH_MAGIC_64,
- MACH_O_MH_CIGAM_64,
- };
-#define MACH_O_NUM_KNOWN_FORMATS \
- ((ssize_t) ARRAY_SIZE (mach_o_known_formats))
-
- startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
- if (read (mach_o_file->fd, &magic, sizeof (magic)) != 4
- || lseek (mach_o_file->fd, -4, SEEK_CUR) != startpos)
- {
- error ("cannot read file %s", mach_o_file->base.filename);
- return false;
- }
-
- for (i = 0; i < MACH_O_NUM_KNOWN_FORMATS; ++i)
- if (get_uint32 (&magic[0]) == mach_o_known_formats[i])
- break;
- if (i == MACH_O_NUM_KNOWN_FORMATS)
- goto not_for_target;
-
- /* Check the endian-ness. */
- if (BYTES_BIG_ENDIAN && magic[0] != 0xfe)
- goto not_for_target;
-
- /* Set or check cached magic number. */
- if (cached_mach_o_magic == 0)
- cached_mach_o_magic = get_uint32 (&magic[0]);
- else if (cached_mach_o_magic != get_uint32 (&magic[0]))
- goto not_for_target;
-
- n = mach_o_word_size () == 64
- ? sizeof (mach_o_header_64) : sizeof (mach_o_header_32);
- if (read (mach_o_file->fd, &mach_o_file->u.header, n) != n)
- goto not_for_target;
-
- /* Is this a supported CPU? */
- /* ??? Would be nice to validate the exact target architecture. */
- cputype = get_uint32 (&mach_o_file->u.header.cputype[0]);
- if (cputype == MACH_O_CPU_TYPE_I386
- || cputype == MACH_O_CPU_TYPE_POWERPC)
- {
- if (mach_o_word_size () != 32)
- goto not_for_target;
- }
- else if (cputype == MACH_O_CPU_TYPE_X86_64
- || cputype == MACH_O_CPU_TYPE_POWERPC_64)
- {
- if (mach_o_word_size () != 64)
- goto not_for_target;
- }
-
- /* Is this an MH_OBJECT file? */
- if (get_uint32 (&mach_o_file->u.header.filetype[0]) != MACH_O_MH_OBJECT)
- error ("Mach-O file %s is not an MH_OBJECT file",
- mach_o_file->base.filename);
-
- /* Save the header for future use. */
- memcpy (&cached_mach_o_header, &mach_o_file->u.header,
- sizeof (cached_mach_o_header));
-
- return true;
-
- not_for_target:
- error ("file %s is not a Mach-O object file for target",
- mach_o_file->base.filename);
- return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT command (32 bits) from MACH_O_FILE and
- validate it.
- The file descriptor in MACH_O_FILE points at the start of the load
- command. On sucess, returns true and advances the file pointer
- past the end of the load command. On failure, returns false. */
-
-static bool
-validate_mach_o_segment_command_32 (lto_mach_o_file *mach_o_file)
-{
- mach_o_segment_command_32 seg_cmd_32;
- unsigned int i;
- ssize_t n;
- off_t startpos;
-
- /* Fields we're interested in. */
- uint32_t cmd;
- uint32_t cmdsize;
- uint32_t nsects;
-
- startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
- n = sizeof (mach_o_segment_command_32);
- if (read (mach_o_file->fd, (void *) &seg_cmd_32, n) != n)
- goto fail;
-
- cmd = get_uint32 (&seg_cmd_32.cmd[0]);
- cmdsize = get_uint32 (&seg_cmd_32.cmdsize[0]);
- nsects = get_uint32 (&seg_cmd_32.nsects[0]);
- gcc_assert (cmd == MACH_O_LC_SEGMENT);
-
- /* Validate section table entries. */
- for (i = 0; i < nsects; i++)
- {
- mach_o_section_32 sec_32;
- lto_mach_o_section ltosec;
-
- n = sizeof (mach_o_section_32);
- if (read (mach_o_file->fd, &sec_32, n) != n)
- goto fail;
-
- /* ??? Perform some checks. */
-
- /* Looks ok, so record its details. We don't read the
- string table or set up names yet; we'll do that when
- we build the hash table. */
- ltosec = mach_o_new_section (mach_o_file, NULL);
- memcpy (&ltosec->u.section_32, &sec_32, sizeof (sec_32));
- }
-
- if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
- goto fail;
-
- return true;
-
- fail:
- error ("could not read LC_SEGMENT command in Mach-O file %s",
- mach_o_file->base.filename);
- return false;
-}
-
-
-/* Read a Mach-O LC_SEGMENT_64 command from MACH_O_FILE and validate it.
- The file descriptor in MACH_O_FILE points at the start of the load
- command. On sucess, returns true and advances the file pointer
- past the end of the load command. On failure, returns false. */
-
-static bool
-validate_mach_o_segment_command_64 (lto_mach_o_file *mach_o_file)
-{
- mach_o_segment_command_64 seg_cmd_64;
- unsigned int i;
- ssize_t n;
- off_t startpos;
-
- /* Fields we're interested in. */
- uint32_t cmd;
- uint32_t cmdsize;
- uint32_t nsects;
-
- startpos = lseek (mach_o_file->fd, 0, SEEK_CUR);
-
- n = sizeof (mach_o_segment_command_64);
- if (read (mach_o_file->fd, (void *) &seg_cmd_64, n) != n)
- goto fail;
-
- cmd = get_uint32 (&seg_cmd_64.cmd[0]);
- cmdsize = get_uint32 (&seg_cmd_64.cmdsize[0]);
- nsects = get_uint32 (&seg_cmd_64.nsects[0]);
- gcc_assert (cmd == MACH_O_LC_SEGMENT_64);
-
- /* Validate section table entries. */
- for (i = 0; i < nsects; i++)
- {
- mach_o_section_64 sec_64;
- lto_mach_o_section ltosec;
-
- n = sizeof (mach_o_section_64);
- if (read (mach_o_file->fd, &sec_64, n) != n)
- goto fail;
-
- /* ??? Perform some checks. */
-
- /* Looks ok, so record its details. We don't read the
- string table or set up names yet; we'll do that when
- we build the hash table. */
- ltosec = mach_o_new_section (mach_o_file, NULL);
- memcpy (&ltosec->u.section_64, &sec_64, sizeof (sec_64));
- }
-
- if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize)
- goto fail;
-
- return true;
-
- fail:
- error ("could not read LC_SEGMENT_64 command in Mach-O file %s",
- mach_o_file->base.filename);
- return false;
-}
-
-/* Read a Mach-O load commands from MACH_O_FILE and validate it.
- The file descriptor in MACH_O_FILE points at the start of the load
- command. On sucess, returns true and advances the file pointer
- past the end of the load command. On failure, returns false. */
-
-static bool
-validate_mach_o_load_command (lto_mach_o_file *mach_o_file)
-{
- mach_o_load_command load_command;
- uint32_t cmd;
- uint32_t cmdsize;
- ssize_t n;
-
- n = sizeof (load_command);
- if (read (mach_o_file->fd, &load_command, n) != n)
- {
- error ("could not read load commands in Mach-O file %s",
- mach_o_file->base.filename);
- return false;
- }
- lseek (mach_o_file->fd, -1 * (off_t) sizeof (load_command), SEEK_CUR);
-
- cmd = get_uint32 (&load_command.cmd[0]);
- cmdsize = get_uint32 (&load_command.cmdsize[0]);
- switch (cmd)
- {
- case MACH_O_LC_SEGMENT:
- return validate_mach_o_segment_command_32 (mach_o_file);
- case MACH_O_LC_SEGMENT_64:
- return validate_mach_o_segment_command_64 (mach_o_file);
-
- default:
- /* Just skip over it. */
- lseek (mach_o_file->fd, cmdsize, SEEK_CUR);
- return true;
- }
-}
-
-/* Validate's MACH_O_FILE's executable header and, if cached_mach_o_header is
- uninitialized, caches the results. Also records the section header string
- table's section index. Returns true on success, false on failure. */
-
-static bool
-validate_file (lto_mach_o_file *mach_o_file)
-{
- uint32_t i, ncmds;
-
- /* Read and sanity check the raw header. */
- if (! validate_mach_o_header (mach_o_file))
- return false;
-
- ncmds = get_uint32 (&mach_o_file->u.header.ncmds[0]);
- for (i = 0; i < ncmds; ++i)
- if (! validate_mach_o_load_command (mach_o_file))
- return false;
-
- return true;
-}
-
-/* Initialize MACH_O_FILE's executable header using cached data from previously
- read files. */
-
-static void
-init_mach_o_header (lto_mach_o_file *mach_o_file)
-{
- gcc_assert (cached_mach_o_magic != 0);
- memcpy (&mach_o_file->u.header,
- &cached_mach_o_header,
- sizeof (mach_o_file->u.header));
- put_uint32 (&mach_o_file->u.header.ncmds[0], 0);
- put_uint32 (&mach_o_file->u.header.sizeofcmds[0], 0);
-}
-
-/* Open Mach-O file FILENAME. If WRITABLE is true, the file is opened for write
- and, if necessary, created. Otherwise, the file is opened for reading.
- Returns the opened file. */
-
-lto_file *
-lto_obj_file_open (const char *filename, bool writable)
-{
- lto_mach_o_file *mach_o_file;
- lto_file *result = NULL;
- off_t offset;
- const char *offset_p;
- char *fname;
- struct stat statbuf;
-
- offset_p = strchr (filename, '@');
- if (!offset_p)
- {
- fname = xstrdup (filename);
- offset = 0;
- }
- else
- {
- /* The file started with '@' is a file containing command line
- options. Stop if it doesn't exist. */
- if (offset_p == filename)
- fatal_error ("command line option file '%s' does not exist",
- filename);
-
- fname = (char *) xmalloc (offset_p - filename + 1);
- memcpy (fname, filename, offset_p - filename);
- fname[offset_p - filename] = '\0';
- offset_p += 3; /* skip the @0x */
- offset = lto_parse_hex (offset_p);
- }
-
- /* Set up. */
- mach_o_file = XCNEW (lto_mach_o_file);
- result = (lto_file *) mach_o_file;
- lto_file_init (result, fname, offset);
- mach_o_file->fd = -1;
- mach_o_file->writable = writable;
-
- /* Open the file. */
- mach_o_file->fd = open (fname,
- O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
-
- if (mach_o_file->fd == -1)
- {
- error ("could not open file %s", fname);
- goto fail;
- }
-
- if (stat (fname, &statbuf) < 0)
- {
- error ("could not stat file %s", fname);
- goto fail;
- }
-
- mach_o_file->file_size = statbuf.st_size;
-
- /* If the object is in an archive, get it out. */
- if (offset != 0)
- {
- char ar_tail[12];
- int size;
-
- /* Surely not? */
- gcc_assert (!writable);
-
- /* Seek to offset, or error. */
- if (lseek (mach_o_file->fd, offset, SEEK_SET) != (ssize_t) offset)
- {
- error ("could not find archive member @0x%lx", (long) offset);
- goto fail;
- }
-
- /* Now seek back 12 chars and read the tail of the AR header to
- find the length of the member file. */
- if (lseek (mach_o_file->fd, -12, SEEK_CUR) < 0
- || read (mach_o_file->fd, ar_tail, 12) != 12
- || lseek (mach_o_file->fd, 0, SEEK_CUR) != (ssize_t) offset
- || ar_tail[10] != '`' || ar_tail[11] != '\n')
- {
- error ("could not find archive header @0x%lx", (long) offset);
- goto fail;
- }
-
- ar_tail[11] = 0;
- if (sscanf (ar_tail, "%d", &size) != 1)
- {
- error ("invalid archive header @0x%lx", (long) offset);
- goto fail;
- }
- mach_o_file->file_size = size;
- }
-
- if (writable)
- {
- init_mach_o_header (mach_o_file);
- }
- else
- if (! validate_file (mach_o_file))
- goto fail;
-
- return result;
-
- fail:
- if (result)
- lto_obj_file_close (result);
- return NULL;
-}
-
-
-/* Write the data in MACH_O_FILE to a real Mach-O binary object.
- We write a header, a segment load command, and section data. */
-
-static bool
-mach_o_write_object_file (lto_mach_o_file *mach_o_file)
-{
- lto_mach_o_section sec, snsec;
- lto_mach_o_data snsec_data;
- ssize_t hdrsize, cmdsize, secsize;
- size_t num_sections, snsec_size, total_sec_size;
- unsigned int sec_offs, strtab_offs;
- int i;
- bool write_err = false;
-
- /* The number of sections we will write is the number of sections added by
- the streamer, plus 1 for the section names section. */
- num_sections = VEC_length (lto_mach_o_section, mach_o_file->section_vec) + 1;
-
- /* Calculate the size of the basic data structures on disk. */
- if (mach_o_word_size () == 64)
- {
- hdrsize = sizeof (mach_o_header_64);
- secsize = sizeof (mach_o_section_64);
- cmdsize = sizeof (mach_o_segment_command_64) + num_sections * secsize;
- }
- else
- {
- hdrsize = sizeof (mach_o_header_32);
- secsize = sizeof (mach_o_section_32);
- cmdsize = sizeof (mach_o_segment_command_32) + num_sections * secsize;
- }
-
- /* Allocate the section names section. */
- snsec_size = 0;
- for (i = 0;
- VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- snsec_size += strlen (sec->name) + 1;
- snsec = mach_o_new_section (mach_o_file, NULL);
- snsec->name = LTO_NAMES_SECTION;
- snsec_data = mach_o_new_data (snsec);
- snsec_data->d_buf = XCNEWVEC (char, snsec_size);
- snsec_data->d_size = snsec_size;
-
- /* Position all the sections, and fill out their headers. */
- sec_offs = hdrsize + cmdsize;
- strtab_offs = 0;
- total_sec_size = 0;
- for (i = 0;
- VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- {
- lto_mach_o_data data;
- size_t data_size;
- /* Put the section and segment names. Add the section name to the
- section names section (unless, of course, this *is* the section
- names section). */
- if (sec == snsec)
- snprintf (sec->u.section.sectname, 16, "%s", LTO_NAMES_SECTION);
- else
- {
- sprintf (sec->u.section.sectname, "__%08X", strtab_offs);
- memcpy ((char *) snsec_data->d_buf + strtab_offs, sec->name, strlen (sec->name));
- }
- memcpy (&sec->u.section.segname[0],
- LTO_SEGMENT_NAME, strlen (LTO_SEGMENT_NAME));
-
- /* Add layout and attributes. */
- for (data = sec->data_chain, data_size = 0; data; data = data->next)
- data_size += data->d_size;
- if (mach_o_word_size () == 64)
- {
- put_uint64 (&sec->u.section_64.addr[0], total_sec_size);
- put_uint64 (&sec->u.section_64.size[0], data_size);
- put_uint32 (&sec->u.section_64.offset[0], sec_offs);
- put_uint32 (&sec->u.section_64.flags[0], MACH_O_S_ATTR_DEBUG);
- }
- else
- {
- put_uint32 (&sec->u.section_64.addr[0], total_sec_size);
- put_uint32 (&sec->u.section_32.size[0], data_size);
- put_uint32 (&sec->u.section_32.offset[0], sec_offs);
- put_uint32 (&sec->u.section_32.flags[0], MACH_O_S_ATTR_DEBUG);
- }
-
- sec_offs += data_size;
- total_sec_size += data_size;
- strtab_offs += strlen (sec->name) + 1;
- }
-
- /* We can write the data now. As there's no way to indicate an error return
- from this hook, error handling is limited to not wasting our time doing
- any more writes in the event that any one fails. */
-
- /* Write the header. */
- put_uint32 (&mach_o_file->u.header.ncmds[0], 1);
- put_uint32 (&mach_o_file->u.header.sizeofcmds[0], cmdsize);
- write_err = (write (mach_o_file->fd,
- &mach_o_file->u.header, hdrsize) != hdrsize);
- /* Write the segment load command. */
- if (mach_o_word_size () == 64)
- {
- mach_o_segment_command_64 lc;
- ssize_t lc_size = sizeof (lc);
- memset (&lc, 0, lc_size);
- put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT_64);
- put_uint32 (&lc.cmdsize[0], cmdsize);
- put_uint64 (&lc.fileoff[0], hdrsize + cmdsize);
- put_uint64 (&lc.filesize[0], total_sec_size);
- put_uint32 (&lc.nsects[0], num_sections);
- write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
- }
- else
- {
- mach_o_segment_command_32 lc;
- ssize_t lc_size = sizeof (lc);
- memset (&lc, 0, lc_size);
- put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT);
- put_uint32 (&lc.cmdsize[0], cmdsize);
- put_uint32 (&lc.fileoff[0], hdrsize + cmdsize);
- put_uint32 (&lc.filesize[0], total_sec_size);
- put_uint32 (&lc.nsects[0], num_sections);
- write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size);
- }
- for (i = 0;
- !write_err
- && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- write_err = (write (mach_o_file->fd,
- &sec->u.section, secsize) != secsize);
-
- gcc_assert (lseek (mach_o_file->fd, 0, SEEK_CUR) == hdrsize + cmdsize);
-
- /* Write the section data. */
- for (i = 0;
- !write_err
- && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- {
- lto_mach_o_data data;
-
- for (data = sec->data_chain; data; data = data->next)
- {
- if (!write_err)
- write_err = (write (mach_o_file->fd, data->d_buf, data->d_size)
- != data->d_size);
- else
- break;
- }
- }
-
- return !write_err;
-}
-
-/* Close Mach-O file FILE and clean up any associated data structures. If FILE
- was opened for writing, the file's Mach-O data is written at this time. Any
- cached data buffers are freed. */
-
-void
-lto_obj_file_close (lto_file *file)
-{
- lto_mach_o_file *mach_o_file = (lto_mach_o_file *) file;
- struct lto_char_ptr_base *cur, *tmp;
- lto_mach_o_section sec;
- bool write_err = false;
- int i;
-
- /* If this file is open for writing, write a Mach-O object file. */
- if (mach_o_file->writable)
- {
- if (! mach_o_write_object_file (mach_o_file))
- fatal_error ("cannot write Mach-O object file");
- }
-
- /* Close the file, we're done. */
- if (mach_o_file->fd != -1)
- close (mach_o_file->fd);
-
- /* Free any data buffers. */
- cur = mach_o_file->data;
- while (cur)
- {
- tmp = cur;
- cur = (struct lto_char_ptr_base *) cur->ptr;
- free (tmp);
- }
-
- /* Free any sections and their data chains. */
- for (i = 0;
- VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec);
- i++)
- {
- lto_mach_o_data curdata, nextdata;
- curdata = sec->data_chain;
- while (curdata)
- {
- nextdata = curdata->next;
- free (curdata);
- curdata = nextdata;
- }
- free (sec);
- }
- VEC_free (lto_mach_o_section, heap, mach_o_file->section_vec);
-
- free (file);
-
- /* If there was an error, mention it. */
- if (write_err)
- error ("I/O error writing Mach-O output file");
-}
-
diff --git a/gcc/lto/lto-macho.h b/gcc/lto/lto-macho.h
deleted file mode 100644
index dcd0de3ca3f..00000000000
--- a/gcc/lto/lto-macho.h
+++ /dev/null
@@ -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 */
-
diff --git a/gcc/lto/lto-object.c b/gcc/lto/lto-object.c
new file mode 100644
index 00000000000..e4a998163cf
--- /dev/null
+++ b/gcc/lto/lto-object.c
@@ -0,0 +1,376 @@
+/* LTO routines to use object files.
+ Copyright 2010 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<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 "simple-object.h"
+
+/* Handle opening elf files on hosts, such as Windows, that may use
+ text file handling that will break binary access. */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* Segment name for LTO sections. This is only used for Mach-O.
+ FIXME: This needs to be kept in sync with darwin.c. */
+
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* An LTO file wrapped around an simple_object. */
+
+struct lto_simple_object
+{
+ /* The base information. */
+ lto_file base;
+
+ /* The system file descriptor. */
+ int fd;
+
+ /* The simple_object if we are reading the file. */
+ simple_object_read *sobj_r;
+
+ /* The simple_object if we are writing the file. */
+ simple_object_write *sobj_w;
+
+ /* The currently active section. */
+ simple_object_write_section *section;
+};
+
+/* Saved simple_object attributes. FIXME: Once set, this is never
+ cleared. */
+
+static simple_object_attributes *saved_attributes;
+
+/* Initialize FILE, an LTO file object for FILENAME. */
+
+static void
+lto_file_init (lto_file *file, const char *filename, off_t offset)
+{
+ file->filename = filename;
+ file->offset = offset;
+}
+
+/* Open the file FILENAME. It WRITABLE is true, the file is opened
+ for write and, if necessary, created. Otherwise, the file is
+ opened for reading. Returns the opened file. */
+
+lto_file *
+lto_obj_file_open (const char *filename, bool writable)
+{
+ const char *offset_p;
+ long loffset;
+ int consumed;
+ char *fname;
+ off_t offset;
+ struct lto_simple_object *lo;
+ const char *errmsg;
+ int err;
+
+ offset_p = strrchr (filename, '@');
+ if (offset_p != NULL
+ && offset_p != filename
+ && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (offset_p) == (unsigned int) consumed)
+ {
+ fname = XNEWVEC (char, offset_p - filename + 1);
+ memcpy (fname, filename, offset_p - filename);
+ fname[offset_p - filename] = '\0';
+ offset = (off_t) loffset;
+ }
+ else
+ {
+ fname = xstrdup (filename);
+ offset = 0;
+ }
+
+ lo = XCNEW (struct lto_simple_object);
+ lto_file_init ((lto_file *) lo, fname, offset);
+
+ lo->fd = open (fname,
+ (writable
+ ? O_WRONLY | O_CREAT | O_BINARY
+ : O_RDONLY | O_BINARY),
+ 0666);
+ if (lo->fd == -1)
+ {
+ error ("open %s failed: %s", fname, xstrerror (errno));
+ goto fail;
+ }
+
+ if (!writable)
+ {
+ simple_object_attributes *attrs;
+
+ lo->sobj_r = simple_object_start_read (lo->fd, offset, LTO_SEGMENT_NAME,
+ &errmsg, &err);
+ if (lo->sobj_r == NULL)
+ goto fail_errmsg;
+
+ attrs = simple_object_fetch_attributes (lo->sobj_r, &errmsg, &err);
+ if (attrs == NULL)
+ goto fail_errmsg;
+
+ if (saved_attributes == NULL)
+ saved_attributes = attrs;
+ else
+ {
+ errmsg = simple_object_attributes_compare (saved_attributes, attrs,
+ &err);
+ if (errmsg != NULL)
+ goto fail_errmsg;
+ }
+ }
+ else
+ {
+ gcc_assert (saved_attributes != NULL);
+ lo->sobj_w = simple_object_start_write (saved_attributes,
+ LTO_SEGMENT_NAME,
+ &errmsg, &err);
+ if (lo->sobj_w == NULL)
+ goto fail_errmsg;
+ }
+
+ return &lo->base;
+
+ fail_errmsg:
+ if (err == 0)
+ error ("%s: %s", fname, errmsg);
+ else
+ error ("%s: %s: %s", fname, errmsg, xstrerror (err));
+
+ fail:
+ if (lo != NULL)
+ lto_obj_file_close ((lto_file *) lo);
+ return NULL;
+}
+
+/* Close FILE. If FILE was opened for writing, it is written out
+ now. */
+
+void
+lto_obj_file_close (lto_file *file)
+{
+ struct lto_simple_object *lo = (struct lto_simple_object *) file;
+
+ if (lo->sobj_r != NULL)
+ simple_object_release_read (lo->sobj_r);
+ else if (lo->sobj_w != NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ gcc_assert (lo->base.offset == 0);
+
+ errmsg = simple_object_write_to_file (lo->sobj_w, lo->fd, &err);
+ if (errmsg != NULL)
+ {
+ if (err == 0)
+ fatal_error ("%s", errmsg);
+ else
+ fatal_error ("%s: %s", errmsg, xstrerror (err));
+ }
+
+ simple_object_release_write (lo->sobj_w);
+ }
+
+ if (lo->fd != -1)
+ {
+ if (close (lo->fd) < 0)
+ fatal_error ("close: %s", xstrerror (errno));
+ }
+}
+
+/* This is passed to lto_obj_add_section. */
+
+struct lto_obj_add_section_data
+{
+ /* The hash table of sections. */
+ htab_t section_hash_table;
+ /* The offset of this file. */
+ off_t base_offset;
+};
+
+/* This is called for each section in the file. */
+
+static int
+lto_obj_add_section (void *data, const char *name, off_t offset,
+ off_t length)
+{
+ struct lto_obj_add_section_data *loasd =
+ (struct lto_obj_add_section_data *) data;
+ htab_t section_hash_table = (htab_t) loasd->section_hash_table;
+ char *new_name;
+ struct lto_section_slot s_slot;
+ void **slot;
+
+ if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+ strlen (LTO_SECTION_NAME_PREFIX)) != 0)
+ return 1;
+
+ new_name = xstrdup (name);
+ s_slot.name = new_name;
+ slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
+ if (*slot == NULL)
+ {
+ struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
+
+ new_slot->name = new_name;
+ new_slot->start = loasd->base_offset + offset;
+ new_slot->len = length;
+ *slot = new_slot;
+ }
+ else
+ {
+ error ("two or more sections for %s", new_name);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Build a hash table whose key is the section name and whose data is
+ the start and size of each section in the .o file. */
+
+htab_t
+lto_obj_build_section_table (lto_file *lto_file)
+{
+ struct lto_simple_object *lo = (struct lto_simple_object *) lto_file;
+ htab_t section_hash_table;
+ struct lto_obj_add_section_data loasd;
+ const char *errmsg;
+ int err;
+
+ section_hash_table = lto_obj_create_section_hash_table ();
+
+ gcc_assert (lo->sobj_r != NULL && lo->sobj_w == NULL);
+ loasd.section_hash_table = section_hash_table;
+ loasd.base_offset = lo->base.offset;
+ errmsg = simple_object_find_sections (lo->sobj_r, lto_obj_add_section,
+ &loasd, &err);
+ if (errmsg != NULL)
+ {
+ if (err == 0)
+ error ("%s", errmsg);
+ else
+ error ("%s: %s", errmsg, xstrerror (err));
+ htab_delete (section_hash_table);
+ return NULL;
+ }
+
+ return section_hash_table;
+}
+
+/* The current output file. */
+
+static lto_file *current_out_file;
+
+/* Set the current output file. Return the old one. */
+
+lto_file *
+lto_set_current_out_file (lto_file *file)
+{
+ lto_file *old_file;
+
+ old_file = current_out_file;
+ current_out_file = file;
+ return old_file;
+}
+
+/* Return the current output file. */
+
+lto_file *
+lto_get_current_out_file (void)
+{
+ return current_out_file;
+}
+
+/* Begin writing a new section named NAME in the current output
+ file. */
+
+void
+lto_obj_begin_section (const char *name)
+{
+ struct lto_simple_object *lo;
+ int align;
+ const char *errmsg;
+ int err;
+
+ lo = (struct lto_simple_object *) current_out_file;
+ gcc_assert (lo != NULL
+ && lo->sobj_r == NULL
+ && lo->sobj_w != NULL
+ && lo->section == NULL);
+
+ align = exact_log2 (POINTER_SIZE / BITS_PER_UNIT);
+ lo->section = simple_object_write_create_section (lo->sobj_w, name, align,
+ &errmsg, &err);
+ if (lo->section == NULL)
+ {
+ if (err == 0)
+ fatal_error ("%s", errmsg);
+ else
+ fatal_error ("%s: %s", errmsg, xstrerror (errno));
+ }
+}
+
+/* Add data to a section. BLOCK is a pointer to memory containing
+ DATA. */
+
+void
+lto_obj_append_data (const void *data, size_t len, void *block)
+{
+ struct lto_simple_object *lo;
+ const char *errmsg;
+ int err;
+
+ lo = (struct lto_simple_object *) current_out_file;
+ gcc_assert (lo != NULL && lo->section != NULL);
+
+ errmsg = simple_object_write_add_data (lo->sobj_w, lo->section, data, len,
+ 1, &err);
+ if (errmsg != NULL)
+ {
+ if (err == 0)
+ fatal_error ("%s", errmsg);
+ else
+ fatal_error ("%s: %s", errmsg, xstrerror (errno));
+ }
+
+ free (block);
+}
+
+/* Stop writing to the current output section. */
+
+void
+lto_obj_end_section (void)
+{
+ struct lto_simple_object *lo;
+
+ lo = (struct lto_simple_object *) current_out_file;
+ gcc_assert (lo != NULL && lo->section != NULL);
+ lo->section = NULL;
+}