re PR lto/42776 (LTO doesn't work on non-ELF platforms.)

ChangeLog:

	PR lto/42776
	* configure.ac (--enable-lto): Refactor handling so libelf tests
	are only performed inside then-clause of ACX_ELF_TARGET_IFELSE,
	and allow LTO to be explicitly enabled on non-ELF platforms that
	are known to support it inside else-clause.
	* configure: Regenerate.

gcc/ChangeLog:

	PR lto/42776
	* configure.ac (gcc_cv_as_section_has_align): Set if installed
	binutils supports extended .section directive needed by LTO, or
	warn if older binutils found.
	(LTO_BINARY_READER): New AC_SUBST'd variable.
	(LTO_USE_LIBELF): Likewise.
	* gcc/config.gcc (lto_binary_reader): New target-specific configure
	variable.
	* gcc/Makefile.in (LTO_BINARY_READER): Import AC_SUBST'd autoconf var.
	(LTO_USE_LIBELF): Likewise.
	* configure: Regenerate.

	* collect2.c (is_elf): Rename from this ...
	(is_elf_or_coff): ... to this, and recognize and allow i386 COFF
	 object files in addition to ELF-formatted ones.
	(scan_prog_file): Caller updated.  Also allow for LTO info marker
	symbol to be prefixed or not by an extra underscore.

	* config/i386/t-cygming (winnt.o): Also depend on LTO_STREAMER_H.
	* config/i386/winnt.c: Also #include lto-streamer.h
	(i386_pe_asm_named_section): Specify 1-byte section alignment for
	LTO named sections.
	(i386_pe_asm_output_aligned_decl_common): Add comment.
	(i386_pe_maybe_record_exported_symbol): Allow decl arg to be NULL.

gcc/lto/ChangeLog:

	PR lto/42776
	* Make-lang.in (LTO_OBJS): Use LTO_BINARY_READER instead of
	hardcoding 'lto-elf.o'.
	($(LTO_EXE)): Use LTO_USE_LIBELF instead of hardcoding '-lelf'.

	* lto-coff.h: New file.
	* lto-coff.c: Likewise.

gcc/testsuite/ChangeLog:

	PR lto/42776
	* lib/lto.exp (lto_prune_vis_warns): New function.
	(lto-link-and-maybe-run): Call it.

From-SVN: r158762
This commit is contained in:
Dave Korn 2010-04-27 02:22:40 +00:00 committed by Dave Korn
parent 45c384e375
commit 3bec79c52e
15 changed files with 1431 additions and 25 deletions

View File

@ -1,3 +1,12 @@
2010-04-27 Dave Korn <dave.korn.cygwin@gmail.com>
PR lto/42776
* configure.ac (--enable-lto): Refactor handling so libelf tests
are only performed inside then-clause of ACX_ELF_TARGET_IFELSE,
and allow LTO to be explicitly enabled on non-ELF platforms that
are known to support it inside else-clause.
* configure: Regenerate.
2010-04-20 Eric Botcazou <ebotcazou@adacore.com>
* configure.ac (BUILD_CONFIG): Redirect output to /dev/null.

View File

@ -1637,17 +1637,8 @@ AC_ARG_ENABLE(lto,
enable_lto=$enableval,
enable_lto=yes; default_enable_lto=yes)
ACX_ELF_TARGET_IFELSE([],
if test x"$default_enable_lto" = x"yes" ; then
enable_lto=no
else
if test x"$enable_lto" = x"yes"; then
AC_MSG_ERROR([LTO support requires an ELF target.])
fi
fi
default_enable_lto=no)
if test x"$enable_lto" = x"yes" ; then
ACX_ELF_TARGET_IFELSE([if test x"$enable_lto" = x"yes" ; then
# Make sure that libelf.h and gelf.h are available.
AC_ARG_WITH(libelf, [ --with-libelf=PATH Specify prefix directory for the installed libelf package
Equivalent to --with-libelf-include=PATH/include
@ -1783,7 +1774,24 @@ to specify its location.])
# Flags needed for libelf.
AC_SUBST(libelflibs)
AC_SUBST(libelfinc)
fi
fi],[if test x"$default_enable_lto" = x"yes" ; then
# On non-ELF platforms, LTO must be explicitly enabled.
enable_lto=no
else
# Apart from ELF platforms, only Windows supports LTO so far. It
# would also be nice to check the binutils support, but we don't
# have gcc_GAS_CHECK_FEATURE available here. For now, we'll just
# warn during gcc/ subconfigure; unless you're bootstrapping with
# -flto it won't be needed until after installation anyway.
case $target in
*-cygwin*|*-mingw*) ;;
*) if test x"$enable_lto" = x"yes"; then
AC_MSG_ERROR([LTO support is not enabled for this target.])
fi
;;
esac
fi
default_enable_lto=no])
# By default, C is the only stage 1 language.

View File

@ -326,6 +326,10 @@ LIBELFINC = @LIBELFINC@
# Set to 'yes' if the LTO front end is enabled.
enable_lto = @enable_lto@
# Set according to LTO object file format.
LTO_BINARY_READER = @LTO_BINARY_READER@
LTO_USE_LIBELF = @LTO_USE_LIBELF@
# Compiler needed for plugin support
PLUGINCC = @CC@

View File

@ -2548,19 +2548,21 @@ write_aix_file (FILE *stream, struct id *list)
be in ELF format. */
static bool
is_elf (const char *prog_name)
is_elf_or_coff (const char *prog_name)
{
FILE *f;
char buf[4];
static char magic[4] = { 0x7f, 'E', 'L', 'F' };
static char coffmag[2] = { 0x4c, 0x01 };
f = fopen (prog_name, "r");
f = fopen (prog_name, "rb");
if (f == NULL)
return false;
if (fread (buf, sizeof (buf), 1, f) != 1)
buf[0] = 0;
fclose (f);
return memcmp (buf, magic, sizeof (magic)) == 0;
return memcmp (buf, magic, sizeof (magic)) == 0
|| memcmp (buf, coffmag, sizeof (coffmag)) == 0;
}
/* Generic version to scan the name list of the loaded program for
@ -2587,10 +2589,10 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
if (which_pass == PASS_SECOND)
return;
/* LTO objects must be in ELF format. This check prevents
/* LTO objects must be in a known format. This check prevents
us from accepting an archive containing LTO objects, which
gcc cannnot currently handle. */
if (which_pass == PASS_LTOINFO && !is_elf (prog_name))
if (which_pass == PASS_LTOINFO && !is_elf_or_coff (prog_name))
return;
/* If we do not have an `nm', complain. */
@ -2670,9 +2672,9 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
/* Look for the LTO info marker symbol, and add filename to
the LTO objects list if found. */
for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++)
if (ch == ' '
&& (strncmp (p + 1, "__gnu_lto_v1", 12) == 0)
&& ISSPACE (p[13]))
if (ch == ' ' && p[1] == '_' && p[2] == '_'
&& (strncmp (p + (p[3] == '_' ? 2 : 1), "__gnu_lto_v1", 12) == 0)
&& ISSPACE (p[p[3] == '_' ? 14 : 13]))
{
add_lto_object (&lto_objects, prog_name);

View File

@ -200,6 +200,8 @@ default_use_cxa_atexit=no
target_gtfiles=
need_64bit_hwint=
need_64bit_isa=
# Selects the object file format reader/writer used by LTO.
lto_binary_reader=lto-elf
# Don't carry these over build->host->target. Please.
xm_file=
@ -1324,6 +1326,7 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
thread_file='posix'
fi
use_gcc_stdint=wrap
lto_binary_reader=lto-coff
;;
i[34567]86-*-mingw* | x86_64-*-mingw*)
tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/mingw32.h"
@ -1391,6 +1394,7 @@ i[34567]86-*-mingw* | x86_64-*-mingw*)
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
default_use_cxa_atexit=yes
use_gcc_stdint=wrap
lto_binary_reader=lto-coff
case ${enable_threads} in
"" | yes | win32) thread_file='win32'
tmake_file="${tmake_file} i386/t-gthr-win32"

View File

@ -30,7 +30,7 @@ LIBGCC2_INCLUDES = -I$(srcdir)/../winsup/w32api/include
winnt.o: $(srcdir)/config/i386/winnt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
$(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
$(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H) $(LTO_STREAMER_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(srcdir)/config/i386/winnt.c

View File

@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "ggc.h"
#include "target.h"
#include "lto-streamer.h"
/* i386/PE specific attribute support.
@ -465,6 +466,12 @@ i386_pe_asm_named_section (const char *name, unsigned int flags,
*f++ = 's';
}
/* LTO sections need 1-byte alignment to avoid confusing the
zlib decompression algorithm with trailing zero pad bytes. */
if (strncmp (name, LTO_SECTION_NAME_PREFIX,
strlen (LTO_SECTION_NAME_PREFIX)) == 0)
*f++ = '0';
*f = '\0';
fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
@ -485,6 +492,8 @@ i386_pe_asm_named_section (const char *name, unsigned int flags,
}
}
/* Beware, DECL may be NULL if compile_file() is emitting the LTO marker. */
void
i386_pe_asm_output_aligned_decl_common (FILE *stream, tree decl,
const char *name, HOST_WIDE_INT size,
@ -581,7 +590,8 @@ static GTY(()) struct export_list *export_head;
these, so that we can output the export list at the end of the
assembly. We used to output these export symbols in each function,
but that causes problems with GNU ld when the sections are
linkonce. */
linkonce. Beware, DECL may be NULL if compile_file() is emitting
the LTO marker. */
void
i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data)
@ -589,6 +599,9 @@ i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data)
rtx symbol;
struct export_list *p;
if (!decl)
return;
symbol = XEXP (DECL_RTL (decl), 0);
gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
if (!SYMBOL_REF_DLLEXPORT_P (symbol))

59
gcc/configure vendored
View File

@ -671,6 +671,8 @@ subdirs
slibdir
dollar
gcc_tooldir
LTO_USE_LIBELF
LTO_BINARY_READER
enable_lto
MAINT
zlibinc
@ -17092,7 +17094,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 17095 "configure"
#line 17097 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -17198,7 +17200,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 17201 "configure"
#line 17203 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -22942,6 +22944,48 @@ if test $gcc_cv_as_ix86_pe_secrel32 = yes; then
$as_echo "#define HAVE_GAS_PE_SECREL32_RELOC 1" >>confdefs.h
fi
# Test if the assembler supports the extended form of the .section
# directive that specifies section alignment. LTO support uses this,
# but normally only after installation, so we warn but don't fail the
# configure if LTO is enabled but the assembler does not support it.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .section with alignment" >&5
$as_echo_n "checking assembler for .section with alignment... " >&6; }
if test "${gcc_cv_as_section_has_align+set}" = set; then :
$as_echo_n "(cached) " >&6
else
gcc_cv_as_section_has_align=no
if test $in_tree_gas = yes; then
if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 20 \) \* 1000 + 1`
then gcc_cv_as_section_has_align=yes
fi
elif test x$gcc_cv_as != x; then
echo '.section lto_test,"dr0"' > conftest.s
if { ac_try='$gcc_cv_as $gcc_cv_as_flags -fatal-warnings -o conftest.o conftest.s >&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then
gcc_cv_as_section_has_align=yes
else
echo "configure: failed program was" >&5
cat conftest.s >&5
fi
rm -f conftest.o conftest.s
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_section_has_align" >&5
$as_echo "$gcc_cv_as_section_has_align" >&6; }
if test x$gcc_cv_as_section_has_align != xyes; then
case ",$enable_languages," in
*,lto,*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: LTO for $target requires binutils >= 2.20.1, but version found appears insufficient; LTO will not work until binutils is upgraded." >&5
$as_echo "$as_me: WARNING: LTO for $target requires binutils >= 2.20.1, but version found appears insufficient; LTO will not work until binutils is upgraded." >&2;}
;;
esac
fi
;;
esac
@ -25078,6 +25122,17 @@ $as_echo "#define ENABLE_LTO 1" >>confdefs.h
enable_lto=yes
# LTO needs to speak the platform's object file format, and has a
# number of implementations of the required binary file access APIs.
# ELF is the most common, and default. We only link libelf if ELF
# is indeed the selected format.
LTO_BINARY_READER=${lto_binary_reader}
LTO_USE_LIBELF=-lelf
if test "x$lto_binary_reader" != "xlto-elf" ; then
LTO_USE_LIBELF=
fi
;;
*) ;;
esac

View File

@ -3202,6 +3202,19 @@ foo: nop
rm -f conftest],
[AC_DEFINE(HAVE_GAS_PE_SECREL32_RELOC, 1,
[Define if your assembler and linker support 32-bit section relative relocs via '.secrel32 label'.])])
# Test if the assembler supports the extended form of the .section
# directive that specifies section alignment. LTO support uses this,
# but normally only after installation, so we warn but don't fail the
# configure if LTO is enabled but the assembler does not support it.
gcc_GAS_CHECK_FEATURE([.section with alignment], gcc_cv_as_section_has_align,
[2,20,1],-fatal-warnings,[.section lto_test,"dr0"])
if test x$gcc_cv_as_section_has_align != xyes; then
case ",$enable_languages," in
*,lto,*)
AC_MSG_WARN([LTO for $target requires binutils >= 2.20.1, but version found appears insufficient; LTO will not work until binutils is upgraded.])
;;
esac
fi
;;
esac
@ -4270,6 +4283,17 @@ changequote([,])dnl
AC_DEFINE(ENABLE_LTO, 1, [Define to enable LTO support.])
enable_lto=yes
AC_SUBST(enable_lto)
# LTO needs to speak the platform's object file format, and has a
# number of implementations of the required binary file access APIs.
# ELF is the most common, and default. We only link libelf if ELF
# is indeed the selected format.
LTO_BINARY_READER=${lto_binary_reader}
LTO_USE_LIBELF=-lelf
if test "x$lto_binary_reader" != "xlto-elf" ; then
LTO_USE_LIBELF=
fi
AC_SUBST(LTO_BINARY_READER)
AC_SUBST(LTO_USE_LIBELF)
;;
*) ;;
esac

View File

@ -1,3 +1,13 @@
2010-04-27 Dave Korn <dave.korn.cygwin@gmail.com>
PR lto/42776
* Make-lang.in (LTO_OBJS): Use LTO_BINARY_READER instead of
hardcoding 'lto-elf.o'.
($(LTO_EXE)): Use LTO_USE_LIBELF instead of hardcoding '-lelf'.
* lto-coff.h: New file.
* lto-coff.c: Likewise.
2010-04-26 Richard Guenther <rguenther@suse.de>
* lto.c (lto_fixup_type): Deal with non-type TYPE_CONTEXT.

View File

@ -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-elf.o attribs.o
LTO_OBJS = lto/lto-lang.o lto/lto.o lto/$(LTO_BINARY_READER).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) -lelf
$(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) $(LTO_USE_LIBELF)
# Dependencies
lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
@ -88,3 +88,6 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \
$(LTO_TAGS_H) $(LTO_STREAMER_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

845
gcc/lto/lto-coff.c Normal file
View File

@ -0,0 +1,845 @@
/* 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/>. */
#include "config.h"
#include "system.h"
#include "coretypes.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;
}
/* Return an error string after an error, or a predetermined one
if ERRCODE is not -1. */
static const char *
coff_errmsg (int errcode)
{
return strerror (errcode == -1 ? errno : errcode);
}
/* Returns a hash code for P. */
static hashval_t
hash_name (const void *p)
{
const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
return (hashval_t) htab_hash_string (ds->name);
}
/* Returns nonzero if P1 and P2 are equal. */
static int
eq_name (const void *p1, const void *p2)
{
const struct lto_section_slot *s1 =
(const struct lto_section_slot *) p1;
const struct lto_section_slot *s2 =
(const struct lto_section_slot *) p2;
return strcmp (s1->name, s2->name) == 0;
}
/* 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 = htab_create (37, hash_name, eq_name, free);
/* 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: %s", coff_errmsg (-1));
/* 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: %s", coff_errmsg (-1));
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 (COFF_CHARACTERISTICS != (COFF_CHARACTERISTICS & charact))
{
/* ECOFF/XCOFF/PE+ support not implemented. */
error ("not a 32-bit COFF object file");
return false;
}
/* It validated OK, so cached it if we don't already have one. */
if (!cached_coff_hdr_valid)
{
cached_coff_hdr_valid = true;
memcpy (&cached_coff_hdr, &coff_file->coffhdr, sizeof (cached_coff_hdr));
}
if (mach != COFF_GET(&cached_coff_hdr, Machine))
{
error ("inconsistent file architecture detected");
return false;
}
/* Read section headers and string table? */
numsections = COFF_GET(&coff_file->coffhdr, NumberOfSections);
secheaderssize = numsections * sizeof (Coff_section);
sectionsstart = sizeof (Coff_header) + secheaderssize;
symbolsstart = COFF_GET(&coff_file->coffhdr, PointerToSymbolTable);
numsyms = COFF_GET(&coff_file->coffhdr, NumberOfSymbols);
stringsstart = (symbolsstart + COFF_SYMBOL_SIZE * numsyms);
#define CVOFFSETTTED(x) (coff_file->base.offset + (x))
if (numsections <= 0 || symbolsstart <= 0 || numsyms <= 0
|| (CVOFFSETTTED(sectionsstart) >= coff_file->file_size)
|| (CVOFFSETTTED(symbolsstart) >= coff_file->file_size)
|| (CVOFFSETTTED(stringsstart) >= coff_file->file_size))
{
error ("not a valid COFF object file");
return false;
}
#undef CVOFFSETTTED
/* Record start of string table. */
coff_file->strtab_offs = stringsstart;
/* Validate section table entries. */
for (secnum = 0; secnum < numsections; secnum++)
{
Coff_section coffsec;
lto_coff_section *ltosec;
off_t size_raw, offs_raw, offs_relocs, offs_lines;
off_t num_relocs, num_lines;
n = read (coff_file->fd, &coffsec, sizeof (coffsec));
if (n != sizeof (coffsec))
{
error ("short/missing COFF section table");
return false;
}
size_raw = COFF_GET(&coffsec, SizeOfRawData);
offs_raw = COFF_GET(&coffsec, PointerToRawData);
offs_relocs = COFF_GET(&coffsec, PointerToRelocations);
offs_lines = COFF_GET(&coffsec, PointerToLinenumbers);
num_relocs = COFF_GET(&coffsec, NumberOfRelocations);
num_lines = COFF_GET(&coffsec, NumberOfLinenumbers);
if (size_raw < 0 || num_relocs < 0 || num_lines < 0
|| (size_raw
&& ((COFF_GET(&coffsec, Characteristics)
& IMAGE_SCN_CNT_UNINITIALIZED_DATA)
? (offs_raw != 0)
: (offs_raw < sectionsstart || offs_raw >= coff_file->file_size)))
|| (num_relocs
&& (offs_relocs < sectionsstart
|| offs_relocs >= coff_file->file_size))
|| (num_lines
&& (offs_lines < sectionsstart
|| offs_lines >= coff_file->file_size)))
{
error ("invalid COFF section table");
return false;
}
/* Looks ok, so record its details. We don't read the
string table or set up names yet; we'll do that when
we build the hash table. */
ltosec = coff_newsection (coff_file, NULL, 0);
memcpy (&ltosec->coffsec, &coffsec, sizeof (ltosec->coffsec));
}
return true;
}
/* Initialize COFF_FILE's executable header using cached data from previously
read files. */
static void
init_coffhdr (lto_coff_file *coff_file)
{
gcc_assert (cached_coff_hdr_valid);
memset (&coff_file->coffhdr, 0, sizeof (coff_file->coffhdr));
COFF_PUT(&coff_file->coffhdr, Machine, COFF_GET(&cached_coff_hdr, Machine));
COFF_PUT(&coff_file->coffhdr, Characteristics, COFF_GET(&cached_coff_hdr, Characteristics));
}
/* Open COFF file FILENAME. If WRITABLE is true, the file is opened for write
and, if necessary, created. Otherwise, the file is opened for reading.
Returns the opened file. */
lto_file *
lto_obj_file_open (const char *filename, bool writable)
{
lto_coff_file *coff_file;
lto_file *result = NULL;
off_t offset;
const char *offset_p;
char *fname;
struct stat statbuf;
offset_p = strchr (filename, '@');
if (!offset_p)
{
fname = xstrdup (filename);
offset = 0;
}
else
{
/* The file started with '@' is a file containing command line
options. Stop if it doesn't exist. */
if (offset_p == filename)
fatal_error ("command line option file '%s' does not exist",
filename);
fname = (char *) xmalloc (offset_p - filename + 1);
memcpy (fname, filename, offset_p - filename);
fname[offset_p - filename] = '\0';
offset_p += 3; /* skip the @0x */
offset = lto_parse_hex (offset_p);
}
/* Set up. */
coff_file = XCNEW (lto_coff_file);
result = (lto_file *) coff_file;
lto_file_init (result, fname, offset);
coff_file->fd = -1;
/* Open the file. */
coff_file->fd = open (fname,
O_BINARY | (writable ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY), 0666);
if (coff_file->fd == -1)
{
error ("could not open file %s", fname);
goto fail;
}
if (stat (fname, &statbuf) < 0)
{
error ("could not stat file %s", fname);
goto fail;
}
coff_file->file_size = statbuf.st_size;
if (offset != 0)
{
char ar_tail[12];
int size;
/* Surely not? */
gcc_assert (!writable);
/* Seek to offset, or error. */
if (lseek (coff_file->fd, offset, SEEK_SET) != (ssize_t) offset)
{
error ("could not find archive member @0x%lx", (long) offset);
goto fail;
}
/* Now seek back 12 chars and read the tail of the AR header to
find the length of the member file. */
if (lseek (coff_file->fd, -12, SEEK_CUR) < 0
|| read (coff_file->fd, ar_tail, 12) != 12
|| lseek (coff_file->fd, 0, SEEK_CUR) != (ssize_t) offset
|| ar_tail[10] != '`' || ar_tail[11] != '\n')
{
error ("could not find archive header @0x%lx", (long) offset);
goto fail;
}
ar_tail[11] = 0;
if (sscanf (ar_tail, "%d", &size) != 1)
{
error ("invalid archive header @0x%lx", (long) offset);
goto fail;
}
coff_file->file_size = size;
}
if (writable)
{
init_coffhdr (coff_file);
coff_file->shstrtab_stream = XCNEW (struct lto_output_stream);
}
else
if (!validate_file (coff_file))
goto fail;
return result;
fail:
if (result)
lto_obj_file_close (result);
return NULL;
}
/* Close COFF file FILE and clean up any associated data structures. If FILE
was opened for writing, the file's COFF data is written at this time, and
any cached data buffers are freed. Return TRUE if there was an error. */
static bool
coff_write_object_file (lto_coff_file *coff_file)
{
lto_coff_section *cursec, *stringsec;
lto_coff_data *data;
size_t fileoffset, numsections, totalsecsize, numsyms, stringssize;
bool write_err = false;
int secnum;
/* Infer whether this file was opened for reading or writing from the
presence or absense of an initialised stream for the string table;
do nothing if it was opened for reading. */
if (!coff_file->shstrtab_stream)
return false;
else
{
/* Write the COFF string table into a dummy new section that
we will not write a header for. */
lto_file *old_file = lto_set_current_out_file (&coff_file->base);
/* This recursively feeds in the data to a new section. */
lto_coff_begin_section_with_type (".strtab", 1);
lto_write_stream (coff_file->shstrtab_stream);
lto_obj_end_section ();
lto_set_current_out_file (old_file);
free (coff_file->shstrtab_stream);
}
/* Layout the file. Count sections (not dummy string section) and calculate
data size for all of them. */
numsections = 0;
totalsecsize = 0;
stringssize = 0;
stringsec = NULL;
COFF_FOR_ALL_SECTIONS(coff_file, cursec)
{
lto_coff_data *data;
size_t cursecsize;
cursecsize = 0;
COFF_FOR_ALL_DATA(cursec,data)
cursecsize += data->d_size;
if (cursec->type == 0)
{
++numsections;
totalsecsize += COFF_ALIGN(cursecsize);
#if COFF_ALIGNMENT > 1
cursec->pad_needed = COFF_ALIGN(cursecsize) - cursecsize;
#endif
}
else
{
stringssize = cursecsize;
stringsec = cursec;
}
COFF_PUT(&cursec->coffsec, SizeOfRawData, cursecsize);
}
/* There is a file symbol and a section symbol per section,
and each of these has a single auxiliary symbol following. */
numsyms = 2 * (1 + numsections);
/* Great! Now we have enough info to fill out the file header. */
COFF_PUT(&coff_file->coffhdr, NumberOfSections, numsections);
COFF_PUT(&coff_file->coffhdr, NumberOfSymbols, numsyms);
COFF_PUT(&coff_file->coffhdr, PointerToSymbolTable, sizeof (Coff_header)
+ numsections * sizeof (Coff_section) + totalsecsize);
/* The remaining members were initialised to zero or copied from
a cached header, so we leave them alone here. */
/* Now position all the sections, and fill out their headers. */
fileoffset = sizeof (Coff_header) + numsections * sizeof (Coff_section);
COFF_FOR_ALL_SECTIONS(coff_file, cursec)
{
/* Skip dummy string section. */
if (cursec->type == 1)
continue;
COFF_PUT(&cursec->coffsec, PointerToRawData, fileoffset);
fileoffset += COFF_ALIGN (COFF_GET(&cursec->coffsec, SizeOfRawData));
COFF_PUT(&cursec->coffsec, Characteristics, COFF_SECTION_CHARACTERISTICS);
snprintf ((char *)&cursec->coffsec.Name[0], 8, "/%d", cursec->strtab_offs + 4);
}
/* We can write the data now. As there's no way to indicate an error return
from this hook, error handling is limited to not wasting our time doing
any more writes in the event that any one fails. */
/* Write the COFF header. */
write_err = (write (coff_file->fd, &coff_file->coffhdr,
sizeof (coff_file->coffhdr)) != sizeof (coff_file->coffhdr));
/* Write the COFF section headers. */
COFF_FOR_ALL_SECTIONS(coff_file, cursec)
if (cursec->type == 1) /* Skip dummy string section. */
continue;
else if (!write_err)
write_err = (write (coff_file->fd, &cursec->coffsec,
sizeof (cursec->coffsec)) != sizeof (cursec->coffsec));
else
break;
/* Write the COFF sections. */
COFF_FOR_ALL_SECTIONS(coff_file, cursec)
{
#if COFF_ALIGNMENT > 1
static const char padzeros[COFF_ALIGNMENT] = { 0 };
#endif
/* Skip dummy string section. */
if (cursec->type == 1)
continue;
COFF_FOR_ALL_DATA(cursec, data)
if (!write_err)
write_err = (write (coff_file->fd, data->d_buf, data->d_size)
!= data->d_size);
else
break;
#if COFF_ALIGNMENT > 1
if (!write_err && cursec->pad_needed)
write_err = (write (coff_file->fd, padzeros, cursec->pad_needed)
!= cursec->pad_needed);
#endif
}
/* Write the COFF symbol table. */
if (!write_err)
{
union
{
Coff_symbol sym;
Coff_aux_sym_file file;
Coff_aux_sym_section sec;
} symbols[2];
memset (&symbols[0], 0, sizeof (symbols));
strcpy ((char *) &symbols[0].sym.Name[0], ".file");
COFF_PUT(&symbols[0].sym, SectionNumber, IMAGE_SYM_DEBUG);
COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_FILE;
symbols[0].sym.NumberOfAuxSymbols[0] = 1;
snprintf ((char *)symbols[1].file.FileName,
sizeof (symbols[1].file.FileName),
"%s", lbasename (coff_file->base.filename));
write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
!= (2 * COFF_SYMBOL_SIZE));
/* Set up constant parts for section sym loop. */
memset (&symbols[0], 0, sizeof (symbols));
COFF_PUT(&symbols[0].sym, Type, IMAGE_SYM_TYPE);
symbols[0].sym.StorageClass[0] = IMAGE_SYM_CLASS_STATIC;
symbols[0].sym.NumberOfAuxSymbols[0] = 1;
secnum = 1;
if (!write_err)
COFF_FOR_ALL_SECTIONS(coff_file, cursec)
{
/* Skip dummy string section. */
if (cursec->type == 1)
continue;
/* Reuse section name string for section symbol name. */
COFF_PUT_NDXSZ(&symbols[0].sym, Name, 0, 0, 4);
COFF_PUT_NDXSZ(&symbols[0].sym, Name, cursec->strtab_offs + 4, 4, 4);
COFF_PUT(&symbols[0].sym, SectionNumber, secnum++);
COFF_PUT(&symbols[1].sec, Length,
COFF_GET(&cursec->coffsec, SizeOfRawData));
if (!write_err)
write_err = (write (coff_file->fd, &symbols[0], sizeof (symbols))
!= (2 * COFF_SYMBOL_SIZE));
else
break;
}
}
/* Write the COFF string table. */
if (!write_err)
{
unsigned char outlen[4];
COFF_PUT4(outlen, stringssize + 4);
if (!write_err)
write_err = (write (coff_file->fd, outlen, 4) != 4);
if (stringsec)
COFF_FOR_ALL_DATA(stringsec, data)
if (!write_err)
write_err = (write (coff_file->fd, data->d_buf, data->d_size)
!= data->d_size);
else
break;
}
return write_err;
}
/* Close COFF file FILE and clean up any associated data structures. If FILE
was opened for writing, the file's COFF data is written at this time, and
any cached data buffers are freed. */
void
lto_obj_file_close (lto_file *file)
{
lto_coff_file *coff_file = (lto_coff_file *) file;
struct lto_char_ptr_base *cur, *tmp;
lto_coff_section *cursec, *nextsec;
bool write_err = false;
/* Write the COFF string table into a dummy new section that
we will not write a header for. */
if (coff_file->shstrtab_stream)
coff_write_object_file (coff_file);
/* Close the file, we're done. */
if (coff_file->fd != -1)
close (coff_file->fd);
/* Free any data buffers. */
cur = coff_file->data;
while (cur)
{
tmp = cur;
cur = (struct lto_char_ptr_base *) cur->ptr;
free (tmp);
}
/* Free any sections and their data chains. */
cursec = coff_file->section_chain;
while (cursec)
{
lto_coff_data *curdata, *nextdata;
nextsec = cursec->next;
curdata = cursec->data_chain;
while (curdata)
{
nextdata = curdata->next;
free (curdata);
curdata = nextdata;
}
free (cursec);
cursec = nextsec;
}
free (file);
/* If there was an error, mention it. */
if (write_err)
error ("I/O error writing COFF output file");
}

406
gcc/lto/lto-coff.h Normal file
View File

@ -0,0 +1,406 @@
/* 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)
/* Known header magics for validation, as an array initialiser. */
#define COFF_KNOWN_MACHINES \
{ IMAGE_FILE_MACHINE_I386/*, ... 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 */

View File

@ -1,3 +1,9 @@
2010-04-27 Dave Korn <dave.korn.cygwin@gmail.com>
PR lto/42776
* lib/lto.exp (lto_prune_vis_warns): New function.
(lto-link-and-maybe-run): Call it.
2010-04-26 H.J. Lu <hongjiu.lu@intel.com>
PR tree-optimization/43904

View File

@ -16,6 +16,19 @@
# Contributed by Diego Novillo <dnovillo@google.com>
# Prune messages from gcc that aren't useful.
proc lto_prune_vis_warns { text } {
# Many tests that use visibility will still pass on platforms that don't support it.
regsub -all "(^|\n)\[^\n\]*: warning: visibility attribute not supported in this configuration; ignored\[^\n\]*" $text "" text
# And any stray location lines.
regsub -all "(^|\n)\[^\n\]*: In function \[^\n\]*" $text "" text
regsub -all "(^|\n)In file included from :\[^\n\]*" $text "" text
return $text
}
# lto_init -- called at the start of each subdir of tests
@ -147,6 +160,10 @@ proc lto-link-and-maybe-run { testname objlist dest optall optfile optstr } {
# Link the objects into an executable.
set comp_output [${tool}_target_compile "$objlist" $dest executable \
"$options"]
# Prune unimportant visibility warnings before checking output.
set comp_output [lto_prune_vis_warns $comp_output]
if ![${tool}_check_compile "$testcase $testname link" "" \
$dest $comp_output] then {
unresolved "$testcase $testname execute $optstr"