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:
parent
45c384e375
commit
3bec79c52e
@ -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.
|
||||
|
30
configure.ac
30
configure.ac
@ -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.
|
||||
|
@ -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@
|
||||
|
||||
|
@ -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 (<o_objects, prog_name);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
59
gcc/configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
845
gcc/lto/lto-coff.c
Normal 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 (<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");
|
||||
}
|
||||
|
406
gcc/lto/lto-coff.h
Normal file
406
gcc/lto/lto-coff.h
Normal 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 */
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user