Mercurial > projects > winelf > hg > index.cgi
changeset 1:cabe9c86a5b5
Moving some old patches to their own directory.
author | Gregor Richards <Richards@codu.org> |
---|---|
date | Fri, 24 Jul 2009 21:13:46 -0400 |
parents | b10489e764e3 |
children | 994ca5c4a51c |
files | diffs/binutils-2.17-winelf.diff diffs/binutils-2.18-winelf.diff diffs/gcc-3.4.5-20060117-1-winelf.diff diffs/gcc-4.1.2-winelf.diff diffs/gcc-4.2.3-winelf.diff diffs/gdc-0.23-winelf.diff diffs/gdc-0.24-winelf.diff diffs/old/binutils-2.17-winelf.diff diffs/old/binutils-2.18-winelf.diff diffs/old/gcc-3.4.5-20060117-1-winelf.diff diffs/old/gcc-4.1.2-winelf.diff diffs/old/gcc-4.2.3-winelf.diff diffs/old/gdc-0.23-winelf.diff diffs/old/gdc-0.24-winelf.diff |
diffstat | 14 files changed, 144813 insertions(+), 144813 deletions(-) [+] |
line wrap: on
line diff
--- a/diffs/binutils-2.17-winelf.diff Fri Jul 24 21:08:19 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -diff -ruN binutils-2.17/bfd/config.bfd binutils-2.17-winelf/bfd/config.bfd ---- binutils-2.17/bfd/config.bfd 2006-04-05 05:41:57.000000000 -0700 -+++ binutils-2.17-winelf/bfd/config.bfd 2007-03-09 10:59:13.000000000 -0800 -@@ -448,7 +448,8 @@ - ;; - i[3-7]86-*-sysv4* | i[3-7]86-*-unixware* | \ - i[3-7]86-*-elf | i[3-7]86-*-sco3.2v5* | \ -- i[3-7]86-*-dgux* | i[3-7]86-*-sysv5*) -+ i[3-7]86-*-dgux* | i[3-7]86-*-sysv5* | \ -+ i[3-7]86-*-win32elf*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386coff_vec - ;; -diff -ruN binutils-2.17/config.sub binutils-2.17-winelf/config.sub ---- binutils-2.17/config.sub 2006-01-16 09:34:37.000000000 -0800 -+++ binutils-2.17-winelf/config.sub 2007-03-09 11:04:45.000000000 -0800 -@@ -1206,7 +1206,7 @@ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ -- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* | -win32elf* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ -diff -ruN binutils-2.17/gas/configure.tgt binutils-2.17-winelf/gas/configure.tgt ---- binutils-2.17/gas/configure.tgt 2006-04-05 05:41:57.000000000 -0700 -+++ binutils-2.17-winelf/gas/configure.tgt 2007-03-09 11:00:48.000000000 -0800 -@@ -210,6 +210,7 @@ - i386-*-cygwin*) fmt=coff em=pe ;; - i386-*-interix*) fmt=coff em=interix ;; - i386-*-mingw32*) fmt=coff em=pe ;; -+ i386-*-win32elf*) fmt=elf ;; - i386-*-nto-qnx*) fmt=elf ;; - i386-*-*nt*) fmt=coff em=pe ;; - i386-*-chaos) fmt=elf ;; -diff -ruN binutils-2.17/ld/configure.tgt binutils-2.17-winelf/ld/configure.tgt ---- binutils-2.17/ld/configure.tgt 2006-04-05 05:41:57.000000000 -0700 -+++ binutils-2.17-winelf/ld/configure.tgt 2007-03-09 11:16:10.000000000 -0800 -@@ -219,6 +219,7 @@ - targ_extra_ofiles="deffilep.o pe-dll.o" ;; - i[3-7]86-*-interix*) targ_emul=i386pe_posix; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; -+i[3-7]86-*-win32elf*) targ_emul=elf_i386 ;; - i[3-7]86-*-beospe*) targ_emul=i386beos ;; - i[3-7]86-*-beos*) targ_emul=elf_i386_be ;; - i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks ;; -diff -ruN binutils-2.17/libiberty/configure binutils-2.17-winelf/libiberty/configure ---- binutils-2.17/libiberty/configure 2006-04-06 17:01:25.000000000 -0700 -+++ binutils-2.17-winelf/libiberty/configure 2007-03-09 15:13:28.000000000 -0800 -@@ -5713,7 +5713,7 @@ - - - case "${host}" in -- *-*-cygwin* | *-*-mingw*) -+ *-*-cygwin* | *-*-mingw* | *-*-win32elf*) - cat >>confdefs.h <<\_ACEOF - #define HAVE_SYS_ERRLIST 1 - _ACEOF -@@ -5877,7 +5877,7 @@ - fi - ;; - -- *-*-mingw32*) -+ *-*-mingw32* | *-*-win32elf*) - # Under mingw32, sys_nerr and sys_errlist exist, but they are - # macros, so the test below won't find them. - libiberty_cv_var_sys_nerr=yes -@@ -8198,7 +8198,7 @@ - - # Figure out which version of pexecute to use. - case "${host}" in -- *-*-mingw* | *-*-winnt*) pexecute=./pex-win32.o ;; -+ *-*-mingw* | *-*-winnt* | *-*-win32elf*) pexecute=./pex-win32.o ;; - *-*-msdosdjgpp*) pexecute=./pex-djgpp.o ;; - *-*-msdos*) pexecute=./pex-msdos.o ;; - *) pexecute=./pex-unix.o ;; -diff -ruN binutils-2.17/libiberty/configure.ac binutils-2.17-winelf/libiberty/configure.ac ---- binutils-2.17/libiberty/configure.ac 2006-04-06 17:01:25.000000000 -0700 -+++ binutils-2.17-winelf/libiberty/configure.ac 2007-03-09 15:12:44.000000000 -0800 -@@ -451,7 +451,7 @@ - AC_SUBST(target_header_dir) - - case "${host}" in -- *-*-cygwin* | *-*-mingw*) -+ *-*-cygwin* | *-*-mingw* | *-*-win32elf*) - AC_DEFINE(HAVE_SYS_ERRLIST) - AC_DEFINE(HAVE_SYS_NERR) - ;; -@@ -526,7 +526,7 @@ - fi - ;; - -- *-*-mingw32*) -+ *-*-mingw32* | *-*-win32elf*) - # Under mingw32, sys_nerr and sys_errlist exist, but they are - # macros, so the test below won't find them. - libiberty_cv_var_sys_nerr=yes -@@ -611,7 +611,7 @@ - - # Figure out which version of pexecute to use. - case "${host}" in -- *-*-mingw* | *-*-winnt*) pexecute=./pex-win32.o ;; -+ *-*-mingw* | *-*-winnt* | *-*-win32elf) pexecute=./pex-win32.o ;; - *-*-msdosdjgpp*) pexecute=./pex-djgpp.o ;; - *-*-msdos*) pexecute=./pex-msdos.o ;; - *) pexecute=./pex-unix.o ;;
--- a/diffs/binutils-2.18-winelf.diff Fri Jul 24 21:08:19 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -diff -ruN binutils-2.18/bfd/config.bfd binutils-2.18-winelf/bfd/config.bfd ---- binutils-2.18/bfd/config.bfd 2007-08-28 10:19:33.000000000 -0700 -+++ binutils-2.18-winelf/bfd/config.bfd 2008-02-24 16:20:57.000000000 -0800 -@@ -478,7 +478,8 @@ - ;; - i[3-7]86-*-sysv4* | i[3-7]86-*-unixware* | \ - i[3-7]86-*-elf | i[3-7]86-*-sco3.2v5* | \ -- i[3-7]86-*-dgux* | i[3-7]86-*-sysv5*) -+ i[3-7]86-*-dgux* | i[3-7]86-*-sysv5* | \ -+ i[3-7]86-*-win32elf*) - targ_defvec=bfd_elf32_i386_vec - targ_selvecs=i386coff_vec - ;; -diff -ruN binutils-2.18/config.sub binutils-2.18-winelf/config.sub ---- binutils-2.18/config.sub 2007-08-06 13:00:30.000000000 -0700 -+++ binutils-2.18-winelf/config.sub 2008-02-24 16:20:57.000000000 -0800 -@@ -1217,7 +1217,7 @@ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ -- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* | -win32elf* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ -diff -ruN binutils-2.18/gas/configure.tgt binutils-2.18-winelf/gas/configure.tgt ---- binutils-2.18/gas/configure.tgt 2007-08-28 10:19:36.000000000 -0700 -+++ binutils-2.18-winelf/gas/configure.tgt 2008-02-24 16:21:28.000000000 -0800 -@@ -221,6 +221,7 @@ - x86_64*) fmt=coff em=pep ;; - i*) fmt=coff em=pe ;; - esac ;; -+ i386-*-win32elf*) fmt=elf ;; - i386-*-nto-qnx*) fmt=elf ;; - i386-*-*nt*) fmt=coff em=pe ;; - i386-*-chaos) fmt=elf ;; -diff -ruN binutils-2.18/ld/configure.tgt binutils-2.18-winelf/ld/configure.tgt ---- binutils-2.18/ld/configure.tgt 2007-08-28 10:19:42.000000000 -0700 -+++ binutils-2.18-winelf/ld/configure.tgt 2008-02-24 16:20:57.000000000 -0800 -@@ -267,6 +267,7 @@ - targ_extra_ofiles="deffilep.o pep-dll.o" ;; - i[3-7]86-*-interix*) targ_emul=i386pe_posix; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; -+i[3-7]86-*-win32elf*) targ_emul=elf_i386 ;; - i[3-7]86-*-beospe*) targ_emul=i386beos ;; - i[3-7]86-*-beos*) targ_emul=elf_i386_be ;; - i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks ;; -diff -ruN binutils-2.18/libiberty/configure binutils-2.18-winelf/libiberty/configure ---- binutils-2.18/libiberty/configure 2007-08-06 12:59:45.000000000 -0700 -+++ binutils-2.18-winelf/libiberty/configure 2008-02-24 16:20:57.000000000 -0800 -@@ -6012,7 +6012,7 @@ - - - case "${host}" in -- *-*-cygwin* | *-*-mingw*) -+ *-*-cygwin* | *-*-mingw* | *-*-win32elf*) - cat >>confdefs.h <<\_ACEOF - #define HAVE_SYS_ERRLIST 1 - _ACEOF -@@ -6196,7 +6196,7 @@ - fi - ;; - -- *-*-mingw32*) -+ *-*-mingw32* | *-*-win32elf*) - # Under mingw32, sys_nerr and sys_errlist exist, but they are - # macros, so the test below won't find them. - libiberty_cv_var_sys_nerr=yes -@@ -8517,7 +8517,7 @@ - - # Figure out which version of pexecute to use. - case "${host}" in -- *-*-mingw* | *-*-winnt*) pexecute=./pex-win32.o ;; -+ *-*-mingw* | *-*-winnt* | *-*-win32elf*) pexecute=./pex-win32.o ;; - *-*-msdosdjgpp*) pexecute=./pex-djgpp.o ;; - *-*-msdos*) pexecute=./pex-msdos.o ;; - *) pexecute=./pex-unix.o ;; -diff -ruN binutils-2.18/libiberty/configure.ac binutils-2.18-winelf/libiberty/configure.ac ---- binutils-2.18/libiberty/configure.ac 2007-08-06 12:59:45.000000000 -0700 -+++ binutils-2.18-winelf/libiberty/configure.ac 2008-02-24 16:20:57.000000000 -0800 -@@ -502,7 +502,7 @@ - AC_SUBST(target_header_dir) - - case "${host}" in -- *-*-cygwin* | *-*-mingw*) -+ *-*-cygwin* | *-*-mingw* | *-*-win32elf*) - AC_DEFINE(HAVE_SYS_ERRLIST) - AC_DEFINE(HAVE_SYS_NERR) - ;; -@@ -594,7 +594,7 @@ - fi - ;; - -- *-*-mingw32*) -+ *-*-mingw32* | *-*-win32elf*) - # Under mingw32, sys_nerr and sys_errlist exist, but they are - # macros, so the test below won't find them. - libiberty_cv_var_sys_nerr=yes -@@ -679,7 +679,7 @@ - - # Figure out which version of pexecute to use. - case "${host}" in -- *-*-mingw* | *-*-winnt*) pexecute=./pex-win32.o ;; -+ *-*-mingw* | *-*-winnt* | *-*-win32elf) pexecute=./pex-win32.o ;; - *-*-msdosdjgpp*) pexecute=./pex-djgpp.o ;; - *-*-msdos*) pexecute=./pex-msdos.o ;; - *) pexecute=./pex-unix.o ;;
--- a/diffs/gcc-3.4.5-20060117-1-winelf.diff Fri Jul 24 21:08:19 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131617 +0,0 @@ -diff -ruN gcc-3.4.5-20060117-1/config.sub gcc-3.4.5-20060117-1-winelf/config.sub ---- gcc-3.4.5-20060117-1/config.sub 2004-02-22 06:44:23.000000000 -0800 -+++ gcc-3.4.5-20060117-1-winelf/config.sub 2008-02-26 22:19:17.000000000 -0800 -@@ -1156,7 +1156,7 @@ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ -- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* | -win32elf* \ - | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ -diff -ruN gcc-3.4.5-20060117-1/gcc/c-format.c.orig gcc-3.4.5-20060117-1-winelf/gcc/c-format.c.orig ---- gcc-3.4.5-20060117-1/gcc/c-format.c.orig 2005-05-01 03:39:15.000000000 -0700 -+++ gcc-3.4.5-20060117-1-winelf/gcc/c-format.c.orig 1969-12-31 16:00:00.000000000 -0800 -@@ -1,2817 +0,0 @@ --/* Check calls to formatted I/O functions (-Wformat). -- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -- 2001, 2002, 2003 Free Software Foundation, Inc. -- --This file is part of GCC. -- --GCC is free software; you can redistribute it and/or modify it under --the terms of the GNU General Public License as published by the Free --Software Foundation; either version 2, 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 COPYING. If not, write to the Free --Software Foundation, 59 Temple Place - Suite 330, Boston, MA --02111-1307, USA. */ -- --#include "config.h" --#include "system.h" --#include "coretypes.h" --#include "tm.h" --#include "tree.h" --#include "flags.h" --#include "toplev.h" --#include "c-common.h" --#include "intl.h" --#include "diagnostic.h" --#include "langhooks.h" -- --/* Set format warning options according to a -Wformat=n option. */ -- --void --set_Wformat (int setting) --{ -- warn_format = setting; -- warn_format_extra_args = setting; -- warn_format_zero_length = setting; -- if (setting != 1) -- { -- warn_format_nonliteral = setting; -- warn_format_security = setting; -- warn_format_y2k = setting; -- } -- /* Make sure not to disable -Wnonnull if -Wformat=0 is specified. */ -- if (setting) -- warn_nonnull = setting; --} -- -- --/* Handle attributes associated with format checking. */ -- --/* This must be in the same order as format_types, with format_type_error -- last. */ --enum format_type { printf_format_type, asm_fprintf_format_type, -- gcc_diag_format_type, gcc_cdiag_format_type, -- gcc_cxxdiag_format_type, -- scanf_format_type, strftime_format_type, -- strfmon_format_type, format_type_error }; -- --typedef struct function_format_info --{ -- enum format_type format_type; /* type of format (printf, scanf, etc.) */ -- unsigned HOST_WIDE_INT format_num; /* number of format argument */ -- unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ --} function_format_info; -- --static bool decode_format_attr (tree, function_format_info *, int); --static enum format_type decode_format_type (const char *); -- --static bool check_format_string (tree argument, -- unsigned HOST_WIDE_INT format_num, -- int flags, bool *no_add_attrs); --static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, -- int validated_p); -- -- --/* Handle a "format_arg" attribute; arguments as in -- struct attribute_spec.handler. */ --tree --handle_format_arg_attribute (tree *node, tree name ATTRIBUTE_UNUSED, -- tree args, int flags, bool *no_add_attrs) --{ -- tree type = *node; -- tree format_num_expr = TREE_VALUE (args); -- unsigned HOST_WIDE_INT format_num; -- tree argument; -- -- if (!get_constant (format_num_expr, &format_num, 0)) -- { -- error ("format string has invalid operand number"); -- *no_add_attrs = true; -- return NULL_TREE; -- } -- -- argument = TYPE_ARG_TYPES (type); -- if (argument) -- { -- if (!check_format_string (argument, format_num, flags, no_add_attrs)) -- return NULL_TREE; -- } -- -- if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE -- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) -- != char_type_node)) -- { -- if (!(flags & (int) ATTR_FLAG_BUILT_IN)) -- error ("function does not return string type"); -- *no_add_attrs = true; -- return NULL_TREE; -- } -- -- return NULL_TREE; --} -- --/* Verify that the format_num argument is actually a string, in case -- the format attribute is in error. */ --static bool --check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, -- int flags, bool *no_add_attrs) --{ -- unsigned HOST_WIDE_INT i; -- -- for (i = 1; i != format_num; i++) -- { -- if (argument == 0) -- break; -- argument = TREE_CHAIN (argument); -- } -- -- if (!argument -- || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE -- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) -- != char_type_node)) -- { -- if (!(flags & (int) ATTR_FLAG_BUILT_IN)) -- error ("format string arg not a string type"); -- *no_add_attrs = true; -- return false; -- } -- -- return true; --} -- --/* Strip any conversions from the expression, verify it is a constant, -- and store its value. If validated_p is true, abort on errors. -- Returns true on success, false otherwise. */ --static bool --get_constant(tree expr, unsigned HOST_WIDE_INT *value, int validated_p) --{ -- while (TREE_CODE (expr) == NOP_EXPR -- || TREE_CODE (expr) == CONVERT_EXPR -- || TREE_CODE (expr) == NON_LVALUE_EXPR) -- expr = TREE_OPERAND (expr, 0); -- -- if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0) -- { -- if (validated_p) -- abort (); -- return false; -- } -- -- *value = TREE_INT_CST_LOW (expr); -- -- return true; --} -- --/* Decode the arguments to a "format" attribute into a function_format_info -- structure. It is already known that the list is of the right length. -- If VALIDATED_P is true, then these attributes have already been validated -- and this function will abort if they are erroneous; if false, it -- will give an error message. Returns true if the attributes are -- successfully decoded, false otherwise. */ -- --static bool --decode_format_attr (tree args, function_format_info *info, int validated_p) --{ -- tree format_type_id = TREE_VALUE (args); -- tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); -- tree first_arg_num_expr -- = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); -- -- if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) -- { -- if (validated_p) -- abort (); -- error ("unrecognized format specifier"); -- return false; -- } -- else -- { -- const char *p = IDENTIFIER_POINTER (format_type_id); -- -- info->format_type = decode_format_type (p); -- -- if (info->format_type == format_type_error) -- { -- if (validated_p) -- abort (); -- warning ("`%s' is an unrecognized format function type", p); -- return false; -- } -- } -- -- if (!get_constant (format_num_expr, &info->format_num, validated_p)) -- { -- error ("format string has invalid operand number"); -- return false; -- } -- -- if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) -- { -- error ("'...' has invalid operand number"); -- return false; -- } -- -- if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) -- { -- if (validated_p) -- abort (); -- error ("format string arg follows the args to be formatted"); -- return false; -- } -- -- return true; --} -- --/* Check a call to a format function against a parameter list. */ -- --/* The meaningfully distinct length modifiers for format checking recognized -- by GCC. */ --enum format_lengths --{ -- FMT_LEN_none, -- FMT_LEN_hh, -- FMT_LEN_h, -- FMT_LEN_l, -- FMT_LEN_ll, -- FMT_LEN_L, -- FMT_LEN_z, -- FMT_LEN_t, -- FMT_LEN_j, -- FMT_LEN_MAX --}; -- -- --/* The standard versions in which various format features appeared. */ --enum format_std_version --{ -- STD_C89, -- STD_C94, -- STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ -- STD_C99, -- STD_EXT --}; -- --/* The C standard version C++ is treated as equivalent to -- or inheriting from, for the purpose of format features supported. */ --#define CPLUSPLUS_STD_VER STD_C94 --/* The C standard version we are checking formats against when pedantic. */ --#define C_STD_VER ((int)(c_dialect_cxx () \ -- ? CPLUSPLUS_STD_VER \ -- : (flag_isoc99 \ -- ? STD_C99 \ -- : (flag_isoc94 ? STD_C94 : STD_C89)))) --/* The name to give to the standard version we are warning about when -- pedantic. FEATURE_VER is the version in which the feature warned out -- appeared, which is higher than C_STD_VER. */ --#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ -- ? "ISO C++" \ -- : ((FEATURE_VER) == STD_EXT \ -- ? "ISO C" \ -- : "ISO C90")) --/* Adjust a C standard version, which may be STD_C9L, to account for -- -Wno-long-long. Returns other standard versions unchanged. */ --#define ADJ_STD(VER) ((int)((VER) == STD_C9L \ -- ? (warn_long_long ? STD_C99 : STD_C89) \ -- : (VER))) -- --/* Flags that may apply to a particular kind of format checked by GCC. */ --enum --{ -- /* This format converts arguments of types determined by the -- format string. */ -- FMT_FLAG_ARG_CONVERT = 1, -- /* The scanf allocation 'a' kludge applies to this format kind. */ -- FMT_FLAG_SCANF_A_KLUDGE = 2, -- /* A % during parsing a specifier is allowed to be a modified % rather -- that indicating the format is broken and we are out-of-sync. */ -- FMT_FLAG_FANCY_PERCENT_OK = 4, -- /* With $ operand numbers, it is OK to reference the same argument more -- than once. */ -- FMT_FLAG_DOLLAR_MULTIPLE = 8, -- /* This format type uses $ operand numbers (strfmon doesn't). */ -- FMT_FLAG_USE_DOLLAR = 16, -- /* Zero width is bad in this type of format (scanf). */ -- FMT_FLAG_ZERO_WIDTH_BAD = 32, -- /* Empty precision specification is OK in this type of format (printf). */ -- FMT_FLAG_EMPTY_PREC_OK = 64, -- /* Gaps are allowed in the arguments with $ operand numbers if all -- arguments are pointers (scanf). */ -- FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 -- /* Not included here: details of whether width or precision may occur -- (controlled by width_char and precision_char); details of whether -- '*' can be used for these (width_type and precision_type); details -- of whether length modifiers can occur (length_char_specs). */ --}; -- -- --/* Structure describing a length modifier supported in format checking, and -- possibly a doubled version such as "hh". */ --typedef struct --{ -- /* Name of the single-character length modifier. */ -- const char *name; -- /* Index into a format_char_info.types array. */ -- enum format_lengths index; -- /* Standard version this length appears in. */ -- enum format_std_version std; -- /* Same, if the modifier can be repeated, or NULL if it can't. */ -- const char *double_name; -- enum format_lengths double_index; -- enum format_std_version double_std; --} format_length_info; -- -- --/* Structure describing the combination of a conversion specifier -- (or a set of specifiers which act identically) and a length modifier. */ --typedef struct --{ -- /* The standard version this combination of length and type appeared in. -- This is only relevant if greater than those for length and type -- individually; otherwise it is ignored. */ -- enum format_std_version std; -- /* The name to use for the type, if different from that generated internally -- (e.g., "signed size_t"). */ -- const char *name; -- /* The type itself. */ -- tree *type; --} format_type_detail; -- -- --/* Macros to fill out tables of these. */ --#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } --#define BADLEN { 0, NULL, NULL } --#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } -- -- --/* Structure describing a format conversion specifier (or a set of specifiers -- which act identically), and the length modifiers used with it. */ --typedef struct --{ -- const char *format_chars; -- int pointer_count; -- enum format_std_version std; -- /* Types accepted for each length modifier. */ -- format_type_detail types[FMT_LEN_MAX]; -- /* List of other modifier characters allowed with these specifiers. -- This lists flags, and additionally "w" for width, "p" for precision -- (right precision, for strfmon), "#" for left precision (strfmon), -- "a" for scanf "a" allocation extension (not applicable in C99 mode), -- "*" for scanf suppression, and "E" and "O" for those strftime -- modifiers. */ -- const char *flag_chars; -- /* List of additional flags describing these conversion specifiers. -- "c" for generic character pointers being allowed, "2" for strftime -- two digit year formats, "3" for strftime formats giving two digit -- years in some locales, "4" for "2" which becomes "3" with an "E" modifier, -- "o" if use of strftime "O" is a GNU extension beyond C99, -- "W" if the argument is a pointer which is dereferenced and written into, -- "R" if the argument is a pointer which is dereferenced and read from, -- "i" for printf integer formats where the '0' flag is ignored with -- precision, and "[" for the starting character of a scanf scanset. */ -- const char *flags2; --} format_char_info; -- -- --/* Structure describing a flag accepted by some kind of format. */ --typedef struct --{ -- /* The flag character in question (0 for end of array). */ -- int flag_char; -- /* Zero if this entry describes the flag character in general, or a -- nonzero character that may be found in flags2 if it describes the -- flag when used with certain formats only. If the latter, only -- the first such entry found that applies to the current conversion -- specifier is used; the values of `name' and `long_name' it supplies -- will be used, if non-NULL and the standard version is higher than -- the unpredicated one, for any pedantic warning. For example, 'o' -- for strftime formats (meaning 'O' is an extension over C99). */ -- int predicate; -- /* Nonzero if the next character after this flag in the format should -- be skipped ('=' in strfmon), zero otherwise. */ -- int skip_next_char; -- /* The name to use for this flag in diagnostic messages. For example, -- N_("`0' flag"), N_("field width"). */ -- const char *name; -- /* Long name for this flag in diagnostic messages; currently only used for -- "ISO C does not support ...". For example, N_("the `I' printf flag"). */ -- const char *long_name; -- /* The standard version in which it appeared. */ -- enum format_std_version std; --} format_flag_spec; -- -- --/* Structure describing a combination of flags that is bad for some kind -- of format. */ --typedef struct --{ -- /* The first flag character in question (0 for end of array). */ -- int flag_char1; -- /* The second flag character. */ -- int flag_char2; -- /* Nonzero if the message should say that the first flag is ignored with -- the second, zero if the combination should simply be objected to. */ -- int ignored; -- /* Zero if this entry applies whenever this flag combination occurs, -- a nonzero character from flags2 if it only applies in some -- circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ -- int predicate; --} format_flag_pair; -- -- --/* Structure describing a particular kind of format processed by GCC. */ --typedef struct --{ -- /* The name of this kind of format, for use in diagnostics. Also -- the name of the attribute (without preceding and following __). */ -- const char *name; -- /* Specifications of the length modifiers accepted; possibly NULL. */ -- const format_length_info *length_char_specs; -- /* Details of the conversion specification characters accepted. */ -- const format_char_info *conversion_specs; -- /* String listing the flag characters that are accepted. */ -- const char *flag_chars; -- /* String listing modifier characters (strftime) accepted. May be NULL. */ -- const char *modifier_chars; -- /* Details of the flag characters, including pseudo-flags. */ -- const format_flag_spec *flag_specs; -- /* Details of bad combinations of flags. */ -- const format_flag_pair *bad_flag_pairs; -- /* Flags applicable to this kind of format. */ -- int flags; -- /* Flag character to treat a width as, or 0 if width not used. */ -- int width_char; -- /* Flag character to treat a left precision (strfmon) as, -- or 0 if left precision not used. */ -- int left_precision_char; -- /* Flag character to treat a precision (for strfmon, right precision) as, -- or 0 if precision not used. */ -- int precision_char; -- /* If a flag character has the effect of suppressing the conversion of -- an argument ('*' in scanf), that flag character, otherwise 0. */ -- int suppression_char; -- /* Flag character to treat a length modifier as (ignored if length -- modifiers not used). Need not be placed in flag_chars for conversion -- specifiers, but is used to check for bad combinations such as length -- modifier with assignment suppression in scanf. */ -- int length_code_char; -- /* Pointer to type of argument expected if '*' is used for a width, -- or NULL if '*' not used for widths. */ -- tree *width_type; -- /* Pointer to type of argument expected if '*' is used for a precision, -- or NULL if '*' not used for precisions. */ -- tree *precision_type; --} format_kind_info; -- -- --/* Structure describing details of a type expected in format checking, -- and the type to check against it. */ --typedef struct format_wanted_type --{ -- /* The type wanted. */ -- tree wanted_type; -- /* The name of this type to use in diagnostics. */ -- const char *wanted_type_name; -- /* The level of indirection through pointers at which this type occurs. */ -- int pointer_count; -- /* Whether, when pointer_count is 1, to allow any character type when -- pedantic, rather than just the character or void type specified. */ -- int char_lenient_flag; -- /* Whether the argument, dereferenced once, is written into and so the -- argument must not be a pointer to a const-qualified type. */ -- int writing_in_flag; -- /* Whether the argument, dereferenced once, is read from and so -- must not be a NULL pointer. */ -- int reading_from_flag; -- /* If warnings should be of the form "field precision is not type int", -- the name to use (in this case "field precision"), otherwise NULL, -- for "%s format, %s arg" type messages. If (in an extension), this -- is a pointer type, wanted_type_name should be set to include the -- terminating '*' characters of the type name to give a correct -- message. */ -- const char *name; -- /* The actual parameter to check against the wanted type. */ -- tree param; -- /* The argument number of that parameter. */ -- int arg_num; -- /* The next type to check for this format conversion, or NULL if none. */ -- struct format_wanted_type *next; --} format_wanted_type; -- -- --static const format_length_info printf_length_specs[] = --{ -- { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, -- { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, -- { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, -- { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, -- { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, -- { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 }, -- { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, -- { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, -- { NULL, 0, 0, NULL, 0, 0 } --}; -- --/* Length specifiers valid for asm_fprintf. */ --static const format_length_info asm_fprintf_length_specs[] = --{ -- { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, -- { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, -- { NULL, 0, 0, NULL, 0, 0 } --}; -- --/* Length specifiers valid for GCC diagnostics. */ --static const format_length_info gcc_diag_length_specs[] = --{ -- { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, -- { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, -- { NULL, 0, 0, NULL, 0, 0 } --}; -- --/* The custom diagnostics all accept the same length specifiers. */ --#define gcc_cdiag_length_specs gcc_diag_length_specs --#define gcc_cxxdiag_length_specs gcc_diag_length_specs -- --/* This differs from printf_length_specs only in that "Z" is not accepted. */ --static const format_length_info scanf_length_specs[] = --{ -- { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, -- { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, -- { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, -- { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, -- { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, -- { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, -- { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, -- { NULL, 0, 0, NULL, 0, 0 } --}; -- -- --/* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings -- make no sense for a format type not part of any C standard version. */ --static const format_length_info strfmon_length_specs[] = --{ -- /* A GNU extension. */ -- { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, -- { NULL, 0, 0, NULL, 0, 0 } --}; -- --static const format_flag_spec printf_flag_specs[] = --{ -- { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 }, -- { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, -- { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, -- { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 }, -- { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 }, -- { '\'', 0, 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT }, -- { 'I', 0, 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT }, -- { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, -- { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- -- --static const format_flag_pair printf_flag_pairs[] = --{ -- { ' ', '+', 1, 0 }, -- { '0', '-', 1, 0 }, -- { '0', 'p', 1, 'i' }, -- { 0, 0, 0, 0 } --}; -- --static const format_flag_spec asm_fprintf_flag_specs[] = --{ -- { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 }, -- { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, -- { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, -- { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 }, -- { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 }, -- { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, -- { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- --static const format_flag_pair asm_fprintf_flag_pairs[] = --{ -- { ' ', '+', 1, 0 }, -- { '0', '-', 1, 0 }, -- { '0', 'p', 1, 'i' }, -- { 0, 0, 0, 0 } --}; -- --static const format_flag_pair gcc_diag_flag_pairs[] = --{ -- { 0, 0, 0, 0 } --}; -- --#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs --#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs -- --static const format_flag_spec gcc_diag_flag_specs[] = --{ -- { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- --#define gcc_cdiag_flag_specs gcc_diag_flag_specs -- --static const format_flag_spec gcc_cxxdiag_flag_specs[] = --{ -- { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, -- { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, -- { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- --static const format_flag_spec scanf_flag_specs[] = --{ -- { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 }, -- { 'a', 0, 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT }, -- { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, -- { '\'', 0, 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT }, -- { 'I', 0, 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- -- --static const format_flag_pair scanf_flag_pairs[] = --{ -- { '*', 'L', 0, 0 }, -- { 0, 0, 0, 0 } --}; -- -- --static const format_flag_spec strftime_flag_specs[] = --{ -- { '_', 0, 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT }, -- { '-', 0, 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT }, -- { '0', 0, 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT }, -- { '^', 0, 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT }, -- { '#', 0, 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT }, -- { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, -- { 'E', 0, 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 }, -- { 'O', 0, 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 }, -- { 'O', 'o', 0, NULL, N_("the `O' modifier"), STD_EXT }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- -- --static const format_flag_pair strftime_flag_pairs[] = --{ -- { 'E', 'O', 0, 0 }, -- { '_', '-', 0, 0 }, -- { '_', '0', 0, 0 }, -- { '-', '0', 0, 0 }, -- { '^', '#', 0, 0 }, -- { 0, 0, 0, 0 } --}; -- -- --static const format_flag_spec strfmon_flag_specs[] = --{ -- { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 }, -- { '^', 0, 0, N_("`^' flag"), N_("the `^' strfmon flag"), STD_C89 }, -- { '+', 0, 0, N_("`+' flag"), N_("the `+' strfmon flag"), STD_C89 }, -- { '(', 0, 0, N_("`(' flag"), N_("the `(' strfmon flag"), STD_C89 }, -- { '!', 0, 0, N_("`!' flag"), N_("the `!' strfmon flag"), STD_C89 }, -- { '-', 0, 0, N_("`-' flag"), N_("the `-' strfmon flag"), STD_C89 }, -- { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 }, -- { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, -- { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, -- { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 }, -- { 0, 0, 0, NULL, NULL, 0 } --}; -- --static const format_flag_pair strfmon_flag_pairs[] = --{ -- { '+', '(', 0, 0 }, -- { 0, 0, 0, 0 } --}; -- -- --#define T_I &integer_type_node --#define T89_I { STD_C89, NULL, T_I } --#define T_L &long_integer_type_node --#define T89_L { STD_C89, NULL, T_L } --#define T_LL &long_long_integer_type_node --#define T9L_LL { STD_C9L, NULL, T_LL } --#define TEX_LL { STD_EXT, NULL, T_LL } --#define T_S &short_integer_type_node --#define T89_S { STD_C89, NULL, T_S } --#define T_UI &unsigned_type_node --#define T89_UI { STD_C89, NULL, T_UI } --#define T_UL &long_unsigned_type_node --#define T89_UL { STD_C89, NULL, T_UL } --#define T_ULL &long_long_unsigned_type_node --#define T9L_ULL { STD_C9L, NULL, T_ULL } --#define TEX_ULL { STD_EXT, NULL, T_ULL } --#define T_US &short_unsigned_type_node --#define T89_US { STD_C89, NULL, T_US } --#define T_F &float_type_node --#define T89_F { STD_C89, NULL, T_F } --#define T99_F { STD_C99, NULL, T_F } --#define T_D &double_type_node --#define T89_D { STD_C89, NULL, T_D } --#define T99_D { STD_C99, NULL, T_D } --#define T_LD &long_double_type_node --#define T89_LD { STD_C89, NULL, T_LD } --#define T99_LD { STD_C99, NULL, T_LD } --#define T_C &char_type_node --#define T89_C { STD_C89, NULL, T_C } --#define T_SC &signed_char_type_node --#define T99_SC { STD_C99, NULL, T_SC } --#define T_UC &unsigned_char_type_node --#define T99_UC { STD_C99, NULL, T_UC } --#define T_V &void_type_node --#define T89_V { STD_C89, NULL, T_V } --#define T_W &wchar_type_node --#define T94_W { STD_C94, "wchar_t", T_W } --#define TEX_W { STD_EXT, "wchar_t", T_W } --#define T_WI &wint_type_node --#define T94_WI { STD_C94, "wint_t", T_WI } --#define TEX_WI { STD_EXT, "wint_t", T_WI } --#define T_ST &size_type_node --#define T99_ST { STD_C99, "size_t", T_ST } --#define T_SST &signed_size_type_node --#define T99_SST { STD_C99, "signed size_t", T_SST } --#define T_PD &ptrdiff_type_node --#define T99_PD { STD_C99, "ptrdiff_t", T_PD } --#define T_UPD &unsigned_ptrdiff_type_node --#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } --#define T_IM &intmax_type_node --#define T99_IM { STD_C99, "intmax_t", T_IM } --#define T_UIM &uintmax_type_node --#define T99_UIM { STD_C99, "uintmax_t", T_UIM } -- --static const format_char_info print_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-wp0 +'I", "i" }, -- { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i" }, -- { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i" }, -- { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, -- { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "" }, -- { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, -- { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c" }, -- { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, -- /* C99 conversion specifiers. */ -- { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, -- { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" }, -- /* X/Open conversion specifiers. */ -- { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, -- { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R" }, -- /* GNU conversion specifiers. */ -- { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info asm_fprintf_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i" }, -- { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i" }, -- { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i" }, -- { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, -- -- /* asm_fprintf conversion specifiers. */ -- { "O", 0, STD_C89, NOARGUMENTS, "", "" }, -- { "R", 0, STD_C89, NOARGUMENTS, "", "" }, -- { "I", 0, STD_C89, NOARGUMENTS, "", "" }, -- { "L", 0, STD_C89, NOARGUMENTS, "", "" }, -- { "U", 0, STD_C89, NOARGUMENTS, "", "" }, -- { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "@", 0, STD_C89, NOARGUMENTS, "", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info gcc_diag_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, -- { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, -- -- /* Custom conversion specifiers. */ -- -- /* %H will require "location_t" at runtime. */ -- { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- /* These will require a "tree" at runtime. */ -- { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- { "m", 0, STD_C89, NOARGUMENTS, "", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info gcc_cdiag_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, -- { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, -- -- /* Custom conversion specifiers. */ -- -- /* %H will require "location_t" at runtime. */ -- { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- /* These will require a "tree" at runtime. */ -- { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- { "m", 0, STD_C89, NOARGUMENTS, "", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info gcc_cxxdiag_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" }, -- { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" }, -- -- /* Custom conversion specifiers. */ -- -- /* %H will require "location_t" at runtime. */ -- { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- /* These will require a "tree" at runtime. */ -- { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "+#", "" }, -- -- /* These accept either an `int' or an `enum tree_code' (which is handled as an `int'.) */ -- { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, -- -- { "m", 0, STD_C89, NOARGUMENTS, "", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info scan_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "*w'I", "W" }, -- { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w'I", "W" }, -- { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w", "W" }, -- { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, -- { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW" }, -- { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW" }, -- { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[" }, -- { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, -- { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, -- /* C99 conversion specifiers. */ -- { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, -- /* X/Open conversion specifiers. */ -- { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, -- { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info time_char_table[] = --{ -- /* C89 conversion specifiers. */ -- { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" }, -- { "cx", 0, STD_C89, NOLENGTHS, "E", "3" }, -- { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "" }, -- { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o" }, -- { "p", 0, STD_C89, NOLENGTHS, "#", "" }, -- { "X", 0, STD_C89, NOLENGTHS, "E", "" }, -- { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4" }, -- { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o" }, -- { "%", 0, STD_C89, NOLENGTHS, "", "" }, -- /* C99 conversion specifiers. */ -- { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o" }, -- { "D", 0, STD_C99, NOLENGTHS, "", "2" }, -- { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "" }, -- { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "" }, -- { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o" }, -- { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o" }, -- { "h", 0, STD_C99, NOLENGTHS, "^#", "" }, -- { "z", 0, STD_C99, NOLENGTHS, "O", "o" }, -- /* GNU conversion specifiers. */ -- { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "" }, -- { "P", 0, STD_EXT, NOLENGTHS, "", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- --static const format_char_info monetary_char_table[] = --{ -- { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "" }, -- { NULL, 0, 0, NOLENGTHS, NULL, NULL } --}; -- -- --/* This must be in the same order as enum format_type. */ --static const format_kind_info format_types_orig[] = --{ -- { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL, -- printf_flag_specs, printf_flag_pairs, -- FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, -- 'w', 0, 'p', 0, 'L', -- &integer_type_node, &integer_type_node -- }, -- { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, -- asm_fprintf_flag_specs, asm_fprintf_flag_pairs, -- FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, -- 'w', 0, 'p', 0, 'L', -- NULL, NULL -- }, -- { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "", NULL, -- gcc_diag_flag_specs, gcc_diag_flag_pairs, -- FMT_FLAG_ARG_CONVERT, -- 0, 0, 'p', 0, 'L', -- NULL, &integer_type_node -- }, -- { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "", NULL, -- gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, -- FMT_FLAG_ARG_CONVERT, -- 0, 0, 'p', 0, 'L', -- NULL, &integer_type_node -- }, -- { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "+#", NULL, -- gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, -- FMT_FLAG_ARG_CONVERT, -- 0, 0, 'p', 0, 'L', -- NULL, &integer_type_node -- }, -- { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, -- scanf_flag_specs, scanf_flag_pairs, -- FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK, -- 'w', 0, 0, '*', 'L', -- NULL, NULL -- }, -- { "strftime", NULL, time_char_table, "_-0^#", "EO", -- strftime_flag_specs, strftime_flag_pairs, -- FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, -- NULL, NULL -- }, -- { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, -- strfmon_flag_specs, strfmon_flag_pairs, -- FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', -- NULL, NULL -- } --}; -- --/* This layer of indirection allows GCC to reassign format_types with -- new data if necessary, while still allowing the original data to be -- const. */ --static const format_kind_info *format_types = format_types_orig; --/* We can modify this one. */ --static format_kind_info *dynamic_format_types; -- --/* Structure detailing the results of checking a format function call -- where the format expression may be a conditional expression with -- many leaves resulting from nested conditional expressions. */ --typedef struct --{ -- /* Number of leaves of the format argument that could not be checked -- as they were not string literals. */ -- int number_non_literal; -- /* Number of leaves of the format argument that were null pointers or -- string literals, but had extra format arguments. */ -- int number_extra_args; -- /* Number of leaves of the format argument that were null pointers or -- string literals, but had extra format arguments and used $ operand -- numbers. */ -- int number_dollar_extra_args; -- /* Number of leaves of the format argument that were wide string -- literals. */ -- int number_wide; -- /* Number of leaves of the format argument that were empty strings. */ -- int number_empty; -- /* Number of leaves of the format argument that were unterminated -- strings. */ -- int number_unterminated; -- /* Number of leaves of the format argument that were not counted above. */ -- int number_other; --} format_check_results; -- --typedef struct --{ -- format_check_results *res; -- function_format_info *info; -- tree params; -- int *status; --} format_check_context; -- --static void check_format_info (int *, function_format_info *, tree); --static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); --static void check_format_info_main (int *, format_check_results *, -- function_format_info *, -- const char *, int, tree, -- unsigned HOST_WIDE_INT); --static void status_warning (int *, const char *, ...) -- ATTRIBUTE_PRINTF_2; -- --static void init_dollar_format_checking (int, tree); --static int maybe_read_dollar_number (int *, const char **, int, -- tree, tree *, const format_kind_info *); --static void finish_dollar_format_checking (int *, format_check_results *, int); -- --static const format_flag_spec *get_flag_spec (const format_flag_spec *, -- int, const char *); -- --static void check_format_types (int *, format_wanted_type *); -- --/* Decode a format type from a string, returning the type, or -- format_type_error if not valid, in which case the caller should print an -- error message. */ --static enum format_type --decode_format_type (const char *s) --{ -- int i; -- int slen; -- slen = strlen (s); -- for (i = 0; i < (int) format_type_error; i++) -- { -- int alen; -- if (!strcmp (s, format_types[i].name)) -- break; -- alen = strlen (format_types[i].name); -- if (slen == alen + 4 && s[0] == '_' && s[1] == '_' -- && s[slen - 1] == '_' && s[slen - 2] == '_' -- && !strncmp (s + 2, format_types[i].name, alen)) -- break; -- } -- return ((enum format_type) i); --} -- -- --/* Check the argument list of a call to printf, scanf, etc. -- ATTRS are the attributes on the function type. -- PARAMS is the list of argument values. Also, if -Wmissing-format-attribute, -- warn for calls to vprintf or vscanf in functions with no such format -- attribute themselves. */ -- --void --check_function_format (int *status, tree attrs, tree params) --{ -- tree a; -- -- /* See if this function has any format attributes. */ -- for (a = attrs; a; a = TREE_CHAIN (a)) -- { -- if (is_attribute_p ("format", TREE_PURPOSE (a))) -- { -- /* Yup; check it. */ -- function_format_info info; -- decode_format_attr (TREE_VALUE (a), &info, 1); -- check_format_info (status, &info, params); -- if (warn_missing_format_attribute && info.first_arg_num == 0 -- && (format_types[info.format_type].flags -- & (int) FMT_FLAG_ARG_CONVERT)) -- { -- tree c; -- for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); -- c; -- c = TREE_CHAIN (c)) -- if (is_attribute_p ("format", TREE_PURPOSE (c)) -- && (decode_format_type (IDENTIFIER_POINTER -- (TREE_VALUE (TREE_VALUE (c)))) -- == info.format_type)) -- break; -- if (c == NULL_TREE) -- { -- /* Check if the current function has a parameter to which -- the format attribute could be attached; if not, it -- can't be a candidate for a format attribute, despite -- the vprintf-like or vscanf-like call. */ -- tree args; -- for (args = DECL_ARGUMENTS (current_function_decl); -- args != 0; -- args = TREE_CHAIN (args)) -- { -- if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE -- && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) -- == char_type_node)) -- break; -- } -- if (args != 0) -- warning ("function might be possible candidate for `%s' format attribute", -- format_types[info.format_type].name); -- } -- } -- } -- } --} -- --/* This function replaces `warning' inside the printf format checking -- functions. If the `status' parameter is non-NULL, then it is -- dereferenced and set to 1 whenever a warning is caught. Otherwise -- it warns as usual by replicating the innards of the warning -- function from diagnostic.c. */ --static void --status_warning (int *status, const char *msgid, ...) --{ -- diagnostic_info diagnostic ; -- va_list ap; -- -- va_start (ap, msgid); -- -- if (status) -- *status = 1; -- else -- { -- /* This duplicates the warning function behavior. */ -- diagnostic_set_info (&diagnostic, _(msgid), &ap, -- input_location, DK_WARNING); -- report_diagnostic (&diagnostic); -- } -- -- va_end (ap); --} -- --/* Variables used by the checking of $ operand number formats. */ --static char *dollar_arguments_used = NULL; --static char *dollar_arguments_pointer_p = NULL; --static int dollar_arguments_alloc = 0; --static int dollar_arguments_count; --static int dollar_first_arg_num; --static int dollar_max_arg_used; --static int dollar_format_warned; -- --/* Initialize the checking for a format string that may contain $ -- parameter number specifications; we will need to keep track of whether -- each parameter has been used. FIRST_ARG_NUM is the number of the first -- argument that is a parameter to the format, or 0 for a vprintf-style -- function; PARAMS is the list of arguments starting at this argument. */ -- --static void --init_dollar_format_checking (int first_arg_num, tree params) --{ -- tree oparams = params; -- -- dollar_first_arg_num = first_arg_num; -- dollar_arguments_count = 0; -- dollar_max_arg_used = 0; -- dollar_format_warned = 0; -- if (first_arg_num > 0) -- { -- while (params) -- { -- dollar_arguments_count++; -- params = TREE_CHAIN (params); -- } -- } -- if (dollar_arguments_alloc < dollar_arguments_count) -- { -- if (dollar_arguments_used) -- free (dollar_arguments_used); -- if (dollar_arguments_pointer_p) -- free (dollar_arguments_pointer_p); -- dollar_arguments_alloc = dollar_arguments_count; -- dollar_arguments_used = xmalloc (dollar_arguments_alloc); -- dollar_arguments_pointer_p = xmalloc (dollar_arguments_alloc); -- } -- if (dollar_arguments_alloc) -- { -- memset (dollar_arguments_used, 0, dollar_arguments_alloc); -- if (first_arg_num > 0) -- { -- int i = 0; -- params = oparams; -- while (params) -- { -- dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params))) -- == POINTER_TYPE); -- params = TREE_CHAIN (params); -- i++; -- } -- } -- } --} -- -- --/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED -- is set, it is an error if one is not found; otherwise, it is OK. If -- such a number is found, check whether it is within range and mark that -- numbered operand as being used for later checking. Returns the operand -- number if found and within range, zero if no such number was found and -- this is OK, or -1 on error. PARAMS points to the first operand of the -- format; PARAM_PTR is made to point to the parameter referred to. If -- a $ format is found, *FORMAT is updated to point just after it. */ -- --static int --maybe_read_dollar_number (int *status, const char **format, -- int dollar_needed, tree params, tree *param_ptr, -- const format_kind_info *fki) --{ -- int argnum; -- int overflow_flag; -- const char *fcp = *format; -- if (! ISDIGIT (*fcp)) -- { -- if (dollar_needed) -- { -- status_warning (status, "missing $ operand number in format"); -- return -1; -- } -- else -- return 0; -- } -- argnum = 0; -- overflow_flag = 0; -- while (ISDIGIT (*fcp)) -- { -- int nargnum; -- nargnum = 10 * argnum + (*fcp - '0'); -- if (nargnum < 0 || nargnum / 10 != argnum) -- overflow_flag = 1; -- argnum = nargnum; -- fcp++; -- } -- if (*fcp != '$') -- { -- if (dollar_needed) -- { -- status_warning (status, "missing $ operand number in format"); -- return -1; -- } -- else -- return 0; -- } -- *format = fcp + 1; -- if (pedantic && !dollar_format_warned) -- { -- status_warning (status, -- "%s does not support %%n$ operand number formats", -- C_STD_NAME (STD_EXT)); -- dollar_format_warned = 1; -- } -- if (overflow_flag || argnum == 0 -- || (dollar_first_arg_num && argnum > dollar_arguments_count)) -- { -- status_warning (status, "operand number out of range in format"); -- return -1; -- } -- if (argnum > dollar_max_arg_used) -- dollar_max_arg_used = argnum; -- /* For vprintf-style functions we may need to allocate more memory to -- track which arguments are used. */ -- while (dollar_arguments_alloc < dollar_max_arg_used) -- { -- int nalloc; -- nalloc = 2 * dollar_arguments_alloc + 16; -- dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc); -- dollar_arguments_pointer_p = xrealloc (dollar_arguments_pointer_p, -- nalloc); -- memset (dollar_arguments_used + dollar_arguments_alloc, 0, -- nalloc - dollar_arguments_alloc); -- dollar_arguments_alloc = nalloc; -- } -- if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE) -- && dollar_arguments_used[argnum - 1] == 1) -- { -- dollar_arguments_used[argnum - 1] = 2; -- status_warning (status, -- "format argument %d used more than once in %s format", -- argnum, fki->name); -- } -- else -- dollar_arguments_used[argnum - 1] = 1; -- if (dollar_first_arg_num) -- { -- int i; -- *param_ptr = params; -- for (i = 1; i < argnum && *param_ptr != 0; i++) -- *param_ptr = TREE_CHAIN (*param_ptr); -- -- if (*param_ptr == 0) -- { -- /* This case shouldn't be caught here. */ -- abort (); -- } -- } -- else -- *param_ptr = 0; -- return argnum; --} -- -- --/* Finish the checking for a format string that used $ operand number formats -- instead of non-$ formats. We check for unused operands before used ones -- (a serious error, since the implementation of the format function -- can't know what types to pass to va_arg to find the later arguments). -- and for unused operands at the end of the format (if we know how many -- arguments the format had, so not for vprintf). If there were operand -- numbers out of range on a non-vprintf-style format, we won't have reached -- here. If POINTER_GAP_OK, unused arguments are OK if all arguments are -- pointers. */ -- --static void --finish_dollar_format_checking (int *status, format_check_results *res, int pointer_gap_ok) --{ -- int i; -- bool found_pointer_gap = false; -- for (i = 0; i < dollar_max_arg_used; i++) -- { -- if (!dollar_arguments_used[i]) -- { -- if (pointer_gap_ok && (dollar_first_arg_num == 0 -- || dollar_arguments_pointer_p[i])) -- found_pointer_gap = true; -- else -- status_warning (status, "format argument %d unused before used argument %d in $-style format", -- i + 1, dollar_max_arg_used); -- } -- } -- if (found_pointer_gap -- || (dollar_first_arg_num -- && dollar_max_arg_used < dollar_arguments_count)) -- { -- res->number_other--; -- res->number_dollar_extra_args++; -- } --} -- -- --/* Retrieve the specification for a format flag. SPEC contains the -- specifications for format flags for the applicable kind of format. -- FLAG is the flag in question. If PREDICATES is NULL, the basic -- spec for that flag must be retrieved and this function aborts if -- it cannot be found. If PREDICATES is not NULL, it is a string listing -- possible predicates for the spec entry; if an entry predicated on any -- of these is found, it is returned, otherwise NULL is returned. */ -- --static const format_flag_spec * --get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) --{ -- int i; -- for (i = 0; spec[i].flag_char != 0; i++) -- { -- if (spec[i].flag_char != flag) -- continue; -- if (predicates != NULL) -- { -- if (spec[i].predicate != 0 -- && strchr (predicates, spec[i].predicate) != 0) -- return &spec[i]; -- } -- else if (spec[i].predicate == 0) -- return &spec[i]; -- } -- if (predicates == NULL) -- abort (); -- else -- return NULL; --} -- -- --/* Check the argument list of a call to printf, scanf, etc. -- INFO points to the function_format_info structure. -- PARAMS is the list of argument values. */ -- --static void --check_format_info (int *status, function_format_info *info, tree params) --{ -- format_check_context format_ctx; -- unsigned HOST_WIDE_INT arg_num; -- tree format_tree; -- format_check_results res; -- /* Skip to format argument. If the argument isn't available, there's -- no work for us to do; prototype checking will catch the problem. */ -- for (arg_num = 1; ; ++arg_num) -- { -- if (params == 0) -- return; -- if (arg_num == info->format_num) -- break; -- params = TREE_CHAIN (params); -- } -- format_tree = TREE_VALUE (params); -- params = TREE_CHAIN (params); -- if (format_tree == 0) -- return; -- -- res.number_non_literal = 0; -- res.number_extra_args = 0; -- res.number_dollar_extra_args = 0; -- res.number_wide = 0; -- res.number_empty = 0; -- res.number_unterminated = 0; -- res.number_other = 0; -- -- format_ctx.res = &res; -- format_ctx.info = info; -- format_ctx.params = params; -- format_ctx.status = status; -- -- check_function_arguments_recurse (check_format_arg, &format_ctx, -- format_tree, arg_num); -- -- if (res.number_non_literal > 0) -- { -- /* Functions taking a va_list normally pass a non-literal format -- string. These functions typically are declared with -- first_arg_num == 0, so avoid warning in those cases. */ -- if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) -- { -- /* For strftime-like formats, warn for not checking the format -- string; but there are no arguments to check. */ -- if (warn_format_nonliteral) -- status_warning (status, "format not a string literal, format string not checked"); -- } -- else if (info->first_arg_num != 0) -- { -- /* If there are no arguments for the format at all, we may have -- printf (foo) which is likely to be a security hole. */ -- while (arg_num + 1 < info->first_arg_num) -- { -- if (params == 0) -- break; -- params = TREE_CHAIN (params); -- ++arg_num; -- } -- if (params == 0 && (warn_format_nonliteral || warn_format_security)) -- status_warning (status, "format not a string literal and no format arguments"); -- else if (warn_format_nonliteral) -- status_warning (status, "format not a string literal, argument types not checked"); -- } -- } -- -- /* If there were extra arguments to the format, normally warn. However, -- the standard does say extra arguments are ignored, so in the specific -- case where we have multiple leaves (conditional expressions or -- ngettext) allow extra arguments if at least one leaf didn't have extra -- arguments, but was otherwise OK (either non-literal or checked OK). -- If the format is an empty string, this should be counted similarly to the -- case of extra format arguments. */ -- if (res.number_extra_args > 0 && res.number_non_literal == 0 -- && res.number_other == 0 && warn_format_extra_args) -- status_warning (status, "too many arguments for format"); -- if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 -- && res.number_other == 0 && warn_format_extra_args) -- status_warning (status, "unused arguments in $-style format"); -- if (res.number_empty > 0 && res.number_non_literal == 0 -- && res.number_other == 0 && warn_format_zero_length) -- status_warning (status, "zero-length %s format string", -- format_types[info->format_type].name); -- -- if (res.number_wide > 0) -- status_warning (status, "format is a wide character string"); -- -- if (res.number_unterminated > 0) -- status_warning (status, "unterminated format string"); --} -- --/* Callback from check_function_arguments_recurse to check a -- format string. FORMAT_TREE is the format parameter. ARG_NUM -- is the number of the format argument. CTX points to a -- format_check_context. */ -- --static void --check_format_arg (void *ctx, tree format_tree, -- unsigned HOST_WIDE_INT arg_num) --{ -- format_check_context *format_ctx = ctx; -- format_check_results *res = format_ctx->res; -- function_format_info *info = format_ctx->info; -- tree params = format_ctx->params; -- int *status = format_ctx->status; -- -- int format_length; -- HOST_WIDE_INT offset; -- const char *format_chars; -- tree array_size = 0; -- tree array_init; -- -- if (integer_zerop (format_tree)) -- { -- /* Skip to first argument to check, so we can see if this format -- has any arguments (it shouldn't). */ -- while (arg_num + 1 < info->first_arg_num) -- { -- if (params == 0) -- return; -- params = TREE_CHAIN (params); -- ++arg_num; -- } -- -- if (params == 0) -- res->number_other++; -- else -- res->number_extra_args++; -- -- return; -- } -- -- offset = 0; -- if (TREE_CODE (format_tree) == PLUS_EXPR) -- { -- tree arg0, arg1; -- -- arg0 = TREE_OPERAND (format_tree, 0); -- arg1 = TREE_OPERAND (format_tree, 1); -- STRIP_NOPS (arg0); -- STRIP_NOPS (arg1); -- if (TREE_CODE (arg1) == INTEGER_CST) -- format_tree = arg0; -- else if (TREE_CODE (arg0) == INTEGER_CST) -- { -- format_tree = arg1; -- arg1 = arg0; -- } -- else -- { -- res->number_non_literal++; -- return; -- } -- if (!host_integerp (arg1, 0) -- || (offset = tree_low_cst (arg1, 0)) < 0) -- { -- res->number_non_literal++; -- return; -- } -- } -- if (TREE_CODE (format_tree) != ADDR_EXPR) -- { -- res->number_non_literal++; -- return; -- } -- format_tree = TREE_OPERAND (format_tree, 0); -- if (TREE_CODE (format_tree) == VAR_DECL -- && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE -- && (array_init = decl_constant_value (format_tree)) != format_tree -- && TREE_CODE (array_init) == STRING_CST) -- { -- /* Extract the string constant initializer. Note that this may include -- a trailing NUL character that is not in the array (e.g. -- const char a[3] = "foo";). */ -- array_size = DECL_SIZE_UNIT (format_tree); -- format_tree = array_init; -- } -- if (TREE_CODE (format_tree) != STRING_CST) -- { -- res->number_non_literal++; -- return; -- } -- if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node) -- { -- res->number_wide++; -- return; -- } -- format_chars = TREE_STRING_POINTER (format_tree); -- format_length = TREE_STRING_LENGTH (format_tree); -- if (array_size != 0) -- { -- /* Variable length arrays can't be initialized. */ -- if (TREE_CODE (array_size) != INTEGER_CST) -- abort (); -- if (host_integerp (array_size, 0)) -- { -- HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); -- if (array_size_value > 0 -- && array_size_value == (int) array_size_value -- && format_length > array_size_value) -- format_length = array_size_value; -- } -- } -- if (offset) -- { -- if (offset >= format_length) -- { -- res->number_non_literal++; -- return; -- } -- format_chars += offset; -- format_length -= offset; -- } -- if (format_length < 1) -- { -- res->number_unterminated++; -- return; -- } -- if (format_length == 1) -- { -- res->number_empty++; -- return; -- } -- if (format_chars[--format_length] != 0) -- { -- res->number_unterminated++; -- return; -- } -- -- /* Skip to first argument to check. */ -- while (arg_num + 1 < info->first_arg_num) -- { -- if (params == 0) -- return; -- params = TREE_CHAIN (params); -- ++arg_num; -- } -- /* Provisionally increment res->number_other; check_format_info_main -- will decrement it if it finds there are extra arguments, but this way -- need not adjust it for every return. */ -- res->number_other++; -- check_format_info_main (status, res, info, format_chars, format_length, -- params, arg_num); --} -- -- --/* Do the main part of checking a call to a format function. FORMAT_CHARS -- is the NUL-terminated format string (which at this point may contain -- internal NUL characters); FORMAT_LENGTH is its length (excluding the -- terminating NUL character). ARG_NUM is one less than the number of -- the first format argument to check; PARAMS points to that format -- argument in the list of arguments. */ -- --static void --check_format_info_main (int *status, format_check_results *res, -- function_format_info *info, const char *format_chars, -- int format_length, tree params, -- unsigned HOST_WIDE_INT arg_num) --{ -- const char *orig_format_chars = format_chars; -- tree first_fillin_param = params; -- -- const format_kind_info *fki = &format_types[info->format_type]; -- const format_flag_spec *flag_specs = fki->flag_specs; -- const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs; -- -- /* -1 if no conversions taking an operand have been found; 0 if one has -- and it didn't use $; 1 if $ formats are in use. */ -- int has_operand_number = -1; -- -- init_dollar_format_checking (info->first_arg_num, first_fillin_param); -- -- while (1) -- { -- int i; -- int suppressed = FALSE; -- const char *length_chars = NULL; -- enum format_lengths length_chars_val = FMT_LEN_none; -- enum format_std_version length_chars_std = STD_C89; -- int format_char; -- tree cur_param; -- tree wanted_type; -- int main_arg_num = 0; -- tree main_arg_params = 0; -- enum format_std_version wanted_type_std; -- const char *wanted_type_name; -- format_wanted_type width_wanted_type; -- format_wanted_type precision_wanted_type; -- format_wanted_type main_wanted_type; -- format_wanted_type *first_wanted_type = NULL; -- format_wanted_type *last_wanted_type = NULL; -- const format_length_info *fli = NULL; -- const format_char_info *fci = NULL; -- char flag_chars[256]; -- int aflag = 0; -- if (*format_chars == 0) -- { -- if (format_chars - orig_format_chars != format_length) -- status_warning (status, "embedded `\\0' in format"); -- if (info->first_arg_num != 0 && params != 0 -- && has_operand_number <= 0) -- { -- res->number_other--; -- res->number_extra_args++; -- } -- if (has_operand_number > 0) -- finish_dollar_format_checking (status, res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); -- return; -- } -- if (*format_chars++ != '%') -- continue; -- if (*format_chars == 0) -- { -- status_warning (status, "spurious trailing `%%' in format"); -- continue; -- } -- if (*format_chars == '%') -- { -- ++format_chars; -- continue; -- } -- flag_chars[0] = 0; -- -- if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0) -- { -- /* Possibly read a $ operand number at the start of the format. -- If one was previously used, one is required here. If one -- is not used here, we can't immediately conclude this is a -- format without them, since it could be printf %m or scanf %*. */ -- int opnum; -- opnum = maybe_read_dollar_number (status, &format_chars, 0, -- first_fillin_param, -- &main_arg_params, fki); -- if (opnum == -1) -- return; -- else if (opnum > 0) -- { -- has_operand_number = 1; -- main_arg_num = opnum + info->first_arg_num - 1; -- } -- } -- -- /* Read any format flags, but do not yet validate them beyond removing -- duplicates, since in general validation depends on the rest of -- the format. */ -- while (*format_chars != 0 -- && strchr (fki->flag_chars, *format_chars) != 0) -- { -- const format_flag_spec *s = get_flag_spec (flag_specs, -- *format_chars, NULL); -- if (strchr (flag_chars, *format_chars) != 0) -- { -- status_warning (status, "repeated %s in format", _(s->name)); -- } -- else -- { -- i = strlen (flag_chars); -- flag_chars[i++] = *format_chars; -- flag_chars[i] = 0; -- } -- if (s->skip_next_char) -- { -- ++format_chars; -- if (*format_chars == 0) -- { -- status_warning (status, "missing fill character at end of strfmon format"); -- return; -- } -- } -- ++format_chars; -- } -- -- /* Read any format width, possibly * or *m$. */ -- if (fki->width_char != 0) -- { -- if (fki->width_type != NULL && *format_chars == '*') -- { -- i = strlen (flag_chars); -- flag_chars[i++] = fki->width_char; -- flag_chars[i] = 0; -- /* "...a field width...may be indicated by an asterisk. -- In this case, an int argument supplies the field width..." */ -- ++format_chars; -- if (has_operand_number != 0) -- { -- int opnum; -- opnum = maybe_read_dollar_number (status, &format_chars, -- has_operand_number == 1, -- first_fillin_param, -- ¶ms, fki); -- if (opnum == -1) -- return; -- else if (opnum > 0) -- { -- has_operand_number = 1; -- arg_num = opnum + info->first_arg_num - 1; -- } -- else -- has_operand_number = 0; -- } -- if (info->first_arg_num != 0) -- { -- if (params == 0) -- { -- status_warning (status, "too few arguments for format"); -- return; -- } -- cur_param = TREE_VALUE (params); -- if (has_operand_number <= 0) -- { -- params = TREE_CHAIN (params); -- ++arg_num; -- } -- width_wanted_type.wanted_type = *fki->width_type; -- width_wanted_type.wanted_type_name = NULL; -- width_wanted_type.pointer_count = 0; -- width_wanted_type.char_lenient_flag = 0; -- width_wanted_type.writing_in_flag = 0; -- width_wanted_type.reading_from_flag = 0; -- width_wanted_type.name = _("field width"); -- width_wanted_type.param = cur_param; -- width_wanted_type.arg_num = arg_num; -- width_wanted_type.next = NULL; -- if (last_wanted_type != 0) -- last_wanted_type->next = &width_wanted_type; -- if (first_wanted_type == 0) -- first_wanted_type = &width_wanted_type; -- last_wanted_type = &width_wanted_type; -- } -- } -- else -- { -- /* Possibly read a numeric width. If the width is zero, -- we complain if appropriate. */ -- int non_zero_width_char = FALSE; -- int found_width = FALSE; -- while (ISDIGIT (*format_chars)) -- { -- found_width = TRUE; -- if (*format_chars != '0') -- non_zero_width_char = TRUE; -- ++format_chars; -- } -- if (found_width && !non_zero_width_char && -- (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) -- status_warning (status, "zero width in %s format", -- fki->name); -- if (found_width) -- { -- i = strlen (flag_chars); -- flag_chars[i++] = fki->width_char; -- flag_chars[i] = 0; -- } -- } -- } -- -- /* Read any format left precision (must be a number, not *). */ -- if (fki->left_precision_char != 0 && *format_chars == '#') -- { -- ++format_chars; -- i = strlen (flag_chars); -- flag_chars[i++] = fki->left_precision_char; -- flag_chars[i] = 0; -- if (!ISDIGIT (*format_chars)) -- status_warning (status, "empty left precision in %s format", -- fki->name); -- while (ISDIGIT (*format_chars)) -- ++format_chars; -- } -- -- /* Read any format precision, possibly * or *m$. */ -- if (fki->precision_char != 0 && *format_chars == '.') -- { -- ++format_chars; -- i = strlen (flag_chars); -- flag_chars[i++] = fki->precision_char; -- flag_chars[i] = 0; -- if (fki->precision_type != NULL && *format_chars == '*') -- { -- /* "...a...precision...may be indicated by an asterisk. -- In this case, an int argument supplies the...precision." */ -- ++format_chars; -- if (has_operand_number != 0) -- { -- int opnum; -- opnum = maybe_read_dollar_number (status, &format_chars, -- has_operand_number == 1, -- first_fillin_param, -- ¶ms, fki); -- if (opnum == -1) -- return; -- else if (opnum > 0) -- { -- has_operand_number = 1; -- arg_num = opnum + info->first_arg_num - 1; -- } -- else -- has_operand_number = 0; -- } -- if (info->first_arg_num != 0) -- { -- if (params == 0) -- { -- status_warning (status, "too few arguments for format"); -- return; -- } -- cur_param = TREE_VALUE (params); -- if (has_operand_number <= 0) -- { -- params = TREE_CHAIN (params); -- ++arg_num; -- } -- precision_wanted_type.wanted_type = *fki->precision_type; -- precision_wanted_type.wanted_type_name = NULL; -- precision_wanted_type.pointer_count = 0; -- precision_wanted_type.char_lenient_flag = 0; -- precision_wanted_type.writing_in_flag = 0; -- precision_wanted_type.reading_from_flag = 0; -- precision_wanted_type.name = _("field precision"); -- precision_wanted_type.param = cur_param; -- precision_wanted_type.arg_num = arg_num; -- precision_wanted_type.next = NULL; -- if (last_wanted_type != 0) -- last_wanted_type->next = &precision_wanted_type; -- if (first_wanted_type == 0) -- first_wanted_type = &precision_wanted_type; -- last_wanted_type = &precision_wanted_type; -- } -- } -- else -- { -- if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) -- && !ISDIGIT (*format_chars)) -- status_warning (status, "empty precision in %s format", -- fki->name); -- while (ISDIGIT (*format_chars)) -- ++format_chars; -- } -- } -- -- /* Read any length modifier, if this kind of format has them. */ -- fli = fki->length_char_specs; -- length_chars = NULL; -- length_chars_val = FMT_LEN_none; -- length_chars_std = STD_C89; -- if (fli) -- { -- while (fli->name != 0 && fli->name[0] != *format_chars) -- fli++; -- if (fli->name != 0) -- { -- format_chars++; -- if (fli->double_name != 0 && fli->name[0] == *format_chars) -- { -- format_chars++; -- length_chars = fli->double_name; -- length_chars_val = fli->double_index; -- length_chars_std = fli->double_std; -- } -- else -- { -- length_chars = fli->name; -- length_chars_val = fli->index; -- length_chars_std = fli->std; -- } -- i = strlen (flag_chars); -- flag_chars[i++] = fki->length_code_char; -- flag_chars[i] = 0; -- } -- if (pedantic) -- { -- /* Warn if the length modifier is non-standard. */ -- if (ADJ_STD (length_chars_std) > C_STD_VER) -- status_warning (status, "%s does not support the `%s' %s length modifier", -- C_STD_NAME (length_chars_std), length_chars, -- fki->name); -- } -- } -- -- /* Read any modifier (strftime E/O). */ -- if (fki->modifier_chars != NULL) -- { -- while (*format_chars != 0 -- && strchr (fki->modifier_chars, *format_chars) != 0) -- { -- if (strchr (flag_chars, *format_chars) != 0) -- { -- const format_flag_spec *s = get_flag_spec (flag_specs, -- *format_chars, NULL); -- status_warning (status, "repeated %s in format", _(s->name)); -- } -- else -- { -- i = strlen (flag_chars); -- flag_chars[i++] = *format_chars; -- flag_chars[i] = 0; -- } -- ++format_chars; -- } -- } -- -- /* Handle the scanf allocation kludge. */ -- if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) -- { -- if (*format_chars == 'a' && !flag_isoc99) -- { -- if (format_chars[1] == 's' || format_chars[1] == 'S' -- || format_chars[1] == '[') -- { -- /* `a' is used as a flag. */ -- i = strlen (flag_chars); -- flag_chars[i++] = 'a'; -- flag_chars[i] = 0; -- format_chars++; -- } -- } -- } -- -- format_char = *format_chars; -- if (format_char == 0 -- || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) -- && format_char == '%')) -- { -- status_warning (status, "conversion lacks type at end of format"); -- continue; -- } -- format_chars++; -- fci = fki->conversion_specs; -- while (fci->format_chars != 0 -- && strchr (fci->format_chars, format_char) == 0) -- ++fci; -- if (fci->format_chars == 0) -- { -- if (ISGRAPH(format_char)) -- status_warning (status, "unknown conversion type character `%c' in format", -- format_char); -- else -- status_warning (status, "unknown conversion type character 0x%x in format", -- format_char); -- continue; -- } -- if (pedantic) -- { -- if (ADJ_STD (fci->std) > C_STD_VER) -- status_warning (status, "%s does not support the `%%%c' %s format", -- C_STD_NAME (fci->std), format_char, fki->name); -- } -- -- /* Validate the individual flags used, removing any that are invalid. */ -- { -- int d = 0; -- for (i = 0; flag_chars[i] != 0; i++) -- { -- const format_flag_spec *s = get_flag_spec (flag_specs, -- flag_chars[i], NULL); -- flag_chars[i - d] = flag_chars[i]; -- if (flag_chars[i] == fki->length_code_char) -- continue; -- if (strchr (fci->flag_chars, flag_chars[i]) == 0) -- { -- status_warning (status, "%s used with `%%%c' %s format", -- _(s->name), format_char, fki->name); -- d++; -- continue; -- } -- if (pedantic) -- { -- const format_flag_spec *t; -- if (ADJ_STD (s->std) > C_STD_VER) -- status_warning (status, "%s does not support %s", -- C_STD_NAME (s->std), _(s->long_name)); -- t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2); -- if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) -- { -- const char *long_name = (t->long_name != NULL -- ? t->long_name -- : s->long_name); -- if (ADJ_STD (t->std) > C_STD_VER) -- status_warning (status, "%s does not support %s with the `%%%c' %s format", -- C_STD_NAME (t->std), _(long_name), -- format_char, fki->name); -- } -- } -- } -- flag_chars[i - d] = 0; -- } -- -- if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) -- && strchr (flag_chars, 'a') != 0) -- aflag = 1; -- -- if (fki->suppression_char -- && strchr (flag_chars, fki->suppression_char) != 0) -- suppressed = 1; -- -- /* Validate the pairs of flags used. */ -- for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++) -- { -- const format_flag_spec *s, *t; -- if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0) -- continue; -- if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0) -- continue; -- if (bad_flag_pairs[i].predicate != 0 -- && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0) -- continue; -- s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL); -- t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL); -- if (bad_flag_pairs[i].ignored) -- { -- if (bad_flag_pairs[i].predicate != 0) -- status_warning (status, "%s ignored with %s and `%%%c' %s format", -- _(s->name), _(t->name), format_char, -- fki->name); -- else -- status_warning (status, "%s ignored with %s in %s format", -- _(s->name), _(t->name), fki->name); -- } -- else -- { -- if (bad_flag_pairs[i].predicate != 0) -- status_warning (status, "use of %s and %s together with `%%%c' %s format", -- _(s->name), _(t->name), format_char, -- fki->name); -- else -- status_warning (status, "use of %s and %s together in %s format", -- _(s->name), _(t->name), fki->name); -- } -- } -- -- /* Give Y2K warnings. */ -- if (warn_format_y2k) -- { -- int y2k_level = 0; -- if (strchr (fci->flags2, '4') != 0) -- if (strchr (flag_chars, 'E') != 0) -- y2k_level = 3; -- else -- y2k_level = 2; -- else if (strchr (fci->flags2, '3') != 0) -- y2k_level = 3; -- else if (strchr (fci->flags2, '2') != 0) -- y2k_level = 2; -- if (y2k_level == 3) -- status_warning (status, "`%%%c' yields only last 2 digits of year in some locales", -- format_char); -- else if (y2k_level == 2) -- status_warning (status, "`%%%c' yields only last 2 digits of year", format_char); -- } -- -- if (strchr (fci->flags2, '[') != 0) -- { -- /* Skip over scan set, in case it happens to have '%' in it. */ -- if (*format_chars == '^') -- ++format_chars; -- /* Find closing bracket; if one is hit immediately, then -- it's part of the scan set rather than a terminator. */ -- if (*format_chars == ']') -- ++format_chars; -- while (*format_chars && *format_chars != ']') -- ++format_chars; -- if (*format_chars != ']') -- /* The end of the format string was reached. */ -- status_warning (status, "no closing `]' for `%%[' format"); -- } -- -- wanted_type = 0; -- wanted_type_name = 0; -- if (fki->flags & (int) FMT_FLAG_ARG_CONVERT) -- { -- wanted_type = (fci->types[length_chars_val].type -- ? *fci->types[length_chars_val].type : 0); -- wanted_type_name = fci->types[length_chars_val].name; -- wanted_type_std = fci->types[length_chars_val].std; -- if (wanted_type == 0) -- { -- status_warning (status, "use of `%s' length modifier with `%c' type character", -- length_chars, format_char); -- /* Heuristic: skip one argument when an invalid length/type -- combination is encountered. */ -- arg_num++; -- if (params == 0) -- { -- status_warning (status, "too few arguments for format"); -- return; -- } -- params = TREE_CHAIN (params); -- continue; -- } -- else if (pedantic -- /* Warn if non-standard, provided it is more non-standard -- than the length and type characters that may already -- have been warned for. */ -- && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std) -- && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) -- { -- if (ADJ_STD (wanted_type_std) > C_STD_VER) -- status_warning (status, "%s does not support the `%%%s%c' %s format", -- C_STD_NAME (wanted_type_std), length_chars, -- format_char, fki->name); -- } -- } -- -- /* Finally. . .check type of argument against desired type! */ -- if (info->first_arg_num == 0) -- continue; -- if ((fci->pointer_count == 0 && wanted_type == void_type_node) -- || suppressed) -- { -- if (main_arg_num != 0) -- { -- if (suppressed) -- status_warning (status, "operand number specified with suppressed assignment"); -- else -- status_warning (status, "operand number specified for format taking no argument"); -- } -- } -- else -- { -- if (main_arg_num != 0) -- { -- arg_num = main_arg_num; -- params = main_arg_params; -- } -- else -- { -- ++arg_num; -- if (has_operand_number > 0) -- { -- status_warning (status, "missing $ operand number in format"); -- return; -- } -- else -- has_operand_number = 0; -- if (params == 0) -- { -- status_warning (status, "too few arguments for format"); -- return; -- } -- } -- cur_param = TREE_VALUE (params); -- params = TREE_CHAIN (params); -- main_wanted_type.wanted_type = wanted_type; -- main_wanted_type.wanted_type_name = wanted_type_name; -- main_wanted_type.pointer_count = fci->pointer_count + aflag; -- main_wanted_type.char_lenient_flag = 0; -- if (strchr (fci->flags2, 'c') != 0) -- main_wanted_type.char_lenient_flag = 1; -- main_wanted_type.writing_in_flag = 0; -- main_wanted_type.reading_from_flag = 0; -- if (aflag) -- main_wanted_type.writing_in_flag = 1; -- else -- { -- if (strchr (fci->flags2, 'W') != 0) -- main_wanted_type.writing_in_flag = 1; -- if (strchr (fci->flags2, 'R') != 0) -- main_wanted_type.reading_from_flag = 1; -- } -- main_wanted_type.name = NULL; -- main_wanted_type.param = cur_param; -- main_wanted_type.arg_num = arg_num; -- main_wanted_type.next = NULL; -- if (last_wanted_type != 0) -- last_wanted_type->next = &main_wanted_type; -- if (first_wanted_type == 0) -- first_wanted_type = &main_wanted_type; -- last_wanted_type = &main_wanted_type; -- } -- -- if (first_wanted_type != 0) -- check_format_types (status, first_wanted_type); -- -- } --} -- -- --/* Check the argument types from a single format conversion (possibly -- including width and precision arguments). */ --static void --check_format_types (int *status, format_wanted_type *types) --{ -- for (; types != 0; types = types->next) -- { -- tree cur_param; -- tree cur_type; -- tree orig_cur_type; -- tree wanted_type; -- int arg_num; -- int i; -- int char_type_flag; -- cur_param = types->param; -- cur_type = TREE_TYPE (cur_param); -- if (cur_type == error_mark_node) -- continue; -- char_type_flag = 0; -- wanted_type = types->wanted_type; -- arg_num = types->arg_num; -- -- /* The following should not occur here. */ -- if (wanted_type == 0) -- abort (); -- if (wanted_type == void_type_node && types->pointer_count == 0) -- abort (); -- -- if (types->pointer_count == 0) -- wanted_type = (*lang_hooks.types.type_promotes_to) (wanted_type); -- -- STRIP_NOPS (cur_param); -- -- /* Check the types of any additional pointer arguments -- that precede the "real" argument. */ -- for (i = 0; i < types->pointer_count; ++i) -- { -- if (TREE_CODE (cur_type) == POINTER_TYPE) -- { -- cur_type = TREE_TYPE (cur_type); -- if (cur_type == error_mark_node) -- break; -- -- /* Check for writing through a NULL pointer. */ -- if (types->writing_in_flag -- && i == 0 -- && cur_param != 0 -- && integer_zerop (cur_param)) -- status_warning (status, -- "writing through null pointer (arg %d)", -- arg_num); -- -- /* Check for reading through a NULL pointer. */ -- if (types->reading_from_flag -- && i == 0 -- && cur_param != 0 -- && integer_zerop (cur_param)) -- status_warning (status, -- "reading through null pointer (arg %d)", -- arg_num); -- -- if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) -- cur_param = TREE_OPERAND (cur_param, 0); -- else -- cur_param = 0; -- -- /* See if this is an attempt to write into a const type with -- scanf or with printf "%n". Note: the writing in happens -- at the first indirection only, if for example -- void * const * is passed to scanf %p; passing -- const void ** is simply passing an incompatible type. */ -- if (types->writing_in_flag -- && i == 0 -- && (TYPE_READONLY (cur_type) -- || (cur_param != 0 -- && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c' -- || (DECL_P (cur_param) -- && TREE_READONLY (cur_param)))))) -- status_warning (status, "writing into constant object (arg %d)", arg_num); -- -- /* If there are extra type qualifiers beyond the first -- indirection, then this makes the types technically -- incompatible. */ -- if (i > 0 -- && pedantic -- && (TYPE_READONLY (cur_type) -- || TYPE_VOLATILE (cur_type) -- || TYPE_RESTRICT (cur_type))) -- status_warning (status, "extra type qualifiers in format argument (arg %d)", -- arg_num); -- -- } -- else -- { -- if (types->pointer_count == 1) -- status_warning (status, "format argument is not a pointer (arg %d)", arg_num); -- else -- status_warning (status, "format argument is not a pointer to a pointer (arg %d)", arg_num); -- break; -- } -- } -- -- if (i < types->pointer_count) -- continue; -- -- orig_cur_type = cur_type; -- cur_type = TYPE_MAIN_VARIANT (cur_type); -- -- /* Check whether the argument type is a character type. This leniency -- only applies to certain formats, flagged with 'c'. -- */ -- if (types->char_lenient_flag) -- char_type_flag = (cur_type == char_type_node -- || cur_type == signed_char_type_node -- || cur_type == unsigned_char_type_node); -- -- /* Check the type of the "real" argument, if there's a type we want. */ -- if (wanted_type == cur_type) -- continue; -- /* If we want `void *', allow any pointer type. -- (Anything else would already have got a warning.) -- With -pedantic, only allow pointers to void and to character -- types. */ -- if (wanted_type == void_type_node -- && (!pedantic || (i == 1 && char_type_flag))) -- continue; -- /* Don't warn about differences merely in signedness, unless -- -pedantic. With -pedantic, warn if the type is a pointer -- target and not a character type, and for character types at -- a second level of indirection. */ -- if (TREE_CODE (wanted_type) == INTEGER_TYPE -- && TREE_CODE (cur_type) == INTEGER_TYPE -- && (! pedantic || i == 0 || (i == 1 && char_type_flag)) -- && (TREE_UNSIGNED (wanted_type) -- ? wanted_type == c_common_unsigned_type (cur_type) -- : wanted_type == c_common_signed_type (cur_type))) -- continue; -- /* Likewise, "signed char", "unsigned char" and "char" are -- equivalent but the above test won't consider them equivalent. */ -- if (wanted_type == char_type_node -- && (! pedantic || i < 2) -- && char_type_flag) -- continue; -- /* Now we have a type mismatch. */ -- { -- const char *this; -- const char *that; -- tree tmp; -- -- tmp = TYPE_NAME (wanted_type); -- if (TREE_CODE (tmp) == TYPE_DECL) -- tmp = DECL_NAME (tmp); -- this = IDENTIFIER_POINTER (tmp); -- -- that = 0; -- if (TYPE_NAME (orig_cur_type) != 0 -- && TREE_CODE (orig_cur_type) != INTEGER_TYPE -- && !(TREE_CODE (orig_cur_type) == POINTER_TYPE -- && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE)) -- { -- tmp = TYPE_NAME (orig_cur_type); -- if (TREE_CODE (tmp) == TYPE_DECL) -- tmp = DECL_NAME (tmp); -- if (tmp) -- that = IDENTIFIER_POINTER (tmp); -- } -- -- /* A nameless type can't possibly match what the format wants. -- So there will be a warning for it. -- Make up a string to describe vaguely what it is. */ -- if (that == 0) -- { -- if (TREE_CODE (orig_cur_type) == POINTER_TYPE) -- that = _("pointer"); -- else -- that = _("different type"); -- } -- -- /* Make the warning better in case of mismatch of int vs long. */ -- if (TREE_CODE (orig_cur_type) == INTEGER_TYPE -- && TREE_CODE (wanted_type) == INTEGER_TYPE -- && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type) -- && TYPE_NAME (orig_cur_type) != 0 -- && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL) -- that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type))); -- -- if (strcmp (this, that) != 0) -- { -- /* There may be a better name for the format, e.g. size_t, -- but we should allow for programs with a perverse typedef -- making size_t something other than what the compiler -- thinks. */ -- if (types->wanted_type_name != 0 -- && strcmp (types->wanted_type_name, that) != 0) -- this = types->wanted_type_name; -- if (types->name != 0) -- status_warning (status, "%s is not type %s (arg %d)", types->name, this, -- arg_num); -- else -- status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num); -- } -- } -- } --} -- --/* Given a format_char_info array FCI, and a character C, this function -- returns the index into the conversion_specs where that specifier's -- data is located. If the character isn't found it aborts. */ --static unsigned int --find_char_info_specifier_index (const format_char_info *fci, int c) --{ -- unsigned int i = 0; -- -- while (fci->format_chars) -- { -- if (strchr (fci->format_chars, c)) -- return i; -- i++; fci++; -- } -- -- /* We shouldn't be looking for a non-existent specifier. */ -- abort (); --} -- --/* Given a format_length_info array FLI, and a character C, this -- function returns the index into the conversion_specs where that -- modifier's data is located. If the character isn't found it -- aborts. */ --static unsigned int --find_length_info_modifier_index (const format_length_info *fli, int c) --{ -- unsigned int i = 0; -- -- while (fli->name) -- { -- if (strchr (fli->name, c)) -- return i; -- i++; fli++; -- } -- -- /* We shouldn't be looking for a non-existent modifier. */ -- abort (); --} -- --/* Determine the type of HOST_WIDE_INT in the code being compiled for -- use in GCC's __asm_fprintf__ custom format attribute. You must -- have set dynamic_format_types before calling this function. */ --static void --init_dynamic_asm_fprintf_info (void) --{ -- static tree hwi; -- -- if (!hwi) -- { -- format_length_info *new_asm_fprintf_length_specs; -- unsigned int i; -- -- /* Find the underlying type for HOST_WIDE_INT. For the %w -- length modifier to work, one must have issued: "typedef -- HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code -- prior to using that modifier. */ -- hwi = maybe_get_identifier ("__gcc_host_wide_int__"); -- if (!hwi) -- { -- error ("'__gcc_host_wide_int__' is not defined as a type"); -- return; -- } -- hwi = identifier_global_value (hwi); -- if (!hwi || TREE_CODE (hwi) != TYPE_DECL) -- { -- error ("'__gcc_host_wide_int__' is not defined as a type"); -- return; -- } -- hwi = DECL_ORIGINAL_TYPE (hwi); -- if (!hwi) -- abort (); -- if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) -- { -- error ("'__gcc_host_wide_int__' is not defined as 'long'" -- " or 'long long'"); -- return; -- } -- -- /* Create a new (writable) copy of asm_fprintf_length_specs. */ -- new_asm_fprintf_length_specs = xmemdup (asm_fprintf_length_specs, -- sizeof (asm_fprintf_length_specs), -- sizeof (asm_fprintf_length_specs)); -- -- /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ -- i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w'); -- if (hwi == long_integer_type_node) -- new_asm_fprintf_length_specs[i].index = FMT_LEN_l; -- else if (hwi == long_long_integer_type_node) -- new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; -- else -- abort (); -- -- /* Assign the new data for use. */ -- dynamic_format_types[asm_fprintf_format_type].length_char_specs = -- new_asm_fprintf_length_specs; -- } --} -- --/* Determine the types of "tree" and "location_t" in the code being -- compiled for use in GCC's diagnostic custom format attributes. You -- must have set dynamic_format_types before calling this function. */ --static void --init_dynamic_diag_info (void) --{ -- static tree t, loc, hwi; -- -- if (!loc || !t || !hwi) -- { -- static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci; -- static format_length_info *diag_ls; -- unsigned int i; -- -- /* For the GCC-diagnostics custom format specifiers to work, one -- must have declared `tree' and/or `location_t' prior to using -- those attributes. If we haven't seen these declarations then -- you shouldn't use the specifiers requiring these types. -- However we don't force a hard ICE because we may see only one -- or the other type. */ -- if ((loc = maybe_get_identifier ("location_t"))) -- { -- loc = identifier_global_value (loc); -- if (loc) -- { -- if (TREE_CODE (loc) != TYPE_DECL) -- { -- error ("'location_t' is not defined as a type"); -- loc = 0; -- } -- else -- loc = TREE_TYPE (loc); -- } -- } -- -- /* We need to grab the underlying `union tree_node' so peek into -- an extra type level. */ -- if ((t = maybe_get_identifier ("tree"))) -- { -- t = identifier_global_value (t); -- if (t) -- { -- if (TREE_CODE (t) != TYPE_DECL) -- { -- error ("'tree' is not defined as a type"); -- t = 0; -- } -- else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) -- { -- error ("'tree' is not defined as a pointer type"); -- t = 0; -- } -- else -- t = TREE_TYPE (TREE_TYPE (t)); -- } -- } -- -- /* Find the underlying type for HOST_WIDE_INT. For the %w -- length modifier to work, one must have issued: "typedef -- HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code -- prior to using that modifier. */ -- if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__"))) -- { -- hwi = identifier_global_value (hwi); -- if (hwi) -- { -- if (TREE_CODE (hwi) != TYPE_DECL) -- { -- error ("'__gcc_host_wide_int__' is not defined as a type"); -- hwi = 0; -- } -- else -- { -- hwi = DECL_ORIGINAL_TYPE (hwi); -- if (!hwi) -- abort (); -- if (hwi != long_integer_type_node -- && hwi != long_long_integer_type_node) -- { -- error ("'__gcc_host_wide_int__' is not defined" -- " as 'long' or 'long long'"); -- hwi = 0; -- } -- } -- } -- } -- -- /* Assign the new data for use. */ -- -- /* All the GCC diag formats use the same length specs. */ -- if (! diag_ls) -- dynamic_format_types[gcc_diag_format_type].length_char_specs = -- dynamic_format_types[gcc_cdiag_format_type].length_char_specs = -- dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs = -- diag_ls = xmemdup (gcc_diag_length_specs, -- sizeof (gcc_diag_length_specs), -- sizeof (gcc_diag_length_specs)); -- if (hwi) -- { -- /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ -- i = find_length_info_modifier_index (diag_ls, 'w'); -- if (hwi == long_integer_type_node) -- diag_ls[i].index = FMT_LEN_l; -- else if (hwi == long_long_integer_type_node) -- diag_ls[i].index = FMT_LEN_ll; -- else -- abort (); -- } -- -- /* Handle the __gcc_diag__ format specifics. */ -- if (! diag_fci) -- dynamic_format_types[gcc_diag_format_type].conversion_specs = -- diag_fci = xmemdup (gcc_diag_char_table, -- sizeof(gcc_diag_char_table), -- sizeof(gcc_diag_char_table)); -- if (loc) -- { -- i = find_char_info_specifier_index (diag_fci, 'H'); -- diag_fci[i].types[0].type = &loc; -- diag_fci[i].pointer_count = 1; -- } -- if (t) -- { -- i = find_char_info_specifier_index (diag_fci, 'J'); -- diag_fci[i].types[0].type = &t; -- diag_fci[i].pointer_count = 1; -- } -- -- /* Handle the __gcc_cdiag__ format specifics. */ -- if (! cdiag_fci) -- dynamic_format_types[gcc_cdiag_format_type].conversion_specs = -- cdiag_fci = xmemdup (gcc_cdiag_char_table, -- sizeof(gcc_cdiag_char_table), -- sizeof(gcc_cdiag_char_table)); -- if (loc) -- { -- i = find_char_info_specifier_index (cdiag_fci, 'H'); -- cdiag_fci[i].types[0].type = &loc; -- cdiag_fci[i].pointer_count = 1; -- } -- if (t) -- { -- /* All specifiers taking a tree share the same struct. */ -- i = find_char_info_specifier_index (cdiag_fci, 'D'); -- cdiag_fci[i].types[0].type = &t; -- cdiag_fci[i].pointer_count = 1; -- i = find_char_info_specifier_index (cdiag_fci, 'J'); -- cdiag_fci[i].types[0].type = &t; -- cdiag_fci[i].pointer_count = 1; -- } -- -- /* Handle the __gcc_cxxdiag__ format specifics. */ -- if (! cxxdiag_fci) -- dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs = -- cxxdiag_fci = xmemdup (gcc_cxxdiag_char_table, -- sizeof(gcc_cxxdiag_char_table), -- sizeof(gcc_cxxdiag_char_table)); -- if (loc) -- { -- i = find_char_info_specifier_index (cxxdiag_fci, 'H'); -- cxxdiag_fci[i].types[0].type = &loc; -- cxxdiag_fci[i].pointer_count = 1; -- } -- if (t) -- { -- /* All specifiers taking a tree share the same struct. */ -- i = find_char_info_specifier_index (cxxdiag_fci, 'D'); -- cxxdiag_fci[i].types[0].type = &t; -- cxxdiag_fci[i].pointer_count = 1; -- i = find_char_info_specifier_index (cxxdiag_fci, 'J'); -- cxxdiag_fci[i].types[0].type = &t; -- cxxdiag_fci[i].pointer_count = 1; -- } -- } --} -- --/* Handle a "format" attribute; arguments as in -- struct attribute_spec.handler. */ --tree --handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, -- int flags, bool *no_add_attrs) --{ -- tree type = *node; -- function_format_info info; -- tree argument; -- -- if (!decode_format_attr (args, &info, 0)) -- { -- *no_add_attrs = true; -- return NULL_TREE; -- } -- -- argument = TYPE_ARG_TYPES (type); -- if (argument) -- { -- if (!check_format_string (argument, info.format_num, flags, -- no_add_attrs)) -- return NULL_TREE; -- -- if (info.first_arg_num != 0) -- { -- unsigned HOST_WIDE_INT arg_num = 1; -- -- /* Verify that first_arg_num points to the last arg, -- the ... */ -- while (argument) -- arg_num++, argument = TREE_CHAIN (argument); -- -- if (arg_num != info.first_arg_num) -- { -- if (!(flags & (int) ATTR_FLAG_BUILT_IN)) -- error ("args to be formatted is not '...'"); -- *no_add_attrs = true; -- return NULL_TREE; -- } -- } -- } -- -- if (info.format_type == strftime_format_type && info.first_arg_num != 0) -- { -- error ("strftime formats cannot format arguments"); -- *no_add_attrs = true; -- return NULL_TREE; -- } -- -- /* If this is a custom GCC-internal format type, we have to -- initialize certain bits a runtime. */ -- if (info.format_type == asm_fprintf_format_type -- || info.format_type == gcc_diag_format_type -- || info.format_type == gcc_cdiag_format_type -- || info.format_type == gcc_cxxdiag_format_type) -- { -- /* Our first time through, we have to make sure that our -- format_type data is allocated dynamically and is modifiable. */ -- if (!dynamic_format_types) -- format_types = dynamic_format_types = -- xmemdup (format_types_orig, sizeof (format_types_orig), -- sizeof (format_types_orig)); -- -- /* If this is format __asm_fprintf__, we have to initialize -- GCC's notion of HOST_WIDE_INT for checking %wd. */ -- if (info.format_type == asm_fprintf_format_type) -- init_dynamic_asm_fprintf_info(); -- /* If this is one of the diagnostic attributes, then we have to -- initialize `location_t' and `tree' at runtime. */ -- else if (info.format_type == gcc_diag_format_type -- || info.format_type == gcc_cdiag_format_type -- || info.format_type == gcc_cxxdiag_format_type) -- init_dynamic_diag_info(); -- else -- abort(); -- } -- -- return NULL_TREE; --} -diff -ruN gcc-3.4.5-20060117-1/gcc/c-incpath.c.orig gcc-3.4.5-20060117-1-winelf/gcc/c-incpath.c.orig ---- gcc-3.4.5-20060117-1/gcc/c-incpath.c.orig 2004-05-31 03:37:47.000000000 -0700 -+++ gcc-3.4.5-20060117-1-winelf/gcc/c-incpath.c.orig 1969-12-31 16:00:00.000000000 -0800 -@@ -1,364 +0,0 @@ --/* Set up combined include path chain for the preprocessor. -- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -- -- Broken out of cppinit.c and cppfiles.c and rewritten Mar 2003. -- --This program is free software; you can redistribute it and/or modify it --under the terms of the GNU General Public License as published by the --Free Software Foundation; either version 2, or (at your option) any --later version. -- --This program is distributed in the hope that it will be useful, --but WITHOUT ANY WARRANTY; without even the implied warranty of --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --GNU General Public License for more details. -- --You should have received a copy of the GNU General Public License --along with this program; if not, write to the Free Software --Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -- --#include "config.h" --#include "system.h" --#include "coretypes.h" --#include "tm.h" --#include "cpplib.h" --#include "prefix.h" --#include "intl.h" --#include "c-incpath.h" --#include "cppdefault.h" -- --/* Windows does not natively support inodes, and neither does MSDOS. -- Cygwin's emulation can generate non-unique inodes, so don't use it. -- VMS has non-numeric inodes. */ --#ifdef VMS --# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A))) --# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC)) --#else --# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__ --# define INO_T_EQ(A, B) 0 --# else --# define INO_T_EQ(A, B) ((A) == (B)) --# endif --# define INO_T_COPY(DEST, SRC) (DEST) = (SRC) --#endif -- --static void add_env_var_paths (const char *, int); --static void add_standard_paths (const char *, const char *, int); --static void free_path (struct cpp_dir *, int); --static void merge_include_chains (cpp_reader *, int); --static struct cpp_dir *remove_duplicates (cpp_reader *, struct cpp_dir *, -- struct cpp_dir *, -- struct cpp_dir *, int); -- --/* Include chains heads and tails. */ --static struct cpp_dir *heads[4]; --static struct cpp_dir *tails[4]; --static bool quote_ignores_source_dir; --enum { REASON_QUIET = 0, REASON_NOENT, REASON_DUP, REASON_DUP_SYS }; -- --/* Free an element of the include chain, possibly giving a reason. */ --static void --free_path (struct cpp_dir *path, int reason) --{ -- switch (reason) -- { -- case REASON_DUP: -- case REASON_DUP_SYS: -- fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), path->name); -- if (reason == REASON_DUP_SYS) -- fprintf (stderr, -- _(" as it is a non-system directory that duplicates a system directory\n")); -- break; -- -- case REASON_NOENT: -- fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), -- path->name); -- break; -- -- case REASON_QUIET: -- default: -- break; -- } -- -- free (path->name); -- free (path); --} -- --/* Read ENV_VAR for a PATH_SEPARATOR-separated list of file names; and -- append all the names to the search path CHAIN. */ --static void --add_env_var_paths (const char *env_var, int chain) --{ -- char *p, *q, *path; -- -- GET_ENVIRONMENT (q, env_var); -- -- if (!q) -- return; -- -- for (p = q; *q; p = q + 1) -- { -- q = p; -- while (*q != 0 && *q != PATH_SEPARATOR) -- q++; -- -- if (p == q) -- path = xstrdup ("."); -- else -- { -- path = xmalloc (q - p + 1); -- memcpy (path, p, q - p); -- path[q - p] = '\0'; -- } -- -- add_path (path, chain, chain == SYSTEM); -- } --} -- --/* Append the standard include chain defined in cppdefault.c. */ --static void --add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc) --{ -- const struct default_include *p; -- size_t len; -- -- if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0) -- { -- /* Look for directories that start with the standard prefix. -- "Translate" them, ie. replace /usr/local/lib/gcc... with -- IPREFIX and search them first. */ -- for (p = cpp_include_defaults; p->fname; p++) -- { -- if (!p->cplusplus || cxx_stdinc) -- { -- /* Should we be translating sysrooted dirs too? Assume -- that iprefix and sysroot are mutually exclusive, for -- now. */ -- if (sysroot && p->add_sysroot) -- continue; -- if (!strncmp (p->fname, cpp_GCC_INCLUDE_DIR, len)) -- { -- char *str = concat (iprefix, p->fname + len, NULL); -- add_path (str, SYSTEM, p->cxx_aware); -- } -- } -- } -- } -- -- for (p = cpp_include_defaults; p->fname; p++) -- { -- if (!p->cplusplus || cxx_stdinc) -- { -- char *str; -- -- /* Should this directory start with the sysroot? */ -- if (sysroot && p->add_sysroot) -- str = concat (sysroot, p->fname, NULL); -- else -- str = update_path (p->fname, p->component); -- -- add_path (str, SYSTEM, p->cxx_aware); -- } -- } --} -- --/* For each duplicate path in chain HEAD, keep just the first one. -- Remove each path in chain HEAD that also exists in chain SYSTEM. -- Set the NEXT pointer of the last path in the resulting chain to -- JOIN, unless it duplicates JOIN in which case the last path is -- removed. Return the head of the resulting chain. Any of HEAD, -- JOIN and SYSTEM can be NULL. */ --static struct cpp_dir * --remove_duplicates (cpp_reader *pfile, struct cpp_dir *head, -- struct cpp_dir *system, struct cpp_dir *join, -- int verbose) --{ -- struct cpp_dir **pcur, *tmp, *cur; -- struct stat st; -- -- for (pcur = &head; *pcur; ) -- { -- int reason = REASON_QUIET; -- -- cur = *pcur; -- -- if (stat (cur->name, &st)) -- { -- /* Dirs that don't exist are silently ignored, unless verbose. */ -- if (errno != ENOENT) -- cpp_errno (pfile, CPP_DL_ERROR, cur->name); -- else -- reason = REASON_NOENT; -- } -- else if (!S_ISDIR (st.st_mode)) -- cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0, -- "%s: not a directory", cur->name); -- else -- { -- INO_T_COPY (cur->ino, st.st_ino); -- cur->dev = st.st_dev; -- -- /* Remove this one if it is in the system chain. */ -- reason = REASON_DUP_SYS; -- for (tmp = system; tmp; tmp = tmp->next) -- if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev) -- break; -- -- if (!tmp) -- { -- /* Duplicate of something earlier in the same chain? */ -- reason = REASON_DUP; -- for (tmp = head; tmp != cur; tmp = tmp->next) -- if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev) -- break; -- -- if (tmp == cur -- /* Last in the chain and duplicate of JOIN? */ -- && !(cur->next == NULL && join -- && INO_T_EQ (cur->ino, join->ino) -- && cur->dev == join->dev)) -- { -- /* Unique, so keep this directory. */ -- pcur = &cur->next; -- continue; -- } -- } -- } -- -- /* Remove this entry from the chain. */ -- *pcur = cur->next; -- free_path (cur, verbose ? reason: REASON_QUIET); -- } -- -- *pcur = join; -- return head; --} -- --/* Merge the four include chains together in the order quote, bracket, -- system, after. Remove duplicate dirs (as determined by -- INO_T_EQ()). -- -- We can't just merge the lists and then uniquify them because then -- we may lose directories from the <> search path that should be -- there; consider -Ifoo -Ibar -I- -Ifoo -Iquux. It is however safe -- to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written -Ibar -I- -Ifoo -- -Iquux. */ --static void --merge_include_chains (cpp_reader *pfile, int verbose) --{ -- /* Join the SYSTEM and AFTER chains. Remove duplicates in the -- resulting SYSTEM chain. */ -- if (heads[SYSTEM]) -- tails[SYSTEM]->next = heads[AFTER]; -- else -- heads[SYSTEM] = heads[AFTER]; -- heads[SYSTEM] = remove_duplicates (pfile, heads[SYSTEM], 0, 0, verbose); -- -- /* Remove duplicates from BRACKET that are in itself or SYSTEM, and -- join it to SYSTEM. */ -- heads[BRACKET] = remove_duplicates (pfile, heads[BRACKET], heads[SYSTEM], -- heads[SYSTEM], verbose); -- -- /* Remove duplicates from QUOTE that are in itself or SYSTEM, and -- join it to BRACKET. */ -- heads[QUOTE] = remove_duplicates (pfile, heads[QUOTE], heads[SYSTEM], -- heads[BRACKET], verbose); -- -- /* If verbose, print the list of dirs to search. */ -- if (verbose) -- { -- struct cpp_dir *p; -- -- fprintf (stderr, _("#include \"...\" search starts here:\n")); -- for (p = heads[QUOTE];; p = p->next) -- { -- if (p == heads[BRACKET]) -- fprintf (stderr, _("#include <...> search starts here:\n")); -- if (!p) -- break; -- fprintf (stderr, " %s\n", p->name); -- } -- fprintf (stderr, _("End of search list.\n")); -- } --} -- --/* Use given -I paths for #include "..." but not #include <...>, and -- don't search the directory of the present file for #include "...". -- (Note that -I. -I- is not the same as the default setup; -I. uses -- the compiler's working dir.) */ --void --split_quote_chain (void) --{ -- heads[QUOTE] = heads[BRACKET]; -- tails[QUOTE] = tails[BRACKET]; -- heads[BRACKET] = NULL; -- tails[BRACKET] = NULL; -- /* This is NOT redundant. */ -- quote_ignores_source_dir = true; --} -- --/* Add PATH to the include chain CHAIN. PATH must be malloc-ed and -- NUL-terminated. */ --void --add_path (char *path, int chain, int cxx_aware) --{ -- struct cpp_dir *p; -- --#if defined (HAVE_DOS_BASED_FILE_SYSTEM) -- /* Convert all backslashes to slashes. The native CRT stat() -- function does not recognise a directory that ends in a backslash -- (unless it is a drive root dir, such "c:\"). Forward slashes, -- trailing or otherwise, cause no problems for stat(). */ -- char* c; -- for (c = path; *c; c++) -- if (*c == '\\') *c = '/'; --#endif -- -- p = xmalloc (sizeof (struct cpp_dir)); -- p->next = NULL; -- p->name = path; -- if (chain == SYSTEM || chain == AFTER) -- p->sysp = 1 + !cxx_aware; -- else -- p->sysp = 0; -- -- if (tails[chain]) -- tails[chain]->next = p; -- else -- heads[chain] = p; -- tails[chain] = p; --} -- --/* Exported function to handle include chain merging, duplicate -- removal, and registration with cpplib. */ --void --register_include_chains (cpp_reader *pfile, const char *sysroot, -- const char *iprefix, int stdinc, int cxx_stdinc, -- int verbose) --{ -- static const char *const lang_env_vars[] = -- { "C_INCLUDE_PATH", "CPLUS_INCLUDE_PATH", -- "OBJC_INCLUDE_PATH", "OBJCPLUS_INCLUDE_PATH" }; -- cpp_options *cpp_opts = cpp_get_options (pfile); -- size_t idx = (cpp_opts->objc ? 2: 0); -- -- if (cpp_opts->cplusplus) -- idx++; -- else -- cxx_stdinc = false; -- -- /* CPATH and language-dependent environment variables may add to the -- include chain. */ -- add_env_var_paths ("CPATH", BRACKET); -- add_env_var_paths (lang_env_vars[idx], SYSTEM); -- -- /* Finally chain on the standard directories. */ -- if (stdinc) -- add_standard_paths (sysroot, iprefix, cxx_stdinc); -- -- merge_include_chains (pfile, verbose); -- -- cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET], -- quote_ignores_source_dir); --} -diff -ruN gcc-3.4.5-20060117-1/gcc/collect2.c.orig gcc-3.4.5-20060117-1-winelf/gcc/collect2.c.orig ---- gcc-3.4.5-20060117-1/gcc/collect2.c.orig 2005-01-10 07:25:23.000000000 -0800 -+++ gcc-3.4.5-20060117-1-winelf/gcc/collect2.c.orig 1969-12-31 16:00:00.000000000 -0800 -@@ -1,2868 +0,0 @@ --/* Collect static initialization info into data structures that can be -- traversed by C++ initialization and finalization routines. -- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, -- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. -- Contributed by Chris Smith (csmith@convex.com). -- Heavily modified by Michael Meissner (meissner@cygnus.com), -- Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com). -- --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 2, 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 COPYING. If not, write to the Free --Software Foundation, 59 Temple Place - Suite 330, Boston, MA --02111-1307, USA. */ -- -- --/* Build tables of static constructors and destructors and run ld. */ -- --#include "config.h" --#include "system.h" --#include "coretypes.h" --#include "tm.h" --#include <signal.h> --#if ! defined( SIGCHLD ) && defined( SIGCLD ) --# define SIGCHLD SIGCLD --#endif -- --#ifdef vfork /* Autoconf may define this to fork for us. */ --# define VFORK_STRING "fork" --#else --# define VFORK_STRING "vfork" --#endif --#ifdef HAVE_VFORK_H --#include <vfork.h> --#endif --#ifdef VMS --#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \ -- lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1) --#endif /* VMS */ -- --#ifndef LIBRARY_PATH_ENV --#define LIBRARY_PATH_ENV "LIBRARY_PATH" --#endif -- --#define COLLECT -- --#include "collect2.h" --#include "demangle.h" --#include "obstack.h" --#include "intl.h" --#include "version.h" -- --/* On certain systems, we have code that works by scanning the object file -- directly. But this code uses system-specific header files and library -- functions, so turn it off in a cross-compiler. Likewise, the names of -- the utilities are not correct for a cross-compiler; we have to hope that -- cross-versions are in the proper directories. */ -- --#ifdef CROSS_COMPILE --#undef SUNOS4_SHARED_LIBRARIES --#undef OBJECT_FORMAT_COFF --#undef MD_EXEC_PREFIX --#undef REAL_LD_FILE_NAME --#undef REAL_NM_FILE_NAME --#undef REAL_STRIP_FILE_NAME --#endif -- --/* If we cannot use a special method, use the ordinary one: -- run nm to find what symbols are present. -- In a cross-compiler, this means you need a cross nm, -- but that is not quite as unpleasant as special headers. */ -- --#if !defined (OBJECT_FORMAT_COFF) --#define OBJECT_FORMAT_NONE --#endif -- --#ifdef OBJECT_FORMAT_COFF -- --#include <a.out.h> --#include <ar.h> -- --#ifdef UMAX --#include <sgs.h> --#endif -- --/* Many versions of ldfcn.h define these. */ --#ifdef FREAD --#undef FREAD --#undef FWRITE --#endif -- --#include <ldfcn.h> -- --/* Some systems have an ISCOFF macro, but others do not. In some cases -- the macro may be wrong. MY_ISCOFF is defined in tm.h files for machines -- that either do not have an ISCOFF macro in /usr/include or for those -- where it is wrong. */ -- --#ifndef MY_ISCOFF --#define MY_ISCOFF(X) ISCOFF (X) --#endif -- --#endif /* OBJECT_FORMAT_COFF */ -- --#ifdef OBJECT_FORMAT_NONE -- --/* Default flags to pass to nm. */ --#ifndef NM_FLAGS --#define NM_FLAGS "-n" --#endif -- --#endif /* OBJECT_FORMAT_NONE */ -- --/* Some systems use __main in a way incompatible with its use in gcc, in these -- cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to -- give the same symbol without quotes for an alternative entry point. */ --#ifndef NAME__MAIN --#define NAME__MAIN "__main" --#endif -- --/* This must match tree.h. */ --#define DEFAULT_INIT_PRIORITY 65535 -- --#ifndef COLLECT_SHARED_INIT_FUNC --#define COLLECT_SHARED_INIT_FUNC(STREAM, FUNC) \ -- fprintf ((STREAM), "void _GLOBAL__DI() {\n\t%s();\n}\n", (FUNC)) --#endif --#ifndef COLLECT_SHARED_FINI_FUNC --#define COLLECT_SHARED_FINI_FUNC(STREAM, FUNC) \ -- fprintf ((STREAM), "void _GLOBAL__DD() {\n\t%s();\n}\n", (FUNC)) --#endif -- --#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES --#define SCAN_LIBRARIES --#endif -- --#ifdef USE_COLLECT2 --int do_collecting = 1; --#else --int do_collecting = 0; --#endif -- --#ifndef COLLECT_PARSE_FLAG --#define COLLECT_PARSE_FLAG(FLAG) --#endif -- --/* Nonzero if we should suppress the automatic demangling of identifiers -- in linker error messages. Set from COLLECT_NO_DEMANGLE. */ --int no_demangle; -- --/* Linked lists of constructor and destructor names. */ -- --struct id --{ -- struct id *next; -- int sequence; -- char name[1]; --}; -- --struct head --{ -- struct id *first; -- struct id *last; -- int number; --}; -- --/* Enumeration giving which pass this is for scanning the program file. */ -- --enum pass { -- PASS_FIRST, /* without constructors */ -- PASS_OBJ, /* individual objects */ -- PASS_LIB, /* looking for shared libraries */ -- PASS_SECOND /* with constructors linked in */ --}; -- --int vflag; /* true if -v */ --static int rflag; /* true if -r */ --static int strip_flag; /* true if -s */ --#ifdef COLLECT_EXPORT_LIST --static int export_flag; /* true if -bE */ --static int aix64_flag; /* true if -b64 */ --static int aixrtl_flag; /* true if -brtl */ --#endif -- --int debug; /* true if -debug */ -- --static int shared_obj; /* true if -shared */ -- --static const char *c_file; /* <xxx>.c for constructor/destructor list. */ --static const char *o_file; /* <xxx>.o for constructor/destructor list. */ --#ifdef COLLECT_EXPORT_LIST --static const char *export_file; /* <xxx>.x for AIX export list. */ --#endif --const char *ldout; /* File for ld errors. */ --static const char *output_file; /* Output file for ld. */ --static const char *nm_file_name; /* pathname of nm */ --#ifdef LDD_SUFFIX --static const char *ldd_file_name; /* pathname of ldd (or equivalent) */ --#endif --static const char *strip_file_name; /* pathname of strip */ --const char *c_file_name; /* pathname of gcc */ --static char *initname, *fininame; /* names of init and fini funcs */ -- --static struct head constructors; /* list of constructors found */ --static struct head destructors; /* list of destructors found */ --#ifdef COLLECT_EXPORT_LIST --static struct head exports; /* list of exported symbols */ --#endif --static struct head frame_tables; /* list of frame unwind info tables */ -- --struct obstack temporary_obstack; --char * temporary_firstobj; -- --/* Holds the return value of pexecute and fork. */ --int pid; -- --/* Structure to hold all the directories in which to search for files to -- execute. */ -- --struct prefix_list --{ -- const char *prefix; /* String to prepend to the path. */ -- struct prefix_list *next; /* Next in linked list. */ --}; -- --struct path_prefix --{ -- struct prefix_list *plist; /* List of prefixes to try */ -- int max_len; /* Max length of a prefix in PLIST */ -- const char *name; /* Name of this list (used in config stuff) */ --}; -- --#ifdef COLLECT_EXPORT_LIST --/* Lists to keep libraries to be scanned for global constructors/destructors. */ --static struct head libs; /* list of libraries */ --static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */ --static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */ --static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs, -- &libpath_lib_dirs, NULL}; --#endif -- --static void handler (int); --static int is_ctor_dtor (const char *); --static char *find_a_file (struct path_prefix *, const char *); --static void add_prefix (struct path_prefix *, const char *); --static void prefix_from_env (const char *, struct path_prefix *); --static void prefix_from_string (const char *, struct path_prefix *); --static void do_wait (const char *); --static void fork_execute (const char *, char **); --static void maybe_unlink (const char *); --static void add_to_list (struct head *, const char *); --static int extract_init_priority (const char *); --static void sort_ids (struct head *); --static void write_list (FILE *, const char *, struct id *); --#ifdef COLLECT_EXPORT_LIST --static void dump_list (FILE *, const char *, struct id *); --#endif --#if 0 --static void dump_prefix_list (FILE *, const char *, struct prefix_list *); --#endif --static void write_list_with_asm (FILE *, const char *, struct id *); --static void write_c_file (FILE *, const char *); --static void write_c_file_stat (FILE *, const char *); --#ifndef LD_INIT_SWITCH --static void write_c_file_glob (FILE *, const char *); --#endif --static void scan_prog_file (const char *, enum pass); --#ifdef SCAN_LIBRARIES --static void scan_libraries (const char *); --#endif --#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES --static int is_in_args (const char *, const char **, const char **); --#endif --#ifdef COLLECT_EXPORT_LIST --#if 0 --static int is_in_list (const char *, struct id *); --#endif --static void write_aix_file (FILE *, struct id *); --static char *resolve_lib_name (const char *); --#endif --static char *extract_string (const char **); -- --#ifndef HAVE_DUP2 --static int --dup2 (int oldfd, int newfd) --{ -- int fdtmp[256]; -- int fdx = 0; -- int fd; -- -- if (oldfd == newfd) -- return oldfd; -- close (newfd); -- while ((fd = dup (oldfd)) != newfd && fd >= 0) /* good enough for low fd's */ -- fdtmp[fdx++] = fd; -- while (fdx > 0) -- close (fdtmp[--fdx]); -- -- return fd; --} --#endif /* ! HAVE_DUP2 */ -- --/* Delete tempfiles and exit function. */ -- --void --collect_exit (int status) --{ -- if (c_file != 0 && c_file[0]) -- maybe_unlink (c_file); -- -- if (o_file != 0 && o_file[0]) -- maybe_unlink (o_file); -- --#ifdef COLLECT_EXPORT_LIST -- if (export_file != 0 && export_file[0]) -- maybe_unlink (export_file); --#endif -- -- if (ldout != 0 && ldout[0]) -- { -- dump_file (ldout); -- maybe_unlink (ldout); -- } -- -- if (status != 0 && output_file != 0 && output_file[0]) -- maybe_unlink (output_file); -- -- exit (status); --} -- -- --/* Notify user of a non-error. */ --void --notice (const char *msgid, ...) --{ -- va_list ap; -- -- va_start (ap, msgid); -- vfprintf (stderr, _(msgid), ap); -- va_end (ap); --} -- --/* Die when sys call fails. */ -- --void --fatal_perror (const char * msgid, ...) --{ -- int e = errno; -- va_list ap; -- -- va_start (ap, msgid); -- fprintf (stderr, "collect2: "); -- vfprintf (stderr, _(msgid), ap); -- fprintf (stderr, ": %s\n", xstrerror (e)); -- va_end (ap); -- -- collect_exit (FATAL_EXIT_CODE); --} -- --/* Just die. */ -- --void --fatal (const char * msgid, ...) --{ -- va_list ap; -- -- va_start (ap, msgid); -- fprintf (stderr, "collect2: "); -- vfprintf (stderr, _(msgid), ap); -- fprintf (stderr, "\n"); -- va_end (ap); -- -- collect_exit (FATAL_EXIT_CODE); --} -- --/* Write error message. */ -- --void --error (const char * msgid, ...) --{ -- va_list ap; -- -- va_start (ap, msgid); -- fprintf (stderr, "collect2: "); -- vfprintf (stderr, _(msgid), ap); -- fprintf (stderr, "\n"); -- va_end(ap); --} -- --/* In case obstack is linked in, and abort is defined to fancy_abort, -- provide a default entry. */ -- --void --fancy_abort (void) --{ -- fatal ("internal error"); --} -- --static void --handler (int signo) --{ -- if (c_file != 0 && c_file[0]) -- maybe_unlink (c_file); -- -- if (o_file != 0 && o_file[0]) -- maybe_unlink (o_file); -- -- if (ldout != 0 && ldout[0]) -- maybe_unlink (ldout); -- --#ifdef COLLECT_EXPORT_LIST -- if (export_file != 0 && export_file[0]) -- maybe_unlink (export_file); --#endif -- -- signal (signo, SIG_DFL); -- kill (getpid (), signo); --} -- -- --int --file_exists (const char *name) --{ -- return access (name, R_OK) == 0; --} -- --/* Parse a reasonable subset of shell quoting syntax. */ -- --static char * --extract_string (const char **pp) --{ -- const char *p = *pp; -- int backquote = 0; -- int inside = 0; -- -- for (;;) -- { -- char c = *p; -- if (c == '\0') -- break; -- ++p; -- if (backquote) -- obstack_1grow (&temporary_obstack, c); -- else if (! inside && c == ' ') -- break; -- else if (! inside && c == '\\') -- backquote = 1; -- else if (c == '\'') -- inside = !inside; -- else -- obstack_1grow (&temporary_obstack, c); -- } -- -- obstack_1grow (&temporary_obstack, '\0'); -- *pp = p; -- return obstack_finish (&temporary_obstack); --} -- --void --dump_file (const char *name) --{ -- FILE *stream = fopen (name, "r"); -- -- if (stream == 0) -- return; -- while (1) -- { -- int c; -- while (c = getc (stream), -- c != EOF && (ISIDNUM (c) || c == '$' || c == '.')) -- obstack_1grow (&temporary_obstack, c); -- if (obstack_object_size (&temporary_obstack) > 0) -- { -- const char *word, *p; -- char *result; -- obstack_1grow (&temporary_obstack, '\0'); -- word = obstack_finish (&temporary_obstack); -- -- if (*word == '.') -- ++word, putc ('.', stderr); -- p = word; -- if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX))) -- p += strlen (USER_LABEL_PREFIX); -- -- if (no_demangle) -- result = 0; -- else -- result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE); -- -- if (result) -- { -- int diff; -- fputs (result, stderr); -- -- diff = strlen (word) - strlen (result); -- while (diff > 0 && c == ' ') -- --diff, putc (' ', stderr); -- while (diff < 0 && c == ' ') -- ++diff, c = getc (stream); -- -- free (result); -- } -- else -- fputs (word, stderr); -- -- fflush (stderr); -- obstack_free (&temporary_obstack, temporary_firstobj); -- } -- if (c == EOF) -- break; -- putc (c, stderr); -- } -- fclose (stream); --} -- --/* Decide whether the given symbol is: a constructor (1), a destructor -- (2), a routine in a shared object that calls all the constructors -- (3) or destructors (4), a DWARF exception-handling table (5), or -- nothing special (0). */ -- --static int --is_ctor_dtor (const char *s) --{ -- struct names { const char *const name; const int len; const int ret; -- const int two_underscores; }; -- -- const struct names *p; -- int ch; -- const char *orig_s = s; -- -- static const struct names special[] = { --#ifndef NO_DOLLAR_IN_LABEL -- { "GLOBAL__I$", sizeof ("GLOBAL__I$")-1, 1, 0 }, -- { "GLOBAL__D$", sizeof ("GLOBAL__D$")-1, 2, 0 }, --#else --#ifndef NO_DOT_IN_LABEL -- { "GLOBAL__I.", sizeof ("GLOBAL__I.")-1, 1, 0 }, -- { "GLOBAL__D.", sizeof ("GLOBAL__D.")-1, 2, 0 }, --#endif /* NO_DOT_IN_LABEL */ --#endif /* NO_DOLLAR_IN_LABEL */ -- { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 }, -- { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 }, -- { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 }, -- { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 }, -- { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 }, -- { NULL, 0, 0, 0 } -- }; -- -- while ((ch = *s) == '_') -- ++s; -- -- if (s == orig_s) -- return 0; -- -- for (p = &special[0]; p->len > 0; p++) -- { -- if (ch == p->name[0] -- && (!p->two_underscores || ((s - orig_s) >= 2)) -- && strncmp(s, p->name, p->len) == 0) -- { -- return p->ret; -- } -- } -- return 0; --} -- --/* We maintain two prefix lists: one from COMPILER_PATH environment variable -- and one from the PATH variable. */ -- --static struct path_prefix cpath, path; -- --#ifdef CROSS_COMPILE --/* This is the name of the target machine. We use it to form the name -- of the files to execute. */ -- --static const char *const target_machine = TARGET_MACHINE; --#endif -- --/* Search for NAME using prefix list PPREFIX. We only look for executable -- files. -- -- Return 0 if not found, otherwise return its name, allocated with malloc. */ -- --static char * --find_a_file (struct path_prefix *pprefix, const char *name) --{ -- char *temp; -- struct prefix_list *pl; -- int len = pprefix->max_len + strlen (name) + 1; -- -- if (debug) -- fprintf (stderr, "Looking for '%s'\n", name); -- --#ifdef HOST_EXECUTABLE_SUFFIX -- len += strlen (HOST_EXECUTABLE_SUFFIX); --#endif -- -- temp = xmalloc (len); -- -- /* Determine the filename to execute (special case for absolute paths). */ -- -- if (*name == '/' --#ifdef HAVE_DOS_BASED_FILE_SYSTEM -- || (*name && name[1] == ':') --#endif -- ) -- { -- if (access (name, X_OK) == 0) -- { -- strcpy (temp, name); -- -- if (debug) -- fprintf (stderr, " - found: absolute path\n"); -- -- return temp; -- } -- --#ifdef HOST_EXECUTABLE_SUFFIX -- /* Some systems have a suffix for executable files. -- So try appending that. */ -- strcpy (temp, name); -- strcat (temp, HOST_EXECUTABLE_SUFFIX); -- -- if (access (temp, X_OK) == 0) -- return temp; --#endif -- -- if (debug) -- fprintf (stderr, " - failed to locate using absolute path\n"); -- } -- else -- for (pl = pprefix->plist; pl; pl = pl->next) -- { -- struct stat st; -- -- strcpy (temp, pl->prefix); -- strcat (temp, name); -- -- if (stat (temp, &st) >= 0 -- && ! S_ISDIR (st.st_mode) -- && access (temp, X_OK) == 0) -- return temp; -- --#ifdef HOST_EXECUTABLE_SUFFIX -- /* Some systems have a suffix for executable files. -- So try appending that. */ -- strcat (temp, HOST_EXECUTABLE_SUFFIX); -- -- if (stat (temp, &st) >= 0 -- && ! S_ISDIR (st.st_mode) -- && access (temp, X_OK) == 0) -- return temp; --#endif -- } -- -- if (debug && pprefix->plist == NULL) -- fprintf (stderr, " - failed: no entries in prefix list\n"); -- -- free (temp); -- return 0; --} -- --/* Add an entry for PREFIX to prefix list PPREFIX. */ -- --static void --add_prefix (struct path_prefix *pprefix, const char *prefix) --{ -- struct prefix_list *pl, **prev; -- int len; -- -- if (pprefix->plist) -- { -- for (pl = pprefix->plist; pl->next; pl = pl->next) -- ; -- prev = &pl->next; -- } -- else -- prev = &pprefix->plist; -- -- /* Keep track of the longest prefix. */ -- -- len = strlen (prefix); -- if (len > pprefix->max_len) -- pprefix->max_len = len; -- -- pl = xmalloc (sizeof (struct prefix_list)); -- pl->prefix = xstrdup (prefix); -- -- if (*prev) -- pl->next = *prev; -- else -- pl->next = (struct prefix_list *) 0; -- *prev = pl; --} -- --/* Take the value of the environment variable ENV, break it into a path, and -- add of the entries to PPREFIX. */ -- --static void --prefix_from_env (const char *env, struct path_prefix *pprefix) --{ -- const char *p; -- GET_ENVIRONMENT (p, env); -- -- if (p) -- prefix_from_string (p, pprefix); --} -- --static void --prefix_from_string (const char *p, struct path_prefix *pprefix) --{ -- const char *startp, *endp; -- char *nstore = xmalloc (strlen (p) + 3); -- -- if (debug) -- fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR); -- -- startp = endp = p; -- while (1) -- { -- if (*endp == PATH_SEPARATOR || *endp == 0) -- { -- strncpy (nstore, startp, endp-startp); -- if (endp == startp) -- { -- strcpy (nstore, "./"); -- } -- else if (! IS_DIR_SEPARATOR (endp[-1])) -- { -- nstore[endp-startp] = DIR_SEPARATOR; -- nstore[endp-startp+1] = 0; -- } -- else -- nstore[endp-startp] = 0; -- -- if (debug) -- fprintf (stderr, " - add prefix: %s\n", nstore); -- -- add_prefix (pprefix, nstore); -- if (*endp == 0) -- break; -- endp = startp = endp + 1; -- } -- else -- endp++; -- } --} -- --/* Main program. */ -- --int --main (int argc, char **argv) --{ -- static const char *const ld_suffix = "ld"; -- static const char *const real_ld_suffix = "real-ld"; -- static const char *const collect_ld_suffix = "collect-ld"; -- static const char *const nm_suffix = "nm"; -- static const char *const gnm_suffix = "gnm"; --#ifdef LDD_SUFFIX -- static const char *const ldd_suffix = LDD_SUFFIX; --#endif -- static const char *const strip_suffix = "strip"; -- static const char *const gstrip_suffix = "gstrip"; -- --#ifdef CROSS_COMPILE -- /* If we look for a program in the compiler directories, we just use -- the short name, since these directories are already system-specific. -- But it we look for a program in the system directories, we need to -- qualify the program name with the target machine. */ -- -- const char *const full_ld_suffix = -- concat(target_machine, "-", ld_suffix, NULL); -- const char *const full_nm_suffix = -- concat (target_machine, "-", nm_suffix, NULL); -- const char *const full_gnm_suffix = -- concat (target_machine, "-", gnm_suffix, NULL); --#ifdef LDD_SUFFIX -- const char *const full_ldd_suffix = -- concat (target_machine, "-", ldd_suffix, NULL); --#endif -- const char *const full_strip_suffix = -- concat (target_machine, "-", strip_suffix, NULL); -- const char *const full_gstrip_suffix = -- concat (target_machine, "-", gstrip_suffix, NULL); --#else -- const char *const full_ld_suffix = ld_suffix; -- const char *const full_nm_suffix = nm_suffix; -- const char *const full_gnm_suffix = gnm_suffix; --#ifdef LDD_SUFFIX -- const char *const full_ldd_suffix = ldd_suffix; --#endif -- const char *const full_strip_suffix = strip_suffix; -- const char *const full_gstrip_suffix = gstrip_suffix; --#endif /* CROSS_COMPILE */ -- -- const char *arg; -- FILE *outf; --#ifdef COLLECT_EXPORT_LIST -- FILE *exportf; --#endif -- const char *ld_file_name; -- const char *p; -- char **c_argv; -- const char **c_ptr; -- char **ld1_argv; -- const char **ld1; -- char **ld2_argv; -- const char **ld2; -- char **object_lst; -- const char **object; -- int first_file; -- int num_c_args = argc+9; -- -- no_demangle = !! getenv ("COLLECT_NO_DEMANGLE"); -- -- /* Suppress demangling by the real linker, which may be broken. */ -- putenv (xstrdup ("COLLECT_NO_DEMANGLE=")); -- --#if defined (COLLECT2_HOST_INITIALIZATION) -- /* Perform system dependent initialization, if necessary. */ -- COLLECT2_HOST_INITIALIZATION; --#endif -- --#ifdef SIGCHLD -- /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will -- receive the signal. A different setting is inheritable */ -- signal (SIGCHLD, SIG_DFL); --#endif -- -- gcc_init_libintl (); -- -- /* Do not invoke xcalloc before this point, since locale needs to be -- set first, in case a diagnostic is issued. */ -- -- ld1 = (const char **)(ld1_argv = xcalloc(sizeof (char *), argc+3)); -- ld2 = (const char **)(ld2_argv = xcalloc(sizeof (char *), argc+10)); -- object = (const char **)(object_lst = xcalloc(sizeof (char *), argc)); -- --#ifdef DEBUG -- debug = 1; --#endif -- -- /* Parse command line early for instances of -debug. This allows -- the debug flag to be set before functions like find_a_file() -- are called. */ -- { -- int i; -- -- for (i = 1; argv[i] != NULL; i ++) -- { -- if (! strcmp (argv[i], "-debug")) -- debug = 1; -- COLLECT_PARSE_FLAG (argv[i]); -- } -- vflag = debug; -- } -- --#ifndef DEFAULT_A_OUT_NAME -- output_file = "a.out"; --#else -- output_file = DEFAULT_A_OUT_NAME; --#endif -- -- obstack_begin (&temporary_obstack, 0); -- temporary_firstobj = obstack_alloc (&temporary_obstack, 0); -- -- current_demangling_style = auto_demangling; -- p = getenv ("COLLECT_GCC_OPTIONS"); -- while (p && *p) -- { -- const char *q = extract_string (&p); -- if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) -- num_c_args++; -- } -- obstack_free (&temporary_obstack, temporary_firstobj); -- -- /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities -- -fno-exceptions -w */ -- num_c_args += 5; -- -- c_ptr = (const char **) (c_argv = xcalloc (sizeof (char *), num_c_args)); -- -- if (argc < 2) -- fatal ("no arguments"); -- --#ifdef SIGQUIT -- if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) -- signal (SIGQUIT, handler); --#endif -- if (signal (SIGINT, SIG_IGN) != SIG_IGN) -- signal (SIGINT, handler); --#ifdef SIGALRM -- if (signal (SIGALRM, SIG_IGN) != SIG_IGN) -- signal (SIGALRM, handler); --#endif --#ifdef SIGHUP -- if (signal (SIGHUP, SIG_IGN) != SIG_IGN) -- signal (SIGHUP, handler); --#endif -- if (signal (SIGSEGV, SIG_IGN) != SIG_IGN) -- signal (SIGSEGV, handler); --#ifdef SIGBUS -- if (signal (SIGBUS, SIG_IGN) != SIG_IGN) -- signal (SIGBUS, handler); --#endif -- -- /* Extract COMPILER_PATH and PATH into our prefix list. */ -- prefix_from_env ("COMPILER_PATH", &cpath); -- prefix_from_env ("PATH", &path); -- -- /* Try to discover a valid linker/nm/strip to use. */ -- -- /* Maybe we know the right file to use (if not cross). */ -- ld_file_name = 0; --#ifdef DEFAULT_LINKER -- if (access (DEFAULT_LINKER, X_OK) == 0) -- ld_file_name = DEFAULT_LINKER; -- if (ld_file_name == 0) --#endif --#ifdef REAL_LD_FILE_NAME -- ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME); -- if (ld_file_name == 0) --#endif -- /* Search the (target-specific) compiler dirs for ld'. */ -- ld_file_name = find_a_file (&cpath, real_ld_suffix); -- /* Likewise for `collect-ld'. */ -- if (ld_file_name == 0) -- ld_file_name = find_a_file (&cpath, collect_ld_suffix); -- /* Search the compiler directories for `ld'. We have protection against -- recursive calls in find_a_file. */ -- if (ld_file_name == 0) -- ld_file_name = find_a_file (&cpath, ld_suffix); -- /* Search the ordinary system bin directories -- for `ld' (if native linking) or `TARGET-ld' (if cross). */ -- if (ld_file_name == 0) -- ld_file_name = find_a_file (&path, full_ld_suffix); -- --#ifdef REAL_NM_FILE_NAME -- nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME); -- if (nm_file_name == 0) --#endif -- nm_file_name = find_a_file (&cpath, gnm_suffix); -- if (nm_file_name == 0) -- nm_file_name = find_a_file (&path, full_gnm_suffix); -- if (nm_file_name == 0) -- nm_file_name = find_a_file (&cpath, nm_suffix); -- if (nm_file_name == 0) -- nm_file_name = find_a_file (&path, full_nm_suffix); -- --#ifdef LDD_SUFFIX -- ldd_file_name = find_a_file (&cpath, ldd_suffix); -- if (ldd_file_name == 0) -- ldd_file_name = find_a_file (&path, full_ldd_suffix); --#endif -- --#ifdef REAL_STRIP_FILE_NAME -- strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME); -- if (strip_file_name == 0) --#endif -- strip_file_name = find_a_file (&cpath, gstrip_suffix); -- if (strip_file_name == 0) -- strip_file_name = find_a_file (&path, full_gstrip_suffix); -- if (strip_file_name == 0) -- strip_file_name = find_a_file (&cpath, strip_suffix); -- if (strip_file_name == 0) -- strip_file_name = find_a_file (&path, full_strip_suffix); -- -- /* Determine the full path name of the C compiler to use. */ -- c_file_name = getenv ("COLLECT_GCC"); -- if (c_file_name == 0) -- { --#ifdef CROSS_COMPILE -- c_file_name = concat (target_machine, "-gcc", NULL); --#else -- c_file_name = "gcc"; --#endif -- } -- -- p = find_a_file (&cpath, c_file_name); -- -- /* Here it should be safe to use the system search path since we should have -- already qualified the name of the compiler when it is needed. */ -- if (p == 0) -- p = find_a_file (&path, c_file_name); -- -- if (p) -- c_file_name = p; -- -- *ld1++ = *ld2++ = ld_file_name; -- -- /* Make temp file names. */ -- c_file = make_temp_file (".c"); -- o_file = make_temp_file (".o"); --#ifdef COLLECT_EXPORT_LIST -- export_file = make_temp_file (".x"); --#endif -- ldout = make_temp_file (".ld"); -- *c_ptr++ = c_file_name; -- *c_ptr++ = "-x"; -- *c_ptr++ = "c"; -- *c_ptr++ = "-c"; -- *c_ptr++ = "-o"; -- *c_ptr++ = o_file; -- --#ifdef COLLECT_EXPORT_LIST -- /* Generate a list of directories from LIBPATH. */ -- prefix_from_env ("LIBPATH", &libpath_lib_dirs); -- /* Add to this list also two standard directories where -- AIX loader always searches for libraries. */ -- add_prefix (&libpath_lib_dirs, "/lib"); -- add_prefix (&libpath_lib_dirs, "/usr/lib"); --#endif -- -- /* Get any options that the upper GCC wants to pass to the sub-GCC. -- -- AIX support needs to know if -shared has been specified before -- parsing commandline arguments. */ -- -- p = getenv ("COLLECT_GCC_OPTIONS"); -- while (p && *p) -- { -- const char *q = extract_string (&p); -- if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) -- *c_ptr++ = xstrdup (q); -- if (strcmp (q, "-EL") == 0 || strcmp (q, "-EB") == 0) -- *c_ptr++ = xstrdup (q); -- if (strcmp (q, "-shared") == 0) -- shared_obj = 1; -- if (*q == '-' && q[1] == 'B') -- { -- *c_ptr++ = xstrdup (q); -- if (q[2] == 0) -- { -- q = extract_string (&p); -- *c_ptr++ = xstrdup (q); -- } -- } -- } -- obstack_free (&temporary_obstack, temporary_firstobj); -- *c_ptr++ = "-fno-profile-arcs"; -- *c_ptr++ = "-fno-test-coverage"; -- *c_ptr++ = "-fno-branch-probabilities"; -- *c_ptr++ = "-fno-exceptions"; -- *c_ptr++ = "-w"; -- -- /* !!! When GCC calls collect2, -- it does not know whether it is calling collect2 or ld. -- So collect2 cannot meaningfully understand any options -- except those ld understands. -- If you propose to make GCC pass some other option, -- just imagine what will happen if ld is really ld!!! */ -- -- /* Parse arguments. Remember output file spec, pass the rest to ld. */ -- /* After the first file, put in the c++ rt0. */ -- -- first_file = 1; -- while ((arg = *++argv) != (char *) 0) -- { -- *ld1++ = *ld2++ = arg; -- -- if (arg[0] == '-') -- { -- switch (arg[1]) -- { --#ifdef COLLECT_EXPORT_LIST -- /* We want to disable automatic exports on AIX when user -- explicitly puts an export list in command line */ -- case 'b': -- if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0) -- export_flag = 1; -- else if (arg[2] == '6' && arg[3] == '4') -- aix64_flag = 1; -- else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l') -- aixrtl_flag = 1; -- break; --#endif -- -- case 'd': -- if (!strcmp (arg, "-debug")) -- { -- /* Already parsed. */ -- ld1--; -- ld2--; -- } -- break; -- -- case 'l': -- if (first_file) -- { -- /* place o_file BEFORE this argument! */ -- first_file = 0; -- ld2--; -- *ld2++ = o_file; -- *ld2++ = arg; -- } --#ifdef COLLECT_EXPORT_LIST -- { -- /* Resolving full library name. */ -- const char *s = resolve_lib_name (arg+2); -- -- /* Saving a full library name. */ -- add_to_list (&libs, s); -- } --#endif -- break; -- --#ifdef COLLECT_EXPORT_LIST -- /* Saving directories where to search for libraries. */ -- case 'L': -- add_prefix (&cmdline_lib_dirs, arg+2); -- break; --#else --#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES -- case 'L': -- if (is_in_args (arg, (const char **) ld1_argv, ld1-1)) -- --ld1; -- break; --#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */ --#endif -- -- case 'o': -- if (arg[2] == '\0') -- output_file = *ld1++ = *ld2++ = *++argv; -- else if (1 --#ifdef SWITCHES_NEED_SPACES -- && ! strchr (SWITCHES_NEED_SPACES, arg[1]) --#endif -- ) -- -- output_file = &arg[2]; -- break; -- -- case 'r': -- if (arg[2] == '\0') -- rflag = 1; -- break; -- -- case 's': -- if (arg[2] == '\0' && do_collecting) -- { -- /* We must strip after the nm run, otherwise C++ linking -- will not work. Thus we strip in the second ld run, or -- else with strip if there is no second ld run. */ -- strip_flag = 1; -- ld1--; -- } -- break; -- -- case 'v': -- if (arg[2] == '\0') -- vflag = 1; -- break; -- } -- } -- else if ((p = strrchr (arg, '.')) != (char *) 0 -- && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0 -- || strcmp (p, ".so") == 0 || strcmp (p, ".lo") == 0 -- || strcmp (p, ".obj") == 0)) -- { -- if (first_file) -- { -- first_file = 0; -- if (p[1] == 'o') -- *ld2++ = o_file; -- else -- { -- /* place o_file BEFORE this argument! */ -- ld2--; -- *ld2++ = o_file; -- *ld2++ = arg; -- } -- } -- if (p[1] == 'o' || p[1] == 'l') -- *object++ = arg; --#ifdef COLLECT_EXPORT_LIST -- /* libraries can be specified directly, i.e. without -l flag. */ -- else -- { -- /* Saving a full library name. */ -- add_to_list (&libs, arg); -- } --#endif -- } -- } -- --#ifdef COLLECT_EXPORT_LIST -- /* This is added only for debugging purposes. */ -- if (debug) -- { -- fprintf (stderr, "List of libraries:\n"); -- dump_list (stderr, "\t", libs.first); -- } -- -- /* The AIX linker will discard static constructors in object files if -- nothing else in the file is referenced, so look at them first. */ -- { -- const char **export_object_lst = (const char **)object_lst; -- -- while (export_object_lst < object) -- scan_prog_file (*export_object_lst++, PASS_OBJ); -- } -- { -- struct id *list = libs.first; -- -- for (; list; list = list->next) -- scan_prog_file (list->name, PASS_FIRST); -- } -- -- if (exports.first) -- { -- char *buf = concat ("-bE:", export_file, NULL); -- -- *ld1++ = buf; -- *ld2++ = buf; -- -- exportf = fopen (export_file, "w"); -- if (exportf == (FILE *) 0) -- fatal_perror ("fopen %s", export_file); -- write_aix_file (exportf, exports.first); -- if (fclose (exportf)) -- fatal_perror ("fclose %s", export_file); -- } --#endif -- -- *c_ptr++ = c_file; -- *c_ptr = *ld1 = *object = (char *) 0; -- -- if (vflag) -- { -- notice ("collect2 version %s", version_string); --#ifdef TARGET_VERSION -- TARGET_VERSION; --#endif -- fprintf (stderr, "\n"); -- } -- -- if (debug) -- { -- const char *ptr; -- fprintf (stderr, "ld_file_name = %s\n", -- (ld_file_name ? ld_file_name : "not found")); -- fprintf (stderr, "c_file_name = %s\n", -- (c_file_name ? c_file_name : "not found")); -- fprintf (stderr, "nm_file_name = %s\n", -- (nm_file_name ? nm_file_name : "not found")); --#ifdef LDD_SUFFIX -- fprintf (stderr, "ldd_file_name = %s\n", -- (ldd_file_name ? ldd_file_name : "not found")); --#endif -- fprintf (stderr, "strip_file_name = %s\n", -- (strip_file_name ? strip_file_name : "not found")); -- fprintf (stderr, "c_file = %s\n", -- (c_file ? c_file : "not found")); -- fprintf (stderr, "o_file = %s\n", -- (o_file ? o_file : "not found")); -- -- ptr = getenv ("COLLECT_GCC_OPTIONS"); -- if (ptr) -- fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr); -- -- ptr = getenv ("COLLECT_GCC"); -- if (ptr) -- fprintf (stderr, "COLLECT_GCC = %s\n", ptr); -- -- ptr = getenv ("COMPILER_PATH"); -- if (ptr) -- fprintf (stderr, "COMPILER_PATH = %s\n", ptr); -- -- ptr = getenv (LIBRARY_PATH_ENV); -- if (ptr) -- fprintf (stderr, "%-20s= %s\n", LIBRARY_PATH_ENV, ptr); -- -- fprintf (stderr, "\n"); -- } -- -- /* Load the program, searching all libraries and attempting to provide -- undefined symbols from repository information. */ -- -- /* On AIX we do this later. */ --#ifndef COLLECT_EXPORT_LIST -- do_tlink (ld1_argv, object_lst); --#endif -- -- /* If -r or they will be run via some other method, do not build the -- constructor or destructor list, just return now. */ -- if (rflag --#ifndef COLLECT_EXPORT_LIST -- || ! do_collecting --#endif -- ) -- { --#ifdef COLLECT_EXPORT_LIST -- /* Do the link we avoided above if we are exiting. */ -- do_tlink (ld1_argv, object_lst); -- -- /* But make sure we delete the export file we may have created. */ -- if (export_file != 0 && export_file[0]) -- maybe_unlink (export_file); --#endif -- maybe_unlink (c_file); -- maybe_unlink (o_file); -- return 0; -- } -- -- /* Examine the namelist with nm and search it for static constructors -- and destructors to call. -- Write the constructor and destructor tables to a .s file and reload. */ -- -- /* On AIX we already scanned for global constructors/destructors. */ --#ifndef COLLECT_EXPORT_LIST -- scan_prog_file (output_file, PASS_FIRST); --#endif -- --#ifdef SCAN_LIBRARIES -- scan_libraries (output_file); --#endif -- -- if (debug) -- { -- notice ("%d constructor(s) found\n", constructors.number); -- notice ("%d destructor(s) found\n", destructors.number); -- notice ("%d frame table(s) found\n", frame_tables.number); -- } -- -- if (constructors.number == 0 && destructors.number == 0 -- && frame_tables.number == 0 --#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST) -- /* If we will be running these functions ourselves, we want to emit -- stubs into the shared library so that we do not have to relink -- dependent programs when we add static objects. */ -- && ! shared_obj --#endif -- ) -- { --#ifdef COLLECT_EXPORT_LIST -- /* Do tlink without additional code generation. */ -- do_tlink (ld1_argv, object_lst); --#endif -- /* Strip now if it was requested on the command line. */ -- if (strip_flag) -- { -- char **real_strip_argv = xcalloc (sizeof (char *), 3); -- const char ** strip_argv = (const char **) real_strip_argv; -- -- strip_argv[0] = strip_file_name; -- strip_argv[1] = output_file; -- strip_argv[2] = (char *) 0; -- fork_execute ("strip", real_strip_argv); -- } -- --#ifdef COLLECT_EXPORT_LIST -- maybe_unlink (export_file); --#endif -- maybe_unlink (c_file); -- maybe_unlink (o_file); -- return 0; -- } -- -- /* Sort ctor and dtor lists by priority. */ -- sort_ids (&constructors); -- sort_ids (&destructors); -- -- maybe_unlink(output_file); -- outf = fopen (c_file, "w"); -- if (outf == (FILE *) 0) -- fatal_perror ("fopen %s", c_file); -- -- write_c_file (outf, c_file); -- -- if (fclose (outf)) -- fatal_perror ("fclose %s", c_file); -- -- /* Tell the linker that we have initializer and finalizer functions. */ --#ifdef LD_INIT_SWITCH --#ifdef COLLECT_EXPORT_LIST -- *ld2++ = concat (LD_INIT_SWITCH, ":", initname, ":", fininame, NULL); --#else -- *ld2++ = LD_INIT_SWITCH; -- *ld2++ = initname; -- *ld2++ = LD_FINI_SWITCH; -- *ld2++ = fininame; --#endif --#endif -- --#ifdef COLLECT_EXPORT_LIST -- if (shared_obj) -- { -- /* If we did not add export flag to link arguments before, add it to -- second link phase now. No new exports should have been added. */ -- if (! exports.first) -- *ld2++ = concat ("-bE:", export_file, NULL); -- --#ifndef LD_INIT_SWITCH -- add_to_list (&exports, initname); -- add_to_list (&exports, fininame); -- add_to_list (&exports, "_GLOBAL__DI"); -- add_to_list (&exports, "_GLOBAL__DD"); --#endif -- exportf = fopen (export_file, "w"); -- if (exportf == (FILE *) 0) -- fatal_perror ("fopen %s", export_file); -- write_aix_file (exportf, exports.first); -- if (fclose (exportf)) -- fatal_perror ("fclose %s", export_file); -- } --#endif -- -- /* End of arguments to second link phase. */ -- *ld2 = (char*) 0; -- -- if (debug) -- { -- fprintf (stderr, "\n========== output_file = %s, c_file = %s\n", -- output_file, c_file); -- write_c_file (stderr, "stderr"); -- fprintf (stderr, "========== end of c_file\n\n"); --#ifdef COLLECT_EXPORT_LIST -- fprintf (stderr, "\n========== export_file = %s\n", export_file); -- write_aix_file (stderr, exports.first); -- fprintf (stderr, "========== end of export_file\n\n"); --#endif -- } -- -- /* Assemble the constructor and destructor tables. -- Link the tables in with the rest of the program. */ -- -- fork_execute ("gcc", c_argv); --#ifdef COLLECT_EXPORT_LIST -- /* On AIX we must call tlink because of possible templates resolution. */ -- do_tlink (ld2_argv, object_lst); --#else -- /* Otherwise, simply call ld because tlink is already done. */ -- fork_execute ("ld", ld2_argv); -- -- /* Let scan_prog_file do any final mods (OSF/rose needs this for -- constructors/destructors in shared libraries. */ -- scan_prog_file (output_file, PASS_SECOND); --#endif -- -- maybe_unlink (c_file); -- maybe_unlink (o_file); -- --#ifdef COLLECT_EXPORT_LIST -- maybe_unlink (export_file); --#endif -- -- return 0; --} -- -- --/* Wait for a process to finish, and exit if a nonzero status is found. */ -- --int --collect_wait (const char *prog) --{ -- int status; -- -- pwait (pid, &status, 0); -- if (status) -- { -- if (WIFSIGNALED (status)) -- { -- int sig = WTERMSIG (status); -- error ("%s terminated with signal %d [%s]%s", -- prog, sig, strsignal(sig), -- WCOREDUMP(status) ? ", core dumped" : ""); -- collect_exit (FATAL_EXIT_CODE); -- } -- -- if (WIFEXITED (status)) -- return WEXITSTATUS (status); -- } -- return 0; --} -- --static void --do_wait (const char *prog) --{ -- int ret = collect_wait (prog); -- if (ret != 0) -- { -- error ("%s returned %d exit status", prog, ret); -- collect_exit (ret); -- } --} -- -- --/* Execute a program, and wait for the reply. */ -- --void --collect_execute (const char *prog, char **argv, const char *redir) --{ -- char *errmsg_fmt; -- char *errmsg_arg; -- int redir_handle = -1; -- int stdout_save = -1; -- int stderr_save = -1; -- -- if (vflag || debug) -- { -- char **p_argv; -- const char *str; -- -- if (argv[0]) -- fprintf (stderr, "%s", argv[0]); -- else -- notice ("[cannot find %s]", prog); -- -- for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++) -- fprintf (stderr, " %s", str); -- -- fprintf (stderr, "\n"); -- } -- -- fflush (stdout); -- fflush (stderr); -- -- /* If we cannot find a program we need, complain error. Do this here -- since we might not end up needing something that we could not find. */ -- -- if (argv[0] == 0) -- fatal ("cannot find `%s'", prog); -- -- if (redir) -- { -- /* Open response file. */ -- redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT); -- -- /* Duplicate the stdout and stderr file handles -- so they can be restored later. */ -- stdout_save = dup (STDOUT_FILENO); -- if (stdout_save == -1) -- fatal_perror ("redirecting stdout: %s", redir); -- stderr_save = dup (STDERR_FILENO); -- if (stderr_save == -1) -- fatal_perror ("redirecting stdout: %s", redir); -- -- /* Redirect stdout & stderr to our response file. */ -- dup2 (redir_handle, STDOUT_FILENO); -- dup2 (redir_handle, STDERR_FILENO); -- } -- -- pid = pexecute (argv[0], argv, argv[0], NULL, &errmsg_fmt, &errmsg_arg, -- (PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH)); -- -- if (redir) -- { -- /* Restore stdout and stderr to their previous settings. */ -- dup2 (stdout_save, STDOUT_FILENO); -- dup2 (stderr_save, STDERR_FILENO); -- -- /* Close response file. */ -- close (redir_handle); -- } -- -- if (pid == -1) -- fatal_perror (errmsg_fmt, errmsg_arg); --} -- --static void --fork_execute (const char *prog, char **argv) --{ -- collect_execute (prog, argv, NULL); -- do_wait (prog); --} -- --/* Unlink a file unless we are debugging. */ -- --static void --maybe_unlink (const char *file) --{ -- if (!debug) -- unlink (file); -- else -- notice ("[Leaving %s]\n", file); --} -- -- --static long sequence_number = 0; -- --/* Add a name to a linked list. */ -- --static void --add_to_list (struct head *head_ptr, const char *name) --{ -- struct id *newid = xcalloc (sizeof (struct id) + strlen (name), 1); -- struct id *p; -- strcpy (newid->name, name); -- -- if (head_ptr->first) -- head_ptr->last->next = newid; -- else -- head_ptr->first = newid; -- -- /* Check for duplicate symbols. */ -- for (p = head_ptr->first; -- strcmp (name, p->name) != 0; -- p = p->next) -- ; -- if (p != newid) -- { -- head_ptr->last->next = 0; -- free (newid); -- return; -- } -- -- newid->sequence = ++sequence_number; -- head_ptr->last = newid; -- head_ptr->number++; --} -- --/* Grab the init priority number from an init function name that -- looks like "_GLOBAL_.I.12345.foo". */ -- --static int --extract_init_priority (const char *name) --{ -- int pos = 0, pri; -- -- while (name[pos] == '_') -- ++pos; -- pos += 10; /* strlen ("GLOBAL__X_") */ -- -- /* Extract init_p number from ctor/dtor name. */ -- pri = atoi (name + pos); -- return pri ? pri : DEFAULT_INIT_PRIORITY; --} -- --/* Insertion sort the ids from ctor/dtor list HEAD_PTR in descending order. -- ctors will be run from right to left, dtors from left to right. */ -- --static void --sort_ids (struct head *head_ptr) --{ -- /* id holds the current element to insert. id_next holds the next -- element to insert. id_ptr iterates through the already sorted elements -- looking for the place to insert id. */ -- struct id *id, *id_next, **id_ptr; -- -- id = head_ptr->first; -- -- /* We don't have any sorted elements yet. */ -- head_ptr->first = NULL; -- -- for (; id; id = id_next) -- { -- id_next = id->next; -- id->sequence = extract_init_priority (id->name); -- -- for (id_ptr = &(head_ptr->first); ; id_ptr = &((*id_ptr)->next)) -- if (*id_ptr == NULL -- /* If the sequence numbers are the same, we put the id from the -- file later on the command line later in the list. */ -- || id->sequence > (*id_ptr)->sequence -- /* Hack: do lexical compare, too. -- || (id->sequence == (*id_ptr)->sequence -- && strcmp (id->name, (*id_ptr)->name) > 0) */ -- ) -- { -- id->next = *id_ptr; -- *id_ptr = id; -- break; -- } -- } -- -- /* Now set the sequence numbers properly so write_c_file works. */ -- for (id = head_ptr->first; id; id = id->next) -- id->sequence = ++sequence_number; --} -- --/* Write: `prefix', the names on list LIST, `suffix'. */ -- --static void --write_list (FILE *stream, const char *prefix, struct id *list) --{ -- while (list) -- { -- fprintf (stream, "%sx%d,\n", prefix, list->sequence); -- list = list->next; -- } --} -- --#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES --/* Given a STRING, return nonzero if it occurs in the list in range -- [ARGS_BEGIN,ARGS_END). */ -- --static int --is_in_args (const char *string, const char **args_begin, -- const char **args_end) --{ -- const char **args_pointer; -- for (args_pointer = args_begin; args_pointer != args_end; ++args_pointer) -- if (strcmp (string, *args_pointer) == 0) -- return 1; -- return 0; --} --#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */ -- --#ifdef COLLECT_EXPORT_LIST --/* This function is really used only on AIX, but may be useful. */ --#if 0 --static int --is_in_list (const char *prefix, struct id *list) --{ -- while (list) -- { -- if (!strcmp (prefix, list->name)) return 1; -- list = list->next; -- } -- return 0; --} --#endif --#endif /* COLLECT_EXPORT_LIST */ -- --/* Added for debugging purpose. */ --#ifdef COLLECT_EXPORT_LIST --static void --dump_list (FILE *stream, const char *prefix, struct id *list) --{ -- while (list) -- { -- fprintf (stream, "%s%s,\n", prefix, list->name); -- list = list->next; -- } --} --#endif -- --#if 0 --static void --dump_prefix_list (FILE *stream, const char *prefix, struct prefix_list *list) --{ -- while (list) -- { -- fprintf (stream, "%s%s,\n", prefix, list->prefix); -- list = list->next; -- } --} --#endif -- --static void --write_list_with_asm (FILE *stream, const char *prefix, struct id *list) --{ -- while (list) -- { -- fprintf (stream, "%sx%d __asm__ (\"%s\");\n", -- prefix, list->sequence, list->name); -- list = list->next; -- } --} -- --/* Write out the constructor and destructor tables statically (for a shared -- object), along with the functions to execute them. */ -- --static void --write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) --{ -- const char *p, *q; -- char *prefix, *r; -- int frames = (frame_tables.number > 0); -- -- /* Figure out name of output_file, stripping off .so version. */ -- p = strrchr (output_file, '/'); -- if (p == 0) -- p = output_file; -- else -- p++; -- q = p; -- while (q) -- { -- q = strchr (q,'.'); -- if (q == 0) -- { -- q = p + strlen (p); -- break; -- } -- else -- { -- if (strncmp (q, ".so", 3) == 0) -- { -- q += 3; -- break; -- } -- else -- q++; -- } -- } -- /* q points to null at end of the string (or . of the .so version) */ -- prefix = xmalloc (q - p + 1); -- strncpy (prefix, p, q - p); -- prefix[q - p] = 0; -- for (r = prefix; *r; r++) -- if (!ISALNUM ((unsigned char)*r)) -- *r = '_'; -- if (debug) -- notice ("\nwrite_c_file - output name is %s, prefix is %s\n", -- output_file, prefix); -- -- initname = concat ("_GLOBAL__FI_", prefix, NULL); -- fininame = concat ("_GLOBAL__FD_", prefix, NULL); -- -- free (prefix); -- -- /* Write the tables as C code. */ -- -- fprintf (stream, "static int count;\n"); -- fprintf (stream, "typedef void entry_pt();\n"); -- write_list_with_asm (stream, "extern entry_pt ", constructors.first); -- -- if (frames) -- { -- write_list_with_asm (stream, "extern void *", frame_tables.first); -- -- fprintf (stream, "\tstatic void *frame_table[] = {\n"); -- write_list (stream, "\t\t&", frame_tables.first); -- fprintf (stream, "\t0\n};\n"); -- -- /* This must match what's in frame.h. */ -- fprintf (stream, "struct object {\n"); -- fprintf (stream, " void *pc_begin;\n"); -- fprintf (stream, " void *pc_end;\n"); -- fprintf (stream, " void *fde_begin;\n"); -- fprintf (stream, " void *fde_array;\n"); -- fprintf (stream, " __SIZE_TYPE__ count;\n"); -- fprintf (stream, " struct object *next;\n"); -- fprintf (stream, "};\n"); -- -- fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n"); -- fprintf (stream, "extern void *__deregister_frame_info (void *);\n"); -- -- fprintf (stream, "static void reg_frame () {\n"); -- fprintf (stream, "\tstatic struct object ob;\n"); -- fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n"); -- fprintf (stream, "\t}\n"); -- -- fprintf (stream, "static void dereg_frame () {\n"); -- fprintf (stream, "\t__deregister_frame_info (frame_table);\n"); -- fprintf (stream, "\t}\n"); -- } -- -- fprintf (stream, "void %s() {\n", initname); -- if (constructors.number > 0 || frames) -- { -- fprintf (stream, "\tstatic entry_pt *ctors[] = {\n"); -- write_list (stream, "\t\t", constructors.first); -- if (frames) -- fprintf (stream, "\treg_frame,\n"); -- fprintf (stream, "\t};\n"); -- fprintf (stream, "\tentry_pt **p;\n"); -- fprintf (stream, "\tif (count++ != 0) return;\n"); -- fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames); -- fprintf (stream, "\twhile (p > ctors) (*--p)();\n"); -- } -- else -- fprintf (stream, "\t++count;\n"); -- fprintf (stream, "}\n"); -- write_list_with_asm (stream, "extern entry_pt ", destructors.first); -- fprintf (stream, "void %s() {\n", fininame); -- if (destructors.number > 0 || frames) -- { -- fprintf (stream, "\tstatic entry_pt *dtors[] = {\n"); -- write_list (stream, "\t\t", destructors.first); -- if (frames) -- fprintf (stream, "\tdereg_frame,\n"); -- fprintf (stream, "\t};\n"); -- fprintf (stream, "\tentry_pt **p;\n"); -- fprintf (stream, "\tif (--count != 0) return;\n"); -- fprintf (stream, "\tp = dtors;\n"); -- fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n", -- destructors.number + frames); -- } -- fprintf (stream, "}\n"); -- -- if (shared_obj) -- { -- COLLECT_SHARED_INIT_FUNC(stream, initname); -- COLLECT_SHARED_FINI_FUNC(stream, fininame); -- } --} -- --/* Write the constructor/destructor tables. */ -- --#ifndef LD_INIT_SWITCH --static void --write_c_file_glob (FILE *stream, const char *name ATTRIBUTE_UNUSED) --{ -- /* Write the tables as C code. */ -- -- int frames = (frame_tables.number > 0); -- -- fprintf (stream, "typedef void entry_pt();\n\n"); -- -- write_list_with_asm (stream, "extern entry_pt ", constructors.first); -- -- if (frames) -- { -- write_list_with_asm (stream, "extern void *", frame_tables.first); -- -- fprintf (stream, "\tstatic void *frame_table[] = {\n"); -- write_list (stream, "\t\t&", frame_tables.first); -- fprintf (stream, "\t0\n};\n"); -- -- /* This must match what's in frame.h. */ -- fprintf (stream, "struct object {\n"); -- fprintf (stream, " void *pc_begin;\n"); -- fprintf (stream, " void *pc_end;\n"); -- fprintf (stream, " void *fde_begin;\n"); -- fprintf (stream, " void *fde_array;\n"); -- fprintf (stream, " __SIZE_TYPE__ count;\n"); -- fprintf (stream, " struct object *next;\n"); -- fprintf (stream, "};\n"); -- -- fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n"); -- fprintf (stream, "extern void *__deregister_frame_info (void *);\n"); -- -- fprintf (stream, "static void reg_frame () {\n"); -- fprintf (stream, "\tstatic struct object ob;\n"); -- fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n"); -- fprintf (stream, "\t}\n"); -- -- fprintf (stream, "static void dereg_frame () {\n"); -- fprintf (stream, "\t__deregister_frame_info (frame_table);\n"); -- fprintf (stream, "\t}\n"); -- } -- -- fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n"); -- fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames); -- write_list (stream, "\t", constructors.first); -- if (frames) -- fprintf (stream, "\treg_frame,\n"); -- fprintf (stream, "\t0\n};\n\n"); -- -- write_list_with_asm (stream, "extern entry_pt ", destructors.first); -- -- fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n"); -- fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames); -- write_list (stream, "\t", destructors.first); -- if (frames) -- fprintf (stream, "\tdereg_frame,\n"); -- fprintf (stream, "\t0\n};\n\n"); -- -- fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN); -- fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN); --} --#endif /* ! LD_INIT_SWITCH */ -- --static void --write_c_file (FILE *stream, const char *name) --{ -- fprintf (stream, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); --#ifndef LD_INIT_SWITCH -- if (! shared_obj) -- write_c_file_glob (stream, name); -- else --#endif -- write_c_file_stat (stream, name); -- fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n"); --} -- --#ifdef COLLECT_EXPORT_LIST --static void --write_aix_file (FILE *stream, struct id *list) --{ -- for (; list; list = list->next) -- { -- fputs (list->name, stream); -- putc ('\n', stream); -- } --} --#endif -- --#ifdef OBJECT_FORMAT_NONE -- --/* Generic version to scan the name list of the loaded program for -- the symbols g++ uses for static constructors and destructors. -- -- The constructor table begins at __CTOR_LIST__ and contains a count -- of the number of pointers (or -1 if the constructors are built in a -- separate section by the linker), followed by the pointers to the -- constructor functions, terminated with a null pointer. The -- destructor table has the same format, and begins at __DTOR_LIST__. */ -- --static void --scan_prog_file (const char *prog_name, enum pass which_pass) --{ -- void (*int_handler) (int); -- void (*quit_handler) (int); -- char *real_nm_argv[4]; -- const char **nm_argv = (const char **) real_nm_argv; -- int argc = 0; -- int pipe_fd[2]; -- char *p, buf[1024]; -- FILE *inf; -- -- if (which_pass == PASS_SECOND) -- return; -- -- /* If we do not have an `nm', complain. */ -- if (nm_file_name == 0) -- fatal ("cannot find `nm'"); -- -- nm_argv[argc++] = nm_file_name; -- if (NM_FLAGS[0] != '\0') -- nm_argv[argc++] = NM_FLAGS; -- -- nm_argv[argc++] = prog_name; -- nm_argv[argc++] = (char *) 0; -- -- if (pipe (pipe_fd) < 0) -- fatal_perror ("pipe"); -- -- inf = fdopen (pipe_fd[0], "r"); -- if (inf == (FILE *) 0) -- fatal_perror ("fdopen"); -- -- /* Trace if needed. */ -- if (vflag) -- { -- const char **p_argv; -- const char *str; -- -- for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++) -- fprintf (stderr, " %s", str); -- -- fprintf (stderr, "\n"); -- } -- -- fflush (stdout); -- fflush (stderr); -- -- /* Spawn child nm on pipe. */ -- pid = vfork (); -- if (pid == -1) -- fatal_perror (VFORK_STRING); -- -- if (pid == 0) /* child context */ -- { -- /* setup stdout */ -- if (dup2 (pipe_fd[1], 1) < 0) -- fatal_perror ("dup2 %d 1", pipe_fd[1]); -- -- if (close (pipe_fd[0]) < 0) -- fatal_perror ("close %d", pipe_fd[0]); -- -- if (close (pipe_fd[1]) < 0) -- fatal_perror ("close %d", pipe_fd[1]); -- -- execv (nm_file_name, real_nm_argv); -- fatal_perror ("execv %s", nm_file_name); -- } -- -- /* Parent context from here on. */ -- int_handler = (void (*) (int)) signal (SIGINT, SIG_IGN); --#ifdef SIGQUIT -- quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN); --#endif -- -- if (close (pipe_fd[1]) < 0) -- fatal_perror ("close %d", pipe_fd[1]); -- -- if (debug) -- fprintf (stderr, "\nnm output with constructors/destructors.\n"); -- -- /* Read each line of nm output. */ -- while (fgets (buf, sizeof buf, inf) != (char *) 0) -- { -- int ch, ch2; -- char *name, *end; -- -- /* If it contains a constructor or destructor name, add the name -- to the appropriate list. */ -- -- for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++) -- if (ch == ' ' && p[1] == 'U' && p[2] == ' ') -- break; -- -- if (ch != '_') -- continue; -- -- name = p; -- /* Find the end of the symbol name. -- Do not include `|', because Encore nm can tack that on the end. */ -- for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|'; -- end++) -- continue; -- -- -- *end = '\0'; -- switch (is_ctor_dtor (name)) -- { -- case 1: -- if (which_pass != PASS_LIB) -- add_to_list (&constructors, name); -- break; -- -- case 2: -- if (which_pass != PASS_LIB) -- add_to_list (&destructors, name); -- break; -- -- case 3: -- if (which_pass != PASS_LIB) -- fatal ("init function found in object %s", prog_name); --#ifndef LD_INIT_SWITCH -- add_to_list (&constructors, name); --#endif -- break; -- -- case 4: -- if (which_pass != PASS_LIB) -- fatal ("fini function found in object %s", prog_name); --#ifndef LD_FINI_SWITCH -- add_to_list (&destructors, name); --#endif -- break; -- -- case 5: -- if (which_pass != PASS_LIB) -- add_to_list (&frame_tables, name); -- break; -- -- default: /* not a constructor or destructor */ -- continue; -- } -- -- if (debug) -- fprintf (stderr, "\t%s\n", buf); -- } -- -- if (debug) -- fprintf (stderr, "\n"); -- -- if (fclose (inf) != 0) -- fatal_perror ("fclose"); -- -- do_wait (nm_file_name); -- -- signal (SIGINT, int_handler); --#ifdef SIGQUIT -- signal (SIGQUIT, quit_handler); --#endif --} -- --#if SUNOS4_SHARED_LIBRARIES -- --/* Routines to scan the SunOS 4 _DYNAMIC structure to find shared libraries -- that the output file depends upon and their initialization/finalization -- routines, if any. */ -- --#include <a.out.h> --#include <fcntl.h> --#include <link.h> --#include <sys/mman.h> --#include <sys/param.h> --#include <unistd.h> --#include <sys/dir.h> -- --/* pointers to the object file */ --unsigned object; /* address of memory mapped file */ --unsigned objsize; /* size of memory mapped to file */ --char * code; /* pointer to code segment */ --char * data; /* pointer to data segment */ --struct nlist *symtab; /* pointer to symbol table */ --struct link_dynamic *ld; --struct link_dynamic_2 *ld_2; --struct head libraries; -- --/* Map the file indicated by NAME into memory and store its address. */ -- --static void --mapfile (const char *name) --{ -- int fp; -- struct stat s; -- if ((fp = open (name, O_RDONLY)) == -1) -- fatal ("unable to open file '%s'", name); -- if (fstat (fp, &s) == -1) -- fatal ("unable to stat file '%s'", name); -- -- objsize = s.st_size; -- object = (unsigned) mmap (0, objsize, PROT_READ|PROT_WRITE, MAP_PRIVATE, -- fp, 0); -- if (object == (unsigned)-1) -- fatal ("unable to mmap file '%s'", name); -- -- close (fp); --} -- --/* Helpers for locatelib. */ -- --static const char *libname; -- --static int --libselect (struct direct *d) --{ -- return (strncmp (libname, d->d_name, strlen (libname)) == 0); --} -- --/* If one file has an additional numeric extension past LIBNAME, then put -- that one first in the sort. If both files have additional numeric -- extensions, then put the one with the higher number first in the sort. -- -- We must verify that the extension is numeric, because Sun saves the -- original versions of patched libraries with a .FCS extension. Files with -- invalid extensions must go last in the sort, so that they will not be used. */ -- --static int --libcompare (struct direct **d1, struct direct **d2) --{ -- int i1, i2 = strlen (libname); -- char *e1 = (*d1)->d_name + i2; -- char *e2 = (*d2)->d_name + i2; -- -- while (*e1 && *e2 && *e1 == '.' && *e2 == '.' -- && e1[1] && ISDIGIT (e1[1]) && e2[1] && ISDIGIT (e2[1])) -- { -- ++e1; -- ++e2; -- i1 = strtol (e1, &e1, 10); -- i2 = strtol (e2, &e2, 10); -- if (i1 != i2) -- return i1 - i2; -- } -- -- if (*e1) -- { -- /* It has a valid numeric extension, prefer this one. */ -- if (*e1 == '.' && e1[1] && ISDIGIT (e1[1])) -- return 1; -- /* It has an invalid numeric extension, must prefer the other one. */ -- else -- return -1; -- } -- else if (*e2) -- { -- /* It has a valid numeric extension, prefer this one. */ -- if (*e2 == '.' && e2[1] && ISDIGIT (e2[1])) -- return -1; -- /* It has an invalid numeric extension, must prefer the other one. */ -- else -- return 1; -- } -- else -- return 0; --} -- --/* Given the name NAME of a dynamic dependency, find its pathname and add -- it to the list of libraries. */ -- --static void --locatelib (const char *name) --{ -- static const char **l; -- static int cnt; -- char buf[MAXPATHLEN]; -- char *p, *q; -- const char **pp; -- -- if (l == 0) -- { -- char *ld_rules; -- char *ldr = 0; -- /* counting elements in array, need 1 extra for null */ -- cnt = 1; -- ld_rules = (char *) (ld_2->ld_rules + code); -- if (ld_rules) -- { -- cnt++; -- for (; *ld_rules != 0; ld_rules++) -- if (*ld_rules == ':') -- cnt++; -- ld_rules = (char *) (ld_2->ld_rules + code); -- ldr = xstrdup (ld_rules); -- } -- p = getenv ("LD_LIBRARY_PATH"); -- q = 0; -- if (p) -- { -- cnt++; -- for (q = p ; *q != 0; q++) -- if (*q == ':') -- cnt++; -- q = xstrdup (p); -- } -- l = xmalloc ((cnt + 3) * sizeof (char *)); -- pp = l; -- if (ldr) -- { -- *pp++ = ldr; -- for (; *ldr != 0; ldr++) -- if (*ldr == ':') -- { -- *ldr++ = 0; -- *pp++ = ldr; -- } -- } -- if (q) -- { -- *pp++ = q; -- for (; *q != 0; q++) -- if (*q == ':') -- { -- *q++ = 0; -- *pp++ = q; -- } -- } -- /* built in directories are /lib, /usr/lib, and /usr/local/lib */ -- *pp++ = "/lib"; -- *pp++ = "/usr/lib"; -- *pp++ = "/usr/local/lib"; -- *pp = 0; -- } -- libname = name; -- for (pp = l; *pp != 0 ; pp++) -- { -- struct direct **namelist; -- int entries; -- if ((entries = scandir (*pp, &namelist, libselect, libcompare)) > 0) -- { -- sprintf (buf, "%s/%s", *pp, namelist[entries - 1]->d_name); -- add_to_list (&libraries, buf); -- if (debug) -- fprintf (stderr, "%s\n", buf); -- break; -- } -- } -- if (*pp == 0) -- { -- if (debug) -- notice ("not found\n"); -- else -- fatal ("dynamic dependency %s not found", name); -- } --} -- --/* Scan the _DYNAMIC structure of the output file to find shared libraries -- that it depends upon and any constructors or destructors they contain. */ -- --static void --scan_libraries (const char *prog_name) --{ -- struct exec *header; -- char *base; -- struct link_object *lo; -- char buff[MAXPATHLEN]; -- struct id *list; -- -- mapfile (prog_name); -- header = (struct exec *)object; -- if (N_BADMAG (*header)) -- fatal ("bad magic number in file '%s'", prog_name); -- if (header->a_dynamic == 0) -- return; -- -- code = (char *) (N_TXTOFF (*header) + (long) header); -- data = (char *) (N_DATOFF (*header) + (long) header); -- symtab = (struct nlist *) (N_SYMOFF (*header) + (long) header); -- -- if (header->a_magic == ZMAGIC && header->a_entry == 0x20) -- { -- /* shared object */ -- ld = (struct link_dynamic *) (symtab->n_value + code); -- base = code; -- } -- else -- { -- /* executable */ -- ld = (struct link_dynamic *) data; -- base = code-PAGSIZ; -- } -- -- if (debug) -- notice ("dynamic dependencies.\n"); -- -- ld_2 = (struct link_dynamic_2 *) ((long) ld->ld_un.ld_2 + (long)base); -- for (lo = (struct link_object *) ld_2->ld_need; lo; -- lo = (struct link_object *) lo->lo_next) -- { -- char *name; -- lo = (struct link_object *) ((long) lo + code); -- name = (char *) (code + lo->lo_name); -- if (lo->lo_library) -- { -- if (debug) -- fprintf (stderr, "\t-l%s.%d => ", name, lo->lo_major); -- sprintf (buff, "lib%s.so.%d.%d", name, lo->lo_major, lo->lo_minor); -- locatelib (buff); -- } -- else -- { -- if (debug) -- fprintf (stderr, "\t%s\n", name); -- add_to_list (&libraries, name); -- } -- } -- -- if (debug) -- fprintf (stderr, "\n"); -- -- /* Now iterate through the library list adding their symbols to -- the list. */ -- for (list = libraries.first; list; list = list->next) -- scan_prog_file (list->name, PASS_LIB); --} -- --#else /* SUNOS4_SHARED_LIBRARIES */ --#ifdef LDD_SUFFIX -- --/* Use the List Dynamic Dependencies program to find shared libraries that -- the output file depends upon and their initialization/finalization -- routines, if any. */ -- --static void --scan_libraries (const char *prog_name) --{ -- static struct head libraries; /* list of shared libraries found */ -- struct id *list; -- void (*int_handler) (int); -- void (*quit_handler) (int); -- char *real_ldd_argv[4]; -- const char **ldd_argv = (const char **) real_ldd_argv; -- int argc = 0; -- int pipe_fd[2]; -- char buf[1024]; -- FILE *inf; -- -- /* If we do not have an `ldd', complain. */ -- if (ldd_file_name == 0) -- { -- error ("cannot find `ldd'"); -- return; -- } -- -- ldd_argv[argc++] = ldd_file_name; -- ldd_argv[argc++] = prog_name; -- ldd_argv[argc++] = (char *) 0; -- -- if (pipe (pipe_fd) < 0) -- fatal_perror ("pipe"); -- -- inf = fdopen (pipe_fd[0], "r"); -- if (inf == (FILE *) 0) -- fatal_perror ("fdopen"); -- -- /* Trace if needed. */ -- if (vflag) -- { -- const char **p_argv; -- const char *str; -- -- for (p_argv = &ldd_argv[0]; (str = *p_argv) != (char *) 0; p_argv++) -- fprintf (stderr, " %s", str); -- -- fprintf (stderr, "\n"); -- } -- -- fflush (stdout); -- fflush (stderr); -- -- /* Spawn child ldd on pipe. */ -- pid = vfork (); -- if (pid == -1) -- fatal_perror (VFORK_STRING); -- -- if (pid == 0) /* child context */ -- { -- /* setup stdout */ -- if (dup2 (pipe_fd[1], 1) < 0) -- fatal_perror ("dup2 %d 1", pipe_fd[1]); -- -- if (close (pipe_fd[0]) < 0) -- fatal_perror ("close %d", pipe_fd[0]); -- -- if (close (pipe_fd[1]) < 0) -- fatal_perror ("close %d", pipe_fd[1]); -- -- execv (ldd_file_name, real_ldd_argv); -- fatal_perror ("execv %s", ldd_file_name); -- } -- -- /* Parent context from here on. */ -- int_handler = (void (*) (int)) signal (SIGINT, SIG_IGN); --#ifdef SIGQUIT -- quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN); --#endif -- -- if (close (pipe_fd[1]) < 0) -- fatal_perror ("close %d", pipe_fd[1]); -- -- if (debug) -- notice ("\nldd output with constructors/destructors.\n"); -- -- /* Read each line of ldd output. */ -- while (fgets (buf, sizeof buf, inf) != (char *) 0) -- { -- int ch2; -- char *name, *end, *p = buf; -- -- /* Extract names of libraries and add to list. */ -- PARSE_LDD_OUTPUT (p); -- if (p == 0) -- continue; -- -- name = p; -- if (strncmp (name, "not found", sizeof ("not found") - 1) == 0) -- fatal ("dynamic dependency %s not found", buf); -- -- /* Find the end of the symbol name. */ -- for (end = p; -- (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|'; -- end++) -- continue; -- *end = '\0'; -- -- if (access (name, R_OK) == 0) -- add_to_list (&libraries, name); -- else -- fatal ("unable to open dynamic dependency '%s'", buf); -- -- if (debug) -- fprintf (stderr, "\t%s\n", buf); -- } -- if (debug) -- fprintf (stderr, "\n"); -- -- if (fclose (inf) != 0) -- fatal_perror ("fclose"); -- -- do_wait (ldd_file_name); -- -- signal (SIGINT, int_handler); --#ifdef SIGQUIT -- signal (SIGQUIT, quit_handler); --#endif -- -- /* Now iterate through the library list adding their symbols to -- the list. */ -- for (list = libraries.first; list; list = list->next) -- scan_prog_file (list->name, PASS_LIB); --} -- --#endif /* LDD_SUFFIX */ --#endif /* SUNOS4_SHARED_LIBRARIES */ -- --#endif /* OBJECT_FORMAT_NONE */ -- -- --/* -- * COFF specific stuff. -- */ -- --#ifdef OBJECT_FORMAT_COFF -- --#if defined (EXTENDED_COFF) -- --# define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax + SYMHEADER(X).iextMax) --# define GCC_SYMENT SYMR --# define GCC_OK_SYMBOL(X) ((X).st == stProc || (X).st == stGlobal) --# define GCC_SYMINC(X) (1) --# define GCC_SYMZERO(X) (SYMHEADER(X).isymMax) --# define GCC_CHECK_HDR(X) (PSYMTAB(X) != 0) -- --#else -- --# define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms) --# define GCC_SYMENT SYMENT --# if defined (C_WEAKEXT) --# define GCC_OK_SYMBOL(X) \ -- (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \ -- ((X).n_scnum > N_UNDEF) && \ -- (aix64_flag \ -- || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \ -- || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))) --# define GCC_UNDEF_SYMBOL(X) \ -- (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \ -- ((X).n_scnum == N_UNDEF)) --# else --# define GCC_OK_SYMBOL(X) \ -- (((X).n_sclass == C_EXT) && \ -- ((X).n_scnum > N_UNDEF) && \ -- (aix64_flag \ -- || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \ -- || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))) --# define GCC_UNDEF_SYMBOL(X) \ -- (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF)) --# endif --# define GCC_SYMINC(X) ((X).n_numaux+1) --# define GCC_SYMZERO(X) 0 -- --/* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */ --#ifdef _AIX51 --# define GCC_CHECK_HDR(X) \ -- ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ -- || (HEADER (X).f_magic == 0767 && aix64_flag)) --#else --# define GCC_CHECK_HDR(X) \ -- ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ -- || (HEADER (X).f_magic == 0757 && aix64_flag)) --#endif -- --#endif -- --#ifdef COLLECT_EXPORT_LIST --/* Array of standard AIX libraries which should not -- be scanned for ctors/dtors. */ --static const char *const aix_std_libs[] = { -- "/unix", -- "/lib/libc.a", -- "/lib/libm.a", -- "/lib/libc_r.a", -- "/lib/libm_r.a", -- "/usr/lib/libc.a", -- "/usr/lib/libm.a", -- "/usr/lib/libc_r.a", -- "/usr/lib/libm_r.a", -- "/usr/lib/threads/libc.a", -- "/usr/ccs/lib/libc.a", -- "/usr/ccs/lib/libm.a", -- "/usr/ccs/lib/libc_r.a", -- "/usr/ccs/lib/libm_r.a", -- NULL --}; -- --/* This function checks the filename and returns 1 -- if this name matches the location of a standard AIX library. */ --static int ignore_library (const char *); --static int --ignore_library (const char *name) --{ -- const char *const *p = &aix_std_libs[0]; -- while (*p++ != NULL) -- if (! strcmp (name, *p)) return 1; -- return 0; --} --#endif /* COLLECT_EXPORT_LIST */ -- --#if defined (HAVE_DECL_LDGETNAME) && !HAVE_DECL_LDGETNAME --extern char *ldgetname (LDFILE *, GCC_SYMENT *); --#endif -- --/* COFF version to scan the name list of the loaded program for -- the symbols g++ uses for static constructors and destructors. -- -- The constructor table begins at __CTOR_LIST__ and contains a count -- of the number of pointers (or -1 if the constructors are built in a -- separate section by the linker), followed by the pointers to the -- constructor functions, terminated with a null pointer. The -- destructor table has the same format, and begins at __DTOR_LIST__. */ -- --static void --scan_prog_file (const char *prog_name, enum pass which_pass) --{ -- LDFILE *ldptr = NULL; -- int sym_index, sym_count; -- int is_shared = 0; -- -- if (which_pass != PASS_FIRST && which_pass != PASS_OBJ) -- return; -- --#ifdef COLLECT_EXPORT_LIST -- /* We do not need scanning for some standard C libraries. */ -- if (which_pass == PASS_FIRST && ignore_library (prog_name)) -- return; -- -- /* On AIX we have a loop, because there is not much difference -- between an object and an archive. This trick allows us to -- eliminate scan_libraries() function. */ -- do -- { --#endif -- /* Some platforms (e.g. OSF4) declare ldopen as taking a -- non-const char * filename parameter, even though it will not -- modify that string. So we must cast away const-ness here, -- which will cause -Wcast-qual to burp. */ -- if ((ldptr = ldopen ((char *)prog_name, ldptr)) != NULL) -- { -- if (! MY_ISCOFF (HEADER (ldptr).f_magic)) -- fatal ("%s: not a COFF file", prog_name); -- -- if (GCC_CHECK_HDR (ldptr)) -- { -- sym_count = GCC_SYMBOLS (ldptr); -- sym_index = GCC_SYMZERO (ldptr); -- --#ifdef COLLECT_EXPORT_LIST -- /* Is current archive member a shared object? */ -- is_shared = HEADER (ldptr).f_flags & F_SHROBJ; --#endif -- -- while (sym_index < sym_count) -- { -- GCC_SYMENT symbol; -- -- if (ldtbread (ldptr, sym_index, &symbol) <= 0) -- break; -- sym_index += GCC_SYMINC (symbol); -- -- if (GCC_OK_SYMBOL (symbol)) -- { -- char *name; -- -- if ((name = ldgetname (ldptr, &symbol)) == NULL) -- continue; /* Should never happen. */ -- --#ifdef XCOFF_DEBUGGING_INFO -- /* All AIX function names have a duplicate entry -- beginning with a dot. */ -- if (*name == '.') -- ++name; --#endif -- -- switch (is_ctor_dtor (name)) -- { -- case 1: -- if (! is_shared) -- add_to_list (&constructors, name); --#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH) -- if (which_pass == PASS_OBJ) -- add_to_list (&exports, name); --#endif -- break; -- -- case 2: -- if (! is_shared) -- add_to_list (&destructors, name); --#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH) -- if (which_pass == PASS_OBJ) -- add_to_list (&exports, name); --#endif -- break; -- --#ifdef COLLECT_EXPORT_LIST -- case 3: --#ifndef LD_INIT_SWITCH -- if (is_shared) -- add_to_list (&constructors, name); --#endif -- break; -- -- case 4: --#ifndef LD_INIT_SWITCH -- if (is_shared) -- add_to_list (&destructors, name); --#endif -- break; --#endif -- -- case 5: -- if (! is_shared) -- add_to_list (&frame_tables, name); --#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH) -- if (which_pass == PASS_OBJ) -- add_to_list (&exports, name); --#endif -- break; -- -- default: /* not a constructor or destructor */ --#ifdef COLLECT_EXPORT_LIST -- /* Explicitly export all global symbols when -- building a shared object on AIX, but do not -- re-export symbols from another shared object -- and do not export symbols if the user -- provides an explicit export list. */ -- if (shared_obj && !is_shared -- && which_pass == PASS_OBJ && !export_flag) -- add_to_list (&exports, name); --#endif -- continue; -- } -- -- if (debug) --#if !defined(EXTENDED_COFF) -- fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n", -- symbol.n_scnum, symbol.n_sclass, -- (symbol.n_type ? "0" : ""), symbol.n_type, -- name); --#else -- fprintf (stderr, -- "\tiss = %5d, value = %5ld, index = %5d, name = %s\n", -- symbol.iss, (long) symbol.value, symbol.index, name); --#endif -- } -- } -- } --#ifdef COLLECT_EXPORT_LIST -- else -- { -- /* If archive contains both 32-bit and 64-bit objects, -- we want to skip objects in other mode so mismatch normal. */ -- if (debug) -- fprintf (stderr, "%s : magic=%o aix64=%d mismatch\n", -- prog_name, HEADER (ldptr).f_magic, aix64_flag); -- } --#endif -- } -- else -- { -- fatal ("%s: cannot open as COFF file", prog_name); -- } --#ifdef COLLECT_EXPORT_LIST -- /* On AIX loop continues while there are more members in archive. */ -- } -- while (ldclose (ldptr) == FAILURE); --#else -- /* Otherwise we simply close ldptr. */ -- (void) ldclose(ldptr); --#endif --} --#endif /* OBJECT_FORMAT_COFF */ -- --#ifdef COLLECT_EXPORT_LIST --/* Given a library name without "lib" prefix, this function -- returns a full library name including a path. */ --static char * --resolve_lib_name (const char *name) --{ -- char *lib_buf; -- int i, j, l = 0; -- /* Library extensions for AIX dynamic linking. */ -- const char * const libexts[2] = {"a", "so"}; -- -- for (i = 0; libpaths[i]; i++) -- if (libpaths[i]->max_len > l) -- l = libpaths[i]->max_len; -- -- lib_buf = xmalloc (l + strlen(name) + 10); -- -- for (i = 0; libpaths[i]; i++) -- { -- struct prefix_list *list = libpaths[i]->plist; -- for (; list; list = list->next) -- { -- /* The following lines are needed because path_prefix list -- may contain directories both with trailing '/' and -- without it. */ -- const char *p = ""; -- if (list->prefix[strlen(list->prefix)-1] != '/') -- p = "/"; -- for (j = 0; j < 2; j++) -- { -- sprintf (lib_buf, "%s%slib%s.%s", -- list->prefix, p, name, -- libexts[(j + aixrtl_flag) % 2]); -- if (debug) fprintf (stderr, "searching for: %s\n", lib_buf); -- if (file_exists (lib_buf)) -- { -- if (debug) fprintf (stderr, "found: %s\n", lib_buf); -- return (lib_buf); -- } -- } -- } -- } -- if (debug) -- fprintf (stderr, "not found\n"); -- else -- fatal ("library lib%s not found", name); -- return (NULL); --} --#endif /* COLLECT_EXPORT_LIST */ -diff -ruN gcc-3.4.5-20060117-1/gcc/config/i386/cygming.h.orig gcc-3.4.5-20060117-1-winelf/gcc/config/i386/cygming.h.orig ---- gcc-3.4.5-20060117-1/gcc/config/i386/cygming.h.orig 2004-06-07 23:30:32.000000000 -0700 -+++ gcc-3.4.5-20060117-1-winelf/gcc/config/i386/cygming.h.orig 1969-12-31 16:00:00.000000000 -0800 -@@ -1,391 +0,0 @@ --/* Operating system specific defines to be used when targeting GCC for -- hosting on Windows32, using a Unix style C library and tools. -- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 -- Free Software Foundation, Inc. -- --This file is part of GCC. -- --GCC is free software; you can redistribute it and/or modify --it under the terms of the GNU General Public License as published by --the Free Software Foundation; either version 2, 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 COPYING. If not, write to --the Free Software Foundation, 59 Temple Place - Suite 330, --Boston, MA 02111-1307, USA. */ -- --#define DBX_DEBUGGING_INFO 1 --#define SDB_DEBUGGING_INFO 1 --#undef PREFERRED_DEBUGGING_TYPE --#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG -- --#define TARGET_EXECUTABLE_SUFFIX ".exe" -- --#define TARGET_IS_PE_COFF 1 -- --#include <stdio.h> -- --/* Masks for subtarget switches used by other files. */ --#define MASK_NOP_FUN_DLLIMPORT 0x08000000 /* Ignore dllimport for functions */ -- --/* Used in winnt.c. */ --#define TARGET_NOP_FUN_DLLIMPORT (target_flags & MASK_NOP_FUN_DLLIMPORT) -- --#undef SUBTARGET_SWITCHES --#define SUBTARGET_SWITCHES \ --{ "cygwin", 0, N_("Use the Cygwin interface") }, \ --{ "no-cygwin", 0, N_("Use the Mingw32 interface") }, \ --{ "windows", 0, N_("Create GUI application") }, \ --{ "no-win32", 0, N_("Don't set Windows defines") }, \ --{ "win32", 0, N_("Set Windows defines") }, \ --{ "console", 0, N_("Create console application") },\ --{ "dll", 0, N_("Generate code for a DLL") }, \ --{ "nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, \ -- N_("Ignore dllimport for functions") }, \ --{ "no-nop-fun-dllimport", -MASK_NOP_FUN_DLLIMPORT, "" }, \ --{ "threads", 0, N_("Use Mingw-specific thread support") }, -- --#define MAYBE_UWIN_CPP_BUILTINS() /* Nothing. */ -- --/* Support the __declspec keyword by turning them into attributes. -- We currently only support: dllimport and dllexport. -- Note that the current way we do this may result in a collision with -- predefined attributes later on. This can be solved by using one attribute, -- say __declspec__, and passing args to it. The problem with that approach -- is that args are not accumulated: each new appearance would clobber any -- existing args. */ -- --#define TARGET_OS_CPP_BUILTINS() \ -- do \ -- { \ -- builtin_define ("_X86_=1"); \ -- builtin_assert ("system=winnt"); \ -- builtin_define ("__stdcall=__attribute__((__stdcall__))"); \ -- builtin_define ("__fastcall=__attribute__((__fastcall__))"); \ -- builtin_define ("__cdecl=__attribute__((__cdecl__))"); \ -- builtin_define ("__declspec(x)=__attribute__((x))"); \ -- if (!flag_iso) \ -- { \ -- builtin_define ("_stdcall=__attribute__((__stdcall__))"); \ -- builtin_define ("_fastcall=__attribute__((__fastcall__))"); \ -- builtin_define ("_cdecl=__attribute__((__cdecl__))"); \ -- } \ -- MAYBE_UWIN_CPP_BUILTINS (); \ -- EXTRA_OS_CPP_BUILTINS (); \ -- } \ -- while (0) -- --/* Get tree.c to declare a target-specific specialization of -- merge_decl_attributes. */ --#define TARGET_DLLIMPORT_DECL_ATTRIBUTES -- --/* This macro defines names of additional specifications to put in the specs -- that can be used in various specifications like CC1_SPEC. Its definition -- is an initializer with a subgrouping for each command option. -- -- Each subgrouping contains a string constant, that defines the -- specification name, and a string constant that used by the GCC driver -- program. -- -- Do not define this macro if it does not need to do anything. */ -- --#undef SUBTARGET_EXTRA_SPECS --#define SUBTARGET_EXTRA_SPECS \ -- { "mingw_include_path", DEFAULT_TARGET_MACHINE } -- --#undef MATH_LIBRARY --#define MATH_LIBRARY "" -- --#define SIZE_TYPE "unsigned int" --#define PTRDIFF_TYPE "int" --#define WCHAR_TYPE_SIZE 16 --#define WCHAR_TYPE "short unsigned int" -- -- --/* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop). */ --#define HANDLE_PRAGMA_PACK_PUSH_POP 1 -- --union tree_node; --#define TREE union tree_node * -- --#undef EXTRA_SECTIONS --#define EXTRA_SECTIONS in_drectve -- --#undef EXTRA_SECTION_FUNCTIONS --#define EXTRA_SECTION_FUNCTIONS \ -- DRECTVE_SECTION_FUNCTION \ -- SWITCH_TO_SECTION_FUNCTION -- --#define DRECTVE_SECTION_FUNCTION \ --void \ --drectve_section (void) \ --{ \ -- if (in_section != in_drectve) \ -- { \ -- fprintf (asm_out_file, "%s\n", "\t.section .drectve\n"); \ -- in_section = in_drectve; \ -- } \ --} --void drectve_section (void); -- --/* Older versions of gas don't handle 'r' as data. -- Explicitly set data flag with 'd'. */ --#define READONLY_DATA_SECTION_ASM_OP "\t.section .rdata,\"dr\"" -- --/* Switch to SECTION (an `enum in_section'). -- -- ??? This facility should be provided by GCC proper. -- The problem is that we want to temporarily switch sections in -- ASM_DECLARE_OBJECT_NAME and then switch back to the original section -- afterwards. */ --#define SWITCH_TO_SECTION_FUNCTION \ --void switch_to_section (enum in_section, tree); \ --void \ --switch_to_section (enum in_section section, tree decl) \ --{ \ -- switch (section) \ -- { \ -- case in_text: text_section (); break; \ -- case in_data: data_section (); break; \ -- case in_readonly_data: readonly_data_section (); break; \ -- case in_named: named_section (decl, NULL, 0); break; \ -- case in_drectve: drectve_section (); break; \ -- default: abort (); break; \ -- } \ --} -- --/* Don't allow flag_pic to propagate since gas may produce invalid code -- otherwise. */ -- --#undef SUBTARGET_OVERRIDE_OPTIONS --#define SUBTARGET_OVERRIDE_OPTIONS \ --do { \ -- if (flag_pic) \ -- { \ -- warning ("-f%s ignored for target (all code is position independent)",\ -- (flag_pic > 1) ? "PIC" : "pic"); \ -- flag_pic = 0; \ -- } \ --} while (0) \ -- --/* Define this macro if references to a symbol must be treated -- differently depending on something about the variable or -- function named by the symbol (such as what section it is in). -- -- On i386 running Windows NT, modify the assembler name with a suffix -- consisting of an atsign (@) followed by string of digits that represents -- the number of bytes of arguments passed to the function, if it has the -- attribute STDCALL. -- -- In addition, we must mark dll symbols specially. Definitions of -- dllexport'd objects install some info in the .drectve section. -- References to dllimport'd objects are fetched indirectly via -- _imp__. If both are declared, dllexport overrides. This is also -- needed to implement one-only vtables: they go into their own -- section and we need to set DECL_SECTION_NAME so we do that here. -- Note that we can be called twice on the same decl. */ -- --#undef TARGET_ENCODE_SECTION_INFO --#define TARGET_ENCODE_SECTION_INFO i386_pe_encode_section_info --#undef TARGET_STRIP_NAME_ENCODING --#define TARGET_STRIP_NAME_ENCODING i386_pe_strip_name_encoding_full -- --/* Output a reference to a label. */ --#undef ASM_OUTPUT_LABELREF --#define ASM_OUTPUT_LABELREF i386_pe_output_labelref -- --/* Output a common block. */ --#undef ASM_OUTPUT_COMMON --#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ --do { \ -- if (i386_pe_dllexport_name_p (NAME)) \ -- i386_pe_record_exported_symbol (NAME, 1); \ -- if (! i386_pe_dllimport_name_p (NAME)) \ -- { \ -- fprintf ((STREAM), "\t.comm\t"); \ -- assemble_name ((STREAM), (NAME)); \ -- fprintf ((STREAM), ", %d\t%s %d\n", \ -- (int)(ROUNDED), ASM_COMMENT_START, (int)(SIZE)); \ -- } \ --} while (0) -- --/* Output the label for an initialized variable. */ --#undef ASM_DECLARE_OBJECT_NAME --#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ --do { \ -- if (i386_pe_dllexport_name_p (NAME)) \ -- i386_pe_record_exported_symbol (NAME, 1); \ -- ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ --} while (0) -- -- --/* Emit code to check the stack when allocating more that 4000 -- bytes in one go. */ -- --#define CHECK_STACK_LIMIT 4000 -- --/* By default, target has a 80387, uses IEEE compatible arithmetic, -- returns float values in the 387 and needs stack probes. -- We also align doubles to 64-bits for MSVC default compatibility. */ -- --#undef TARGET_SUBTARGET_DEFAULT --#define TARGET_SUBTARGET_DEFAULT \ -- (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE \ -- | MASK_ALIGN_DOUBLE) -- --/* This is how to output an assembler line -- that says to advance the location counter -- to a multiple of 2**LOG bytes. */ -- --#undef ASM_OUTPUT_ALIGN --#define ASM_OUTPUT_ALIGN(FILE,LOG) \ -- if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) -- --/* Define this macro if in some cases global symbols from one translation -- unit may not be bound to undefined symbols in another translation unit -- without user intervention. For instance, under Microsoft Windows -- symbols must be explicitly imported from shared libraries (DLLs). */ --#define MULTIPLE_SYMBOL_SPACES -- --extern void i386_pe_unique_section (TREE, int); --#define TARGET_ASM_UNIQUE_SECTION i386_pe_unique_section -- --#define SUPPORTS_ONE_ONLY 1 -- --/* Switch into a generic section. */ --#define TARGET_ASM_NAMED_SECTION i386_pe_asm_named_section -- --/* Select attributes for named sections. */ --#define TARGET_SECTION_TYPE_FLAGS i386_pe_section_type_flags -- --/* Write the extra assembler code needed to declare a function -- properly. If we are generating SDB debugging information, this -- will happen automatically, so we only need to handle other cases. */ --#undef ASM_DECLARE_FUNCTION_NAME --#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ -- do \ -- { \ -- if (i386_pe_dllexport_name_p (NAME)) \ -- i386_pe_record_exported_symbol (NAME, 0); \ -- if (write_symbols != SDB_DEBUG) \ -- i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ -- ASM_OUTPUT_LABEL (FILE, NAME); \ -- } \ -- while (0) -- --/* Add an external function to the list of functions to be declared at -- the end of the file. */ --#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ -- do \ -- { \ -- if (TREE_CODE (DECL) == FUNCTION_DECL) \ -- i386_pe_record_external_function (NAME); \ -- } \ -- while (0) -- --/* Declare the type properly for any external libcall. */ --#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ -- i386_pe_declare_function_type (FILE, XSTR (FUN, 0), 1) -- --/* This says out to put a global symbol in the BSS section. */ --#undef ASM_OUTPUT_ALIGNED_BSS --#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ -- asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) -- --/* Output function declarations at the end of the file. */ --#undef TARGET_ASM_FILE_END --#define TARGET_ASM_FILE_END i386_pe_file_end -- --#undef ASM_COMMENT_START --#define ASM_COMMENT_START " #" -- --/* DWARF2 Unwinding doesn't work with exception handling yet. To make -- it work, we need to build a libgcc_s.dll, and dcrt0.o should be -- changed to call __register_frame_info/__deregister_frame_info. */ --#define DWARF2_UNWIND_INFO 0 -- --/* Don't assume anything about the header files. */ --#define NO_IMPLICIT_EXTERN_C -- --#undef PROFILE_HOOK --#define PROFILE_HOOK(LABEL) \ -- if (MAIN_NAME_P (DECL_NAME (current_function_decl))) \ -- { \ -- emit_call_insn (gen_rtx (CALL, VOIDmode, \ -- gen_rtx_MEM (FUNCTION_MODE, \ -- gen_rtx_SYMBOL_REF (Pmode, "_monstartup")), \ -- const0_rtx)); \ -- } -- --/* Java Native Interface (JNI) methods on Win32 are invoked using the -- stdcall calling convention. */ --#undef MODIFY_JNI_METHOD_CALL --#define MODIFY_JNI_METHOD_CALL(MDECL) \ -- build_type_attribute_variant ((MDECL), \ -- build_tree_list (get_identifier ("stdcall"), \ -- NULL)) -- --/* External function declarations. */ -- --extern void i386_pe_record_external_function (const char *); --extern void i386_pe_declare_function_type (FILE *, const char *, int); --extern void i386_pe_record_exported_symbol (const char *, int); --extern void i386_pe_file_end (void); --extern int i386_pe_dllexport_name_p (const char *); --extern int i386_pe_dllimport_name_p (const char *); -- --/* For Win32 ABI compatibility */ --#undef DEFAULT_PCC_STRUCT_RETURN --#define DEFAULT_PCC_STRUCT_RETURN 0 -- --/* MSVC returns aggregate types of up to 8 bytes via registers. -- See i386.c:ix86_return_in_memory. */ --#undef MS_AGGREGATE_RETURN --#define MS_AGGREGATE_RETURN 1 -- --/* No data type wants to be aligned rounder than this. */ --#undef BIGGEST_ALIGNMENT --#define BIGGEST_ALIGNMENT 128 -- --/* Native complier aligns internal doubles in structures on dword boundaries. */ --#undef BIGGEST_FIELD_ALIGNMENT --#define BIGGEST_FIELD_ALIGNMENT 64 -- --/* A bit-field declared as `int' forces `int' alignment for the struct. */ --#undef PCC_BITFIELD_TYPE_MATTERS --#define PCC_BITFIELD_TYPE_MATTERS 1 --#define GROUP_BITFIELDS_BY_ALIGN TYPE_NATIVE(rec) -- --/* Enable alias attribute support. */ --#ifndef SET_ASM_OP --#define SET_ASM_OP "\t.set\t" --#endif --/* This implements the `alias' attribute, keeping any stdcall or -- fastcall decoration. */ --#undef ASM_OUTPUT_DEF_FROM_DECLS --#define ASM_OUTPUT_DEF_FROM_DECLS(STREAM, DECL, TARGET) \ -- do \ -- { \ -- const char *alias; \ -- rtx rtlname = XEXP (DECL_RTL (DECL), 0); \ -- if (GET_CODE (rtlname) == SYMBOL_REF) \ -- alias = XSTR (rtlname, 0); \ -- else \ -- abort (); \ -- if (TREE_CODE (DECL) == FUNCTION_DECL) \ -- i386_pe_declare_function_type (STREAM, alias, \ -- TREE_PUBLIC (DECL)); \ -- ASM_OUTPUT_DEF (STREAM, alias, IDENTIFIER_POINTER (TARGET)); \ -- } while (0) -- --#undef TREE -- --#ifndef BUFSIZ --# undef FILE --#endif -diff -ruN gcc-3.4.5-20060117-1/gcc/config/i386/i386.c.orig gcc-3.4.5-20060117-1-winelf/gcc/config/i386/i386.c.orig ---- gcc-3.4.5-20060117-1/gcc/config/i386/i386.c.orig 2005-08-03 07:15:28.000000000 -0700 -+++ gcc-3.4.5-20060117-1-winelf/gcc/config/i386/i386.c.orig 1969-12-31 16:00:00.000000000 -0800 -@@ -1,16094 +0,0 @@ --/* Subroutines used for code generation on IA-32. -- Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -- 2002, 2003, 2004 Free Software Foundation, Inc. -- --This file is part of GCC. -- --GCC is free software; you can redistribute it and/or modify --it under the terms of the GNU General Public License as published by --the Free Software Foundation; either version 2, 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 COPYING. If not, write to --the Free Software Foundation, 59 Temple Place - Suite 330, --Boston, MA 02111-1307, USA. */ -- --#include "config.h" --#include "system.h" --#include "coretypes.h" --#include "tm.h" --#include "rtl.h" --#include "tree.h" --#include "tm_p.h" --#include "regs.h" --#include "hard-reg-set.h" --#include "real.h" --#include "insn-config.h" --#include "conditions.h" --#include "output.h" --#include "insn-attr.h" --#include "flags.h" --#include "except.h" --#include "function.h" --#include "recog.h" --#include "expr.h" --#include "optabs.h" --#include "toplev.h" --#include "basic-block.h" --#include "ggc.h" --#include "target.h" --#include "target-def.h" --#include "langhooks.h" --#include "cgraph.h" -- --#ifndef CHECK_STACK_LIMIT --#define CHECK_STACK_LIMIT (-1) --#endif -- --/* Return index of given mode in mult and division cost tables. */ --#define MODE_INDEX(mode) \ -- ((mode) == QImode ? 0 \ -- : (mode) == HImode ? 1 \ -- : (mode) == SImode ? 2 \ -- : (mode) == DImode ? 3 \ -- : 4) -- --/* Processor costs (relative to an add) */ --static const --struct processor_costs size_cost = { /* costs for tunning for size */ -- 2, /* cost of an add instruction */ -- 3, /* cost of a lea instruction */ -- 2, /* variable shift costs */ -- 3, /* constant shift costs */ -- {3, 3, 3, 3, 5}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {3, 3, 3, 3, 5}, /* cost of a divide/mod */ -- 3, /* cost of movsx */ -- 3, /* cost of movzx */ -- 0, /* "large" insn */ -- 2, /* MOVE_RATIO */ -- 2, /* cost for loading QImode using movzbl */ -- {2, 2, 2}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 2, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {2, 2, 2}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {2, 2, 2}, /* cost of loading integer registers */ -- 3, /* cost of moving MMX register */ -- {3, 3}, /* cost of loading MMX registers -- in SImode and DImode */ -- {3, 3}, /* cost of storing MMX registers -- in SImode and DImode */ -- 3, /* cost of moving SSE register */ -- {3, 3, 3}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {3, 3, 3}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 3, /* MMX or SSE register to integer */ -- 0, /* size of prefetch block */ -- 0, /* number of parallel prefetches */ -- 1, /* Branch cost */ -- 2, /* cost of FADD and FSUB insns. */ -- 2, /* cost of FMUL instruction. */ -- 2, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 2, /* cost of FSQRT instruction. */ --}; -- --/* Processor costs (relative to an add) */ --static const --struct processor_costs i386_cost = { /* 386 specific costs */ -- 1, /* cost of an add instruction */ -- 1, /* cost of a lea instruction */ -- 3, /* variable shift costs */ -- 2, /* constant shift costs */ -- {6, 6, 6, 6, 6}, /* cost of starting a multiply */ -- 1, /* cost of multiply per each bit set */ -- {23, 23, 23, 23, 23}, /* cost of a divide/mod */ -- 3, /* cost of movsx */ -- 2, /* cost of movzx */ -- 15, /* "large" insn */ -- 3, /* MOVE_RATIO */ -- 4, /* cost for loading QImode using movzbl */ -- {2, 4, 2}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 4, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {8, 8, 8}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {8, 8, 8}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {4, 8}, /* cost of loading MMX registers -- in SImode and DImode */ -- {4, 8}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {4, 8, 16}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {4, 8, 16}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 3, /* MMX or SSE register to integer */ -- 0, /* size of prefetch block */ -- 0, /* number of parallel prefetches */ -- 1, /* Branch cost */ -- 23, /* cost of FADD and FSUB insns. */ -- 27, /* cost of FMUL instruction. */ -- 88, /* cost of FDIV instruction. */ -- 22, /* cost of FABS instruction. */ -- 24, /* cost of FCHS instruction. */ -- 122, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs i486_cost = { /* 486 specific costs */ -- 1, /* cost of an add instruction */ -- 1, /* cost of a lea instruction */ -- 3, /* variable shift costs */ -- 2, /* constant shift costs */ -- {12, 12, 12, 12, 12}, /* cost of starting a multiply */ -- 1, /* cost of multiply per each bit set */ -- {40, 40, 40, 40, 40}, /* cost of a divide/mod */ -- 3, /* cost of movsx */ -- 2, /* cost of movzx */ -- 15, /* "large" insn */ -- 3, /* MOVE_RATIO */ -- 4, /* cost for loading QImode using movzbl */ -- {2, 4, 2}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 4, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {8, 8, 8}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {8, 8, 8}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {4, 8}, /* cost of loading MMX registers -- in SImode and DImode */ -- {4, 8}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {4, 8, 16}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {4, 8, 16}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 3, /* MMX or SSE register to integer */ -- 0, /* size of prefetch block */ -- 0, /* number of parallel prefetches */ -- 1, /* Branch cost */ -- 8, /* cost of FADD and FSUB insns. */ -- 16, /* cost of FMUL instruction. */ -- 73, /* cost of FDIV instruction. */ -- 3, /* cost of FABS instruction. */ -- 3, /* cost of FCHS instruction. */ -- 83, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs pentium_cost = { -- 1, /* cost of an add instruction */ -- 1, /* cost of a lea instruction */ -- 4, /* variable shift costs */ -- 1, /* constant shift costs */ -- {11, 11, 11, 11, 11}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {25, 25, 25, 25, 25}, /* cost of a divide/mod */ -- 3, /* cost of movsx */ -- 2, /* cost of movzx */ -- 8, /* "large" insn */ -- 6, /* MOVE_RATIO */ -- 6, /* cost for loading QImode using movzbl */ -- {2, 4, 2}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 4, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {2, 2, 6}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {4, 4, 6}, /* cost of loading integer registers */ -- 8, /* cost of moving MMX register */ -- {8, 8}, /* cost of loading MMX registers -- in SImode and DImode */ -- {8, 8}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {4, 8, 16}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {4, 8, 16}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 3, /* MMX or SSE register to integer */ -- 0, /* size of prefetch block */ -- 0, /* number of parallel prefetches */ -- 2, /* Branch cost */ -- 3, /* cost of FADD and FSUB insns. */ -- 3, /* cost of FMUL instruction. */ -- 39, /* cost of FDIV instruction. */ -- 1, /* cost of FABS instruction. */ -- 1, /* cost of FCHS instruction. */ -- 70, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs pentiumpro_cost = { -- 1, /* cost of an add instruction */ -- 1, /* cost of a lea instruction */ -- 1, /* variable shift costs */ -- 1, /* constant shift costs */ -- {4, 4, 4, 4, 4}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {17, 17, 17, 17, 17}, /* cost of a divide/mod */ -- 1, /* cost of movsx */ -- 1, /* cost of movzx */ -- 8, /* "large" insn */ -- 6, /* MOVE_RATIO */ -- 2, /* cost for loading QImode using movzbl */ -- {4, 4, 4}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 2, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {2, 2, 6}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {4, 4, 6}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {2, 2}, /* cost of loading MMX registers -- in SImode and DImode */ -- {2, 2}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {2, 2, 8}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {2, 2, 8}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 3, /* MMX or SSE register to integer */ -- 32, /* size of prefetch block */ -- 6, /* number of parallel prefetches */ -- 2, /* Branch cost */ -- 3, /* cost of FADD and FSUB insns. */ -- 5, /* cost of FMUL instruction. */ -- 56, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 56, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs k6_cost = { -- 1, /* cost of an add instruction */ -- 2, /* cost of a lea instruction */ -- 1, /* variable shift costs */ -- 1, /* constant shift costs */ -- {3, 3, 3, 3, 3}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {18, 18, 18, 18, 18}, /* cost of a divide/mod */ -- 2, /* cost of movsx */ -- 2, /* cost of movzx */ -- 8, /* "large" insn */ -- 4, /* MOVE_RATIO */ -- 3, /* cost for loading QImode using movzbl */ -- {4, 5, 4}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 3, 2}, /* cost of storing integer registers */ -- 4, /* cost of reg,reg fld/fst */ -- {6, 6, 6}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {4, 4, 4}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {2, 2}, /* cost of loading MMX registers -- in SImode and DImode */ -- {2, 2}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {2, 2, 8}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {2, 2, 8}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 6, /* MMX or SSE register to integer */ -- 32, /* size of prefetch block */ -- 1, /* number of parallel prefetches */ -- 1, /* Branch cost */ -- 2, /* cost of FADD and FSUB insns. */ -- 2, /* cost of FMUL instruction. */ -- 56, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 56, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs athlon_cost = { -- 1, /* cost of an add instruction */ -- 2, /* cost of a lea instruction */ -- 1, /* variable shift costs */ -- 1, /* constant shift costs */ -- {5, 5, 5, 5, 5}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {18, 26, 42, 74, 74}, /* cost of a divide/mod */ -- 1, /* cost of movsx */ -- 1, /* cost of movzx */ -- 8, /* "large" insn */ -- 9, /* MOVE_RATIO */ -- 4, /* cost for loading QImode using movzbl */ -- {3, 4, 3}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {3, 4, 3}, /* cost of storing integer registers */ -- 4, /* cost of reg,reg fld/fst */ -- {4, 4, 12}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {6, 6, 8}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {4, 4}, /* cost of loading MMX registers -- in SImode and DImode */ -- {4, 4}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {4, 4, 6}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {4, 4, 5}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 5, /* MMX or SSE register to integer */ -- 64, /* size of prefetch block */ -- 6, /* number of parallel prefetches */ -- 2, /* Branch cost */ -- 4, /* cost of FADD and FSUB insns. */ -- 4, /* cost of FMUL instruction. */ -- 24, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 35, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs k8_cost = { -- 1, /* cost of an add instruction */ -- 2, /* cost of a lea instruction */ -- 1, /* variable shift costs */ -- 1, /* constant shift costs */ -- {3, 4, 3, 4, 5}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {18, 26, 42, 74, 74}, /* cost of a divide/mod */ -- 1, /* cost of movsx */ -- 1, /* cost of movzx */ -- 8, /* "large" insn */ -- 9, /* MOVE_RATIO */ -- 4, /* cost for loading QImode using movzbl */ -- {3, 4, 3}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {3, 4, 3}, /* cost of storing integer registers */ -- 4, /* cost of reg,reg fld/fst */ -- {4, 4, 12}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {6, 6, 8}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {3, 3}, /* cost of loading MMX registers -- in SImode and DImode */ -- {4, 4}, /* cost of storing MMX registers -- in SImode and DImode */ -- 2, /* cost of moving SSE register */ -- {4, 3, 6}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {4, 4, 5}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 5, /* MMX or SSE register to integer */ -- 64, /* size of prefetch block */ -- 6, /* number of parallel prefetches */ -- 2, /* Branch cost */ -- 4, /* cost of FADD and FSUB insns. */ -- 4, /* cost of FMUL instruction. */ -- 19, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 35, /* cost of FSQRT instruction. */ --}; -- --static const --struct processor_costs pentium4_cost = { -- 1, /* cost of an add instruction */ -- 1, /* cost of a lea instruction */ -- 4, /* variable shift costs */ -- 4, /* constant shift costs */ -- {15, 15, 15, 15, 15}, /* cost of starting a multiply */ -- 0, /* cost of multiply per each bit set */ -- {56, 56, 56, 56, 56}, /* cost of a divide/mod */ -- 1, /* cost of movsx */ -- 1, /* cost of movzx */ -- 16, /* "large" insn */ -- 6, /* MOVE_RATIO */ -- 2, /* cost for loading QImode using movzbl */ -- {4, 5, 4}, /* cost of loading integer registers -- in QImode, HImode and SImode. -- Relative to reg-reg move (2). */ -- {2, 3, 2}, /* cost of storing integer registers */ -- 2, /* cost of reg,reg fld/fst */ -- {2, 2, 6}, /* cost of loading fp registers -- in SFmode, DFmode and XFmode */ -- {4, 4, 6}, /* cost of loading integer registers */ -- 2, /* cost of moving MMX register */ -- {2, 2}, /* cost of loading MMX registers -- in SImode and DImode */ -- {2, 2}, /* cost of storing MMX registers -- in SImode and DImode */ -- 12, /* cost of moving SSE register */ -- {12, 12, 12}, /* cost of loading SSE registers -- in SImode, DImode and TImode */ -- {2, 2, 8}, /* cost of storing SSE registers -- in SImode, DImode and TImode */ -- 10, /* MMX or SSE register to integer */ -- 64, /* size of prefetch block */ -- 6, /* number of parallel prefetches */ -- 2, /* Branch cost */ -- 5, /* cost of FADD and FSUB insns. */ -- 7, /* cost of FMUL instruction. */ -- 43, /* cost of FDIV instruction. */ -- 2, /* cost of FABS instruction. */ -- 2, /* cost of FCHS instruction. */ -- 43, /* cost of FSQRT instruction. */ --}; -- --const struct processor_costs *ix86_cost = &pentium_cost; -- --/* Processor feature/optimization bitmasks. */ --#define m_386 (1<<PROCESSOR_I386) --#define m_486 (1<<PROCESSOR_I486) --#define m_PENT (1<<PROCESSOR_PENTIUM) --#define m_PPRO (1<<PROCESSOR_PENTIUMPRO) --#define m_K6 (1<<PROCESSOR_K6) --#define m_ATHLON (1<<PROCESSOR_ATHLON) --#define m_PENT4 (1<<PROCESSOR_PENTIUM4) --#define m_K8 (1<<PROCESSOR_K8) --#define m_ATHLON_K8 (m_K8 | m_ATHLON) -- --const int x86_use_leave = m_386 | m_K6 | m_ATHLON_K8; --const int x86_push_memory = m_386 | m_K6 | m_ATHLON_K8 | m_PENT4; --const int x86_zero_extend_with_and = m_486 | m_PENT; --const int x86_movx = m_ATHLON_K8 | m_PPRO | m_PENT4 /* m_386 | m_K6 */; --const int x86_double_with_add = ~m_386; --const int x86_use_bit_test = m_386; --const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON_K8 | m_K6; --const int x86_cmove = m_PPRO | m_ATHLON_K8 | m_PENT4; --const int x86_3dnow_a = m_ATHLON_K8; --const int x86_deep_branch = m_PPRO | m_K6 | m_ATHLON_K8 | m_PENT4; --const int x86_branch_hints = m_PENT4; --const int x86_use_sahf = m_PPRO | m_K6 | m_PENT4; --const int x86_partial_reg_stall = m_PPRO; --const int x86_use_loop = m_K6; --const int x86_use_fiop = ~(m_PPRO | m_ATHLON_K8 | m_PENT); --const int x86_use_mov0 = m_K6; --const int x86_use_cltd = ~(m_PENT | m_K6); --const int x86_read_modify_write = ~m_PENT; --const int x86_read_modify = ~(m_PENT | m_PPRO); --const int x86_split_long_moves = m_PPRO; --const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486 | m_ATHLON_K8; --const int x86_fast_prefix = ~(m_PENT | m_486 | m_386); --const int x86_single_stringop = m_386 | m_PENT4; --const int x86_qimode_math = ~(0); --const int x86_promote_qi_regs = 0; --const int x86_himode_math = ~(m_PPRO); --const int x86_promote_hi_regs = m_PPRO; --const int x86_sub_esp_4 = m_ATHLON_K8 | m_PPRO | m_PENT4; --const int x86_sub_esp_8 = m_ATHLON_K8 | m_PPRO | m_386 | m_486 | m_PENT4; --const int x86_add_esp_4 = m_ATHLON_K8 | m_K6 | m_PENT4; --const int x86_add_esp_8 = m_ATHLON_K8 | m_PPRO | m_K6 | m_386 | m_486 | m_PENT4; --const int x86_integer_DFmode_moves = ~(m_ATHLON_K8 | m_PENT4 | m_PPRO); --const int x86_partial_reg_dependency = m_ATHLON_K8 | m_PENT4; --const int x86_memory_mismatch_stall = m_ATHLON_K8 | m_PENT4; --const int x86_accumulate_outgoing_args = m_ATHLON_K8 | m_PENT4 | m_PPRO; --const int x86_prologue_using_move = m_ATHLON_K8 | m_PENT4 | m_PPRO; --const int x86_epilogue_using_move = m_ATHLON_K8 | m_PENT4 | m_PPRO; --const int x86_decompose_lea = m_PENT4; --const int x86_shift1 = ~m_486; --const int x86_arch_always_fancy_math_387 = m_PENT | m_PPRO | m_ATHLON_K8 | m_PENT4; --const int x86_sse_partial_reg_dependency = m_PENT4 | m_PPRO; --/* Set for machines where the type and dependencies are resolved on SSE register -- parts instead of whole registers, so we may maintain just lower part of -- scalar values in proper format leaving the upper part undefined. */ --const int x86_sse_partial_regs = m_ATHLON_K8; --/* Athlon optimizes partial-register FPS special case, thus avoiding the -- need for extra instructions beforehand */ --const int x86_sse_partial_regs_for_cvtsd2ss = 0; --const int x86_sse_typeless_stores = m_ATHLON_K8; --const int x86_sse_load0_by_pxor = m_PPRO | m_PENT4; --const int x86_use_ffreep = m_ATHLON_K8; --const int x86_rep_movl_optimal = m_386 | m_PENT | m_PPRO | m_K6; -- --/* ??? HACK! The following is a lie. SSE can hold e.g. SImode, and -- indeed *must* be able to hold SImode so that SSE2 shifts are able -- to work right. But this can result in some mighty surprising -- register allocation when building kernels. Turning this off should -- make us less likely to all-of-the-sudden select an SSE register. */ --const int x86_inter_unit_moves = 0; /* ~(m_ATHLON_K8) */ -- --const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_PPRO; -- --/* In case the average insn count for single function invocation is -- lower than this constant, emit fast (but longer) prologue and -- epilogue code. */ --#define FAST_PROLOGUE_INSN_COUNT 20 -- --/* Names for 8 (low), 8 (high), and 16-bit registers, respectively. */ --static const char *const qi_reg_name[] = QI_REGISTER_NAMES; --static const char *const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; --static const char *const hi_reg_name[] = HI_REGISTER_NAMES; -- --/* Array of the smallest class containing reg number REGNO, indexed by -- REGNO. Used by REGNO_REG_CLASS in i386.h. */ -- --enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] = --{ -- /* ax, dx, cx, bx */ -- AREG, DREG, CREG, BREG, -- /* si, di, bp, sp */ -- SIREG, DIREG, NON_Q_REGS, NON_Q_REGS, -- /* FP registers */ -- FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS, -- FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, -- /* arg pointer */ -- NON_Q_REGS, -- /* flags, fpsr, dirflag, frame */ -- NO_REGS, NO_REGS, NO_REGS, NON_Q_REGS, -- SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, -- SSE_REGS, SSE_REGS, -- MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, -- MMX_REGS, MMX_REGS, -- NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, -- NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, -- SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, -- SSE_REGS, SSE_REGS, --}; -- --/* The "default" register map used in 32bit mode. */ -- --int const dbx_register_map[FIRST_PSEUDO_REGISTER] = --{ -- 0, 2, 1, 3, 6, 7, 4, 5, /* general regs */ -- 12, 13, 14, 15, 16, 17, 18, 19, /* fp regs */ -- -1, -1, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ -- 21, 22, 23, 24, 25, 26, 27, 28, /* SSE */ -- 29, 30, 31, 32, 33, 34, 35, 36, /* MMX */ -- -1, -1, -1, -1, -1, -1, -1, -1, /* extended integer registers */ -- -1, -1, -1, -1, -1, -1, -1, -1, /* extended SSE registers */ --}; -- --static int const x86_64_int_parameter_registers[6] = --{ -- 5 /*RDI*/, 4 /*RSI*/, 1 /*RDX*/, 2 /*RCX*/, -- FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */ --}; -- --static int const x86_64_int_return_registers[4] = --{ -- 0 /*RAX*/, 1 /*RDI*/, 5 /*RDI*/, 4 /*RSI*/ --}; -- --/* The "default" register map used in 64bit mode. */ --int const dbx64_register_map[FIRST_PSEUDO_REGISTER] = --{ -- 0, 1, 2, 3, 4, 5, 6, 7, /* general regs */ -- 33, 34, 35, 36, 37, 38, 39, 40, /* fp regs */ -- -1, -1, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ -- 17, 18, 19, 20, 21, 22, 23, 24, /* SSE */ -- 41, 42, 43, 44, 45, 46, 47, 48, /* MMX */ -- 8,9,10,11,12,13,14,15, /* extended integer registers */ -- 25, 26, 27, 28, 29, 30, 31, 32, /* extended SSE registers */ --}; -- --/* Define the register numbers to be used in Dwarf debugging information. -- The SVR4 reference port C compiler uses the following register numbers -- in its Dwarf output code: -- 0 for %eax (gcc regno = 0) -- 1 for %ecx (gcc regno = 2) -- 2 for %edx (gcc regno = 1) -- 3 for %ebx (gcc regno = 3) -- 4 for %esp (gcc regno = 7) -- 5 for %ebp (gcc regno = 6) -- 6 for %esi (gcc regno = 4) -- 7 for %edi (gcc regno = 5) -- The following three DWARF register numbers are never generated by -- the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 -- believes these numbers have these meanings. -- 8 for %eip (no gcc equivalent) -- 9 for %eflags (gcc regno = 17) -- 10 for %trapno (no gcc equivalent) -- It is not at all clear how we should number the FP stack registers -- for the x86 architecture. If the version of SDB on x86/svr4 were -- a bit less brain dead with respect to floating-point then we would -- have a precedent to follow with respect to DWARF register numbers -- for x86 FP registers, but the SDB on x86/svr4 is so completely -- broken with respect to FP registers that it is hardly worth thinking -- of it as something to strive for compatibility with. -- The version of x86/svr4 SDB I have at the moment does (partially) -- seem to believe that DWARF register number 11 is associated with -- the x86 register %st(0), but that's about all. Higher DWARF -- register numbers don't seem to be associated with anything in -- particular, and even for DWARF regno 11, SDB only seems to under- -- stand that it should say that a variable lives in %st(0) (when -- asked via an `=' command) if we said it was in DWARF regno 11, -- but SDB still prints garbage when asked for the value of the -- variable in question (via a `/' command). -- (Also note that the labels SDB prints for various FP stack regs -- when doing an `x' command are all wrong.) -- Note that these problems generally don't affect the native SVR4 -- C compiler because it doesn't allow the use of -O with -g and -- because when it is *not* optimizing, it allocates a memory -- location for each floating-point variable, and the memory -- location is what gets described in the DWARF AT_location -- attribute for the variable in question. -- Regardless of the severe mental illness of the x86/svr4 SDB, we -- do something sensible here and we use the following DWARF -- register numbers. Note that these are all stack-top-relative -- numbers. -- 11 for %st(0) (gcc regno = 8) -- 12 for %st(1) (gcc regno = 9) -- 13 for %st(2) (gcc regno = 10) -- 14 for %st(3) (gcc regno = 11) -- 15 for %st(4) (gcc regno = 12) -- 16 for %st(5) (gcc regno = 13) -- 17 for %st(6) (gcc regno = 14) -- 18 for %st(7) (gcc regno = 15) --*/ --int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] = --{ -- 0, 2, 1, 3, 6, 7, 5, 4, /* general regs */ -- 11, 12, 13, 14, 15, 16, 17, 18, /* fp regs */ -- -1, 9, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ -- 21, 22, 23, 24, 25, 26, 27, 28, /* SSE registers */ -- 29, 30, 31, 32, 33, 34, 35, 36, /* MMX registers */ -- -1, -1, -1, -1, -1, -1, -1, -1, /* extended integer registers */ -- -1, -1, -1, -1, -1, -1, -1, -1, /* extended SSE registers */ --}; -- --/* Test and compare insns in i386.md store the information needed to -- generate branch and scc insns here. */ -- --rtx ix86_compare_op0 = NULL_RTX; --rtx ix86_compare_op1 = NULL_RTX; -- --#define MAX_386_STACK_LOCALS 3 --/* Size of the register save area. */ --#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16) -- --/* Define the structure for the machine field in struct function. */ -- --struct stack_local_entry GTY(()) --{ -- unsigned short mode; -- unsigned short n; -- rtx rtl; -- struct stack_local_entry *next; --}; -- --/* Structure describing stack frame layout. -- Stack grows downward: -- -- [arguments] -- <- ARG_POINTER -- saved pc -- -- saved frame pointer if frame_pointer_needed -- <- HARD_FRAME_POINTER -- [saved regs] -- -- [padding1] \ -- ) -- [va_arg registers] ( -- > to_allocate <- FRAME_POINTER -- [frame] ( -- ) -- [padding2] / -- */ --struct ix86_frame --{ -- int nregs; -- int padding1; -- int va_arg_size; -- HOST_WIDE_INT frame; -- int padding2; -- int outgoing_arguments_size; -- int red_zone_size; -- -- HOST_WIDE_INT to_allocate; -- /* The offsets relative to ARG_POINTER. */ -- HOST_WIDE_INT frame_pointer_offset; -- HOST_WIDE_INT hard_frame_pointer_offset; -- HOST_WIDE_INT stack_pointer_offset; -- -- /* When save_regs_using_mov is set, emit prologue using -- move instead of push instructions. */ -- bool save_regs_using_mov; --}; -- --/* Used to enable/disable debugging features. */ --const char *ix86_debug_arg_string, *ix86_debug_addr_string; --/* Code model option as passed by user. */ --const char *ix86_cmodel_string; --/* Parsed value. */ --enum cmodel ix86_cmodel; --/* Asm dialect. */ --const char *ix86_asm_string; --enum asm_dialect ix86_asm_dialect = ASM_ATT; --/* TLS dialext. */ --const char *ix86_tls_dialect_string; --enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU; -- --/* Which unit we are generating floating point math for. */ --enum fpmath_unit ix86_fpmath; -- --/* Which cpu are we scheduling for. */ --enum processor_type ix86_tune; --/* Which instruction set architecture to use. */ --enum processor_type ix86_arch; -- --/* Strings to hold which cpu and instruction set architecture to use. */ --const char *ix86_tune_string; /* for -mtune=<xxx> */ --const char *ix86_arch_string; /* for -march=<xxx> */ --const char *ix86_fpmath_string; /* for -mfpmath=<xxx> */ -- --/* # of registers to use to pass arguments. */ --const char *ix86_regparm_string; -- --/* true if sse prefetch instruction is not NOOP. */ --int x86_prefetch_sse; -- --/* ix86_regparm_string as a number */ --int ix86_regparm; -- --/* Alignment to use for loops and jumps: */ -- --/* Power of two alignment for loops. */ --const char *ix86_align_loops_string; -- --/* Power of two alignment for non-loop jumps. */ --const char *ix86_align_jumps_string; -- --/* Power of two alignment for stack boundary in bytes. */ --const char *ix86_preferred_stack_boundary_string; -- --/* Preferred alignment for stack boundary in bits. */ --int ix86_preferred_stack_boundary; -- --/* Values 1-5: see jump.c */ --int ix86_branch_cost; --const char *ix86_branch_cost_string; -- --/* Power of two alignment for functions. */ --const char *ix86_align_funcs_string; -- --/* Prefix built by ASM_GENERATE_INTERNAL_LABEL. */ --static char internal_label_prefix[16]; --static int internal_label_prefix_len; -- --static int local_symbolic_operand (rtx, enum machine_mode); --static int tls_symbolic_operand_1 (rtx, enum tls_model); --static void output_pic_addr_const (FILE *, rtx, int); --static void put_condition_code (enum rtx_code, enum machine_mode, -- int, int, FILE *); --static const char *get_some_local_dynamic_name (void); --static int get_some_local_dynamic_name_1 (rtx *, void *); --static rtx maybe_get_pool_constant (rtx); --static rtx ix86_expand_int_compare (enum rtx_code, rtx, rtx); --static enum rtx_code ix86_prepare_fp_compare_args (enum rtx_code, rtx *, -- rtx *); --static bool ix86_fixed_condition_code_regs (unsigned int *, unsigned int *); --static enum machine_mode ix86_cc_modes_compatible (enum machine_mode, -- enum machine_mode); --static rtx get_thread_pointer (int); --static rtx legitimize_tls_address (rtx, enum tls_model, int); --static void get_pc_thunk_name (char [32], unsigned int); --static rtx gen_push (rtx); --static int memory_address_length (rtx addr); --static int ix86_flags_dependant (rtx, rtx, enum attr_type); --static int ix86_agi_dependant (rtx, rtx, enum attr_type); --static enum attr_ppro_uops ix86_safe_ppro_uops (rtx); --static void ix86_dump_ppro_packet (FILE *); --static void ix86_reorder_insn (rtx *, rtx *); --static struct machine_function * ix86_init_machine_status (void); --static int ix86_split_to_parts (rtx, rtx *, enum machine_mode); --static int ix86_nsaved_regs (void); --static void ix86_emit_save_regs (void); --static void ix86_emit_save_regs_using_mov (rtx, HOST_WIDE_INT); --static void ix86_emit_restore_regs_using_mov (rtx, HOST_WIDE_INT, int); --static void ix86_output_function_epilogue (FILE *, HOST_WIDE_INT); --static void ix86_sched_reorder_ppro (rtx *, rtx *); --static HOST_WIDE_INT ix86_GOT_alias_set (void); --static void ix86_adjust_counter (rtx, HOST_WIDE_INT); --static rtx ix86_expand_aligntest (rtx, int); --static void ix86_expand_strlensi_unroll_1 (rtx, rtx, rtx); --static int ix86_issue_rate (void); --static int ix86_adjust_cost (rtx, rtx, rtx, int); --static void ix86_sched_init (FILE *, int, int); --static int ix86_sched_reorder (FILE *, int, rtx *, int *, int); --static int ix86_variable_issue (FILE *, int, rtx, int); --static int ia32_use_dfa_pipeline_interface (void); --static int ia32_multipass_dfa_lookahead (void); --static void ix86_init_mmx_sse_builtins (void); --static rtx x86_this_parameter (tree); --static void x86_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, -- HOST_WIDE_INT, tree); --static bool x86_can_output_mi_thunk (tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); --static void x86_file_start (void); --static void ix86_reorg (void); --static bool ix86_expand_carry_flag_compare (enum rtx_code, rtx, rtx, rtx*); --static tree ix86_build_builtin_va_list (void); -- --struct ix86_address --{ -- rtx base, index, disp; -- HOST_WIDE_INT scale; -- enum ix86_address_seg { SEG_DEFAULT, SEG_FS, SEG_GS } seg; --}; -- --static int ix86_decompose_address (rtx, struct ix86_address *); --static int ix86_address_cost (rtx); --static bool ix86_cannot_force_const_mem (rtx); --static rtx ix86_delegitimize_address (rtx); -- --struct builtin_description; --static rtx ix86_expand_sse_comi (const struct builtin_description *, -- tree, rtx); --static rtx ix86_expand_sse_compare (const struct builtin_description *, -- tree, rtx); --static rtx ix86_expand_unop1_builtin (enum insn_code, tree, rtx); --static rtx ix86_expand_unop_builtin (enum insn_code, tree, rtx, int); --static rtx ix86_expand_binop_builtin (enum insn_code, tree, rtx); --static rtx ix86_expand_store_builtin (enum insn_code, tree); --static rtx safe_vector_operand (rtx, enum machine_mode); --static enum rtx_code ix86_fp_compare_code_to_integer (enum rtx_code); --static void ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *, -- enum rtx_code *, enum rtx_code *); --static rtx ix86_expand_fp_compare (enum rtx_code, rtx, rtx, rtx, rtx *, rtx *); --static int ix86_fp_comparison_arithmetics_cost (enum rtx_code code); --static int ix86_fp_comparison_fcomi_cost (enum rtx_code code); --static int ix86_fp_comparison_sahf_cost (enum rtx_code code); --static int ix86_fp_comparison_cost (enum rtx_code code); --static unsigned int ix86_select_alt_pic_regnum (void); --static int ix86_save_reg (unsigned int, int); --static void ix86_compute_frame_layout (struct ix86_frame *); --static int ix86_comp_type_attributes (tree, tree); --static int ix86_function_regparm (tree, tree); --const struct attribute_spec ix86_attribute_table[]; --static bool ix86_function_ok_for_sibcall (tree, tree); --static tree ix86_handle_cdecl_attribute (tree *, tree, tree, int, bool *); --static tree ix86_handle_regparm_attribute (tree *, tree, tree, int, bool *); --static int ix86_value_regno (enum machine_mode); --static bool contains_128bit_aligned_vector_p (tree); --static bool ix86_ms_bitfield_layout_p (tree); --static tree ix86_handle_struct_attribute (tree *, tree, tree, int, bool *); --static int extended_reg_mentioned_1 (rtx *, void *); --static bool ix86_rtx_costs (rtx, int, int, int *); --static int min_insn_size (rtx); --static void k8_avoid_jump_misspredicts (void); -- --#if defined (DO_GLOBAL_CTORS_BODY) && defined (HAS_INIT_SECTION) --static void ix86_svr3_asm_out_constructor (rtx, int); --#endif -- --/* Register class used for passing given 64bit part of the argument. -- These represent classes as documented by the PS ABI, with the exception -- of SSESF, SSEDF classes, that are basically SSE class, just gcc will -- use SF or DFmode move instead of DImode to avoid reformatting penalties. -- -- Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves -- whenever possible (upper half does contain padding). -- */ --enum x86_64_reg_class -- { -- X86_64_NO_CLASS, -- X86_64_INTEGER_CLASS, -- X86_64_INTEGERSI_CLASS, -- X86_64_SSE_CLASS, -- X86_64_SSESF_CLASS, -- X86_64_SSEDF_CLASS, -- X86_64_SSEUP_CLASS, -- X86_64_X87_CLASS, -- X86_64_X87UP_CLASS, -- X86_64_MEMORY_CLASS -- }; --static const char * const x86_64_reg_class_name[] = -- {"no", "integer", "integerSI", "sse", "sseSF", "sseDF", "sseup", "x87", "x87up", "no"}; -- --#define MAX_CLASSES 4 --static int classify_argument (enum machine_mode, tree, -- enum x86_64_reg_class [MAX_CLASSES], int); --static int examine_argument (enum machine_mode, tree, int, int *, int *); --static rtx construct_container (enum machine_mode, tree, int, int, int, -- const int *, int); --static enum x86_64_reg_class merge_classes (enum x86_64_reg_class, -- enum x86_64_reg_class); -- --/* Table of constants used by fldpi, fldln2, etc.... */ --static REAL_VALUE_TYPE ext_80387_constants_table [5]; --static bool ext_80387_constants_init = 0; --static void init_ext_80387_constants (void); -- --/* Initialize the GCC target structure. */ --#undef TARGET_ATTRIBUTE_TABLE --#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table --#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES --# undef TARGET_MERGE_DECL_ATTRIBUTES --# define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes --#endif -- --#undef TARGET_COMP_TYPE_ATTRIBUTES --#define TARGET_COMP_TYPE_ATTRIBUTES ix86_comp_type_attributes -- --#undef TARGET_INIT_BUILTINS --#define TARGET_INIT_BUILTINS ix86_init_builtins -- --#undef TARGET_EXPAND_BUILTIN --#define TARGET_EXPAND_BUILTIN ix86_expand_builtin -- --#undef TARGET_ASM_FUNCTION_EPILOGUE --#define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue -- --#undef TARGET_ASM_OPEN_PAREN --#define TARGET_ASM_OPEN_PAREN "" --#undef TARGET_ASM_CLOSE_PAREN --#define TARGET_ASM_CLOSE_PAREN "" -- --#undef TARGET_ASM_ALIGNED_HI_OP --#define TARGET_ASM_ALIGNED_HI_OP ASM_SHORT --#undef TARGET_ASM_ALIGNED_SI_OP --#define TARGET_ASM_ALIGNED_SI_OP ASM_LONG --#ifdef ASM_QUAD --#undef TARGET_ASM_ALIGNED_DI_OP --#define TARGET_ASM_ALIGNED_DI_OP ASM_QUAD --#endif -- --#undef TARGET_ASM_UNALIGNED_HI_OP --#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP --#undef TARGET_ASM_UNALIGNED_SI_OP --#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP --#undef TARGET_ASM_UNALIGNED_DI_OP --#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP -- --#undef TARGET_SCHED_ADJUST_COST --#define TARGET_SCHED_ADJUST_COST ix86_adjust_cost --#undef TARGET_SCHED_ISSUE_RATE --#define TARGET_SCHED_ISSUE_RATE ix86_issue_rate --#undef TARGET_SCHED_VARIABLE_ISSUE --#define TARGET_SCHED_VARIABLE_ISSUE ix86_variable_issue --#undef TARGET_SCHED_INIT --#define TARGET_SCHED_INIT ix86_sched_init --#undef TARGET_SCHED_REORDER --#define TARGET_SCHED_REORDER ix86_sched_reorder --#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE --#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ -- ia32_use_dfa_pipeline_interface --#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD --#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ -- ia32_multipass_dfa_lookahead -- --#undef TARGET_FUNCTION_OK_FOR_SIBCALL --#define TARGET_FUNCTION_OK_FOR_SIBCALL ix86_function_ok_for_sibcall -- --#ifdef HAVE_AS_TLS --#undef TARGET_HAVE_TLS --#define TARGET_HAVE_TLS true --#endif --#undef TARGET_CANNOT_FORCE_CONST_MEM --#define TARGET_CANNOT_FORCE_CONST_MEM ix86_cannot_force_const_mem -- --#undef TARGET_DELEGITIMIZE_ADDRESS --#define TARGET_DELEGITIMIZE_ADDRESS ix86_delegitimize_address -- --#undef TARGET_MS_BITFIELD_LAYOUT_P --#define TARGET_MS_BITFIELD_LAYOUT_P ix86_ms_bitfield_layout_p -- --#undef TARGET_ASM_OUTPUT_MI_THUNK --#define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk --#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK --#define TARGET_ASM_CAN_OUTPUT_MI_THUNK x86_can_output_mi_thunk -- --#undef TARGET_ASM_FILE_START --#define TARGET_ASM_FILE_START x86_file_start -- --#undef TARGET_RTX_COSTS --#define TARGET_RTX_COSTS ix86_rtx_costs --#undef TARGET_ADDRESS_COST --#define TARGET_ADDRESS_COST ix86_address_cost -- --#undef TARGET_FIXED_CONDITION_CODE_REGS --#define TARGET_FIXED_CONDITION_CODE_REGS ix86_fixed_condition_code_regs --#undef TARGET_CC_MODES_COMPATIBLE --#define TARGET_CC_MODES_COMPATIBLE ix86_cc_modes_compatible -- --#undef TARGET_MACHINE_DEPENDENT_REORG --#define TARGET_MACHINE_DEPENDENT_REORG ix86_reorg -- --#undef TARGET_BUILD_BUILTIN_VA_LIST --#define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list -- --struct gcc_target targetm = TARGET_INITIALIZER; -- --/* The svr4 ABI for the i386 says that records and unions are returned -- in memory. */ --#ifndef DEFAULT_PCC_STRUCT_RETURN --#define DEFAULT_PCC_STRUCT_RETURN 1 --#endif -- --/* Sometimes certain combinations of command options do not make -- sense on a particular target machine. You can define a macro -- `OVERRIDE_OPTIONS' to take account of this. This macro, if -- defined, is executed once just after all the command options have -- been parsed. -- -- Don't use this macro to turn on various extra optimizations for -- `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ -- --void --override_options (void) --{ -- int i; -- /* Comes from final.c -- no real reason to change it. */ --#define MAX_CODE_ALIGN 16 -- -- static struct ptt -- { -- const struct processor_costs *cost; /* Processor costs */ -- const int target_enable; /* Target flags to enable. */ -- const int target_disable; /* Target flags to disable. */ -- const int align_loop; /* Default alignments. */ -- const int align_loop_max_skip; -- const int align_jump; -- const int align_jump_max_skip; -- const int align_func; -- } -- const processor_target_table[PROCESSOR_max] = -- { -- {&i386_cost, 0, 0, 4, 3, 4, 3, 4}, -- {&i486_cost, 0, 0, 16, 15, 16, 15, 16}, -- {&pentium_cost, 0, 0, 16, 7, 16, 7, 16}, -- {&pentiumpro_cost, 0, 0, 16, 15, 16, 7, 16}, -- {&k6_cost, 0, 0, 32, 7, 32, 7, 32}, -- {&athlon_cost, 0, 0, 16, 7, 16, 7, 16}, -- {&pentium4_cost, 0, 0, 0, 0, 0, 0, 0}, -- {&k8_cost, 0, 0, 16, 7, 16, 7, 16} -- }; -- -- static const char * const cpu_names[] = TARGET_CPU_DEFAULT_NAMES; -- static struct pta -- { -- const char *const name; /* processor name or nickname. */ -- const enum processor_type processor; -- const enum pta_flags -- { -- PTA_SSE = 1, -- PTA_SSE2 = 2, -- PTA_SSE3 = 4, -- PTA_MMX = 8, -- PTA_PREFETCH_SSE = 16, -- PTA_3DNOW = 32, -- PTA_3DNOW_A = 64, -- PTA_64BIT = 128 -- } flags; -- } -- const processor_alias_table[] = -- { -- {"i386", PROCESSOR_I386, 0}, -- {"i486", PROCESSOR_I486, 0}, -- {"i586", PROCESSOR_PENTIUM, 0}, -- {"pentium", PROCESSOR_PENTIUM, 0}, -- {"pentium-mmx", PROCESSOR_PENTIUM, PTA_MMX}, -- {"winchip-c6", PROCESSOR_I486, PTA_MMX}, -- {"winchip2", PROCESSOR_I486, PTA_MMX | PTA_3DNOW}, -- {"c3", PROCESSOR_I486, PTA_MMX | PTA_3DNOW}, -- {"c3-2", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_PREFETCH_SSE | PTA_SSE}, -- {"i686", PROCESSOR_PENTIUMPRO, 0}, -- {"pentiumpro", PROCESSOR_PENTIUMPRO, 0}, -- {"pentium2", PROCESSOR_PENTIUMPRO, PTA_MMX}, -- {"pentium3", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE}, -- {"pentium3m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE}, -- {"pentium-m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE | PTA_SSE2}, -- {"pentium4", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 -- | PTA_MMX | PTA_PREFETCH_SSE}, -- {"pentium4m", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 -- | PTA_MMX | PTA_PREFETCH_SSE}, -- {"prescott", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | PTA_SSE3 -- | PTA_MMX | PTA_PREFETCH_SSE}, -- {"nocona", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_64BIT -- | PTA_MMX | PTA_PREFETCH_SSE}, -- {"k6", PROCESSOR_K6, PTA_MMX}, -- {"k6-2", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, -- {"k6-3", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, -- {"athlon", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW -- | PTA_3DNOW_A}, -- {"athlon-tbird", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE -- | PTA_3DNOW | PTA_3DNOW_A}, -- {"athlon-4", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW -- | PTA_3DNOW_A | PTA_SSE}, -- {"athlon-xp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW -- | PTA_3DNOW_A | PTA_SSE}, -- {"athlon-mp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW -- | PTA_3DNOW_A | PTA_SSE}, -- {"x86-64", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_64BIT -- | PTA_SSE | PTA_SSE2 }, -- {"k8", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT -- | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, -- {"opteron", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT -- | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, -- {"athlon64", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT -- | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, -- {"athlon-fx", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT -- | PTA_3DNOW_A | PTA_SSE | PTA_SSE2}, -- }; -- -- int const pta_size = ARRAY_SIZE (processor_alias_table); -- -- /* Set the default values for switches whose default depends on TARGET_64BIT -- in case they weren't overwritten by command line options. */ -- if (TARGET_64BIT) -- { -- if (flag_omit_frame_pointer == 2) -- flag_omit_frame_pointer = 1; -- if (flag_asynchronous_unwind_tables == 2) -- flag_asynchronous_unwind_tables = 1; -- if (flag_pcc_struct_return == 2) -- flag_pcc_struct_return = 0; -- } -- else -- { -- if (flag_omit_frame_pointer == 2) -- flag_omit_frame_pointer = 0; -- if (flag_asynchronous_unwind_tables == 2) -- flag_asynchronous_unwind_tables = 0; -- if (flag_pcc_struct_return == 2) -- flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN; -- } -- --#ifdef SUBTARGET_OVERRIDE_OPTIONS -- SUBTARGET_OVERRIDE_OPTIONS; --#endif -- -- if (!ix86_tune_string && ix86_arch_string) -- ix86_tune_string = ix86_arch_string; -- if (!ix86_tune_string) -- ix86_tune_string = cpu_names [TARGET_CPU_DEFAULT]; -- if (!ix86_arch_string) -- ix86_arch_string = TARGET_64BIT ? "x86-64" : "i386"; -- -- if (ix86_cmodel_string != 0) -- { -- if (!strcmp (ix86_cmodel_string, "small")) -- ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; -- else if (flag_pic) -- sorry ("code model %s not supported in PIC mode", ix86_cmodel_string); -- else if (!strcmp (ix86_cmodel_string, "32")) -- ix86_cmodel = CM_32; -- else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic) -- ix86_cmodel = CM_KERNEL; -- else if (!strcmp (ix86_cmodel_string, "medium") && !flag_pic) -- ix86_cmodel = CM_MEDIUM; -- else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic) -- ix86_cmodel = CM_LARGE; -- else -- error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string); -- } -- else -- { -- ix86_cmodel = CM_32; -- if (TARGET_64BIT) -- ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; -- } -- if (ix86_asm_string != 0) -- { -- if (!strcmp (ix86_asm_string, "intel")) -- ix86_asm_dialect = ASM_INTEL; -- else if (!strcmp (ix86_asm_string, "att")) -- ix86_asm_dialect = ASM_ATT; -- else -- error ("bad value (%s) for -masm= switch", ix86_asm_string); -- } -- if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32)) -- error ("code model `%s' not supported in the %s bit mode", -- ix86_cmodel_string, TARGET_64BIT ? "64" : "32"); -- if (ix86_cmodel == CM_LARGE) -- sorry ("code model `large' not supported yet"); -- if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0)) -- sorry ("%i-bit mode not compiled in", -- (target_flags & MASK_64BIT) ? 64 : 32); -- -- for (i = 0; i < pta_size; i++) -- if (! strcmp (ix86_arch_string, processor_alias_table[i].name)) -- { -- ix86_arch = processor_alias_table[i].processor; -- /* Default cpu tuning to the architecture. */ -- ix86_tune = ix86_arch; -- if (processor_alias_table[i].flags & PTA_MMX -- && !(target_flags_explicit & MASK_MMX)) -- target_flags |= MASK_MMX; -- if (processor_alias_table[i].flags & PTA_3DNOW -- && !(target_flags_explicit & MASK_3DNOW)) -- target_flags |= MASK_3DNOW; -- if (processor_alias_table[i].flags & PTA_3DNOW_A -- && !(target_flags_explicit & MASK_3DNOW_A)) -- target_flags |= MASK_3DNOW_A; -- if (processor_alias_table[i].flags & PTA_SSE -- && !(target_flags_explicit & MASK_SSE)) -- target_flags |= MASK_SSE; -- if (processor_alias_table[i].flags & PTA_SSE2 -- && !(target_flags_explicit & MASK_SSE2)) -- target_flags |= MASK_SSE2; -- if (processor_alias_table[i].flags & PTA_SSE3 -- && !(target_flags_explicit & MASK_SSE3)) -- target_flags |= MASK_SSE3; -- if (processor_alias_table[i].flags & PTA_PREFETCH_SSE) -- x86_prefetch_sse = true; -- if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT)) -- error ("CPU you selected does not support x86-64 instruction set"); -- break; -- } -- -- if (i == pta_size) -- error ("bad value (%s) for -march= switch", ix86_arch_string); -- -- for (i = 0; i < pta_size; i++) -- if (! strcmp (ix86_tune_string, processor_alias_table[i].name)) -- { -- ix86_tune = processor_alias_table[i].processor; -- if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT)) -- error ("CPU you selected does not support x86-64 instruction set"); -- -- /* Intel CPUs have always interpreted SSE prefetch instructions as -- NOPs; so, we can enable SSE prefetch instructions even when -- -mtune (rather than -march) points us to a processor that has them. -- However, the VIA C3 gives a SIGILL, so we only do that for i686 and -- higher processors. */ -- if (TARGET_CMOVE && (processor_alias_table[i].flags & PTA_PREFETCH_SSE)) -- x86_prefetch_sse = true; -- break; -- } -- if (i == pta_size) -- error ("bad value (%s) for -mtune= switch", ix86_tune_string); -- -- if (optimize_size) -- ix86_cost = &size_cost; -- else -- ix86_cost = processor_target_table[ix86_tune].cost; -- target_flags |= processor_target_table[ix86_tune].target_enable; -- target_flags &= ~processor_target_table[ix86_tune].target_disable; -- -- /* Arrange to set up i386_stack_locals for all functions. */ -- init_machine_status = ix86_init_machine_status; -- -- /* Validate -mregparm= value. */ -- if (ix86_regparm_string) -- { -- i = atoi (ix86_regparm_string); -- if (i < 0 || i > REGPARM_MAX) -- error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX); -- else -- ix86_regparm = i; -- } -- else -- if (TARGET_64BIT) -- ix86_regparm = REGPARM_MAX; -- -- /* If the user has provided any of the -malign-* options, -- warn and use that value only if -falign-* is not set. -- Remove this code in GCC 3.2 or later. */ -- if (ix86_align_loops_string) -- { -- warning ("-malign-loops is obsolete, use -falign-loops"); -- if (align_loops == 0) -- { -- i = atoi (ix86_align_loops_string); -- if (i < 0 || i > MAX_CODE_ALIGN) -- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); -- else -- align_loops = 1 << i; -- } -- } -- -- if (ix86_align_jumps_string) -- { -- warning ("-malign-jumps is obsolete, use -falign-jumps"); -- if (align_jumps == 0) -- { -- i = atoi (ix86_align_jumps_string); -- if (i < 0 || i > MAX_CODE_ALIGN) -- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); -- else -- align_jumps = 1 << i; -- } -- } -- -- if (ix86_align_funcs_string) -- { -- warning ("-malign-functions is obsolete, use -falign-functions"); -- if (align_functions == 0) -- { -- i = atoi (ix86_align_funcs_string); -- if (i < 0 || i > MAX_CODE_ALIGN) -- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); -- else -- align_functions = 1 << i; -- } -- } -- -- /* Default align_* from the processor table. */ -- if (align_loops == 0) -- { -- align_loops = processor_target_table[ix86_tune].align_loop; -- align_loops_max_skip = processor_target_table[ix86_tune].align_loop_max_skip; -- } -- if (align_jumps == 0) -- { -- align_jumps = processor_target_table[ix86_tune].align_jump; -- align_jumps_max_skip = processor_target_table[ix86_tune].align_jump_max_skip; -- } -- if (align_functions == 0) -- { -- align_functions = processor_target_table[ix86_tune].align_func; -- } -- -- /* Validate -mpreferred-stack-boundary= value, or provide default. -- The default of 128 bits is for Pentium III's SSE __m128, but we -- don't want additional code to keep the stack aligned when -- optimizing for code size. */ -- ix86_preferred_stack_boundary = (optimize_size -- ? TARGET_64BIT ? 128 : 32 -- : 128); -- if (ix86_preferred_stack_boundary_string) -- { -- i = atoi (ix86_preferred_stack_boundary_string); -- if (i < (TARGET_64BIT ? 4 : 2) || i > 12) -- error ("-mpreferred-stack-boundary=%d is not between %d and 12", i, -- TARGET_64BIT ? 4 : 2); -- else -- ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; -- } -- -- /* Validate -mbranch-cost= value, or provide default. */ -- ix86_branch_cost = processor_target_table[ix86_tune].cost->branch_cost; -- if (ix86_branch_cost_string) -- { -- i = atoi (ix86_branch_cost_string); -- if (i < 0 || i > 5) -- error ("-mbranch-cost=%d is not between 0 and 5", i); -- else -- ix86_branch_cost = i; -- } -- -- if (ix86_tls_dialect_string) -- { -- if (strcmp (ix86_tls_dialect_string, "gnu") == 0) -- ix86_tls_dialect = TLS_DIALECT_GNU; -- else if (strcmp (ix86_tls_dialect_string, "sun") == 0) -- ix86_tls_dialect = TLS_DIALECT_SUN; -- else -- error ("bad value (%s) for -mtls-dialect= switch", -- ix86_tls_dialect_string); -- } -- -- /* Keep nonleaf frame pointers. */ -- if (TARGET_OMIT_LEAF_FRAME_POINTER) -- flag_omit_frame_pointer = 1; -- -- /* If we're doing fast math, we don't care about comparison order -- wrt NaNs. This lets us use a shorter comparison sequence. */ -- if (flag_unsafe_math_optimizations) -- target_flags &= ~MASK_IEEE_FP; -- -- /* If the architecture always has an FPU, turn off NO_FANCY_MATH_387, -- since the insns won't need emulation. */ -- if (x86_arch_always_fancy_math_387 & (1 << ix86_arch)) -- target_flags &= ~MASK_NO_FANCY_MATH_387; -- -- /* Turn on SSE2 builtins for -msse3. */ -- if (TARGET_SSE3) -- target_flags |= MASK_SSE2; -- -- /* Turn on SSE builtins for -msse2. */ -- if (TARGET_SSE2) -- target_flags |= MASK_SSE; -- -- if (TARGET_64BIT) -- { -- if (TARGET_ALIGN_DOUBLE) -- error ("-malign-double makes no sense in the 64bit mode"); -- if (TARGET_RTD) -- error ("-mrtd calling convention not supported in the 64bit mode"); -- /* Enable by default the SSE and MMX builtins. */ -- target_flags |= (MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE); -- ix86_fpmath = FPMATH_SSE; -- } -- else -- { -- ix86_fpmath = FPMATH_387; -- /* i386 ABI does not specify red zone. It still makes sense to use it -- when programmer takes care to stack from being destroyed. */ -- if (!(target_flags_explicit & MASK_NO_RED_ZONE)) -- target_flags |= MASK_NO_RED_ZONE; -- } -- -- if (ix86_fpmath_string != 0) -- { -- if (! strcmp (ix86_fpmath_string, "387")) -- ix86_fpmath = FPMATH_387; -- else if (! strcmp (ix86_fpmath_string, "sse")) -- { -- if (!TARGET_SSE) -- { -- warning ("SSE instruction set disabled, using 387 arithmetics"); -- ix86_fpmath = FPMATH_387; -- } -- else -- ix86_fpmath = FPMATH_SSE; -- } -- else if (! strcmp (ix86_fpmath_string, "387,sse") -- || ! strcmp (ix86_fpmath_string, "sse,387")) -- { -- if (!TARGET_SSE) -- { -- warning ("SSE instruction set disabled, using 387 arithmetics"); -- ix86_fpmath = FPMATH_387; -- } -- else if (!TARGET_80387) -- { -- warning ("387 instruction set disabled, using SSE arithmetics"); -- ix86_fpmath = FPMATH_SSE; -- } -- else -- ix86_fpmath = FPMATH_SSE | FPMATH_387; -- } -- else -- error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string); -- } -- -- /* It makes no sense to ask for just SSE builtins, so MMX is also turned -- on by -msse. */ -- if (TARGET_SSE) -- { -- target_flags |= MASK_MMX; -- x86_prefetch_sse = true; -- } -- -- /* If it has 3DNow! it also has MMX so MMX is also turned on by -m3dnow */ -- if (TARGET_3DNOW) -- { -- target_flags |= MASK_MMX; -- /* If we are targeting the Athlon architecture, enable the 3Dnow/MMX -- extensions it adds. */ -- if (x86_3dnow_a & (1 << ix86_arch)) -- target_flags |= MASK_3DNOW_A; -- } -- if ((x86_accumulate_outgoing_args & TUNEMASK) -- && !(target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) -- && !optimize_size) -- target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; -- -- /* Figure out what ASM_GENERATE_INTERNAL_LABEL builds as a prefix. */ -- { -- char *p; -- ASM_GENERATE_INTERNAL_LABEL (internal_label_prefix, "LX", 0); -- p = strchr (internal_label_prefix, 'X'); -- internal_label_prefix_len = p - internal_label_prefix; -- *p = '\0'; -- } --} -- --void --optimization_options (int level, int size ATTRIBUTE_UNUSED) --{ -- /* For -O2 and beyond, turn off -fschedule-insns by default. It tends to -- make the problem with not enough registers even worse. */ --#ifdef INSN_SCHEDULING -- if (level > 1) -- flag_schedule_insns = 0; --#endif -- -- /* The default values of these switches depend on the TARGET_64BIT -- that is not known at this moment. Mark these values with 2 and -- let user the to override these. In case there is no command line option -- specifying them, we will set the defaults in override_options. */ -- if (optimize >= 1) -- flag_omit_frame_pointer = 2; -- flag_pcc_struct_return = 2; -- flag_asynchronous_unwind_tables = 2; --} -- --/* Table of valid machine attributes. */ --const struct attribute_spec ix86_attribute_table[] = --{ -- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ -- /* Stdcall attribute says callee is responsible for popping arguments -- if they are not variable. */ -- { "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, -- /* Fastcall attribute says callee is responsible for popping arguments -- if they are not variable. */ -- { "fastcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, -- /* Cdecl attribute says the callee is a normal C declaration */ -- { "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, -- /* Regparm attribute specifies how many integer arguments are to be -- passed in registers. */ -- { "regparm", 1, 1, false, true, true, ix86_handle_regparm_attribute }, --#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES -- { "dllimport", 0, 0, false, false, false, ix86_handle_dll_attribute }, -- { "dllexport", 0, 0, false, false, false, ix86_handle_dll_attribute }, -- { "shared", 0, 0, true, false, false, ix86_handle_shared_attribute }, --#endif -- { "ms_struct", 0, 0, false, false, false, ix86_handle_struct_attribute }, -- { "gcc_struct", 0, 0, false, false, false, ix86_handle_struct_attribute }, -- { NULL, 0, 0, false, false, false, NULL } --}; -- --/* Decide whether we can make a sibling call to a function. DECL is the -- declaration of the function being targeted by the call and EXP is the -- CALL_EXPR representing the call. */ -- --static bool --ix86_function_ok_for_sibcall (tree decl, tree exp) --{ -- /* If we are generating position-independent code, we cannot sibcall -- optimize any indirect call, or a direct call to a global function, -- as the PLT requires %ebx be live. */ -- if (!TARGET_64BIT && flag_pic && (!decl || TREE_PUBLIC (decl))) -- return false; -- -- /* If we are returning floats on the 80387 register stack, we cannot -- make a sibcall from a function that doesn't return a float to a -- function that does or, conversely, from a function that does return -- a float to a function that doesn't; the necessary stack adjustment -- would not be executed. */ -- if (STACK_REG_P (ix86_function_value (TREE_TYPE (exp))) -- != STACK_REG_P (ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl))))) -- return false; -- -- /* If this call is indirect, we'll need to be able to use a call-clobbered -- register for the address of the target function. Make sure that all -- such registers are not used for passing parameters. */ -- if (!decl && !TARGET_64BIT) -- { -- tree type; -- -- /* We're looking at the CALL_EXPR, we need the type of the function. */ -- type = TREE_OPERAND (exp, 0); /* pointer expression */ -- type = TREE_TYPE (type); /* pointer type */ -- type = TREE_TYPE (type); /* function type */ -- -- if (ix86_function_regparm (type, NULL) >= 3) -- { -- /* ??? Need to count the actual number of registers to be used, -- not the possible number of registers. Fix later. */ -- return false; -- } -- } -- -- /* Otherwise okay. That also includes certain types of indirect calls. */ -- return true; --} -- --/* Handle a "cdecl", "stdcall", or "fastcall" attribute; -- arguments as in struct attribute_spec.handler. */ --static tree --ix86_handle_cdecl_attribute (tree *node, tree name, -- tree args ATTRIBUTE_UNUSED, -- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) --{ -- if (TREE_CODE (*node) != FUNCTION_TYPE -- && TREE_CODE (*node) != METHOD_TYPE -- && TREE_CODE (*node) != FIELD_DECL -- && TREE_CODE (*node) != TYPE_DECL) -- { -- warning ("`%s' attribute only applies to functions", -- IDENTIFIER_POINTER (name)); -- *no_add_attrs = true; -- } -- else -- { -- if (is_attribute_p ("fastcall", name)) -- { -- if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node))) -- { -- error ("fastcall and stdcall attributes are not compatible"); -- } -- else if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node))) -- { -- error ("fastcall and regparm attributes are not compatible"); -- } -- } -- else if (is_attribute_p ("stdcall", name)) -- { -- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) -- { -- error ("fastcall and stdcall attributes are not compatible"); -- } -- } -- } -- -- if (TARGET_64BIT) -- { -- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); -- *no_add_attrs = true; -- } -- -- return NULL_TREE; --} -- --/* Handle a "regparm" attribute; -- arguments as in struct attribute_spec.handler. */ --static tree --ix86_handle_regparm_attribute (tree *node, tree name, tree args, -- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) --{ -- if (TREE_CODE (*node) != FUNCTION_TYPE -- && TREE_CODE (*node) != METHOD_TYPE -- && TREE_CODE (*node) != FIELD_DECL -- && TREE_CODE (*node) != TYPE_DECL) -- { -- warning ("`%s' attribute only applies to functions", -- IDENTIFIER_POINTER (name)); -- *no_add_attrs = true; -- } -- else -- { -- tree cst; -- -- cst = TREE_VALUE (args); -- if (TREE_CODE (cst) != INTEGER_CST) -- { -- warning ("`%s' attribute requires an integer constant argument", -- IDENTIFIER_POINTER (name)); -- *no_add_attrs = true; -- } -- else if (compare_tree_int (cst, REGPARM_MAX) > 0) -- { -- warning ("argument to `%s' attribute larger than %d", -- IDENTIFIER_POINTER (name), REGPARM_MAX); -- *no_add_attrs = true; -- } -- -- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) -- { -- error ("fastcall and regparm attributes are not compatible"); -- } -- } -- -- return NULL_TREE; --} -- --/* Return 0 if the attributes for two types are incompatible, 1 if they -- are compatible, and 2 if they are nearly compatible (which causes a -- warning to be generated). */ -- --static int --ix86_comp_type_attributes (tree type1, tree type2) --{ -- /* Check for mismatch of non-default calling convention. */ -- const char *const rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; -- -- if (TREE_CODE (type1) != FUNCTION_TYPE) -- return 1; -- -- /* Check for mismatched fastcall types */ -- if (!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1)) -- != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2))) -- return 0; -- -- /* Check for mismatched return types (cdecl vs stdcall). */ -- if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) -- != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) -- return 0; -- if (ix86_function_regparm (type1, NULL) -- != ix86_function_regparm (type2, NULL)) -- return 0; -- return 1; --} -- --/* Return the regparm value for a fuctio with the indicated TYPE and DECL. -- DECL may be NULL when calling function indirectly -- or considering a libcall. */ -- --static int --ix86_function_regparm (tree type, tree decl) --{ -- tree attr; -- int regparm = ix86_regparm; -- bool user_convention = false; -- -- if (!TARGET_64BIT) -- { -- attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type)); -- if (attr) -- { -- regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); -- user_convention = true; -- } -- -- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type))) -- { -- regparm = 2; -- user_convention = true; -- } -- -- /* Use register calling convention for local functions when possible. */ -- if (!TARGET_64BIT && !user_convention && decl -- && flag_unit_at_a_time && !profile_flag) -- { -- struct cgraph_local_info *i = cgraph_local_info (decl); -- if (i && i->local) -- { -- /* We can't use regparm(3) for nested functions as these use -- static chain pointer in third argument. */ -- if (DECL_CONTEXT (decl) && !DECL_NO_STATIC_CHAIN (decl)) -- regparm = 2; -- else -- regparm = 3; -- } -- } -- } -- return regparm; --} -- --/* Return true if EAX is live at the start of the function. Used by -- ix86_expand_prologue to determine if we need special help before -- calling allocate_stack_worker. */ -- --static bool --ix86_eax_live_at_start_p (void) --{ -- /* Cheat. Don't bother working forward from ix86_function_regparm -- to the function type to whether an actual argument is located in -- eax. Instead just look at cfg info, which is still close enough -- to correct at this point. This gives false positives for broken -- functions that might use uninitialized data that happens to be -- allocated in eax, but who cares? */ -- return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, 0); --} -- --/* Value is the number of bytes of arguments automatically -- popped when returning from a subroutine call. -- FUNDECL is the declaration node of the function (as a tree), -- FUNTYPE is the data type of the function (as a tree), -- or for a library call it is an identifier node for the subroutine name. -- SIZE is the number of bytes of arguments passed on the stack. -- -- On the 80386, the RTD insn may be used to pop them if the number -- of args is fixed, but if the number is variable then the caller -- must pop them all. RTD can't be used for library calls now -- because the library is compiled with the Unix compiler. -- Use of RTD is a selectable option, since it is incompatible with -- standard Unix calling sequences. If the option is not selected, -- the caller must always pop the args. -- -- The attribute stdcall is equivalent to RTD on a per module basis. */ -- --int --ix86_return_pops_args (tree fundecl, tree funtype, int size) --{ -- int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE); -- -- /* Cdecl functions override -mrtd, and never pop the stack. */ -- if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) { -- -- /* Stdcall and fastcall functions will pop the stack if not -- variable args. */ -- if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)) -- || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype))) -- rtd = 1; -- -- if (rtd -- && (TYPE_ARG_TYPES (funtype) == NULL_TREE -- || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) -- == void_type_node))) -- return size; -- } -- -- /* Lose any fake structure return argument if it is passed on the stack. */ -- if (aggregate_value_p (TREE_TYPE (funtype), fundecl) -- && !TARGET_64BIT) -- { -- int nregs = ix86_function_regparm (funtype, fundecl); -- -- if (!nregs) -- return GET_MODE_SIZE (Pmode); -- } -- -- return 0; --} -- --/* Argument support functions. */ -- --/* Return true when register may be used to pass function parameters. */ --bool --ix86_function_arg_regno_p (int regno) --{ -- int i; -- if (!TARGET_64BIT) -- return (regno < REGPARM_MAX -- || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno])); -- if (SSE_REGNO_P (regno) && TARGET_SSE) -- return true; -- /* RAX is used as hidden argument to va_arg functions. */ -- if (!regno) -- return true; -- for (i = 0; i < REGPARM_MAX; i++) -- if (regno == x86_64_int_parameter_registers[i]) -- return true; -- return false; --} -- --/* Initialize a variable CUM of type CUMULATIVE_ARGS -- for a call to a function whose data type is FNTYPE. -- For a library call, FNTYPE is 0. */ -- --void --init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ -- tree fntype, /* tree ptr for function decl */ -- rtx libname, /* SYMBOL_REF of library name or 0 */ -- tree fndecl) --{ -- static CUMULATIVE_ARGS zero_cum; -- tree param, next_param; -- -- if (TARGET_DEBUG_ARG) -- { -- fprintf (stderr, "\ninit_cumulative_args ("); -- if (fntype) -- fprintf (stderr, "fntype code = %s, ret code = %s", -- tree_code_name[(int) TREE_CODE (fntype)], -- tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]); -- else -- fprintf (stderr, "no fntype"); -- -- if (libname) -- fprintf (stderr, ", libname = %s", XSTR (libname, 0)); -- } -- -- *cum = zero_cum; -- -- /* Set up the number of registers to use for passing arguments. */ -- if (fntype) -- cum->nregs = ix86_function_regparm (fntype, fndecl); -- else -- cum->nregs = ix86_regparm; -- cum->sse_nregs = SSE_REGPARM_MAX; -- cum->mmx_nregs = MMX_REGPARM_MAX; -- cum->warn_sse = true; -- cum->warn_mmx = true; -- cum->maybe_vaarg = false; -- -- /* Use ecx and edx registers if function has fastcall attribute */ -- if (fntype && !TARGET_64BIT) -- { -- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype))) -- { -- cum->nregs = 2; -- cum->fastcall = 1; -- } -- } -- -- -- /* Determine if this function has variable arguments. This is -- indicated by the last argument being 'void_type_mode' if there -- are no variable arguments. If there are variable arguments, then -- we won't pass anything in registers */ -- -- if (cum->nregs || !TARGET_MMX || !TARGET_SSE) -- { -- for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; -- param != 0; param = next_param) -- { -- next_param = TREE_CHAIN (param); -- if (next_param == 0 && TREE_VALUE (param) != void_type_node) -- { -- if (!TARGET_64BIT) -- { -- cum->nregs = 0; -- cum->sse_nregs = 0; -- cum->mmx_nregs = 0; -- cum->warn_sse = 0; -- cum->warn_mmx = 0; -- cum->fastcall = 0; -- } -- cum->maybe_vaarg = true; -- } -- } -- } -- if ((!fntype && !libname) -- || (fntype && !TYPE_ARG_TYPES (fntype))) -- cum->maybe_vaarg = 1; -- -- if (TARGET_DEBUG_ARG) -- fprintf (stderr, ", nregs=%d )\n", cum->nregs); -- -- return; --} -- --/* x86-64 register passing implementation. See x86-64 ABI for details. Goal -- of this code is to classify each 8bytes of incoming argument by the register -- class and assign registers accordingly. */ -- --/* Return the union class of CLASS1 and CLASS2. -- See the x86-64 PS ABI for details. */ -- --static enum x86_64_reg_class --merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) --{ -- /* Rule #1: If both classes are equal, this is the resulting class. */ -- if (class1 == class2) -- return class1; -- -- /* Rule #2: If one of the classes is NO_CLASS, the resulting class is -- the other class. */ -- if (class1 == X86_64_NO_CLASS) -- return class2; -- if (class2 == X86_64_NO_CLASS) -- return class1; -- -- /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ -- if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) -- return X86_64_MEMORY_CLASS; -- -- /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ -- if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) -- || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) -- return X86_64_INTEGERSI_CLASS; -- if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS -- || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) -- return X86_64_INTEGER_CLASS; -- -- /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ -- if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS -- || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) -- return X86_64_MEMORY_CLASS; -- -- /* Rule #6: Otherwise class SSE is used. */ -- return X86_64_SSE_CLASS; --} -- --/* Classify the argument of type TYPE and mode MODE. -- CLASSES will be filled by the register class used to pass each word -- of the operand. The number of words is returned. In case the parameter -- should be passed in memory, 0 is returned. As a special case for zero -- sized containers, classes[0] will be NO_CLASS and 1 is returned. -- -- BIT_OFFSET is used internally for handling records and specifies offset -- of the offset in bits modulo 256 to avoid overflow cases. -- -- See the x86-64 PS ABI for details. --*/ -- --static int --classify_argument (enum machine_mode mode, tree type, -- enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset) --{ -- HOST_WIDE_INT bytes = -- (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); -- int words = (bytes + (bit_offset % 64) / 8 + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -- -- /* Variable sized entities are always passed/returned in memory. */ -- if (bytes < 0) -- return 0; -- -- if (mode != VOIDmode -- && MUST_PASS_IN_STACK (mode, type)) -- return 0; -- -- if (type && AGGREGATE_TYPE_P (type)) -- { -- int i; -- tree field; -- enum x86_64_reg_class subclasses[MAX_CLASSES]; -- -- /* On x86-64 we pass structures larger than 16 bytes on the stack. */ -- if (bytes > 16) -- return 0; -- -- for (i = 0; i < words; i++) -- classes[i] = X86_64_NO_CLASS; -- -- /* Zero sized arrays or structures are NO_CLASS. We return 0 to -- signalize memory class, so handle it as special case. */ -- if (!words) -- { -- classes[0] = X86_64_NO_CLASS; -- return 1; -- } -- -- /* Classify each field of record and merge classes. */ -- if (TREE_CODE (type) == RECORD_TYPE) -- { -- /* For classes first merge in the field of the subclasses. */ -- if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) -- { -- tree bases = TYPE_BINFO_BASETYPES (type); -- int n_bases = TREE_VEC_LENGTH (bases); -- int i; -- -- for (i = 0; i < n_bases; ++i) -- { -- tree binfo = TREE_VEC_ELT (bases, i); -- int num; -- int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8; -- tree type = BINFO_TYPE (binfo); -- -- num = classify_argument (TYPE_MODE (type), -- type, subclasses, -- (offset + bit_offset) % 256); -- if (!num) -- return 0; -- for (i = 0; i < num; i++) -- { -- int pos = (offset + (bit_offset % 64)) / 8 / 8; -- classes[i + pos] = -- merge_classes (subclasses[i], classes[i + pos]); -- } -- } -- } -- /* And now merge the fields of structure. */ -- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) -- { -- if (TREE_CODE (field) == FIELD_DECL) -- { -- int num; -- -- /* Bitfields are always classified as integer. Handle them -- early, since later code would consider them to be -- misaligned integers. */ -- if (DECL_BIT_FIELD (field)) -- { -- for (i = int_bit_position (field) / 8 / 8; -- i < (int_bit_position (field) -- + tree_low_cst (DECL_SIZE (field), 0) -- + 63) / 8 / 8; i++) -- classes[i] = -- merge_classes (X86_64_INTEGER_CLASS, -- classes[i]); -- } -- else -- { -- num = classify_argument (TYPE_MODE (TREE_TYPE (field)), -- TREE_TYPE (field), subclasses, -- (int_bit_position (field) -- + bit_offset) % 256); -- if (!num) -- return 0; -- for (i = 0; i < num; i++) -- { -- int pos = -- (int_bit_position (field) + (bit_offset % 64)) / 8 / 8; -- classes[i + pos] = -- merge_classes (subclasses[i], classes[i + pos]); -- } -- } -- } -- } -- } -- /* Arrays are handled as small records. */ -- else if (TREE_CODE (type) == ARRAY_TYPE) -- { -- int num; -- num = classify_argument (TYPE_MODE (TREE_TYPE (type)), -- TREE_TYPE (type), subclasses, bit_offset); -- if (!num) -- return 0; -- -- /* The partial classes are now full classes. */ -- if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4) -- subclasses[0] = X86_64_SSE_CLASS; -- if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4) -- subclasses[0] = X86_64_INTEGER_CLASS; -- -- for (i = 0; i < words; i++) -- classes[i] = subclasses[i % num]; -- } -- /* Unions are similar to RECORD_TYPE but offset is always 0. */ -- else if (TREE_CODE (type) == UNION_TYPE -- || TREE_CODE (type) == QUAL_UNION_TYPE) -- { -- /* For classes first merge in the field of the subclasses. */ -- if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) -- { -- tree bases = TYPE_BINFO_BASETYPES (type); -- int n_bases = TREE_VEC_LENGTH (bases); -- int i; -- -- for (i = 0; i < n_bases; ++i) -- { -- tree binfo = TREE_VEC_ELT (bases, i); -- int num; -- int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8; -- tree type = BINFO_TYPE (binfo); -- -- num = classify_argument (TYPE_MODE (type), -- type, subclasses, -- (offset + (bit_offset % 64)) % 256); -- if (!num) -- return 0; -- for (i = 0; i < num; i++) -- { -- int pos = (offset + (bit_offset % 64)) / 8 / 8; -- classes[i + pos] = -- merge_classes (subclasses[i], classes[i + pos]); -- } -- } -- } -- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) -- { -- if (TREE_CODE (field) == FIELD_DECL) -- { -- int num; -- num = classify_argument (TYPE_MODE (TREE_TYPE (field)), -- TREE_TYPE (field), subclasses, -- bit_offset); -- if (!num) -- return 0; -- for (i = 0; i < num; i++) -- classes[i] = merge_classes (subclasses[i], classes[i]); -- } -- } -- } -- else if (TREE_CODE (type) == SET_TYPE) -- { -- if (bytes <= 4) -- { -- classes[0] = X86_64_INTEGERSI_CLASS; -- return 1; -- } -- else if (bytes <= 8) -- { -- classes[0] = X86_64_INTEGER_CLASS; -- return 1; -- } -- else if (bytes <= 12) -- { -- classes[0] = X86_64_INTEGER_CLASS; -- classes[1] = X86_64_INTEGERSI_CLASS; -- return 2; -- } -- else -- { -- classes[0] = X86_64_INTEGER_CLASS; -- classes[1] = X86_64_INTEGER_CLASS; -- return 2; -- } -- } -- else -- abort (); -- -- /* Final merger cleanup. */ -- for (i = 0; i < words; i++) -- { -- /* If one class is MEMORY, everything should be passed in -- memory. */ -- if (classes[i] == X86_64_MEMORY_CLASS) -- return 0; -- -- /* The X86_64_SSEUP_CLASS should be always preceded by -- X86_64_SSE_CLASS. */ -- if (classes[i] == X86_64_SSEUP_CLASS -- && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) -- classes[i] = X86_64_SSE_CLASS; -- -- /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ -- if (classes[i] == X86_64_X87UP_CLASS -- && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) -- classes[i] = X86_64_SSE_CLASS; -- } -- return words; -- } -- -- /* Compute alignment needed. We align all types to natural boundaries with -- exception of XFmode that is aligned to 64bits. */ -- if (mode != VOIDmode && mode != BLKmode) -- { -- int mode_alignment = GET_MODE_BITSIZE (mode); -- -- if (mode == XFmode) -- mode_alignment = 128; -- else if (mode == XCmode) -- mode_alignment = 256; -- if (COMPLEX_MODE_P (mode)) -- mode_alignment /= 2; -- /* Misaligned fields are always returned in memory. */ -- if (bit_offset % mode_alignment) -- return 0; -- } -- -- /* Classification of atomic types. */ -- switch (mode) -- { -- case DImode: -- case SImode: -- case HImode: -- case QImode: -- case CSImode: -- case CHImode: -- case CQImode: -- if (bit_offset + GET_MODE_BITSIZE (mode) <= 32) -- classes[0] = X86_64_INTEGERSI_CLASS; -- else -- classes[0] = X86_64_INTEGER_CLASS; -- return 1; -- case CDImode: -- case TImode: -- classes[0] = classes[1] = X86_64_INTEGER_CLASS; -- return 2; -- case CTImode: -- classes[0] = classes[1] = X86_64_INTEGER_CLASS; -- classes[2] = classes[3] = X86_64_INTEGER_CLASS; -- return 4; -- case SFmode: -- if (!(bit_offset % 64)) -- classes[0] = X86_64_SSESF_CLASS; -- else -- classes[0] = X86_64_SSE_CLASS; -- return 1; -- case DFmode: -- classes[0] = X86_64_SSEDF_CLASS; -- return 1; -- case XFmode: -- classes[0] = X86_64_X87_CLASS; -- classes[1] = X86_64_X87UP_CLASS; -- return 2; -- case TFmode: -- case TCmode: -- return 0; -- case XCmode: -- classes[0] = X86_64_X87_CLASS; -- classes[1] = X86_64_X87UP_CLASS; -- classes[2] = X86_64_X87_CLASS; -- classes[3] = X86_64_X87UP_CLASS; -- return 4; -- case DCmode: -- classes[0] = X86_64_SSEDF_CLASS; -- classes[1] = X86_64_SSEDF_CLASS; -- return 2; -- case SCmode: -- classes[0] = X86_64_SSE_CLASS; -- return 1; -- case V4SFmode: -- case V4SImode: -- case V16QImode: -- case V8HImode: -- case V2DFmode: -- case V2DImode: -- classes[0] = X86_64_SSE_CLASS; -- classes[1] = X86_64_SSEUP_CLASS; -- return 2; -- case V2SFmode: -- case V2SImode: -- case V4HImode: -- case V8QImode: -- return 0; -- case BLKmode: -- case VOIDmode: -- return 0; -- default: -- abort (); -- } --} -- --/* Examine the argument and return set number of register required in each -- class. Return 0 iff parameter should be passed in memory. */ --static int --examine_argument (enum machine_mode mode, tree type, int in_return, -- int *int_nregs, int *sse_nregs) --{ -- enum x86_64_reg_class class[MAX_CLASSES]; -- int n = classify_argument (mode, type, class, 0); -- -- *int_nregs = 0; -- *sse_nregs = 0; -- if (!n) -- return 0; -- for (n--; n >= 0; n--) -- switch (class[n]) -- { -- case X86_64_INTEGER_CLASS: -- case X86_64_INTEGERSI_CLASS: -- (*int_nregs)++; -- break; -- case X86_64_SSE_CLASS: -- case X86_64_SSESF_CLASS: -- case X86_64_SSEDF_CLASS: -- (*sse_nregs)++; -- break; -- case X86_64_NO_CLASS: -- case X86_64_SSEUP_CLASS: -- break; -- case X86_64_X87_CLASS: -- case X86_64_X87UP_CLASS: -- if (!in_return) -- return 0; -- break; -- case X86_64_MEMORY_CLASS: -- abort (); -- } -- return 1; --} --/* Construct container for the argument used by GCC interface. See -- FUNCTION_ARG for the detailed description. */ --static rtx --construct_container (enum machine_mode mode, tree type, int in_return, -- int nintregs, int nsseregs, const int * intreg, -- int sse_regno) --{ -- enum machine_mode tmpmode; -- int bytes = -- (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); -- enum x86_64_reg_class class[MAX_CLASSES]; -- int n; -- int i; -- int nexps = 0; -- int needed_sseregs, needed_intregs; -- rtx exp[MAX_CLASSES]; -- rtx ret; -- -- n = classify_argument (mode, type, class, 0); -- if (TARGET_DEBUG_ARG) -- { -- if (!n) -- fprintf (stderr, "Memory class\n"); -- else -- { -- fprintf (stderr, "Classes:"); -- for (i = 0; i < n; i++) -- { -- fprintf (stderr, " %s", x86_64_reg_class_name[class[i]]); -- } -- fprintf (stderr, "\n"); -- } -- } -- if (!n) -- return NULL; -- if (!examine_argument (mode, type, in_return, &needed_intregs, &needed_sseregs)) -- return NULL; -- if (needed_intregs > nintregs || needed_sseregs > nsseregs) -- return NULL; -- -- /* First construct simple cases. Avoid SCmode, since we want to use -- single register to pass this type. */ -- if (n == 1 && mode != SCmode) -- switch (class[0]) -- { -- case X86_64_INTEGER_CLASS: -- case X86_64_INTEGERSI_CLASS: -- return gen_rtx_REG (mode, intreg[0]); -- case X86_64_SSE_CLASS: -- case X86_64_SSESF_CLASS: -- case X86_64_SSEDF_CLASS: -- return gen_rtx_REG (mode, SSE_REGNO (sse_regno)); -- case X86_64_X87_CLASS: -- return gen_rtx_REG (mode, FIRST_STACK_REG); -- case X86_64_NO_CLASS: -- /* Zero sized array, struct or class. */ -- return NULL; -- default: -- abort (); -- } -- if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS -- && mode != BLKmode) -- return gen_rtx_REG (mode, SSE_REGNO (sse_regno)); -- if (n == 2 -- && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS) -- return gen_rtx_REG (XFmode, FIRST_STACK_REG); -- if (n == 2 && class[0] == X86_64_INTEGER_CLASS -- && class[1] == X86_64_INTEGER_CLASS -- && (mode == CDImode || mode == TImode || mode == TFmode) -- && intreg[0] + 1 == intreg[1]) -- return gen_rtx_REG (mode, intreg[0]); -- if (n == 4 -- && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS -- && class[2] == X86_64_X87_CLASS && class[3] == X86_64_X87UP_CLASS -- && mode != BLKmode) -- return gen_rtx_REG (XCmode, FIRST_STACK_REG); -- -- /* Otherwise figure out the entries of the PARALLEL. */ -- for (i = 0; i < n; i++) -- { -- switch (class[i]) -- { -- case X86_64_NO_CLASS: -- break; -- case X86_64_INTEGER_CLASS: -- case X86_64_INTEGERSI_CLASS: -- /* Merge TImodes on aligned occasions here too. */ -- if (i * 8 + 8 > bytes) -- tmpmode = mode_for_size ((bytes - i * 8) * BITS_PER_UNIT, MODE_INT, 0); -- else if (class[i] == X86_64_INTEGERSI_CLASS) -- tmpmode = SImode; -- else -- tmpmode = DImode; -- /* We've requested 24 bytes we don't have mode for. Use DImode. */ -- if (tmpmode == BLKmode) -- tmpmode = DImode; -- exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, -- gen_rtx_REG (tmpmode, *intreg), -- GEN_INT (i*8)); -- intreg++; -- break; -- case X86_64_SSESF_CLASS: -- exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, -- gen_rtx_REG (SFmode, -- SSE_REGNO (sse_regno)), -- GEN_INT (i*8)); -- sse_regno++; -- break; -- case X86_64_SSEDF_CLASS: -- exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, -- gen_rtx_REG (DFmode, -- SSE_REGNO (sse_regno)), -- GEN_INT (i*8)); -- sse_regno++; -- break; -- case X86_64_SSE_CLASS: -- if (i < n - 1 && class[i + 1] == X86_64_SSEUP_CLASS) -- tmpmode = TImode; -- else -- tmpmode = DImode; -- exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, -- gen_rtx_REG (tmpmode, -- SSE_REGNO (sse_regno)), -- GEN_INT (i*8)); -- if (tmpmode == TImode) -- i++; -- sse_regno++; -- break; -- default: -- abort (); -- } -- } -- ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nexps)); -- for (i = 0; i < nexps; i++) -- XVECEXP (ret, 0, i) = exp [i]; -- return ret; --} -- --/* Update the data in CUM to advance over an argument -- of mode MODE and data type TYPE. -- (TYPE is null for libcalls where that information may not be available.) */ -- --void --function_arg_advance (CUMULATIVE_ARGS *cum, /* current arg information */ -- enum machine_mode mode, /* current arg mode */ -- tree type, /* type of the argument or 0 if lib support */ -- int named) /* whether or not the argument was named */ --{ -- int bytes = -- (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); -- int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -- -- if (TARGET_DEBUG_ARG) -- fprintf (stderr, -- "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, mode=%s, named=%d)\n\n", -- words, cum->words, cum->nregs, cum->sse_nregs, GET_MODE_NAME (mode), named); -- if (TARGET_64BIT) -- { -- int int_nregs, sse_nregs; -- if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs)) -- cum->words += words; -- else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) -- { -- cum->nregs -= int_nregs; -- cum->sse_nregs -= sse_nregs; -- cum->regno += int_nregs; -- cum->sse_regno += sse_nregs; -- } -- else -- cum->words += words; -- } -- else -- { -- if (TARGET_SSE && SSE_REG_MODE_P (mode) -- && (!type || !AGGREGATE_TYPE_P (type))) -- { -- cum->sse_words += words; -- cum->sse_nregs -= 1; -- cum->sse_regno += 1; -- if (cum->sse_nregs <= 0) -- { -- cum->sse_nregs = 0; -- cum->sse_regno = 0; -- } -- } -- else if (TARGET_MMX && MMX_REG_MODE_P (mode) -- && (!type || !AGGREGATE_TYPE_P (type))) -- { -- cum->mmx_words += words; -- cum->mmx_nregs -= 1; -- cum->mmx_regno += 1; -- if (cum->mmx_nregs <= 0) -- { -- cum->mmx_nregs = 0; -- cum->mmx_regno = 0; -- } -- } -- else -- { -- cum->words += words; -- cum->nregs -= words; -- cum->regno += words; -- -- if (cum->nregs <= 0) -- { -- cum->nregs = 0; -- cum->regno = 0; -- } -- } -- } -- return; --} -- --/* A subroutine of function_arg. We want to pass a parameter whose nominal -- type is MODE in REGNO. We try to minimize ABI variation, so MODE may not -- actually be valid for REGNO with the current ISA. In this case, ALT_MODE -- is used instead. It must be the same size as MODE, and must be known to -- be valid for REGNO. Finally, ORIG_MODE is the original mode of the -- parameter, as seen by the type system. This may be different from MODE -- when we're mucking with things minimizing ABI variations. -- -- Returns a REG or a PARALLEL as appropriate. */ -- --static rtx --gen_reg_or_parallel (enum machine_mode mode, enum machine_mode alt_mode, -- enum machine_mode orig_mode, unsigned int regno) --{ -- rtx tmp; -- -- if (HARD_REGNO_MODE_OK (regno, mode)) -- tmp = gen_rtx_REG (mode, regno); -- else -- { -- tmp = gen_rtx_REG (alt_mode, regno); -- tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx); -- tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp)); -- } -- -- return tmp; --} -- --/* Define where to put the arguments to a function. -- Value is zero to push the argument on the stack, -- or a hard register in which to store the argument. -- -- MODE is the argument's machine mode. -- TYPE is the data type of the argument (as a tree). -- This is null for libcalls where that information may -- not be available. -- CUM is a variable of type CUMULATIVE_ARGS which gives info about -- the preceding args and about the function being called. -- NAMED is nonzero if this argument is a named parameter -- (otherwise it is an extra parameter matching an ellipsis). */ -- --rtx --function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, -- tree type, int named) --{ -- enum machine_mode mode = orig_mode; -- rtx ret = NULL_RTX; -- int bytes = -- (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); -- int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -- static bool warnedsse, warnedmmx; -- -- /* Handle a hidden AL argument containing number of registers for varargs -- x86-64 functions. For i386 ABI just return constm1_rtx to avoid -- any AL settings. */ -- if (mode == VOIDmode) -- { -- if (TARGET_64BIT) -- return GEN_INT (cum->maybe_vaarg -- ? (cum->sse_nregs < 0 -- ? SSE_REGPARM_MAX -- : cum->sse_regno) -- : -1); -- else -- return constm1_rtx; -- } -- if (TARGET_64BIT) -- ret = construct_container (mode, type, 0, cum->nregs, cum->sse_nregs, -- &x86_64_int_parameter_registers [cum->regno], -- cum->sse_regno); -- else -- switch (mode) -- { -- /* For now, pass fp/complex values on the stack. */ -- default: -- break; -- -- case BLKmode: -- if (bytes < 0) -- break; -- /* FALLTHRU */ -- case DImode: -- case SImode: -- case HImode: -- case QImode: -- if (words <= cum->nregs) -- { -- int regno = cum->regno; -- -- /* Fastcall allocates the first two DWORD (SImode) or -- smaller arguments to ECX and EDX. */ -- if (cum->fastcall) -- { -- if (mode == BLKmode || mode == DImode) -- break; -- -- /* ECX not EAX is the first allocated register. */ -- if (regno == 0) -- regno = 2; -- } -- ret = gen_rtx_REG (mode, regno); -- } -- break; -- case TImode: -- case V16QImode: -- case V8HImode: -- case V4SImode: -- case V2DImode: -- case V4SFmode: -- case V2DFmode: -- if (!type || !AGGREGATE_TYPE_P (type)) -- { -- if (!TARGET_SSE && !warnedmmx && cum->warn_sse) -- { -- warnedsse = true; -- warning ("SSE vector argument without SSE enabled " -- "changes the ABI"); -- } -- if (cum->sse_nregs) -- ret = gen_reg_or_parallel (mode, TImode, orig_mode, -- cum->sse_regno + FIRST_SSE_REG); -- } -- break; -- case V8QImode: -- case V4HImode: -- case V2SImode: -- case V2SFmode: -- if (!type || !AGGREGATE_TYPE_P (type)) -- { -- if (!TARGET_MMX && !warnedmmx && cum->warn_mmx) -- { -- warnedmmx = true; -- warning ("MMX vector argument without MMX enabled " -- "changes the ABI"); -- } -- if (cum->mmx_nregs) -- ret = gen_reg_or_parallel (mode, DImode, orig_mode, -- cum->mmx_regno + FIRST_MMX_REG); -- } -- break; -- } -- -- if (TARGET_DEBUG_ARG) -- { -- fprintf (stderr, -- "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d, ", -- words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); -- -- if (ret) -- print_simple_rtl (stderr, ret); -- else -- fprintf (stderr, ", stack"); -- -- fprintf (stderr, " )\n"); -- } -- -- return ret; --} -- --/* A C expression that indicates when an argument must be passed by -- reference. If nonzero for an argument, a copy of that argument is -- made in memory and a pointer to the argument is passed instead of -- the argument itself. The pointer is passed in whatever way is -- appropriate for passing a pointer to that type. */ -- --int --function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, -- enum machine_mode mode ATTRIBUTE_UNUSED, -- tree type, int named ATTRIBUTE_UNUSED) --{ -- if (!TARGET_64BIT) -- return 0; -- -- if (type && int_size_in_bytes (type) == -1) -- { -- if (TARGET_DEBUG_ARG) -- fprintf (stderr, "function_arg_pass_by_reference\n"); -- return 1; -- } -- -- return 0; --} -- --/* Return true when TYPE should be 128bit aligned for 32bit argument passing -- ABI */ --static bool --contains_128bit_aligned_vector_p (tree type) --{ -- enum machine_mode mode = TYPE_MODE (type); -- if (SSE_REG_MODE_P (mode) -- && (!TYPE_USER_ALIGN (type) || TYPE_ALIGN (type) > 128)) -- return true; -- if (TYPE_ALIGN (type) < 128) -- return false; -- -- if (AGGREGATE_TYPE_P (type)) -- { -- /* Walk the aggregates recursively. */ -- if (TREE_CODE (type) == RECORD_TYPE -- || TREE_CODE (type) == UNION_TYPE -- || TREE_CODE (type) == QUAL_UNION_TYPE) -- { -- tree field; -- -- if (TYPE_BINFO (type) != NULL -- && TYPE_BINFO_BASETYPES (type) != NULL) -- { -- tree bases = TYPE_BINFO_BASETYPES (type); -- int n_bases = TREE_VEC_LENGTH (bases); -- int i; -- -- for (i = 0; i < n_bases; ++i) -- { -- tree binfo = TREE_VEC_ELT (bases, i); -- tree type = BINFO_TYPE (binfo); -- -- if (contains_128bit_aligned_vector_p (type)) -- return true; -- } -- } -- /* And now merge the fields of structure. */ -- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) -- { -- if (TREE_CODE (field) == FIELD_DECL -- && contains_128bit_aligned_vector_p (TREE_TYPE (field))) -- return true; -- } -- } -- /* Just for use if some languages passes arrays by value. */ -- else if (TREE_CODE (type) == ARRAY_TYPE) -- { -- if (contains_128bit_aligned_vector_p (TREE_TYPE (type))) -- return true; -- } -- else -- abort (); -- } -- return false; --} -- --/* Gives the alignment boundary, in bits, of an argument with the -- specified mode and type. */ -- --int --ix86_function_arg_boundary (enum machine_mode mode, tree type) --{ -- int align; -- if (type) -- align = TYPE_ALIGN (type); -- else -- align = GET_MODE_ALIGNMENT (mode); -- if (align < PARM_BOUNDARY) -- align = PARM_BOUNDARY; -- if (!TARGET_64BIT) -- { -- /* i386 ABI defines all arguments to be 4 byte aligned. We have to -- make an exception for SSE modes since these require 128bit -- alignment. -- -- The handling here differs from field_alignment. ICC aligns MMX -- arguments to 4 byte boundaries, while structure fields are aligned -- to 8 byte boundaries. */ -- if (!type) -- { -- if (!SSE_REG_MODE_P (mode)) -- align = PARM_BOUNDARY; -- } -- else -- { -- if (!contains_128bit_aligned_vector_p (type)) -- align = PARM_BOUNDARY; -- } -- } -- if (align > 128) -- align = 128; -- return align; --} -- --/* Return true if N is a possible register number of function value. */ --bool --ix86_function_value_regno_p (int regno) --{ -- if (!TARGET_64BIT) -- { -- return ((regno) == 0 -- || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387) -- || ((regno) == FIRST_SSE_REG && TARGET_SSE)); -- } -- return ((regno) == 0 || (regno) == FIRST_FLOAT_REG -- || ((regno) == FIRST_SSE_REG && TARGET_SSE) -- || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)); --} -- --/* Define how to find the value returned by a function. -- VALTYPE is the data type of the value (as a tree). -- If the precise function being called is known, FUNC is its FUNCTION_DECL; -- otherwise, FUNC is 0. */ --rtx --ix86_function_value (tree valtype) --{ -- if (TARGET_64BIT) -- { -- rtx ret = construct_container (TYPE_MODE (valtype), valtype, 1, -- REGPARM_MAX, SSE_REGPARM_MAX, -- x86_64_int_return_registers, 0); -- /* For zero sized structures, construct_container return NULL, but we need -- to keep rest of compiler happy by returning meaningful value. */ -- if (!ret) -- ret = gen_rtx_REG (TYPE_MODE (valtype), 0); -- return ret; -- } -- else -- return gen_rtx_REG (TYPE_MODE (valtype), -- ix86_value_regno (TYPE_MODE (valtype))); --} -- --/* Return false iff type is returned in memory. */ --int --ix86_return_in_memory (tree type) --{ -- int needed_intregs, needed_sseregs, size; -- enum machine_mode mode = TYPE_MODE (type); -- -- if (TARGET_64BIT) -- return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs); -- -- if (mode == BLKmode) -- return 1; -- -- size = int_size_in_bytes (type); -- -- if (MS_AGGREGATE_RETURN && AGGREGATE_TYPE_P (type) && size <= 8) -- return 0; -- -- if (VECTOR_MODE_P (mode) || mode == TImode) -- { -- /* User-created vectors small enough to fit in EAX. */ -- if (size < 8) -- return 0; -- -- /* MMX/3dNow values are returned on the stack, since we've -- got to EMMS/FEMMS before returning. */ -- if (size == 8) -- return 1; -- -- /* SSE values are returned in XMM0. */ -- /* ??? Except when it doesn't exist? We have a choice of -- either (1) being abi incompatible with a -march switch, -- or (2) generating an error here. Given no good solution, -- I think the safest thing is one warning. The user won't -- be able to use -Werror, but.... */ -- if (size == 16) -- { -- static bool warned; -- -- if (TARGET_SSE) -- return 0; -- -- if (!warned) -- { -- warned = true; -- warning ("SSE vector return without SSE enabled " -- "changes the ABI"); -- } -- return 1; -- } -- } -- -- if (mode == XFmode) -- return 0; -- -- if (size > 12) -- return 1; -- return 0; --} -- --/* Define how to find the value returned by a library function -- assuming the value has mode MODE. */ --rtx --ix86_libcall_value (enum machine_mode mode) --{ -- if (TARGET_64BIT) -- { -- switch (mode) -- { -- case SFmode: -- case SCmode: -- case DFmode: -- case DCmode: -- return gen_rtx_REG (mode, FIRST_SSE_REG); -- case XFmode: -- case XCmode: -- return gen_rtx_REG (mode, FIRST_FLOAT_REG); -- case TFmode: -- case TCmode: -- return NULL; -- default: -- return gen_rtx_REG (mode, 0); -- } -- } -- else -- return gen_rtx_REG (mode, ix86_value_regno (mode)); --} -- --/* Given a mode, return the register to use for a return value. */ -- --static int --ix86_value_regno (enum machine_mode mode) --{ -- /* Floating point return values in %st(0). */ -- if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_FLOAT_RETURNS_IN_80387) -- return FIRST_FLOAT_REG; -- /* 16-byte vector modes in %xmm0. See ix86_return_in_memory for where -- we prevent this case when sse is not available. */ -- if (mode == TImode || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16)) -- return FIRST_SSE_REG; -- /* Everything else in %eax. */ -- return 0; --} -- --/* Create the va_list data type. */ -- --static tree --ix86_build_builtin_va_list (void) --{ -- tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; -- -- /* For i386 we use plain pointer to argument area. */ -- if (!TARGET_64BIT) -- return build_pointer_type (char_type_node); -- -- record = (*lang_hooks.types.make_type) (RECORD_TYPE); -- type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); -- -- f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"), -- unsigned_type_node); -- f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"), -- unsigned_type_node); -- f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"), -- ptr_type_node); -- f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"), -- ptr_type_node); -- -- DECL_FIELD_CONTEXT (f_gpr) = record; -- DECL_FIELD_CONTEXT (f_fpr) = record; -- DECL_FIELD_CONTEXT (f_ovf) = record; -- DECL_FIELD_CONTEXT (f_sav) = record; -- -- TREE_CHAIN (record) = type_decl; -- TYPE_NAME (record) = type_decl; -- TYPE_FIELDS (record) = f_gpr; -- TREE_CHAIN (f_gpr) = f_fpr; -- TREE_CHAIN (f_fpr) = f_ovf; -- TREE_CHAIN (f_ovf) = f_sav; -- -- layout_type (record); -- -- /* The correct type is an array type of one element. */ -- return build_array_type (record, build_index_type (size_zero_node)); --} -- --/* Perform any needed actions needed for a function that is receiving a -- variable number of arguments. -- -- CUM is as above. -- -- MODE and TYPE are the mode and type of the current parameter. -- -- PRETEND_SIZE is a variable that should be set to the amount of stack -- that must be pushed by the prolog to pretend that our caller pushed -- it. -- -- Normally, this macro will push all remaining incoming registers on the -- stack and set PRETEND_SIZE to the length of the registers pushed. */ -- --void --ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, -- tree type, int *pretend_size ATTRIBUTE_UNUSED, -- int no_rtl) --{ -- CUMULATIVE_ARGS next_cum; -- rtx save_area = NULL_RTX, mem; -- rtx label; -- rtx label_ref; -- rtx tmp_reg; -- rtx nsse_reg; -- int set; -- tree fntype; -- int stdarg_p; -- int i; -- -- if (!TARGET_64BIT) -- return; -- -- /* Indicate to allocate space on the stack for varargs save area. */ -- ix86_save_varrargs_registers = 1; -- -- cfun->stack_alignment_needed = 128; -- -- fntype = TREE_TYPE (current_function_decl); -- stdarg_p = (TYPE_ARG_TYPES (fntype) != 0 -- && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) -- != void_type_node)); -- -- /* For varargs, we do not want to skip the dummy va_dcl argument. -- For stdargs, we do want to skip the last named argument. */ -- next_cum = *cum; -- if (stdarg_p) -- function_arg_advance (&next_cum, mode, type, 1); -- -- if (!no_rtl) -- save_area = frame_pointer_rtx; -- -- set = get_varargs_alias_set (); -- -- for (i = next_cum.regno; i < ix86_regparm; i++) -- { -- mem = gen_rtx_MEM (Pmode, -- plus_constant (save_area, i * UNITS_PER_WORD)); -- set_mem_alias_set (mem, set); -- emit_move_insn (mem, gen_rtx_REG (Pmode, -- x86_64_int_parameter_registers[i])); -- } -- -- if (next_cum.sse_nregs) -- { -- /* Now emit code to save SSE registers. The AX parameter contains number -- of SSE parameter registers used to call this function. We use -- sse_prologue_save insn template that produces computed jump across -- SSE saves. We need some preparation work to get this working. */ -- -- label = gen_label_rtx (); -- label_ref = gen_rtx_LABEL_REF (Pmode, label); -- -- /* Compute address to jump to : -- label - 5*eax + nnamed_sse_arguments*5 */ -- tmp_reg = gen_reg_rtx (Pmode); -- nsse_reg = gen_reg_rtx (Pmode); -- emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0))); -- emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, -- gen_rtx_MULT (Pmode, nsse_reg, -- GEN_INT (4)))); -- if (next_cum.sse_regno) -- emit_move_insn -- (nsse_reg, -- gen_rtx_CONST (DImode, -- gen_rtx_PLUS (DImode, -- label_ref, -- GEN_INT (next_cum.sse_regno * 4)))); -- else -- emit_move_insn (nsse_reg, label_ref); -- emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg)); -- -- /* Compute address of memory block we save into. We always use pointer -- pointing 127 bytes after first byte to store - this is needed to keep -- instruction size limited by 4 bytes. */ -- tmp_reg = gen_reg_rtx (Pmode); -- emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, -- plus_constant (save_area, -- 8 * REGPARM_MAX + 127))); -- mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127)); -- set_mem_alias_set (mem, set); -- set_mem_align (mem, BITS_PER_WORD); -- -- /* And finally do the dirty job! */ -- emit_insn (gen_sse_prologue_save (mem, nsse_reg, -- GEN_INT (next_cum.sse_regno), label)); -- } -- --} -- --/* Implement va_start. */ -- --void --ix86_va_start (tree valist, rtx nextarg) --{ -- HOST_WIDE_INT words, n_gpr, n_fpr; -- tree f_gpr, f_fpr, f_ovf, f_sav; -- tree gpr, fpr, ovf, sav, t; -- -- /* Only 64bit target needs something special. */ -- if (!TARGET_64BIT) -- { -- std_expand_builtin_va_start (valist, nextarg); -- return; -- } -- -- f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); -- f_fpr = TREE_CHAIN (f_gpr); -- f_ovf = TREE_CHAIN (f_fpr); -- f_sav = TREE_CHAIN (f_ovf); -- -- valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); -- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); -- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); -- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); -- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); -- -- /* Count number of gp and fp argument registers used. */ -- words = current_function_args_info.words; -- n_gpr = current_function_args_info.regno; -- n_fpr = current_function_args_info.sse_regno; -- -- if (TARGET_DEBUG_ARG) -- fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n", -- (int) words, (int) n_gpr, (int) n_fpr); -- -- t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, -- build_int_2 (n_gpr * 8, 0)); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- -- t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, -- build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0)); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- -- /* Find the overflow area. */ -- t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); -- if (words != 0) -- t = build (PLUS_EXPR, TREE_TYPE (ovf), t, -- build_int_2 (words * UNITS_PER_WORD, 0)); -- t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- -- /* Find the register save area. -- Prologue of the function save it right above stack frame. */ -- t = make_tree (TREE_TYPE (sav), frame_pointer_rtx); -- t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); --} -- --/* Implement va_arg. */ --rtx --ix86_va_arg (tree valist, tree type) --{ -- static const int intreg[6] = { 0, 1, 2, 3, 4, 5 }; -- tree f_gpr, f_fpr, f_ovf, f_sav; -- tree gpr, fpr, ovf, sav, t; -- int size, rsize; -- rtx lab_false, lab_over = NULL_RTX; -- rtx addr_rtx, r; -- rtx container; -- int indirect_p = 0; -- -- /* Only 64bit target needs something special. */ -- if (!TARGET_64BIT) -- { -- return std_expand_builtin_va_arg (valist, type); -- } -- -- f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); -- f_fpr = TREE_CHAIN (f_gpr); -- f_ovf = TREE_CHAIN (f_fpr); -- f_sav = TREE_CHAIN (f_ovf); -- -- valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); -- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); -- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); -- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); -- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); -- -- size = int_size_in_bytes (type); -- if (size == -1) -- { -- /* Passed by reference. */ -- indirect_p = 1; -- type = build_pointer_type (type); -- size = int_size_in_bytes (type); -- } -- rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -- -- container = construct_container (TYPE_MODE (type), type, 0, -- REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0); -- /* -- * Pull the value out of the saved registers ... -- */ -- -- addr_rtx = gen_reg_rtx (Pmode); -- -- if (container) -- { -- rtx int_addr_rtx, sse_addr_rtx; -- int needed_intregs, needed_sseregs; -- int need_temp; -- -- lab_over = gen_label_rtx (); -- lab_false = gen_label_rtx (); -- -- examine_argument (TYPE_MODE (type), type, 0, -- &needed_intregs, &needed_sseregs); -- -- -- need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64) -- || TYPE_ALIGN (type) > 128); -- -- /* In case we are passing structure, verify that it is consecutive block -- on the register save area. If not we need to do moves. */ -- if (!need_temp && !REG_P (container)) -- { -- /* Verify that all registers are strictly consecutive */ -- if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0)))) -- { -- int i; -- -- for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) -- { -- rtx slot = XVECEXP (container, 0, i); -- if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int) i -- || INTVAL (XEXP (slot, 1)) != i * 16) -- need_temp = 1; -- } -- } -- else -- { -- int i; -- -- for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) -- { -- rtx slot = XVECEXP (container, 0, i); -- if (REGNO (XEXP (slot, 0)) != (unsigned int) i -- || INTVAL (XEXP (slot, 1)) != i * 8) -- need_temp = 1; -- } -- } -- } -- if (!need_temp) -- { -- int_addr_rtx = addr_rtx; -- sse_addr_rtx = addr_rtx; -- } -- else -- { -- int_addr_rtx = gen_reg_rtx (Pmode); -- sse_addr_rtx = gen_reg_rtx (Pmode); -- } -- /* First ensure that we fit completely in registers. */ -- if (needed_intregs) -- { -- emit_cmp_and_jump_insns (expand_expr -- (gpr, NULL_RTX, SImode, EXPAND_NORMAL), -- GEN_INT ((REGPARM_MAX - needed_intregs + -- 1) * 8), GE, const1_rtx, SImode, -- 1, lab_false); -- } -- if (needed_sseregs) -- { -- emit_cmp_and_jump_insns (expand_expr -- (fpr, NULL_RTX, SImode, EXPAND_NORMAL), -- GEN_INT ((SSE_REGPARM_MAX - -- needed_sseregs + 1) * 16 + -- REGPARM_MAX * 8), GE, const1_rtx, -- SImode, 1, lab_false); -- } -- -- /* Compute index to start of area used for integer regs. */ -- if (needed_intregs) -- { -- t = build (PLUS_EXPR, ptr_type_node, sav, gpr); -- r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL); -- if (r != int_addr_rtx) -- emit_move_insn (int_addr_rtx, r); -- } -- if (needed_sseregs) -- { -- t = build (PLUS_EXPR, ptr_type_node, sav, fpr); -- r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL); -- if (r != sse_addr_rtx) -- emit_move_insn (sse_addr_rtx, r); -- } -- if (need_temp) -- { -- int i; -- rtx mem; -- rtx x; -- -- /* Never use the memory itself, as it has the alias set. */ -- x = XEXP (assign_temp (type, 0, 1, 0), 0); -- mem = gen_rtx_MEM (BLKmode, x); -- force_operand (x, addr_rtx); -- set_mem_alias_set (mem, get_varargs_alias_set ()); -- set_mem_align (mem, BITS_PER_UNIT); -- -- for (i = 0; i < XVECLEN (container, 0); i++) -- { -- rtx slot = XVECEXP (container, 0, i); -- rtx reg = XEXP (slot, 0); -- enum machine_mode mode = GET_MODE (reg); -- rtx src_addr; -- rtx src_mem; -- int src_offset; -- rtx dest_mem; -- -- if (SSE_REGNO_P (REGNO (reg))) -- { -- src_addr = sse_addr_rtx; -- src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16; -- } -- else -- { -- src_addr = int_addr_rtx; -- src_offset = REGNO (reg) * 8; -- } -- src_mem = gen_rtx_MEM (mode, src_addr); -- set_mem_alias_set (src_mem, get_varargs_alias_set ()); -- src_mem = adjust_address (src_mem, mode, src_offset); -- dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1))); -- emit_move_insn (dest_mem, src_mem); -- } -- } -- -- if (needed_intregs) -- { -- t = -- build (PLUS_EXPR, TREE_TYPE (gpr), gpr, -- build_int_2 (needed_intregs * 8, 0)); -- t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- } -- if (needed_sseregs) -- { -- t = -- build (PLUS_EXPR, TREE_TYPE (fpr), fpr, -- build_int_2 (needed_sseregs * 16, 0)); -- t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- } -- -- emit_jump_insn (gen_jump (lab_over)); -- emit_barrier (); -- emit_label (lab_false); -- } -- -- /* ... otherwise out of the overflow area. */ -- -- /* Care for on-stack alignment if needed. */ -- if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64) -- t = ovf; -- else -- { -- HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8; -- t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0)); -- t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1)); -- } -- t = save_expr (t); -- -- r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL); -- if (r != addr_rtx) -- emit_move_insn (addr_rtx, r); -- -- t = -- build (PLUS_EXPR, TREE_TYPE (t), t, -- build_int_2 (rsize * UNITS_PER_WORD, 0)); -- t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); -- TREE_SIDE_EFFECTS (t) = 1; -- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -- -- if (container) -- emit_label (lab_over); -- -- if (indirect_p) -- { -- r = gen_rtx_MEM (Pmode, addr_rtx); -- set_mem_alias_set (r, get_varargs_alias_set ()); -- emit_move_insn (addr_rtx, r); -- } -- -- return addr_rtx; --} -- --/* Return nonzero if OP is either a i387 or SSE fp register. */ --int --any_fp_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) --{ -- return ANY_FP_REG_P (op); --} -- --/* Return nonzero if OP is an i387 fp register. */ --int --fp_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) --{ -- return FP_REG_P (op); --} -- --/* Return nonzero if OP is a non-fp register_operand. */ --int --register_and_not_any_fp_reg_operand (rtx op, enum machine_mode mode) --{ -- return register_operand (op, mode) && !ANY_FP_REG_P (op); --} -- --/* Return nonzero if OP is a register operand other than an -- i387 fp register. */ --int --register_and_not_fp_reg_operand (rtx op, enum machine_mode mode) --{ -- return register_operand (op, mode) && !FP_REG_P (op); --} -- --/* Return nonzero if OP is general operand representable on x86_64. */ -- --int --x86_64_general_operand (rtx op, enum machine_mode mode) --{ -- if (!TARGET_64BIT) -- return general_operand (op, mode); -- if (nonimmediate_operand (op, mode)) -- return 1; -- return x86_64_sign_extended_value (op); --} -- --/* Return nonzero if OP is general operand representable on x86_64 -- as either sign extended or zero extended constant. */ -- --int --x86_64_szext_general_operand (rtx op, enum machine_mode mode) --{ -- if (!TARGET_64BIT) -- return general_operand (op, mode); -- if (nonimmediate_operand (op, mode)) -- return 1; -- return x86_64_sign_extended_value (op) || x86_64_zero_extended_value (op); --} -- --/* Return nonzero if OP is nonmemory operand representable on x86_64. */ -- --int --x86_64_nonmemory_operand (rtx op, enum machine_mode mode) --{ -- if (!TARGET_64BIT) -- return nonmemory_operand (op, mode); -- if (register_operand (op, mode)) -- return 1; -- return x86_64_sign_extended_value (op); --} -- --/* Return nonzero if OP is nonmemory operand acceptable by movabs patterns. */ -- --int --x86_64_movabs_operand (rtx op, enum machine_mode mode) --{ -- if (!TARGET_64BIT || !flag_pic) -- return nonmemory_operand (op, mode); -- if (register_operand (op, mode) || x86_64_sign_extended_value (op))