diff options
author | Ian Lance Taylor <iant@google.com> | 2010-11-02 14:48:34 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2010-11-02 14:48:34 +0000 |
commit | 6b3456d1ff836cfc40033b9b238c5dcd9b18d9cb (patch) | |
tree | 87d5de3939e75d56c2757de45586be08850b3046 /gcc/lto | |
parent | 1cfabf34d83637a5e9ffa11dc38379d017738cf7 (diff) | |
download | gcc-6b3456d1ff836cfc40033b9b238c5dcd9b18d9cb.zip gcc-6b3456d1ff836cfc40033b9b238c5dcd9b18d9cb.tar.gz gcc-6b3456d1ff836cfc40033b9b238c5dcd9b18d9cb.tar.bz2 |
lto-object.c: New file.
* 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).
From-SVN: r166187
Diffstat (limited to 'gcc/lto')
-rw-r--r-- | gcc/lto/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/lto/Make-lang.in | 17 | ||||
-rw-r--r-- | gcc/lto/lto-coff.c | 817 | ||||
-rw-r--r-- | gcc/lto/lto-coff.h | 408 | ||||
-rw-r--r-- | gcc/lto/lto-elf.c | 817 | ||||
-rw-r--r-- | gcc/lto/lto-macho.c | 948 | ||||
-rw-r--r-- | gcc/lto/lto-macho.h | 251 | ||||
-rw-r--r-- | gcc/lto/lto-object.c | 376 |
8 files changed, 397 insertions, 3252 deletions
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index e718fdb..c963d6f4 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 2dc6409..0c63865 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 f5aaff8..0000000 --- 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 (<osec->coffsec, &coffsec, sizeof (ltosec->coffsec)); - } - - return true; -} - -/* Initialize COFF_FILE's executable header using cached data from previously - read files. */ - -static void -init_coffhdr (lto_coff_file *coff_file) -{ - gcc_assert (cached_coff_hdr_valid); - memset (&coff_file->coffhdr, 0, sizeof (coff_file->coffhdr)); - COFF_PUT(&coff_file->coffhdr, Machine, COFF_GET(&cached_coff_hdr, Machine)); - COFF_PUT(&coff_file->coffhdr, Characteristics, COFF_GET(&cached_coff_hdr, Characteristics)); -} - -/* Open COFF file FILENAME. If WRITABLE is true, the file is opened for write - and, if necessary, created. Otherwise, the file is opened for reading. - Returns the opened file. */ - -lto_file * -lto_obj_file_open (const char *filename, bool writable) -{ - lto_coff_file *coff_file; - lto_file *result = NULL; - off_t offset; - const char *offset_p; - char *fname; - struct stat statbuf; - - offset_p = strchr (filename, '@'); - if (!offset_p) - { - fname = xstrdup (filename); - offset = 0; - } - else - { - /* The file started with '@' is a file containing command line - options. Stop if it doesn't exist. */ - if (offset_p == filename) - fatal_error ("command line option file '%s' does not exist", - filename); - - fname = (char *) xmalloc (offset_p - filename + 1); - memcpy (fname, filename, offset_p - filename); - fname[offset_p - filename] = '\0'; - offset_p += 3; /* skip the @0x */ - offset = lto_parse_hex (offset_p); - } - - /* Set up. */ - coff_file = XCNEW (lto_coff_file); - result = (lto_file *) coff_file; - lto_file_init (result, fname, offset); - coff_file->fd = -1; - - /* Open the file. */ - coff_file->fd = open (fname, - O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666); - - if (coff_file->fd == -1) - { - error ("could not open file %s", fname); - goto fail; - } - - if (stat (fname, &statbuf) < 0) - { - error ("could not stat file %s", fname); - goto fail; - } - - coff_file->file_size = statbuf.st_size; - - if (offset != 0) - { - char ar_tail[12]; - int size; - - /* Surely not? */ - gcc_assert (!writable); - - /* Seek to offset, or error. */ - if (lseek (coff_file->fd, offset, SEEK_SET) != (ssize_t) offset) - { - error ("could not find archive member @0x%lx", (long) offset); - goto fail; - } - - /* Now seek back 12 chars and read the tail of the AR header to - find the length of the member file. */ - if (lseek (coff_file->fd, -12, SEEK_CUR) < 0 - || read (coff_file->fd, ar_tail, 12) != 12 - || lseek (coff_file->fd, 0, SEEK_CUR) != (ssize_t) offset - || ar_tail[10] != '`' || ar_tail[11] != '\n') - { - error ("could not find archive header @0x%lx", (long) offset); - goto fail; - } - - ar_tail[11] = 0; - if (sscanf (ar_tail, "%d", &size) != 1) - { - error ("invalid archive header @0x%lx", (long) offset); - goto fail; - } - coff_file->file_size = size; - } - - if (writable) - { - init_coffhdr (coff_file); - coff_file->shstrtab_stream = XCNEW (struct lto_output_stream); - } - else - if (!validate_file (coff_file)) - goto fail; - - return result; - - fail: - if (result) - lto_obj_file_close (result); - return NULL; -} - - -/* Close COFF file FILE and clean up any associated data structures. If FILE - was opened for writing, the file's COFF data is written at this time, and - any cached data buffers are freed. Return TRUE if there was an error. */ - -static bool -coff_write_object_file (lto_coff_file *coff_file) -{ - lto_coff_section *cursec, *stringsec; - lto_coff_data *data; - size_t fileoffset, numsections, totalsecsize, numsyms, stringssize; - bool write_err = false; - int secnum; - - /* Infer whether this file was opened for reading or writing from the - presence or absense of an initialised stream for the string table; - do nothing if it was opened for reading. */ - if (!coff_file->shstrtab_stream) - return false; - else - { - /* Write the COFF string table into a dummy new section that - we will not write a header for. */ - lto_file *old_file = lto_set_current_out_file (&coff_file->base); - /* This recursively feeds in the data to a new section. */ - lto_coff_begin_section_with_type (".strtab", 1); - lto_write_stream (coff_file->shstrtab_stream); - lto_obj_end_section (); - lto_set_current_out_file (old_file); - free (coff_file->shstrtab_stream); - } - - /* Layout the file. Count sections (not dummy string section) and calculate - data size for all of them. */ - numsections = 0; - totalsecsize = 0; - stringssize = 0; - stringsec = NULL; - COFF_FOR_ALL_SECTIONS(coff_file, cursec) - { - lto_coff_data *data; - size_t cursecsize; - cursecsize = 0; - COFF_FOR_ALL_DATA(cursec,data) - cursecsize += data->d_size; - if (cursec->type == 0) - { - ++numsections; - totalsecsize += COFF_ALIGN(cursecsize); -#if COFF_ALIGNMENT > 1 - cursec->pad_needed = COFF_ALIGN(cursecsize) - cursecsize; -#endif - } - else - { - stringssize = cursecsize; - stringsec = cursec; - } - COFF_PUT(&cursec->coffsec, SizeOfRawData, cursecsize); - } - - /* There is a file symbol and a section symbol per section, - and each of these has a single auxiliary symbol following. */ - numsyms = 2 * (1 + numsections); - - /* Great! Now we have enough info to fill out the file header. */ - COFF_PUT(&coff_file->coffhdr, NumberOfSections, numsections); - COFF_PUT(&coff_file->coffhdr, NumberOfSymbols, numsyms); - COFF_PUT(&coff_file->coffhdr, PointerToSymbolTable, sizeof (Coff_header) - + numsections * sizeof (Coff_section) + totalsecsize); - /* The remaining members were initialised to zero or copied from - a cached header, so we leave them alone here. */ - - /* Now position all the sections, and fill out their headers. */ - fileoffset = sizeof (Coff_header) + numsections * sizeof (Coff_section); - COFF_FOR_ALL_SECTIONS(coff_file, cursec) - { - /* Skip dummy string section. */ - if (cursec->type == 1) - continue; - COFF_PUT(&cursec->coffsec, PointerToRawData, fileoffset); - fileoffset += COFF_ALIGN (COFF_GET(&cursec->coffsec, SizeOfRawData)); - COFF_PUT(&cursec->coffsec, Characteristics, COFF_SECTION_CHARACTERISTICS); - snprintf ((char *)&cursec->coffsec.Name[0], 8, "/%d", cursec->strtab_offs + 4); - } - - /* We can write the data now. As there's no way to indicate an error return - from this hook, error handling is limited to not wasting our time doing - any more writes in the event that any one fails. */ - - /* Write the COFF header. */ - write_err = (write (coff_file->fd, &coff_file->coffhdr, - sizeof (coff_file->coffhdr)) != sizeof (coff_file->coffhdr)); - - /* Write the COFF section headers. */ - COFF_FOR_ALL_SECTIONS(coff_file, cursec) - if (cursec->type == 1) /* Skip dummy string section. */ - continue; - else if (!write_err) - write_err = (write (coff_file->fd, &cursec->coffsec, - sizeof (cursec->coffsec)) != sizeof (cursec->coffsec)); - else - break; - - /* Write the COFF sections. */ - COFF_FOR_ALL_SECTIONS(coff_file, cursec) - { -#if COFF_ALIGNMENT > 1 - static const char padzeros[COFF_ALIGNMENT] = { 0 }; -#endif - /* Skip dummy string section. */ - if (cursec->type == 1) - continue; - COFF_FOR_ALL_DATA(cursec, data) - if (!write_err) - write_err = (write (coff_file->fd, data->d_buf, data->d_size) - != data->d_size); - else - break; -#if COFF_ALIGNMENT > 1 - if (!write_err && cursec->pad_needed) - write_err = (write (coff_file->fd, padzeros, cursec->pad_needed) - != cursec->pad_needed); -#endif - } - - /* Write the COFF symbol table. */ - if (!write_err) - { - union - { - Coff_symbol sym; - Coff_aux_sym_file file; - Coff_aux_sym_section sec; - } symbols[2]; - memset (&symbols[0], 0, sizeof (symbols)); - strcpy ((char *) &symbols[0].sym.Name[0], ".file"); - COFF_PUT(&symbols[0].sym, SectionNumber, IMAGE_SYM_DEBUG); - COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE); - symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_FILE; - symbols[0].sym.NumberOfAuxSymbols[0] = 1; - snprintf ((char *)symbols[1].file.FileName, - sizeof (symbols[1].file.FileName), - "%s", lbasename (coff_file->base.filename)); - write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols)) - != (2 * COFF_SYMBOL_SIZE)); - - /* Set up constant parts for section sym loop. */ - memset (&symbols[0], 0, sizeof (symbols)); - COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE); - symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_STATIC; - symbols[0].sym.NumberOfAuxSymbols[0] = 1; - - secnum = 1; - if (!write_err) - COFF_FOR_ALL_SECTIONS(coff_file, cursec) - { - /* Skip dummy string section. */ - if (cursec->type == 1) - continue; - /* Reuse section name string for section symbol name. */ - COFF_PUT_NDXSZ(&symbols[0].sym, Name, 0, 0, 4); - COFF_PUT_NDXSZ(&symbols[0].sym, Name, cursec->strtab_offs + 4, 4, 4); - COFF_PUT(&symbols[0].sym, SectionNumber, secnum++); - COFF_PUT(&symbols[1].sec, Length, - COFF_GET(&cursec->coffsec, SizeOfRawData)); - if (!write_err) - write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols)) - != (2 * COFF_SYMBOL_SIZE)); - else - break; - } - } - - /* Write the COFF string table. */ - if (!write_err) - { - unsigned char outlen[4]; - COFF_PUT4(outlen, stringssize + 4); - if (!write_err) - write_err = (write (coff_file->fd, outlen, 4) != 4); - if (stringsec) - { - COFF_FOR_ALL_DATA(stringsec, data) - if (!write_err) - write_err = (write (coff_file->fd, data->d_buf, data->d_size) - != data->d_size); - else - break; - } - } - - return write_err; -} - -/* Close COFF file FILE and clean up any associated data structures. If FILE - was opened for writing, the file's COFF data is written at this time, and - any cached data buffers are freed. */ - -void -lto_obj_file_close (lto_file *file) -{ - lto_coff_file *coff_file = (lto_coff_file *) file; - struct lto_char_ptr_base *cur, *tmp; - lto_coff_section *cursec, *nextsec; - bool write_err = false; - - /* Write the COFF string table into a dummy new section that - we will not write a header for. */ - if (coff_file->shstrtab_stream) - coff_write_object_file (coff_file); - - /* Close the file, we're done. */ - if (coff_file->fd != -1) - close (coff_file->fd); - - /* Free any data buffers. */ - cur = coff_file->data; - while (cur) - { - tmp = cur; - cur = (struct lto_char_ptr_base *) cur->ptr; - free (tmp); - } - - /* Free any sections and their data chains. */ - cursec = coff_file->section_chain; - while (cursec) - { - lto_coff_data *curdata, *nextdata; - nextsec = cursec->next; - curdata = cursec->data_chain; - while (curdata) - { - nextdata = curdata->next; - free (curdata); - curdata = nextdata; - } - free (cursec); - cursec = nextsec; - } - - free (file); - - /* If there was an error, mention it. */ - if (write_err) - error ("I/O error writing COFF output file"); -} - diff --git a/gcc/lto/lto-coff.h b/gcc/lto/lto-coff.h deleted file mode 100644 index bdc9fa5..0000000 --- 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 6268a9c..0000000 --- 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 9f89e8e..0000000 --- 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 (<osec->u.section_32, &sec_32, sizeof (sec_32)); - } - - if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize) - goto fail; - - return true; - - fail: - error ("could not read LC_SEGMENT command in Mach-O file %s", - mach_o_file->base.filename); - return false; -} - - -/* Read a Mach-O LC_SEGMENT_64 command from MACH_O_FILE and validate it. - The file descriptor in MACH_O_FILE points at the start of the load - command. On sucess, returns true and advances the file pointer - past the end of the load command. On failure, returns false. */ - -static bool -validate_mach_o_segment_command_64 (lto_mach_o_file *mach_o_file) -{ - mach_o_segment_command_64 seg_cmd_64; - unsigned int i; - ssize_t n; - off_t startpos; - - /* Fields we're interested in. */ - uint32_t cmd; - uint32_t cmdsize; - uint32_t nsects; - - startpos = lseek (mach_o_file->fd, 0, SEEK_CUR); - - n = sizeof (mach_o_segment_command_64); - if (read (mach_o_file->fd, (void *) &seg_cmd_64, n) != n) - goto fail; - - cmd = get_uint32 (&seg_cmd_64.cmd[0]); - cmdsize = get_uint32 (&seg_cmd_64.cmdsize[0]); - nsects = get_uint32 (&seg_cmd_64.nsects[0]); - gcc_assert (cmd == MACH_O_LC_SEGMENT_64); - - /* Validate section table entries. */ - for (i = 0; i < nsects; i++) - { - mach_o_section_64 sec_64; - lto_mach_o_section ltosec; - - n = sizeof (mach_o_section_64); - if (read (mach_o_file->fd, &sec_64, n) != n) - goto fail; - - /* ??? Perform some checks. */ - - /* Looks ok, so record its details. We don't read the - string table or set up names yet; we'll do that when - we build the hash table. */ - ltosec = mach_o_new_section (mach_o_file, NULL); - memcpy (<osec->u.section_64, &sec_64, sizeof (sec_64)); - } - - if (lseek (mach_o_file->fd, 0, SEEK_CUR) != startpos + cmdsize) - goto fail; - - return true; - - fail: - error ("could not read LC_SEGMENT_64 command in Mach-O file %s", - mach_o_file->base.filename); - return false; -} - -/* Read a Mach-O load commands from MACH_O_FILE and validate it. - The file descriptor in MACH_O_FILE points at the start of the load - command. On sucess, returns true and advances the file pointer - past the end of the load command. On failure, returns false. */ - -static bool -validate_mach_o_load_command (lto_mach_o_file *mach_o_file) -{ - mach_o_load_command load_command; - uint32_t cmd; - uint32_t cmdsize; - ssize_t n; - - n = sizeof (load_command); - if (read (mach_o_file->fd, &load_command, n) != n) - { - error ("could not read load commands in Mach-O file %s", - mach_o_file->base.filename); - return false; - } - lseek (mach_o_file->fd, -1 * (off_t) sizeof (load_command), SEEK_CUR); - - cmd = get_uint32 (&load_command.cmd[0]); - cmdsize = get_uint32 (&load_command.cmdsize[0]); - switch (cmd) - { - case MACH_O_LC_SEGMENT: - return validate_mach_o_segment_command_32 (mach_o_file); - case MACH_O_LC_SEGMENT_64: - return validate_mach_o_segment_command_64 (mach_o_file); - - default: - /* Just skip over it. */ - lseek (mach_o_file->fd, cmdsize, SEEK_CUR); - return true; - } -} - -/* Validate's MACH_O_FILE's executable header and, if cached_mach_o_header is - uninitialized, caches the results. Also records the section header string - table's section index. Returns true on success, false on failure. */ - -static bool -validate_file (lto_mach_o_file *mach_o_file) -{ - uint32_t i, ncmds; - - /* Read and sanity check the raw header. */ - if (! validate_mach_o_header (mach_o_file)) - return false; - - ncmds = get_uint32 (&mach_o_file->u.header.ncmds[0]); - for (i = 0; i < ncmds; ++i) - if (! validate_mach_o_load_command (mach_o_file)) - return false; - - return true; -} - -/* Initialize MACH_O_FILE's executable header using cached data from previously - read files. */ - -static void -init_mach_o_header (lto_mach_o_file *mach_o_file) -{ - gcc_assert (cached_mach_o_magic != 0); - memcpy (&mach_o_file->u.header, - &cached_mach_o_header, - sizeof (mach_o_file->u.header)); - put_uint32 (&mach_o_file->u.header.ncmds[0], 0); - put_uint32 (&mach_o_file->u.header.sizeofcmds[0], 0); -} - -/* Open Mach-O file FILENAME. If WRITABLE is true, the file is opened for write - and, if necessary, created. Otherwise, the file is opened for reading. - Returns the opened file. */ - -lto_file * -lto_obj_file_open (const char *filename, bool writable) -{ - lto_mach_o_file *mach_o_file; - lto_file *result = NULL; - off_t offset; - const char *offset_p; - char *fname; - struct stat statbuf; - - offset_p = strchr (filename, '@'); - if (!offset_p) - { - fname = xstrdup (filename); - offset = 0; - } - else - { - /* The file started with '@' is a file containing command line - options. Stop if it doesn't exist. */ - if (offset_p == filename) - fatal_error ("command line option file '%s' does not exist", - filename); - - fname = (char *) xmalloc (offset_p - filename + 1); - memcpy (fname, filename, offset_p - filename); - fname[offset_p - filename] = '\0'; - offset_p += 3; /* skip the @0x */ - offset = lto_parse_hex (offset_p); - } - - /* Set up. */ - mach_o_file = XCNEW (lto_mach_o_file); - result = (lto_file *) mach_o_file; - lto_file_init (result, fname, offset); - mach_o_file->fd = -1; - mach_o_file->writable = writable; - - /* Open the file. */ - mach_o_file->fd = open (fname, - O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666); - - if (mach_o_file->fd == -1) - { - error ("could not open file %s", fname); - goto fail; - } - - if (stat (fname, &statbuf) < 0) - { - error ("could not stat file %s", fname); - goto fail; - } - - mach_o_file->file_size = statbuf.st_size; - - /* If the object is in an archive, get it out. */ - if (offset != 0) - { - char ar_tail[12]; - int size; - - /* Surely not? */ - gcc_assert (!writable); - - /* Seek to offset, or error. */ - if (lseek (mach_o_file->fd, offset, SEEK_SET) != (ssize_t) offset) - { - error ("could not find archive member @0x%lx", (long) offset); - goto fail; - } - - /* Now seek back 12 chars and read the tail of the AR header to - find the length of the member file. */ - if (lseek (mach_o_file->fd, -12, SEEK_CUR) < 0 - || read (mach_o_file->fd, ar_tail, 12) != 12 - || lseek (mach_o_file->fd, 0, SEEK_CUR) != (ssize_t) offset - || ar_tail[10] != '`' || ar_tail[11] != '\n') - { - error ("could not find archive header @0x%lx", (long) offset); - goto fail; - } - - ar_tail[11] = 0; - if (sscanf (ar_tail, "%d", &size) != 1) - { - error ("invalid archive header @0x%lx", (long) offset); - goto fail; - } - mach_o_file->file_size = size; - } - - if (writable) - { - init_mach_o_header (mach_o_file); - } - else - if (! validate_file (mach_o_file)) - goto fail; - - return result; - - fail: - if (result) - lto_obj_file_close (result); - return NULL; -} - - -/* Write the data in MACH_O_FILE to a real Mach-O binary object. - We write a header, a segment load command, and section data. */ - -static bool -mach_o_write_object_file (lto_mach_o_file *mach_o_file) -{ - lto_mach_o_section sec, snsec; - lto_mach_o_data snsec_data; - ssize_t hdrsize, cmdsize, secsize; - size_t num_sections, snsec_size, total_sec_size; - unsigned int sec_offs, strtab_offs; - int i; - bool write_err = false; - - /* The number of sections we will write is the number of sections added by - the streamer, plus 1 for the section names section. */ - num_sections = VEC_length (lto_mach_o_section, mach_o_file->section_vec) + 1; - - /* Calculate the size of the basic data structures on disk. */ - if (mach_o_word_size () == 64) - { - hdrsize = sizeof (mach_o_header_64); - secsize = sizeof (mach_o_section_64); - cmdsize = sizeof (mach_o_segment_command_64) + num_sections * secsize; - } - else - { - hdrsize = sizeof (mach_o_header_32); - secsize = sizeof (mach_o_section_32); - cmdsize = sizeof (mach_o_segment_command_32) + num_sections * secsize; - } - - /* Allocate the section names section. */ - snsec_size = 0; - for (i = 0; - VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec); - i++) - snsec_size += strlen (sec->name) + 1; - snsec = mach_o_new_section (mach_o_file, NULL); - snsec->name = LTO_NAMES_SECTION; - snsec_data = mach_o_new_data (snsec); - snsec_data->d_buf = XCNEWVEC (char, snsec_size); - snsec_data->d_size = snsec_size; - - /* Position all the sections, and fill out their headers. */ - sec_offs = hdrsize + cmdsize; - strtab_offs = 0; - total_sec_size = 0; - for (i = 0; - VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec); - i++) - { - lto_mach_o_data data; - size_t data_size; - /* Put the section and segment names. Add the section name to the - section names section (unless, of course, this *is* the section - names section). */ - if (sec == snsec) - snprintf (sec->u.section.sectname, 16, "%s", LTO_NAMES_SECTION); - else - { - sprintf (sec->u.section.sectname, "__%08X", strtab_offs); - memcpy ((char *) snsec_data->d_buf + strtab_offs, sec->name, strlen (sec->name)); - } - memcpy (&sec->u.section.segname[0], - LTO_SEGMENT_NAME, strlen (LTO_SEGMENT_NAME)); - - /* Add layout and attributes. */ - for (data = sec->data_chain, data_size = 0; data; data = data->next) - data_size += data->d_size; - if (mach_o_word_size () == 64) - { - put_uint64 (&sec->u.section_64.addr[0], total_sec_size); - put_uint64 (&sec->u.section_64.size[0], data_size); - put_uint32 (&sec->u.section_64.offset[0], sec_offs); - put_uint32 (&sec->u.section_64.flags[0], MACH_O_S_ATTR_DEBUG); - } - else - { - put_uint32 (&sec->u.section_64.addr[0], total_sec_size); - put_uint32 (&sec->u.section_32.size[0], data_size); - put_uint32 (&sec->u.section_32.offset[0], sec_offs); - put_uint32 (&sec->u.section_32.flags[0], MACH_O_S_ATTR_DEBUG); - } - - sec_offs += data_size; - total_sec_size += data_size; - strtab_offs += strlen (sec->name) + 1; - } - - /* We can write the data now. As there's no way to indicate an error return - from this hook, error handling is limited to not wasting our time doing - any more writes in the event that any one fails. */ - - /* Write the header. */ - put_uint32 (&mach_o_file->u.header.ncmds[0], 1); - put_uint32 (&mach_o_file->u.header.sizeofcmds[0], cmdsize); - write_err = (write (mach_o_file->fd, - &mach_o_file->u.header, hdrsize) != hdrsize); - /* Write the segment load command. */ - if (mach_o_word_size () == 64) - { - mach_o_segment_command_64 lc; - ssize_t lc_size = sizeof (lc); - memset (&lc, 0, lc_size); - put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT_64); - put_uint32 (&lc.cmdsize[0], cmdsize); - put_uint64 (&lc.fileoff[0], hdrsize + cmdsize); - put_uint64 (&lc.filesize[0], total_sec_size); - put_uint32 (&lc.nsects[0], num_sections); - write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size); - } - else - { - mach_o_segment_command_32 lc; - ssize_t lc_size = sizeof (lc); - memset (&lc, 0, lc_size); - put_uint32 (&lc.cmd[0], MACH_O_LC_SEGMENT); - put_uint32 (&lc.cmdsize[0], cmdsize); - put_uint32 (&lc.fileoff[0], hdrsize + cmdsize); - put_uint32 (&lc.filesize[0], total_sec_size); - put_uint32 (&lc.nsects[0], num_sections); - write_err = (write (mach_o_file->fd, &lc, lc_size) != lc_size); - } - for (i = 0; - !write_err - && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec); - i++) - write_err = (write (mach_o_file->fd, - &sec->u.section, secsize) != secsize); - - gcc_assert (lseek (mach_o_file->fd, 0, SEEK_CUR) == hdrsize + cmdsize); - - /* Write the section data. */ - for (i = 0; - !write_err - && VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec); - i++) - { - lto_mach_o_data data; - - for (data = sec->data_chain; data; data = data->next) - { - if (!write_err) - write_err = (write (mach_o_file->fd, data->d_buf, data->d_size) - != data->d_size); - else - break; - } - } - - return !write_err; -} - -/* Close Mach-O file FILE and clean up any associated data structures. If FILE - was opened for writing, the file's Mach-O data is written at this time. Any - cached data buffers are freed. */ - -void -lto_obj_file_close (lto_file *file) -{ - lto_mach_o_file *mach_o_file = (lto_mach_o_file *) file; - struct lto_char_ptr_base *cur, *tmp; - lto_mach_o_section sec; - bool write_err = false; - int i; - - /* If this file is open for writing, write a Mach-O object file. */ - if (mach_o_file->writable) - { - if (! mach_o_write_object_file (mach_o_file)) - fatal_error ("cannot write Mach-O object file"); - } - - /* Close the file, we're done. */ - if (mach_o_file->fd != -1) - close (mach_o_file->fd); - - /* Free any data buffers. */ - cur = mach_o_file->data; - while (cur) - { - tmp = cur; - cur = (struct lto_char_ptr_base *) cur->ptr; - free (tmp); - } - - /* Free any sections and their data chains. */ - for (i = 0; - VEC_iterate (lto_mach_o_section, mach_o_file->section_vec, i, sec); - i++) - { - lto_mach_o_data curdata, nextdata; - curdata = sec->data_chain; - while (curdata) - { - nextdata = curdata->next; - free (curdata); - curdata = nextdata; - } - free (sec); - } - VEC_free (lto_mach_o_section, heap, mach_o_file->section_vec); - - free (file); - - /* If there was an error, mention it. */ - if (write_err) - error ("I/O error writing Mach-O output file"); -} - diff --git a/gcc/lto/lto-macho.h b/gcc/lto/lto-macho.h deleted file mode 100644 index dcd0de3..0000000 --- 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 0000000..e4a9981 --- /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; +} |