/contrib/toolchain/binutils/ld/Makefile |
---|
0,0 → 1,55 |
NAME= ld-new |
LIB_DIR:= $(SDK_DIR)/lib |
CFLAGS_OPT = -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -U_MSC_VER -O2 |
CFLAGS_OPT+= -fomit-frame-pointer -fno-ident -mno-ms-bitfields |
CFLAGS_OPT+= -W -Wall -Wmissing-prototypes -Wno-format -Werror |
CFLAGS = -c $(CFLAGS_OPT) |
INCLUDES= -I. -I../bfd -I../include -I$(SDK_DIR)/sources/newlib/libc/include |
DEFINES= -DHAVE_CONFIG_H -DLOCALEDIR='"/home/autobuild/tools/win32/share/locale"' |
FDEFS= -DSCRIPTDIR='"/home/autobuild/tools/win32/mingw32/lib"' -DBINDIR='"/home/autobuild/tools/win32/bin"' |
FDEFS+= -DTOOLBINDIR='"/home/autobuild/tools/win32/mingw32/bin"' |
MDEFS= -DDEFAULT_EMULATION='"i386pe"' -DBINDIR='"/home/autobuild/tools/win32/bin"' |
MDEFS+= -DTOOLBINDIR='"/home/autobuild/tools/win32/mingw32/bin"' -DTARGET='"i686-pc-mingw32"' |
MDEFS+= -DTARGET_SYSTEM_ROOT='"/home/autobuild/tools/win32"' -DTARGET_SYSTEM_ROOT_RELOCATABLE |
LIBS= -lbfd -liberty -lz -lgcc -lc.dll -lapp |
LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib |
LDFLAGS = -static -nostdlib --stack 0x200000 -T$(SDK_DIR)/sources/newlib/app.lds --image-base 0 |
SRCS = \ |
deffilep.c ei386pe.c \ |
ldcref.c ldctor.c ldemul.c \ |
ldexp.c ldfile.c ldgram.c \ |
ldlang.c ldlex-wrapper.c \ |
ldmain.c ldmisc.c ldver.c \ |
ldwrite.c lexsup.c mri.c \ |
pe-dll.c |
OBJS = $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))) |
# targets |
all: $(NAME) |
$(NAME): $(OBJS) Makefile |
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LIBS) |
kos32-objcopy $@ -O binary |
%.o : %.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< |
ldfile.o : ldfile.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(FDEFS) $(INCLUDES) -o $@ $< |
ldmain.o : ldmain.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(MDEFS) $(INCLUDES) -o $@ $< |
/contrib/toolchain/binutils/ld/config.h |
---|
0,0 → 1,238 |
/* config.h. Generated from config.in by configure. */ |
/* config.in. Generated from configure.in by autoheader. */ |
/* Check that config.h is #included before system headers |
(this works only for glibc, but that should be enough). */ |
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__) |
# error config.h must be #included before system headers |
#endif |
#define __CONFIG_H__ 1 |
/* Define to 1 if translation of program messages to the user's native |
language is requested. */ |
/* #undef ENABLE_NLS */ |
/* Additional extension a shared object might have. */ |
/* #undef EXTRA_SHLIB_EXTENSION */ |
/* Define to choose default GOT handling scheme */ |
#define GOT_HANDLING_DEFAULT GOT_HANDLING_TARGET_DEFAULT |
/* Define to 1 if you have the `close' function. */ |
#define HAVE_CLOSE 1 |
/* Define to 1 if you have the declaration of `environ', and to 0 if you |
don't. */ |
#define HAVE_DECL_ENVIRON 1 |
/* Define to 1 if you have the declaration of `free', and to 0 if you don't. |
*/ |
#define HAVE_DECL_FREE 1 |
/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. |
*/ |
#define HAVE_DECL_GETENV 1 |
/* Is the prototype for getopt in <unistd.h> in the expected format? */ |
#define HAVE_DECL_GETOPT 1 |
/* Define to 1 if you have the declaration of `sbrk', and to 0 if you don't. |
*/ |
#define HAVE_DECL_SBRK 0 |
/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. |
*/ |
#define HAVE_DECL_STRSTR 1 |
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. |
*/ |
#define HAVE_DIRENT_H 1 |
/* Define to 1 if you have the `dlclose' function. */ |
/* #undef HAVE_DLCLOSE */ |
/* Define to 1 if you have the <dlfcn.h> header file. */ |
/* #undef HAVE_DLFCN_H */ |
/* Define to 1 if you have the `dlopen' function. */ |
/* #undef HAVE_DLOPEN */ |
/* Define to 1 if you have the `dlsym' function. */ |
/* #undef HAVE_DLSYM */ |
/* Define to 1 if you have the <elf-hints.h> header file. */ |
/* #undef HAVE_ELF_HINTS_H */ |
/* Define to 1 if you have the <fcntl.h> header file. */ |
#define HAVE_FCNTL_H 1 |
/* Define to 1 if you have the `glob' function. */ |
/* #undef HAVE_GLOB */ |
/* Define .init_array/.fini_array sections are available and working. */ |
#define HAVE_INITFINI_ARRAY 1 |
/* Define to 1 if you have the <inttypes.h> header file. */ |
#define HAVE_INTTYPES_H 1 |
/* Define if your <locale.h> file defines LC_MESSAGES. */ |
/* #undef HAVE_LC_MESSAGES */ |
/* Define to 1 if you have the <limits.h> header file. */ |
#define HAVE_LIMITS_H 1 |
/* Define to 1 if you have the <locale.h> header file. */ |
#define HAVE_LOCALE_H 1 |
/* Define to 1 if you have the `lseek' function. */ |
#define HAVE_LSEEK 1 |
/* Define to 1 if you have the <memory.h> header file. */ |
#define HAVE_MEMORY_H 1 |
/* Define to 1 if you have the `mkstemp' function. */ |
/* #undef HAVE_MKSTEMP */ |
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ |
/* #undef HAVE_NDIR_H */ |
/* Define to 1 if you have the `open' function. */ |
#define HAVE_OPEN 1 |
/* Define to 1 if you have the `realpath' function. */ |
/* #undef HAVE_REALPATH */ |
/* Define to 1 if you have the `sbrk' function. */ |
/* #undef HAVE_SBRK */ |
/* Define to 1 if you have the `setlocale' function. */ |
#define HAVE_SETLOCALE 1 |
/* Define to 1 if you have the <stdint.h> header file. */ |
#define HAVE_STDINT_H 1 |
/* Define to 1 if you have the <stdlib.h> header file. */ |
#define HAVE_STDLIB_H 1 |
/* Define to 1 if you have the <strings.h> header file. */ |
#define HAVE_STRINGS_H 1 |
/* Define to 1 if you have the <string.h> header file. */ |
#define HAVE_STRING_H 1 |
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. |
*/ |
/* #undef HAVE_SYS_DIR_H */ |
/* Define to 1 if you have the <sys/file.h> header file. */ |
#define HAVE_SYS_FILE_H 1 |
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. |
*/ |
/* #undef HAVE_SYS_NDIR_H */ |
/* Define to 1 if you have the <sys/param.h> header file. */ |
#define HAVE_SYS_PARAM_H 1 |
/* Define to 1 if you have the <sys/stat.h> header file. */ |
#define HAVE_SYS_STAT_H 1 |
/* Define to 1 if you have the <sys/time.h> header file. */ |
#define HAVE_SYS_TIME_H 1 |
/* Define to 1 if you have the <sys/types.h> header file. */ |
#define HAVE_SYS_TYPES_H 1 |
/* Define to 1 if you have the <unistd.h> header file. */ |
#define HAVE_UNISTD_H 1 |
/* Define to 1 if you have the `waitpid' function. */ |
/* #undef HAVE_WAITPID */ |
/* Define to 1 if you have the <windows.h> header file. */ |
//#define HAVE_WINDOWS_H 1 |
/* Define to 1 if you have the <zlib.h> header file. */ |
#define HAVE_ZLIB_H 1 |
/* Define to the sub-directory in which libtool stores uninstalled libraries. |
*/ |
#define LT_OBJDIR ".libs/" |
/* Name of package */ |
#define PACKAGE "ld" |
/* Define to the address where bug reports for this package should be sent. */ |
#define PACKAGE_BUGREPORT "" |
/* Define to the full name of this package. */ |
#define PACKAGE_NAME "" |
/* Define to the full name and version of this package. */ |
#define PACKAGE_STRING "" |
/* Define to the one symbol short name of this package. */ |
#define PACKAGE_TARNAME "" |
/* Define to the home page for this package. */ |
#define PACKAGE_URL "" |
/* Define to the version of this package. */ |
#define PACKAGE_VERSION "" |
/* The size of `void *', as computed by sizeof. */ |
#define SIZEOF_VOID_P 4 |
/* Define to 1 if you have the ANSI C header files. */ |
#define STDC_HEADERS 1 |
/* Define if you can safely include both <string.h> and <strings.h>. */ |
#define STRING_WITH_STRINGS 1 |
/* Use b modifier when opening binary files? */ |
#define USE_BINARY_FOPEN 1 |
/* Enable extensions on AIX 3, Interix. */ |
#ifndef _ALL_SOURCE |
# define _ALL_SOURCE 1 |
#endif |
/* Enable GNU extensions on systems that have them. */ |
#ifndef _GNU_SOURCE |
# define _GNU_SOURCE 1 |
#endif |
/* Enable threading extensions on Solaris. */ |
#ifndef _POSIX_PTHREAD_SEMANTICS |
# define _POSIX_PTHREAD_SEMANTICS 1 |
#endif |
/* Enable extensions on HP NonStop. */ |
#ifndef _TANDEM_SOURCE |
# define _TANDEM_SOURCE 1 |
#endif |
/* Enable general extensions on Solaris. */ |
#ifndef __EXTENSIONS__ |
# define __EXTENSIONS__ 1 |
#endif |
/* Version number of package */ |
#define VERSION "2.24" |
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a |
`char[]'. */ |
/* #undef YYTEXT_POINTER */ |
/* Number of bits in a file offset, on hosts where this is settable. */ |
/* #undef _FILE_OFFSET_BITS */ |
/* Define for large files, on AIX-style hosts. */ |
/* #undef _LARGE_FILES */ |
/* Define to 1 if on MINIX. */ |
/* #undef _MINIX */ |
/* Define to 2 if the system does not provide POSIX.1 features except with |
this defined. */ |
/* #undef _POSIX_1_SOURCE */ |
/* Define to 1 if you need to in order for `stat' and other things to work. */ |
/* #undef _POSIX_SOURCE */ |
/contrib/toolchain/binutils/ld/deffile.h |
---|
0,0 → 1,118 |
/* deffile.h - header for .DEF file parser |
Copyright 1998, 1999, 2000, 2002, 2003, 2005, 2006, 2007, 2009 |
Free Software Foundation, Inc. |
Written by DJ Delorie dj@cygnus.com |
This file is part of the GNU Binutils. |
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 3, or (at your option) |
any later version. |
The 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 GLD; see the file COPYING. If not, write to the Free |
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
02110-1301, USA. */ |
#ifndef DEFFILE_H |
#define DEFFILE_H |
/* DEF storage definitions. Note that any ordinal may be zero, and |
any pointer may be NULL, if not defined by the DEF file. */ |
typedef struct def_file_section { |
char *name; /* always set */ |
char *class; /* may be NULL */ |
char flag_read, flag_write, flag_execute, flag_shared; |
} def_file_section; |
typedef struct def_file_export { |
char *name; /* always set */ |
char *internal_name; /* always set, may == name */ |
char *its_name; /* optional export table name refered to. */ |
int ordinal; /* -1 if not specified */ |
int hint; |
char flag_private, flag_constant, flag_noname, flag_data, flag_forward; |
} def_file_export; |
typedef struct def_file_module { |
struct def_file_module *next; |
void *user_data; |
char name[1]; /* extended via malloc */ |
} def_file_module; |
typedef struct def_file_import { |
char *internal_name; /* always set */ |
def_file_module *module; /* always set */ |
char *name; /* may be NULL; either this or ordinal will be set */ |
char *its_name; /* optional import table name refered to. */ |
int ordinal; /* may be -1 */ |
int data; /* = 1 if data */ |
} def_file_import; |
typedef struct def_file_aligncomm { |
struct def_file_aligncomm *next; /* Chain pointer. */ |
char *symbol_name; /* Name of common symbol. */ |
unsigned int alignment; /* log-2 alignment. */ |
} def_file_aligncomm; |
typedef struct def_file { |
/* From the NAME or LIBRARY command. */ |
char *name; |
int is_dll; /* -1 if NAME/LIBRARY not given */ |
bfd_vma base_address; /* (bfd_vma)(-1) if unspecified */ |
/* From the DESCRIPTION command. */ |
char *description; |
/* From the STACK/HEAP command, -1 if unspecified. */ |
int stack_reserve, stack_commit; |
int heap_reserve, heap_commit; |
/* From the SECTION/SEGMENT commands. */ |
int num_section_defs; |
def_file_section *section_defs; |
/* From the EXPORTS commands. */ |
int num_exports; |
def_file_export *exports; |
/* Used by imports for module names. */ |
def_file_module *modules; |
/* From the IMPORTS commands. */ |
int num_imports; |
def_file_import *imports; |
/* From the VERSION command, -1 if not specified. */ |
int version_major, version_minor; |
/* Only expected from .drectve sections, not .DEF files. */ |
def_file_aligncomm *aligncomms; |
} def_file; |
extern def_file *def_file_empty (void); |
/* The second arg may be NULL. If not, this .def is appended to it. */ |
extern def_file *def_file_parse (const char *, def_file *); |
extern void def_file_free (def_file *); |
extern def_file_export *def_file_add_export (def_file *, const char *, |
const char *, int, |
const char *, int *); |
extern def_file_import *def_file_add_import (def_file *, const char *, |
const char *, int, const char *, |
const char *, int *); |
extern void def_file_add_directive (def_file *, const char *, int); |
extern def_file_module *def_get_module (def_file *, const char *); |
#ifdef DEF_FILE_PRINT |
extern void def_file_print (FILE *, def_file *); |
#endif |
#endif /* DEFFILE_H */ |
/contrib/toolchain/binutils/ld/deffilep.c |
---|
0,0 → 1,3426 |
/* A Bison parser, made by GNU Bison 2.3. */ |
/* Skeleton implementation for Bison's Yacc-like parsers in C |
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 |
Free Software Foundation, Inc. |
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, Inc., 51 Franklin Street, Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* As a special exception, you may create a larger work that contains |
part or all of the Bison parser skeleton and distribute that work |
under terms of your choice, so long as that work isn't itself a |
parser generator using the skeleton or a modified version thereof |
as a parser skeleton. Alternatively, if you modify or redistribute |
the parser skeleton itself, you may (at your option) remove this |
special exception, which will cause the skeleton and the resulting |
Bison output files to be licensed under the GNU General Public |
License without this special exception. |
This special exception was added by the Free Software Foundation in |
version 2.2 of Bison. */ |
/* C LALR(1) parser skeleton written by Richard Stallman, by |
simplifying the original so-called "semantic" parser. */ |
/* All symbols defined below should begin with yy or YY, to avoid |
infringing on user name space. This should be done even for local |
variables, as they might otherwise be expanded by user macros. |
There are some unavoidable exceptions within include files to |
define necessary library symbols; they are noted "INFRINGES ON |
USER NAME SPACE" below. */ |
/* Identify Bison output. */ |
#define YYBISON 1 |
/* Bison version. */ |
#define YYBISON_VERSION "2.3" |
/* Skeleton name. */ |
#define YYSKELETON_NAME "yacc.c" |
/* Pure parsers. */ |
#define YYPURE 0 |
/* Using locations. */ |
#define YYLSP_NEEDED 0 |
/* Tokens. */ |
#ifndef YYTOKENTYPE |
# define YYTOKENTYPE |
/* Put the tokens into the symbol table, so that GDB and other debuggers |
know about them. */ |
enum yytokentype { |
NAME = 258, |
LIBRARY = 259, |
DESCRIPTION = 260, |
STACKSIZE_K = 261, |
HEAPSIZE = 262, |
CODE = 263, |
DATAU = 264, |
DATAL = 265, |
SECTIONS = 266, |
EXPORTS = 267, |
IMPORTS = 268, |
VERSIONK = 269, |
BASE = 270, |
CONSTANTU = 271, |
CONSTANTL = 272, |
PRIVATEU = 273, |
PRIVATEL = 274, |
ALIGNCOMM = 275, |
READ = 276, |
WRITE = 277, |
EXECUTE = 278, |
SHARED = 279, |
NONAMEU = 280, |
NONAMEL = 281, |
DIRECTIVE = 282, |
EQUAL = 283, |
ID = 284, |
DIGITS = 285 |
}; |
#endif |
/* Tokens. */ |
#define NAME 258 |
#define LIBRARY 259 |
#define DESCRIPTION 260 |
#define STACKSIZE_K 261 |
#define HEAPSIZE 262 |
#define CODE 263 |
#define DATAU 264 |
#define DATAL 265 |
#define SECTIONS 266 |
#define EXPORTS 267 |
#define IMPORTS 268 |
#define VERSIONK 269 |
#define BASE 270 |
#define CONSTANTU 271 |
#define CONSTANTL 272 |
#define PRIVATEU 273 |
#define PRIVATEL 274 |
#define ALIGNCOMM 275 |
#define READ 276 |
#define WRITE 277 |
#define EXECUTE 278 |
#define SHARED 279 |
#define NONAMEU 280 |
#define NONAMEL 281 |
#define DIRECTIVE 282 |
#define EQUAL 283 |
#define ID 284 |
#define DIGITS 285 |
/* Copy the first part of user declarations. */ |
#line 1 "deffilep.y" |
/* deffilep.y - parser for .def files */ |
/* Copyright 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, |
2007, 2009 Free Software Foundation, Inc. |
This file is part of GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
#include "bfd.h" |
#include "ld.h" |
#include "ldmisc.h" |
#include "deffile.h" |
#define TRACE 0 |
#define ROUND_UP(a, b) (((a)+((b)-1))&~((b)-1)) |
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), |
as well as gratuitiously global symbol names, so we can have multiple |
yacc generated parsers in ld. Note that these are only the variables |
produced by yacc. If other parser generators (bison, byacc, etc) produce |
additional global names that conflict at link time, then those parser |
generators need to be fixed instead of adding those names to this list. */ |
#define yymaxdepth def_maxdepth |
#define yyparse def_parse |
#define yylex def_lex |
#define yyerror def_error |
#define yylval def_lval |
#define yychar def_char |
#define yydebug def_debug |
#define yypact def_pact |
#define yyr1 def_r1 |
#define yyr2 def_r2 |
#define yydef def_def |
#define yychk def_chk |
#define yypgo def_pgo |
#define yyact def_act |
#define yyexca def_exca |
#define yyerrflag def_errflag |
#define yynerrs def_nerrs |
#define yyps def_ps |
#define yypv def_pv |
#define yys def_s |
#define yy_yys def_yys |
#define yystate def_state |
#define yytmp def_tmp |
#define yyv def_v |
#define yy_yyv def_yyv |
#define yyval def_val |
#define yylloc def_lloc |
#define yyreds def_reds /* With YYDEBUG defined. */ |
#define yytoks def_toks /* With YYDEBUG defined. */ |
#define yylhs def_yylhs |
#define yylen def_yylen |
#define yydefred def_yydefred |
#define yydgoto def_yydgoto |
#define yysindex def_yysindex |
#define yyrindex def_yyrindex |
#define yygindex def_yygindex |
#define yytable def_yytable |
#define yycheck def_yycheck |
typedef struct def_pool_str { |
struct def_pool_str *next; |
char data[1]; |
} def_pool_str; |
static def_pool_str *pool_strs = NULL; |
static char *def_pool_alloc (size_t sz); |
static char *def_pool_strdup (const char *str); |
static void def_pool_free (void); |
static void def_description (const char *); |
static void def_exports (const char *, const char *, int, int, const char *); |
static void def_heapsize (int, int); |
static void def_import (const char *, const char *, const char *, const char *, |
int, const char *); |
static void def_image_name (const char *, bfd_vma, int); |
static void def_section (const char *, int); |
static void def_section_alt (const char *, const char *); |
static void def_stacksize (int, int); |
static void def_version (int, int); |
static void def_directive (char *); |
static void def_aligncomm (char *str, int align); |
static int def_parse (void); |
static int def_error (const char *); |
static int def_lex (void); |
static int lex_forced_token = 0; |
static const char *lex_parse_string = 0; |
static const char *lex_parse_string_end = 0; |
/* Enabling traces. */ |
#ifndef YYDEBUG |
# define YYDEBUG 0 |
#endif |
/* Enabling verbose error messages. */ |
#ifdef YYERROR_VERBOSE |
# undef YYERROR_VERBOSE |
# define YYERROR_VERBOSE 1 |
#else |
# define YYERROR_VERBOSE 0 |
#endif |
/* Enabling the token table. */ |
#ifndef YYTOKEN_TABLE |
# define YYTOKEN_TABLE 0 |
#endif |
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED |
typedef union YYSTYPE |
#line 114 "deffilep.y" |
{ |
char *id; |
const char *id_const; |
int number; |
bfd_vma vma; |
char *digits; |
} |
/* Line 193 of yacc.c. */ |
#line 277 "deffilep.c" |
YYSTYPE; |
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ |
# define YYSTYPE_IS_DECLARED 1 |
# define YYSTYPE_IS_TRIVIAL 1 |
#endif |
/* Copy the second part of user declarations. */ |
/* Line 216 of yacc.c. */ |
#line 290 "deffilep.c" |
#ifdef short |
# undef short |
#endif |
#ifdef YYTYPE_UINT8 |
typedef YYTYPE_UINT8 yytype_uint8; |
#else |
typedef unsigned char yytype_uint8; |
#endif |
#ifdef YYTYPE_INT8 |
typedef YYTYPE_INT8 yytype_int8; |
#elif (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
typedef signed char yytype_int8; |
#else |
typedef short int yytype_int8; |
#endif |
#ifdef YYTYPE_UINT16 |
typedef YYTYPE_UINT16 yytype_uint16; |
#else |
typedef unsigned short int yytype_uint16; |
#endif |
#ifdef YYTYPE_INT16 |
typedef YYTYPE_INT16 yytype_int16; |
#else |
typedef short int yytype_int16; |
#endif |
#ifndef YYSIZE_T |
# ifdef __SIZE_TYPE__ |
# define YYSIZE_T __SIZE_TYPE__ |
# elif defined size_t |
# define YYSIZE_T size_t |
# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ |
# define YYSIZE_T size_t |
# else |
# define YYSIZE_T unsigned int |
# endif |
#endif |
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) |
#ifndef YY_ |
# if defined YYENABLE_NLS && YYENABLE_NLS |
# if ENABLE_NLS |
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ |
# define YY_(msgid) dgettext ("bison-runtime", msgid) |
# endif |
# endif |
# ifndef YY_ |
# define YY_(msgid) msgid |
# endif |
#endif |
/* Suppress unused-variable warnings by "using" E. */ |
#if ! defined lint || defined __GNUC__ |
# define YYUSE(e) ((void) (e)) |
#else |
# define YYUSE(e) /* empty */ |
#endif |
/* Identity function, used to suppress warnings about constant conditions. */ |
#ifndef lint |
# define YYID(n) (n) |
#else |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static int |
YYID (int i) |
#else |
static int |
YYID (i) |
int i; |
#endif |
{ |
return i; |
} |
#endif |
#if ! defined yyoverflow || YYERROR_VERBOSE |
/* The parser invokes alloca or malloc; define the necessary symbols. */ |
# ifdef YYSTACK_USE_ALLOCA |
# if YYSTACK_USE_ALLOCA |
# ifdef __GNUC__ |
# define YYSTACK_ALLOC __builtin_alloca |
# elif defined __BUILTIN_VA_ARG_INCR |
# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ |
# elif defined _AIX |
# define YYSTACK_ALLOC __alloca |
# elif defined _MSC_VER |
# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ |
# define alloca _alloca |
# else |
# define YYSTACK_ALLOC alloca |
# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ |
# ifndef _STDLIB_H |
# define _STDLIB_H 1 |
# endif |
# endif |
# endif |
# endif |
# endif |
# ifdef YYSTACK_ALLOC |
/* Pacify GCC's `empty if-body' warning. */ |
# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) |
# ifndef YYSTACK_ALLOC_MAXIMUM |
/* The OS might guarantee only one guard page at the bottom of the stack, |
and a page size can be as small as 4096 bytes. So we cannot safely |
invoke alloca (N) if N exceeds 4096. Use a slightly smaller number |
to allow for a few compiler-allocated temporary stack slots. */ |
# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ |
# endif |
# else |
# define YYSTACK_ALLOC YYMALLOC |
# define YYSTACK_FREE YYFREE |
# ifndef YYSTACK_ALLOC_MAXIMUM |
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM |
# endif |
# if (defined __cplusplus && ! defined _STDLIB_H \ |
&& ! ((defined YYMALLOC || defined malloc) \ |
&& (defined YYFREE || defined free))) |
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ |
# ifndef _STDLIB_H |
# define _STDLIB_H 1 |
# endif |
# endif |
# ifndef YYMALLOC |
# define YYMALLOC malloc |
# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ |
# endif |
# endif |
# ifndef YYFREE |
# define YYFREE free |
# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
void free (void *); /* INFRINGES ON USER NAME SPACE */ |
# endif |
# endif |
# endif |
#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ |
#if (! defined yyoverflow \ |
&& (! defined __cplusplus \ |
|| (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) |
/* A type that is properly aligned for any stack member. */ |
union yyalloc |
{ |
yytype_int16 yyss; |
YYSTYPE yyvs; |
}; |
/* The size of the maximum gap between one aligned stack and the next. */ |
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) |
/* The size of an array large to enough to hold all stacks, each with |
N elements. */ |
# define YYSTACK_BYTES(N) \ |
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ |
+ YYSTACK_GAP_MAXIMUM) |
/* Copy COUNT objects from FROM to TO. The source and destination do |
not overlap. */ |
# ifndef YYCOPY |
# if defined __GNUC__ && 1 < __GNUC__ |
# define YYCOPY(To, From, Count) \ |
__builtin_memcpy (To, From, (Count) * sizeof (*(From))) |
# else |
# define YYCOPY(To, From, Count) \ |
do \ |
{ \ |
YYSIZE_T yyi; \ |
for (yyi = 0; yyi < (Count); yyi++) \ |
(To)[yyi] = (From)[yyi]; \ |
} \ |
while (YYID (0)) |
# endif |
# endif |
/* Relocate STACK from its old location to the new one. The |
local variables YYSIZE and YYSTACKSIZE give the old and new number of |
elements in the stack, and YYPTR gives the new location of the |
stack. Advance YYPTR to a properly aligned location for the next |
stack. */ |
# define YYSTACK_RELOCATE(Stack) \ |
do \ |
{ \ |
YYSIZE_T yynewbytes; \ |
YYCOPY (&yyptr->Stack, Stack, yysize); \ |
Stack = &yyptr->Stack; \ |
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ |
yyptr += yynewbytes / sizeof (*yyptr); \ |
} \ |
while (YYID (0)) |
#endif |
/* YYFINAL -- State number of the termination state. */ |
#define YYFINAL 69 |
/* YYLAST -- Last index in YYTABLE. */ |
#define YYLAST 149 |
/* YYNTOKENS -- Number of terminals. */ |
#define YYNTOKENS 35 |
/* YYNNTS -- Number of nonterminals. */ |
#define YYNNTS 27 |
/* YYNRULES -- Number of rules. */ |
#define YYNRULES 99 |
/* YYNRULES -- Number of states. */ |
#define YYNSTATES 146 |
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ |
#define YYUNDEFTOK 2 |
#define YYMAXUTOK 285 |
#define YYTRANSLATE(YYX) \ |
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) |
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ |
static const yytype_uint8 yytranslate[] = |
{ |
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 32, 2, 31, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 33, 2, 2, 34, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 1, 2, 3, 4, |
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30 |
}; |
#if YYDEBUG |
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in |
YYRHS. */ |
static const yytype_uint16 yyprhs[] = |
{ |
0, 0, 3, 6, 8, 12, 16, 19, 23, 27, |
30, 33, 36, 39, 42, 45, 50, 53, 58, 59, |
61, 64, 72, 76, 77, 79, 81, 83, 85, 87, |
89, 91, 93, 96, 98, 107, 116, 123, 130, 137, |
142, 145, 147, 150, 153, 157, 159, 161, 162, 165, |
166, 168, 170, 172, 174, 176, 178, 180, 182, 184, |
186, 188, 190, 192, 194, 196, 198, 200, 202, 204, |
206, 208, 210, 212, 214, 216, 218, 220, 223, 226, |
230, 234, 236, 237, 240, 241, 244, 245, 248, 249, |
253, 254, 256, 259, 264, 266, 267, 269, 270, 272 |
}; |
/* YYRHS -- A `-1'-separated list of the rules' RHS. */ |
static const yytype_int8 yyrhs[] = |
{ |
36, 0, -1, 36, 37, -1, 37, -1, 3, 52, |
56, -1, 4, 52, 56, -1, 5, 29, -1, 6, |
60, 48, -1, 7, 60, 48, -1, 8, 46, -1, |
9, 46, -1, 11, 44, -1, 12, 38, -1, 13, |
42, -1, 14, 60, -1, 14, 60, 31, 60, -1, |
27, 29, -1, 20, 57, 32, 60, -1, -1, 39, |
-1, 38, 39, -1, 51, 55, 54, 47, 40, 47, |
53, -1, 41, 47, 40, -1, -1, 25, -1, 26, |
-1, 16, -1, 17, -1, 9, -1, 10, -1, 18, |
-1, 19, -1, 42, 43, -1, 43, -1, 29, 33, |
29, 31, 29, 31, 29, 53, -1, 29, 33, 29, |
31, 29, 31, 60, 53, -1, 29, 33, 29, 31, |
29, 53, -1, 29, 33, 29, 31, 60, 53, -1, |
29, 31, 29, 31, 29, 53, -1, 29, 31, 29, |
53, -1, 44, 45, -1, 45, -1, 29, 46, -1, |
29, 29, -1, 46, 47, 49, -1, 49, -1, 32, |
-1, -1, 32, 60, -1, -1, 21, -1, 22, -1, |
23, -1, 24, -1, 15, -1, 8, -1, 16, -1, |
17, -1, 9, -1, 10, -1, 5, -1, 27, -1, |
23, -1, 12, -1, 7, -1, 13, -1, 3, -1, |
25, -1, 26, -1, 18, -1, 19, -1, 21, -1, |
24, -1, 6, -1, 14, -1, 22, -1, 29, -1, |
31, 50, -1, 31, 51, -1, 50, 31, 51, -1, |
29, 31, 51, -1, 51, -1, -1, 28, 29, -1, |
-1, 34, 60, -1, -1, 33, 51, -1, -1, 15, |
33, 61, -1, -1, 29, -1, 31, 29, -1, 57, |
31, 58, 59, -1, 30, -1, -1, 29, -1, -1, |
30, -1, 30, -1 |
}; |
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ |
static const yytype_uint16 yyrline[] = |
{ |
0, 139, 139, 140, 144, 145, 146, 147, 148, 149, |
150, 151, 152, 153, 154, 155, 156, 157, 161, 163, |
164, 171, 178, 179, 182, 183, 184, 185, 186, 187, |
188, 189, 192, 193, 197, 199, 201, 203, 205, 207, |
212, 213, 217, 218, 222, 223, 227, 228, 230, 231, |
235, 236, 237, 238, 242, 243, 244, 245, 246, 247, |
248, 249, 250, 251, 252, 253, 260, 261, 262, 263, |
264, 265, 266, 267, 268, 269, 272, 273, 279, 285, |
291, 299, 300, 303, 304, 308, 309, 313, 314, 317, |
318, 321, 322, 328, 336, 337, 340, 341, 344, 346 |
}; |
#endif |
#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE |
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. |
First, the terminals, then, starting at YYNTOKENS, nonterminals. */ |
static const char *const yytname[] = |
{ |
"$end", "error", "$undefined", "NAME", "LIBRARY", "DESCRIPTION", |
"STACKSIZE_K", "HEAPSIZE", "CODE", "DATAU", "DATAL", "SECTIONS", |
"EXPORTS", "IMPORTS", "VERSIONK", "BASE", "CONSTANTU", "CONSTANTL", |
"PRIVATEU", "PRIVATEL", "ALIGNCOMM", "READ", "WRITE", "EXECUTE", |
"SHARED", "NONAMEU", "NONAMEL", "DIRECTIVE", "EQUAL", "ID", "DIGITS", |
"'.'", "','", "'='", "'@'", "$accept", "start", "command", "explist", |
"expline", "exp_opt_list", "exp_opt", "implist", "impline", "seclist", |
"secline", "attr_list", "opt_comma", "opt_number", "attr", |
"keyword_as_name", "opt_name2", "opt_name", "opt_equalequal_name", |
"opt_ordinal", "opt_equal_name", "opt_base", "anylang_id", "opt_digits", |
"opt_id", "NUMBER", "VMA", 0 |
}; |
#endif |
# ifdef YYPRINT |
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to |
token YYLEX-NUM. */ |
static const yytype_uint16 yytoknum[] = |
{ |
0, 256, 257, 258, 259, 260, 261, 262, 263, 264, |
265, 266, 267, 268, 269, 270, 271, 272, 273, 274, |
275, 276, 277, 278, 279, 280, 281, 282, 283, 284, |
285, 46, 44, 61, 64 |
}; |
# endif |
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ |
static const yytype_uint8 yyr1[] = |
{ |
0, 35, 36, 36, 37, 37, 37, 37, 37, 37, |
37, 37, 37, 37, 37, 37, 37, 37, 38, 38, |
38, 39, 40, 40, 41, 41, 41, 41, 41, 41, |
41, 41, 42, 42, 43, 43, 43, 43, 43, 43, |
44, 44, 45, 45, 46, 46, 47, 47, 48, 48, |
49, 49, 49, 49, 50, 50, 50, 50, 50, 50, |
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, |
50, 50, 50, 50, 50, 50, 51, 51, 51, 51, |
51, 52, 52, 53, 53, 54, 54, 55, 55, 56, |
56, 57, 57, 57, 58, 58, 59, 59, 60, 61 |
}; |
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ |
static const yytype_uint8 yyr2[] = |
{ |
0, 2, 2, 1, 3, 3, 2, 3, 3, 2, |
2, 2, 2, 2, 2, 4, 2, 4, 0, 1, |
2, 7, 3, 0, 1, 1, 1, 1, 1, 1, |
1, 1, 2, 1, 8, 8, 6, 6, 6, 4, |
2, 1, 2, 2, 3, 1, 1, 0, 2, 0, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 2, 2, 3, |
3, 1, 0, 2, 0, 2, 0, 2, 0, 3, |
0, 1, 2, 4, 1, 0, 1, 0, 1, 1 |
}; |
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state |
STATE-NUM when YYTABLE doesn't specify something else to do. Zero |
means the default is an error. */ |
static const yytype_uint8 yydefact[] = |
{ |
0, 82, 82, 0, 0, 0, 0, 0, 0, 18, |
0, 0, 0, 0, 0, 3, 66, 60, 73, 64, |
55, 58, 59, 63, 65, 74, 54, 56, 57, 69, |
70, 71, 75, 62, 72, 67, 68, 61, 76, 0, |
0, 81, 90, 90, 6, 98, 49, 49, 50, 51, |
52, 53, 9, 45, 10, 0, 11, 41, 12, 19, |
88, 0, 13, 33, 14, 91, 0, 0, 16, 1, |
2, 0, 77, 78, 0, 0, 4, 5, 0, 7, |
8, 46, 0, 43, 42, 40, 20, 0, 86, 0, |
0, 32, 0, 92, 95, 0, 80, 79, 0, 48, |
44, 87, 0, 47, 84, 0, 15, 94, 97, 17, |
99, 89, 85, 23, 0, 0, 39, 0, 96, 93, |
28, 29, 26, 27, 30, 31, 24, 25, 47, 47, |
83, 84, 84, 84, 84, 23, 38, 0, 36, 37, |
21, 22, 84, 84, 34, 35 |
}; |
/* YYDEFGOTO[NTERM-NUM]. */ |
static const yytype_int16 yydefgoto[] = |
{ |
-1, 14, 15, 58, 59, 128, 129, 62, 63, 56, |
57, 52, 82, 79, 53, 40, 41, 42, 116, 103, |
88, 76, 67, 108, 119, 46, 111 |
}; |
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing |
STATE-NUM. */ |
#define YYPACT_NINF -82 |
static const yytype_int8 yypact[] = |
{ |
122, 11, 11, -25, 9, 9, 53, 53, -17, 11, |
14, 9, -18, 20, 95, -82, -82, -82, -82, -82, |
-82, -82, -82, -82, -82, -82, -82, -82, -82, -82, |
-82, -82, -82, -82, -82, -82, -82, -82, 29, 11, |
47, -82, 67, 67, -82, -82, 54, 54, -82, -82, |
-82, -82, 48, -82, 48, -14, -17, -82, 11, -82, |
58, 50, 14, -82, 61, -82, 64, 33, -82, -82, |
-82, 11, 47, -82, 11, 63, -82, -82, 9, -82, |
-82, -82, 53, -82, 48, -82, -82, 11, 60, 76, |
81, -82, 9, -82, 83, 9, -82, -82, 84, -82, |
-82, -82, 9, 79, -26, 85, -82, -82, 88, -82, |
-82, -82, -82, 36, 89, 90, -82, 55, -82, -82, |
-82, -82, -82, -82, -82, -82, -82, -82, 79, 79, |
-82, 92, 13, 92, 92, 36, -82, 59, -82, -82, |
-82, -82, 92, 92, -82, -82 |
}; |
/* YYPGOTO[NTERM-NUM]. */ |
static const yytype_int16 yypgoto[] = |
{ |
-82, -82, 107, -82, 65, -11, -82, -82, 75, -82, |
82, -4, -81, 93, 57, 102, -8, 141, -75, -82, |
-82, 101, -82, -82, -82, -5, -82 |
}; |
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If |
positive, shift that token. If negative, reduce the rule which |
number is the opposite. If zero, do what YYDEFACT says. |
If YYTABLE_NINF, syntax error. */ |
#define YYTABLE_NINF -48 |
static const yytype_int16 yytable[] = |
{ |
47, 60, 114, 54, 44, 115, 64, 48, 49, 50, |
51, 65, 55, 66, 16, 83, 17, 18, 19, 20, |
21, 22, 113, 23, 24, 25, 26, 27, 28, 29, |
30, 73, 31, 32, 33, 34, 35, 36, 37, 45, |
38, 114, 39, 61, 137, 120, 121, 134, 135, 68, |
60, 84, 122, 123, 124, 125, 136, 138, 139, 140, |
71, 126, 127, 96, 94, 95, 97, 144, 145, -47, |
-47, -47, -47, 99, 48, 49, 50, 51, 74, 101, |
81, 89, 75, 90, 132, 45, 78, 106, 142, 45, |
109, 87, 92, 93, 102, 69, 98, 112, 1, 2, |
3, 4, 5, 6, 7, 104, 8, 9, 10, 11, |
105, 81, 133, 107, 110, 12, 117, 118, 130, 131, |
114, 70, 13, 86, 141, 1, 2, 3, 4, 5, |
6, 7, 143, 8, 9, 10, 11, 91, 85, 100, |
80, 72, 12, 43, 77, 0, 0, 0, 0, 13 |
}; |
static const yytype_int16 yycheck[] = |
{ |
5, 9, 28, 7, 29, 31, 11, 21, 22, 23, |
24, 29, 29, 31, 3, 29, 5, 6, 7, 8, |
9, 10, 103, 12, 13, 14, 15, 16, 17, 18, |
19, 39, 21, 22, 23, 24, 25, 26, 27, 30, |
29, 28, 31, 29, 31, 9, 10, 128, 129, 29, |
58, 55, 16, 17, 18, 19, 131, 132, 133, 134, |
31, 25, 26, 71, 31, 32, 74, 142, 143, 21, |
22, 23, 24, 78, 21, 22, 23, 24, 31, 87, |
32, 31, 15, 33, 29, 30, 32, 92, 29, 30, |
95, 33, 31, 29, 34, 0, 33, 102, 3, 4, |
5, 6, 7, 8, 9, 29, 11, 12, 13, 14, |
29, 32, 117, 30, 30, 20, 31, 29, 29, 29, |
28, 14, 27, 58, 135, 3, 4, 5, 6, 7, |
8, 9, 137, 11, 12, 13, 14, 62, 56, 82, |
47, 39, 20, 2, 43, -1, -1, -1, -1, 27 |
}; |
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing |
symbol of state STATE-NUM. */ |
static const yytype_uint8 yystos[] = |
{ |
0, 3, 4, 5, 6, 7, 8, 9, 11, 12, |
13, 14, 20, 27, 36, 37, 3, 5, 6, 7, |
8, 9, 10, 12, 13, 14, 15, 16, 17, 18, |
19, 21, 22, 23, 24, 25, 26, 27, 29, 31, |
50, 51, 52, 52, 29, 30, 60, 60, 21, 22, |
23, 24, 46, 49, 46, 29, 44, 45, 38, 39, |
51, 29, 42, 43, 60, 29, 31, 57, 29, 0, |
37, 31, 50, 51, 31, 15, 56, 56, 32, 48, |
48, 32, 47, 29, 46, 45, 39, 33, 55, 31, |
33, 43, 31, 29, 31, 32, 51, 51, 33, 60, |
49, 51, 34, 54, 29, 29, 60, 30, 58, 60, |
30, 61, 60, 47, 28, 31, 53, 31, 29, 59, |
9, 10, 16, 17, 18, 19, 25, 26, 40, 41, |
29, 29, 29, 60, 47, 47, 53, 31, 53, 53, |
53, 40, 29, 60, 53, 53 |
}; |
#define yyerrok (yyerrstatus = 0) |
#define yyclearin (yychar = YYEMPTY) |
#define YYEMPTY (-2) |
#define YYEOF 0 |
#define YYACCEPT goto yyacceptlab |
#define YYABORT goto yyabortlab |
#define YYERROR goto yyerrorlab |
/* Like YYERROR except do call yyerror. This remains here temporarily |
to ease the transition to the new meaning of YYERROR, for GCC. |
Once GCC version 2 has supplanted version 1, this can go. */ |
#define YYFAIL goto yyerrlab |
#define YYRECOVERING() (!!yyerrstatus) |
#define YYBACKUP(Token, Value) \ |
do \ |
if (yychar == YYEMPTY && yylen == 1) \ |
{ \ |
yychar = (Token); \ |
yylval = (Value); \ |
yytoken = YYTRANSLATE (yychar); \ |
YYPOPSTACK (1); \ |
goto yybackup; \ |
} \ |
else \ |
{ \ |
yyerror (YY_("syntax error: cannot back up")); \ |
YYERROR; \ |
} \ |
while (YYID (0)) |
#define YYTERROR 1 |
#define YYERRCODE 256 |
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. |
If N is 0, then set CURRENT to the empty location which ends |
the previous symbol: RHS[0] (always defined). */ |
#define YYRHSLOC(Rhs, K) ((Rhs)[K]) |
#ifndef YYLLOC_DEFAULT |
# define YYLLOC_DEFAULT(Current, Rhs, N) \ |
do \ |
if (YYID (N)) \ |
{ \ |
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ |
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ |
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \ |
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \ |
} \ |
else \ |
{ \ |
(Current).first_line = (Current).last_line = \ |
YYRHSLOC (Rhs, 0).last_line; \ |
(Current).first_column = (Current).last_column = \ |
YYRHSLOC (Rhs, 0).last_column; \ |
} \ |
while (YYID (0)) |
#endif |
/* YY_LOCATION_PRINT -- Print the location on the stream. |
This macro was not mandated originally: define only if we know |
we won't break user code: when these are the locations we know. */ |
#ifndef YY_LOCATION_PRINT |
# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL |
# define YY_LOCATION_PRINT(File, Loc) \ |
fprintf (File, "%d.%d-%d.%d", \ |
(Loc).first_line, (Loc).first_column, \ |
(Loc).last_line, (Loc).last_column) |
# else |
# define YY_LOCATION_PRINT(File, Loc) ((void) 0) |
# endif |
#endif |
/* YYLEX -- calling `yylex' with the right arguments. */ |
#ifdef YYLEX_PARAM |
# define YYLEX yylex (YYLEX_PARAM) |
#else |
# define YYLEX yylex () |
#endif |
/* Enable debugging if requested. */ |
#if YYDEBUG |
# ifndef YYFPRINTF |
# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ |
# define YYFPRINTF fprintf |
# endif |
# define YYDPRINTF(Args) \ |
do { \ |
if (yydebug) \ |
YYFPRINTF Args; \ |
} while (YYID (0)) |
# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ |
do { \ |
if (yydebug) \ |
{ \ |
YYFPRINTF (stderr, "%s ", Title); \ |
yy_symbol_print (stderr, \ |
Type, Value); \ |
YYFPRINTF (stderr, "\n"); \ |
} \ |
} while (YYID (0)) |
/*--------------------------------. |
| Print this symbol on YYOUTPUT. | |
`--------------------------------*/ |
/*ARGSUSED*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) |
#else |
static void |
yy_symbol_value_print (yyoutput, yytype, yyvaluep) |
FILE *yyoutput; |
int yytype; |
YYSTYPE const * const yyvaluep; |
#endif |
{ |
if (!yyvaluep) |
return; |
# ifdef YYPRINT |
if (yytype < YYNTOKENS) |
YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); |
# else |
YYUSE (yyoutput); |
# endif |
switch (yytype) |
{ |
default: |
break; |
} |
} |
/*--------------------------------. |
| Print this symbol on YYOUTPUT. | |
`--------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) |
#else |
static void |
yy_symbol_print (yyoutput, yytype, yyvaluep) |
FILE *yyoutput; |
int yytype; |
YYSTYPE const * const yyvaluep; |
#endif |
{ |
if (yytype < YYNTOKENS) |
YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); |
else |
YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); |
yy_symbol_value_print (yyoutput, yytype, yyvaluep); |
YYFPRINTF (yyoutput, ")"); |
} |
/*------------------------------------------------------------------. |
| yy_stack_print -- Print the state stack from its BOTTOM up to its | |
| TOP (included). | |
`------------------------------------------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) |
#else |
static void |
yy_stack_print (bottom, top) |
yytype_int16 *bottom; |
yytype_int16 *top; |
#endif |
{ |
YYFPRINTF (stderr, "Stack now"); |
for (; bottom <= top; ++bottom) |
YYFPRINTF (stderr, " %d", *bottom); |
YYFPRINTF (stderr, "\n"); |
} |
# define YY_STACK_PRINT(Bottom, Top) \ |
do { \ |
if (yydebug) \ |
yy_stack_print ((Bottom), (Top)); \ |
} while (YYID (0)) |
/*------------------------------------------------. |
| Report that the YYRULE is going to be reduced. | |
`------------------------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_reduce_print (YYSTYPE *yyvsp, int yyrule) |
#else |
static void |
yy_reduce_print (yyvsp, yyrule) |
YYSTYPE *yyvsp; |
int yyrule; |
#endif |
{ |
int yynrhs = yyr2[yyrule]; |
int yyi; |
unsigned long int yylno = yyrline[yyrule]; |
YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", |
yyrule - 1, yylno); |
/* The symbols being reduced. */ |
for (yyi = 0; yyi < yynrhs; yyi++) |
{ |
fprintf (stderr, " $%d = ", yyi + 1); |
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], |
&(yyvsp[(yyi + 1) - (yynrhs)]) |
); |
fprintf (stderr, "\n"); |
} |
} |
# define YY_REDUCE_PRINT(Rule) \ |
do { \ |
if (yydebug) \ |
yy_reduce_print (yyvsp, Rule); \ |
} while (YYID (0)) |
/* Nonzero means print parse trace. It is left uninitialized so that |
multiple parsers can coexist. */ |
int yydebug; |
#else /* !YYDEBUG */ |
# define YYDPRINTF(Args) |
# define YY_SYMBOL_PRINT(Title, Type, Value, Location) |
# define YY_STACK_PRINT(Bottom, Top) |
# define YY_REDUCE_PRINT(Rule) |
#endif /* !YYDEBUG */ |
/* YYINITDEPTH -- initial size of the parser's stacks. */ |
#ifndef YYINITDEPTH |
# define YYINITDEPTH 200 |
#endif |
/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only |
if the built-in stack extension method is used). |
Do not make this value too large; the results are undefined if |
YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) |
evaluated with infinite-precision integer arithmetic. */ |
#ifndef YYMAXDEPTH |
# define YYMAXDEPTH 10000 |
#endif |
#if YYERROR_VERBOSE |
# ifndef yystrlen |
# if defined __GLIBC__ && defined _STRING_H |
# define yystrlen strlen |
# else |
/* Return the length of YYSTR. */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static YYSIZE_T |
yystrlen (const char *yystr) |
#else |
static YYSIZE_T |
yystrlen (yystr) |
const char *yystr; |
#endif |
{ |
YYSIZE_T yylen; |
for (yylen = 0; yystr[yylen]; yylen++) |
continue; |
return yylen; |
} |
# endif |
# endif |
# ifndef yystpcpy |
# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE |
# define yystpcpy stpcpy |
# else |
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in |
YYDEST. */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static char * |
yystpcpy (char *yydest, const char *yysrc) |
#else |
static char * |
yystpcpy (yydest, yysrc) |
char *yydest; |
const char *yysrc; |
#endif |
{ |
char *yyd = yydest; |
const char *yys = yysrc; |
while ((*yyd++ = *yys++) != '\0') |
continue; |
return yyd - 1; |
} |
# endif |
# endif |
# ifndef yytnamerr |
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary |
quotes and backslashes, so that it's suitable for yyerror. The |
heuristic is that double-quoting is unnecessary unless the string |
contains an apostrophe, a comma, or backslash (other than |
backslash-backslash). YYSTR is taken from yytname. If YYRES is |
null, do not copy; instead, return the length of what the result |
would have been. */ |
static YYSIZE_T |
yytnamerr (char *yyres, const char *yystr) |
{ |
if (*yystr == '"') |
{ |
YYSIZE_T yyn = 0; |
char const *yyp = yystr; |
for (;;) |
switch (*++yyp) |
{ |
case '\'': |
case ',': |
goto do_not_strip_quotes; |
case '\\': |
if (*++yyp != '\\') |
goto do_not_strip_quotes; |
/* Fall through. */ |
default: |
if (yyres) |
yyres[yyn] = *yyp; |
yyn++; |
break; |
case '"': |
if (yyres) |
yyres[yyn] = '\0'; |
return yyn; |
} |
do_not_strip_quotes: ; |
} |
if (! yyres) |
return yystrlen (yystr); |
return yystpcpy (yyres, yystr) - yyres; |
} |
# endif |
/* Copy into YYRESULT an error message about the unexpected token |
YYCHAR while in state YYSTATE. Return the number of bytes copied, |
including the terminating null byte. If YYRESULT is null, do not |
copy anything; just return the number of bytes that would be |
copied. As a special case, return 0 if an ordinary "syntax error" |
message will do. Return YYSIZE_MAXIMUM if overflow occurs during |
size calculation. */ |
static YYSIZE_T |
yysyntax_error (char *yyresult, int yystate, int yychar) |
{ |
int yyn = yypact[yystate]; |
if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) |
return 0; |
else |
{ |
int yytype = YYTRANSLATE (yychar); |
YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); |
YYSIZE_T yysize = yysize0; |
YYSIZE_T yysize1; |
int yysize_overflow = 0; |
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; |
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; |
int yyx; |
# if 0 |
/* This is so xgettext sees the translatable formats that are |
constructed on the fly. */ |
YY_("syntax error, unexpected %s"); |
YY_("syntax error, unexpected %s, expecting %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s or %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); |
# endif |
char *yyfmt; |
char const *yyf; |
static char const yyunexpected[] = "syntax error, unexpected %s"; |
static char const yyexpecting[] = ", expecting %s"; |
static char const yyor[] = " or %s"; |
char yyformat[sizeof yyunexpected |
+ sizeof yyexpecting - 1 |
+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) |
* (sizeof yyor - 1))]; |
char const *yyprefix = yyexpecting; |
/* Start YYX at -YYN if negative to avoid negative indexes in |
YYCHECK. */ |
int yyxbegin = yyn < 0 ? -yyn : 0; |
/* Stay within bounds of both yycheck and yytname. */ |
int yychecklim = YYLAST - yyn + 1; |
int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; |
int yycount = 1; |
yyarg[0] = yytname[yytype]; |
yyfmt = yystpcpy (yyformat, yyunexpected); |
for (yyx = yyxbegin; yyx < yyxend; ++yyx) |
if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) |
{ |
if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) |
{ |
yycount = 1; |
yysize = yysize0; |
yyformat[sizeof yyunexpected - 1] = '\0'; |
break; |
} |
yyarg[yycount++] = yytname[yyx]; |
yysize1 = yysize + yytnamerr (0, yytname[yyx]); |
yysize_overflow |= (yysize1 < yysize); |
yysize = yysize1; |
yyfmt = yystpcpy (yyfmt, yyprefix); |
yyprefix = yyor; |
} |
yyf = YY_(yyformat); |
yysize1 = yysize + yystrlen (yyf); |
yysize_overflow |= (yysize1 < yysize); |
yysize = yysize1; |
if (yysize_overflow) |
return YYSIZE_MAXIMUM; |
if (yyresult) |
{ |
/* Avoid sprintf, as that infringes on the user's name space. |
Don't have undefined behavior even if the translation |
produced a string with the wrong number of "%s"s. */ |
char *yyp = yyresult; |
int yyi = 0; |
while ((*yyp = *yyf) != '\0') |
{ |
if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) |
{ |
yyp += yytnamerr (yyp, yyarg[yyi++]); |
yyf += 2; |
} |
else |
{ |
yyp++; |
yyf++; |
} |
} |
} |
return yysize; |
} |
} |
#endif /* YYERROR_VERBOSE */ |
/*-----------------------------------------------. |
| Release the memory associated to this symbol. | |
`-----------------------------------------------*/ |
/*ARGSUSED*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) |
#else |
static void |
yydestruct (yymsg, yytype, yyvaluep) |
const char *yymsg; |
int yytype; |
YYSTYPE *yyvaluep; |
#endif |
{ |
YYUSE (yyvaluep); |
if (!yymsg) |
yymsg = "Deleting"; |
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); |
switch (yytype) |
{ |
default: |
break; |
} |
} |
/* Prevent warnings from -Wmissing-prototypes. */ |
#ifdef YYPARSE_PARAM |
#if defined __STDC__ || defined __cplusplus |
int yyparse (void *YYPARSE_PARAM); |
#else |
int yyparse (); |
#endif |
#else /* ! YYPARSE_PARAM */ |
#if defined __STDC__ || defined __cplusplus |
int yyparse (void); |
#else |
int yyparse (); |
#endif |
#endif /* ! YYPARSE_PARAM */ |
/* The look-ahead symbol. */ |
int yychar; |
/* The semantic value of the look-ahead symbol. */ |
YYSTYPE yylval; |
/* Number of syntax errors so far. */ |
int yynerrs; |
/*----------. |
| yyparse. | |
`----------*/ |
#ifdef YYPARSE_PARAM |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
int |
yyparse (void *YYPARSE_PARAM) |
#else |
int |
yyparse (YYPARSE_PARAM) |
void *YYPARSE_PARAM; |
#endif |
#else /* ! YYPARSE_PARAM */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
int |
yyparse (void) |
#else |
int |
yyparse () |
#endif |
#endif |
{ |
int yystate; |
int yyn; |
int yyresult; |
/* Number of tokens to shift before error messages enabled. */ |
int yyerrstatus; |
/* Look-ahead token as an internal (translated) token number. */ |
int yytoken = 0; |
#if YYERROR_VERBOSE |
/* Buffer for error messages, and its allocated size. */ |
char yymsgbuf[128]; |
char *yymsg = yymsgbuf; |
YYSIZE_T yymsg_alloc = sizeof yymsgbuf; |
#endif |
/* Three stacks and their tools: |
`yyss': related to states, |
`yyvs': related to semantic values, |
`yyls': related to locations. |
Refer to the stacks thru separate pointers, to allow yyoverflow |
to reallocate them elsewhere. */ |
/* The state stack. */ |
yytype_int16 yyssa[YYINITDEPTH]; |
yytype_int16 *yyss = yyssa; |
yytype_int16 *yyssp; |
/* The semantic value stack. */ |
YYSTYPE yyvsa[YYINITDEPTH]; |
YYSTYPE *yyvs = yyvsa; |
YYSTYPE *yyvsp; |
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) |
YYSIZE_T yystacksize = YYINITDEPTH; |
/* The variables used to return semantic value and location from the |
action routines. */ |
YYSTYPE yyval; |
/* The number of symbols on the RHS of the reduced rule. |
Keep to zero when no symbol should be popped. */ |
int yylen = 0; |
YYDPRINTF ((stderr, "Starting parse\n")); |
yystate = 0; |
yyerrstatus = 0; |
yynerrs = 0; |
yychar = YYEMPTY; /* Cause a token to be read. */ |
/* Initialize stack pointers. |
Waste one element of value and location stack |
so that they stay on the same level as the state stack. |
The wasted elements are never initialized. */ |
yyssp = yyss; |
yyvsp = yyvs; |
goto yysetstate; |
/*------------------------------------------------------------. |
| yynewstate -- Push a new state, which is found in yystate. | |
`------------------------------------------------------------*/ |
yynewstate: |
/* In all cases, when you get here, the value and location stacks |
have just been pushed. So pushing a state here evens the stacks. */ |
yyssp++; |
yysetstate: |
*yyssp = yystate; |
if (yyss + yystacksize - 1 <= yyssp) |
{ |
/* Get the current used size of the three stacks, in elements. */ |
YYSIZE_T yysize = yyssp - yyss + 1; |
#ifdef yyoverflow |
{ |
/* Give user a chance to reallocate the stack. Use copies of |
these so that the &'s don't force the real ones into |
memory. */ |
YYSTYPE *yyvs1 = yyvs; |
yytype_int16 *yyss1 = yyss; |
/* Each stack pointer address is followed by the size of the |
data in use in that stack, in bytes. This used to be a |
conditional around just the two extra args, but that might |
be undefined if yyoverflow is a macro. */ |
yyoverflow (YY_("memory exhausted"), |
&yyss1, yysize * sizeof (*yyssp), |
&yyvs1, yysize * sizeof (*yyvsp), |
&yystacksize); |
yyss = yyss1; |
yyvs = yyvs1; |
} |
#else /* no yyoverflow */ |
# ifndef YYSTACK_RELOCATE |
goto yyexhaustedlab; |
# else |
/* Extend the stack our own way. */ |
if (YYMAXDEPTH <= yystacksize) |
goto yyexhaustedlab; |
yystacksize *= 2; |
if (YYMAXDEPTH < yystacksize) |
yystacksize = YYMAXDEPTH; |
{ |
yytype_int16 *yyss1 = yyss; |
union yyalloc *yyptr = |
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); |
if (! yyptr) |
goto yyexhaustedlab; |
YYSTACK_RELOCATE (yyss); |
YYSTACK_RELOCATE (yyvs); |
# undef YYSTACK_RELOCATE |
if (yyss1 != yyssa) |
YYSTACK_FREE (yyss1); |
} |
# endif |
#endif /* no yyoverflow */ |
yyssp = yyss + yysize - 1; |
yyvsp = yyvs + yysize - 1; |
YYDPRINTF ((stderr, "Stack size increased to %lu\n", |
(unsigned long int) yystacksize)); |
if (yyss + yystacksize - 1 <= yyssp) |
YYABORT; |
} |
YYDPRINTF ((stderr, "Entering state %d\n", yystate)); |
goto yybackup; |
/*-----------. |
| yybackup. | |
`-----------*/ |
yybackup: |
/* Do appropriate processing given the current state. Read a |
look-ahead token if we need one and don't already have one. */ |
/* First try to decide what to do without reference to look-ahead token. */ |
yyn = yypact[yystate]; |
if (yyn == YYPACT_NINF) |
goto yydefault; |
/* Not known => get a look-ahead token if don't already have one. */ |
/* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ |
if (yychar == YYEMPTY) |
{ |
YYDPRINTF ((stderr, "Reading a token: ")); |
yychar = YYLEX; |
} |
if (yychar <= YYEOF) |
{ |
yychar = yytoken = YYEOF; |
YYDPRINTF ((stderr, "Now at end of input.\n")); |
} |
else |
{ |
yytoken = YYTRANSLATE (yychar); |
YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); |
} |
/* If the proper action on seeing token YYTOKEN is to reduce or to |
detect an error, take that action. */ |
yyn += yytoken; |
if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) |
goto yydefault; |
yyn = yytable[yyn]; |
if (yyn <= 0) |
{ |
if (yyn == 0 || yyn == YYTABLE_NINF) |
goto yyerrlab; |
yyn = -yyn; |
goto yyreduce; |
} |
if (yyn == YYFINAL) |
YYACCEPT; |
/* Count tokens shifted since error; after three, turn off error |
status. */ |
if (yyerrstatus) |
yyerrstatus--; |
/* Shift the look-ahead token. */ |
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); |
/* Discard the shifted token unless it is eof. */ |
if (yychar != YYEOF) |
yychar = YYEMPTY; |
yystate = yyn; |
*++yyvsp = yylval; |
goto yynewstate; |
/*-----------------------------------------------------------. |
| yydefault -- do the default action for the current state. | |
`-----------------------------------------------------------*/ |
yydefault: |
yyn = yydefact[yystate]; |
if (yyn == 0) |
goto yyerrlab; |
goto yyreduce; |
/*-----------------------------. |
| yyreduce -- Do a reduction. | |
`-----------------------------*/ |
yyreduce: |
/* yyn is the number of a rule to reduce with. */ |
yylen = yyr2[yyn]; |
/* If YYLEN is nonzero, implement the default value of the action: |
`$$ = $1'. |
Otherwise, the following line sets YYVAL to garbage. |
This behavior is undocumented and Bison |
users should not rely upon it. Assigning to YYVAL |
unconditionally makes the parser a bit smaller, and it avoids a |
GCC warning that YYVAL may be used uninitialized. */ |
yyval = yyvsp[1-yylen]; |
YY_REDUCE_PRINT (yyn); |
switch (yyn) |
{ |
case 4: |
#line 144 "deffilep.y" |
{ def_image_name ((yyvsp[(2) - (3)].id), (yyvsp[(3) - (3)].vma), 0); } |
break; |
case 5: |
#line 145 "deffilep.y" |
{ def_image_name ((yyvsp[(2) - (3)].id), (yyvsp[(3) - (3)].vma), 1); } |
break; |
case 6: |
#line 146 "deffilep.y" |
{ def_description ((yyvsp[(2) - (2)].id));} |
break; |
case 7: |
#line 147 "deffilep.y" |
{ def_stacksize ((yyvsp[(2) - (3)].number), (yyvsp[(3) - (3)].number));} |
break; |
case 8: |
#line 148 "deffilep.y" |
{ def_heapsize ((yyvsp[(2) - (3)].number), (yyvsp[(3) - (3)].number));} |
break; |
case 9: |
#line 149 "deffilep.y" |
{ def_section ("CODE", (yyvsp[(2) - (2)].number));} |
break; |
case 10: |
#line 150 "deffilep.y" |
{ def_section ("DATA", (yyvsp[(2) - (2)].number));} |
break; |
case 14: |
#line 154 "deffilep.y" |
{ def_version ((yyvsp[(2) - (2)].number), 0);} |
break; |
case 15: |
#line 155 "deffilep.y" |
{ def_version ((yyvsp[(2) - (4)].number), (yyvsp[(4) - (4)].number));} |
break; |
case 16: |
#line 156 "deffilep.y" |
{ def_directive ((yyvsp[(2) - (2)].id));} |
break; |
case 17: |
#line 157 "deffilep.y" |
{ def_aligncomm ((yyvsp[(2) - (4)].id), (yyvsp[(4) - (4)].number));} |
break; |
case 21: |
#line 172 "deffilep.y" |
{ def_exports ((yyvsp[(1) - (7)].id), (yyvsp[(2) - (7)].id), (yyvsp[(3) - (7)].number), (yyvsp[(5) - (7)].number), (yyvsp[(7) - (7)].id)); } |
break; |
case 22: |
#line 178 "deffilep.y" |
{ (yyval.number) = (yyvsp[(1) - (3)].number) | (yyvsp[(3) - (3)].number); } |
break; |
case 23: |
#line 179 "deffilep.y" |
{ (yyval.number) = 0; } |
break; |
case 24: |
#line 182 "deffilep.y" |
{ (yyval.number) = 1; } |
break; |
case 25: |
#line 183 "deffilep.y" |
{ (yyval.number) = 1; } |
break; |
case 26: |
#line 184 "deffilep.y" |
{ (yyval.number) = 2; } |
break; |
case 27: |
#line 185 "deffilep.y" |
{ (yyval.number) = 2; } |
break; |
case 28: |
#line 186 "deffilep.y" |
{ (yyval.number) = 4; } |
break; |
case 29: |
#line 187 "deffilep.y" |
{ (yyval.number) = 4; } |
break; |
case 30: |
#line 188 "deffilep.y" |
{ (yyval.number) = 8; } |
break; |
case 31: |
#line 189 "deffilep.y" |
{ (yyval.number) = 8; } |
break; |
case 34: |
#line 198 "deffilep.y" |
{ def_import ((yyvsp[(1) - (8)].id), (yyvsp[(3) - (8)].id), (yyvsp[(5) - (8)].id), (yyvsp[(7) - (8)].id), -1, (yyvsp[(8) - (8)].id)); } |
break; |
case 35: |
#line 200 "deffilep.y" |
{ def_import ((yyvsp[(1) - (8)].id), (yyvsp[(3) - (8)].id), (yyvsp[(5) - (8)].id), 0, (yyvsp[(7) - (8)].number), (yyvsp[(8) - (8)].id)); } |
break; |
case 36: |
#line 202 "deffilep.y" |
{ def_import ((yyvsp[(1) - (6)].id), (yyvsp[(3) - (6)].id), 0, (yyvsp[(5) - (6)].id), -1, (yyvsp[(6) - (6)].id)); } |
break; |
case 37: |
#line 204 "deffilep.y" |
{ def_import ((yyvsp[(1) - (6)].id), (yyvsp[(3) - (6)].id), 0, 0, (yyvsp[(5) - (6)].number), (yyvsp[(6) - (6)].id)); } |
break; |
case 38: |
#line 206 "deffilep.y" |
{ def_import( 0, (yyvsp[(1) - (6)].id), (yyvsp[(3) - (6)].id), (yyvsp[(5) - (6)].id), -1, (yyvsp[(6) - (6)].id)); } |
break; |
case 39: |
#line 208 "deffilep.y" |
{ def_import ( 0, (yyvsp[(1) - (4)].id), 0, (yyvsp[(3) - (4)].id), -1, (yyvsp[(4) - (4)].id)); } |
break; |
case 42: |
#line 217 "deffilep.y" |
{ def_section ((yyvsp[(1) - (2)].id), (yyvsp[(2) - (2)].number));} |
break; |
case 43: |
#line 218 "deffilep.y" |
{ def_section_alt ((yyvsp[(1) - (2)].id), (yyvsp[(2) - (2)].id));} |
break; |
case 44: |
#line 222 "deffilep.y" |
{ (yyval.number) = (yyvsp[(1) - (3)].number) | (yyvsp[(3) - (3)].number); } |
break; |
case 45: |
#line 223 "deffilep.y" |
{ (yyval.number) = (yyvsp[(1) - (1)].number); } |
break; |
case 48: |
#line 230 "deffilep.y" |
{ (yyval.number)=(yyvsp[(2) - (2)].number);} |
break; |
case 49: |
#line 231 "deffilep.y" |
{ (yyval.number)=-1;} |
break; |
case 50: |
#line 235 "deffilep.y" |
{ (yyval.number) = 1;} |
break; |
case 51: |
#line 236 "deffilep.y" |
{ (yyval.number) = 2;} |
break; |
case 52: |
#line 237 "deffilep.y" |
{ (yyval.number)=4;} |
break; |
case 53: |
#line 238 "deffilep.y" |
{ (yyval.number)=8;} |
break; |
case 54: |
#line 242 "deffilep.y" |
{ (yyval.id_const) = "BASE"; } |
break; |
case 55: |
#line 243 "deffilep.y" |
{ (yyval.id_const) = "CODE"; } |
break; |
case 56: |
#line 244 "deffilep.y" |
{ (yyval.id_const) = "CONSTANT"; } |
break; |
case 57: |
#line 245 "deffilep.y" |
{ (yyval.id_const) = "constant"; } |
break; |
case 58: |
#line 246 "deffilep.y" |
{ (yyval.id_const) = "DATA"; } |
break; |
case 59: |
#line 247 "deffilep.y" |
{ (yyval.id_const) = "data"; } |
break; |
case 60: |
#line 248 "deffilep.y" |
{ (yyval.id_const) = "DESCRIPTION"; } |
break; |
case 61: |
#line 249 "deffilep.y" |
{ (yyval.id_const) = "DIRECTIVE"; } |
break; |
case 62: |
#line 250 "deffilep.y" |
{ (yyval.id_const) = "EXECUTE"; } |
break; |
case 63: |
#line 251 "deffilep.y" |
{ (yyval.id_const) = "EXPORTS"; } |
break; |
case 64: |
#line 252 "deffilep.y" |
{ (yyval.id_const) = "HEAPSIZE"; } |
break; |
case 65: |
#line 253 "deffilep.y" |
{ (yyval.id_const) = "IMPORTS"; } |
break; |
case 66: |
#line 260 "deffilep.y" |
{ (yyval.id_const) = "NAME"; } |
break; |
case 67: |
#line 261 "deffilep.y" |
{ (yyval.id_const) = "NONAME"; } |
break; |
case 68: |
#line 262 "deffilep.y" |
{ (yyval.id_const) = "noname"; } |
break; |
case 69: |
#line 263 "deffilep.y" |
{ (yyval.id_const) = "PRIVATE"; } |
break; |
case 70: |
#line 264 "deffilep.y" |
{ (yyval.id_const) = "private"; } |
break; |
case 71: |
#line 265 "deffilep.y" |
{ (yyval.id_const) = "READ"; } |
break; |
case 72: |
#line 266 "deffilep.y" |
{ (yyval.id_const) = "SHARED"; } |
break; |
case 73: |
#line 267 "deffilep.y" |
{ (yyval.id_const) = "STACKSIZE"; } |
break; |
case 74: |
#line 268 "deffilep.y" |
{ (yyval.id_const) = "VERSION"; } |
break; |
case 75: |
#line 269 "deffilep.y" |
{ (yyval.id_const) = "WRITE"; } |
break; |
case 76: |
#line 272 "deffilep.y" |
{ (yyval.id) = (yyvsp[(1) - (1)].id); } |
break; |
case 77: |
#line 274 "deffilep.y" |
{ |
char *name = xmalloc (strlen ((yyvsp[(2) - (2)].id_const)) + 2); |
sprintf (name, ".%s", (yyvsp[(2) - (2)].id_const)); |
(yyval.id) = name; |
} |
break; |
case 78: |
#line 280 "deffilep.y" |
{ |
char *name = def_pool_alloc (strlen ((yyvsp[(2) - (2)].id)) + 2); |
sprintf (name, ".%s", (yyvsp[(2) - (2)].id)); |
(yyval.id) = name; |
} |
break; |
case 79: |
#line 286 "deffilep.y" |
{ |
char *name = def_pool_alloc (strlen ((yyvsp[(1) - (3)].id_const)) + 1 + strlen ((yyvsp[(3) - (3)].id)) + 1); |
sprintf (name, "%s.%s", (yyvsp[(1) - (3)].id_const), (yyvsp[(3) - (3)].id)); |
(yyval.id) = name; |
} |
break; |
case 80: |
#line 292 "deffilep.y" |
{ |
char *name = def_pool_alloc (strlen ((yyvsp[(1) - (3)].id)) + 1 + strlen ((yyvsp[(3) - (3)].id)) + 1); |
sprintf (name, "%s.%s", (yyvsp[(1) - (3)].id), (yyvsp[(3) - (3)].id)); |
(yyval.id) = name; |
} |
break; |
case 81: |
#line 299 "deffilep.y" |
{ (yyval.id) = (yyvsp[(1) - (1)].id); } |
break; |
case 82: |
#line 300 "deffilep.y" |
{ (yyval.id) = ""; } |
break; |
case 83: |
#line 303 "deffilep.y" |
{ (yyval.id) = (yyvsp[(2) - (2)].id); } |
break; |
case 84: |
#line 304 "deffilep.y" |
{ (yyval.id) = 0; } |
break; |
case 85: |
#line 308 "deffilep.y" |
{ (yyval.number) = (yyvsp[(2) - (2)].number);} |
break; |
case 86: |
#line 309 "deffilep.y" |
{ (yyval.number) = -1;} |
break; |
case 87: |
#line 313 "deffilep.y" |
{ (yyval.id) = (yyvsp[(2) - (2)].id); } |
break; |
case 88: |
#line 314 "deffilep.y" |
{ (yyval.id) = 0; } |
break; |
case 89: |
#line 317 "deffilep.y" |
{ (yyval.vma) = (yyvsp[(3) - (3)].vma);} |
break; |
case 90: |
#line 318 "deffilep.y" |
{ (yyval.vma) = (bfd_vma) -1;} |
break; |
case 91: |
#line 321 "deffilep.y" |
{ (yyval.id) = (yyvsp[(1) - (1)].id); } |
break; |
case 92: |
#line 323 "deffilep.y" |
{ |
char *id = def_pool_alloc (strlen ((yyvsp[(2) - (2)].id)) + 2); |
sprintf (id, ".%s", (yyvsp[(2) - (2)].id)); |
(yyval.id) = id; |
} |
break; |
case 93: |
#line 329 "deffilep.y" |
{ |
char *id = def_pool_alloc (strlen ((yyvsp[(1) - (4)].id)) + 1 + strlen ((yyvsp[(3) - (4)].digits)) + strlen ((yyvsp[(4) - (4)].id)) + 1); |
sprintf (id, "%s.%s%s", (yyvsp[(1) - (4)].id), (yyvsp[(3) - (4)].digits), (yyvsp[(4) - (4)].id)); |
(yyval.id) = id; |
} |
break; |
case 94: |
#line 336 "deffilep.y" |
{ (yyval.digits) = (yyvsp[(1) - (1)].digits); } |
break; |
case 95: |
#line 337 "deffilep.y" |
{ (yyval.digits) = ""; } |
break; |
case 96: |
#line 340 "deffilep.y" |
{ (yyval.id) = (yyvsp[(1) - (1)].id); } |
break; |
case 97: |
#line 341 "deffilep.y" |
{ (yyval.id) = ""; } |
break; |
case 98: |
#line 344 "deffilep.y" |
{ (yyval.number) = strtoul ((yyvsp[(1) - (1)].digits), 0, 0); } |
break; |
case 99: |
#line 346 "deffilep.y" |
{ (yyval.vma) = (bfd_vma) strtoull ((yyvsp[(1) - (1)].digits), 0, 0); } |
break; |
/* Line 1267 of yacc.c. */ |
#line 2065 "deffilep.c" |
default: break; |
} |
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); |
YYPOPSTACK (yylen); |
yylen = 0; |
YY_STACK_PRINT (yyss, yyssp); |
*++yyvsp = yyval; |
/* Now `shift' the result of the reduction. Determine what state |
that goes to, based on the state we popped back to and the rule |
number reduced by. */ |
yyn = yyr1[yyn]; |
yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; |
if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) |
yystate = yytable[yystate]; |
else |
yystate = yydefgoto[yyn - YYNTOKENS]; |
goto yynewstate; |
/*------------------------------------. |
| yyerrlab -- here on detecting error | |
`------------------------------------*/ |
yyerrlab: |
/* If not already recovering from an error, report this error. */ |
if (!yyerrstatus) |
{ |
++yynerrs; |
#if ! YYERROR_VERBOSE |
yyerror (YY_("syntax error")); |
#else |
{ |
YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); |
if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) |
{ |
YYSIZE_T yyalloc = 2 * yysize; |
if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) |
yyalloc = YYSTACK_ALLOC_MAXIMUM; |
if (yymsg != yymsgbuf) |
YYSTACK_FREE (yymsg); |
yymsg = (char *) YYSTACK_ALLOC (yyalloc); |
if (yymsg) |
yymsg_alloc = yyalloc; |
else |
{ |
yymsg = yymsgbuf; |
yymsg_alloc = sizeof yymsgbuf; |
} |
} |
if (0 < yysize && yysize <= yymsg_alloc) |
{ |
(void) yysyntax_error (yymsg, yystate, yychar); |
yyerror (yymsg); |
} |
else |
{ |
yyerror (YY_("syntax error")); |
if (yysize != 0) |
goto yyexhaustedlab; |
} |
} |
#endif |
} |
if (yyerrstatus == 3) |
{ |
/* If just tried and failed to reuse look-ahead token after an |
error, discard it. */ |
if (yychar <= YYEOF) |
{ |
/* Return failure if at end of input. */ |
if (yychar == YYEOF) |
YYABORT; |
} |
else |
{ |
yydestruct ("Error: discarding", |
yytoken, &yylval); |
yychar = YYEMPTY; |
} |
} |
/* Else will try to reuse look-ahead token after shifting the error |
token. */ |
goto yyerrlab1; |
/*---------------------------------------------------. |
| yyerrorlab -- error raised explicitly by YYERROR. | |
`---------------------------------------------------*/ |
yyerrorlab: |
/* Pacify compilers like GCC when the user code never invokes |
YYERROR and the label yyerrorlab therefore never appears in user |
code. */ |
if (/*CONSTCOND*/ 0) |
goto yyerrorlab; |
/* Do not reclaim the symbols of the rule which action triggered |
this YYERROR. */ |
YYPOPSTACK (yylen); |
yylen = 0; |
YY_STACK_PRINT (yyss, yyssp); |
yystate = *yyssp; |
goto yyerrlab1; |
/*-------------------------------------------------------------. |
| yyerrlab1 -- common code for both syntax error and YYERROR. | |
`-------------------------------------------------------------*/ |
yyerrlab1: |
yyerrstatus = 3; /* Each real token shifted decrements this. */ |
for (;;) |
{ |
yyn = yypact[yystate]; |
if (yyn != YYPACT_NINF) |
{ |
yyn += YYTERROR; |
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) |
{ |
yyn = yytable[yyn]; |
if (0 < yyn) |
break; |
} |
} |
/* Pop the current state because it cannot handle the error token. */ |
if (yyssp == yyss) |
YYABORT; |
yydestruct ("Error: popping", |
yystos[yystate], yyvsp); |
YYPOPSTACK (1); |
yystate = *yyssp; |
YY_STACK_PRINT (yyss, yyssp); |
} |
if (yyn == YYFINAL) |
YYACCEPT; |
*++yyvsp = yylval; |
/* Shift the error token. */ |
YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); |
yystate = yyn; |
goto yynewstate; |
/*-------------------------------------. |
| yyacceptlab -- YYACCEPT comes here. | |
`-------------------------------------*/ |
yyacceptlab: |
yyresult = 0; |
goto yyreturn; |
/*-----------------------------------. |
| yyabortlab -- YYABORT comes here. | |
`-----------------------------------*/ |
yyabortlab: |
yyresult = 1; |
goto yyreturn; |
#ifndef yyoverflow |
/*-------------------------------------------------. |
| yyexhaustedlab -- memory exhaustion comes here. | |
`-------------------------------------------------*/ |
yyexhaustedlab: |
yyerror (YY_("memory exhausted")); |
yyresult = 2; |
/* Fall through. */ |
#endif |
yyreturn: |
if (yychar != YYEOF && yychar != YYEMPTY) |
yydestruct ("Cleanup: discarding lookahead", |
yytoken, &yylval); |
/* Do not reclaim the symbols of the rule which action triggered |
this YYABORT or YYACCEPT. */ |
YYPOPSTACK (yylen); |
YY_STACK_PRINT (yyss, yyssp); |
while (yyssp != yyss) |
{ |
yydestruct ("Cleanup: popping", |
yystos[*yyssp], yyvsp); |
YYPOPSTACK (1); |
} |
#ifndef yyoverflow |
if (yyss != yyssa) |
YYSTACK_FREE (yyss); |
#endif |
#if YYERROR_VERBOSE |
if (yymsg != yymsgbuf) |
YYSTACK_FREE (yymsg); |
#endif |
/* Make sure YYID is used. */ |
return YYID (yyresult); |
} |
#line 348 "deffilep.y" |
/***************************************************************************** |
API |
*****************************************************************************/ |
static FILE *the_file; |
static const char *def_filename; |
static int linenumber; |
static def_file *def; |
static int saw_newline; |
struct directive |
{ |
struct directive *next; |
char *name; |
int len; |
}; |
static struct directive *directives = 0; |
def_file * |
def_file_empty (void) |
{ |
def_file *rv = xmalloc (sizeof (def_file)); |
memset (rv, 0, sizeof (def_file)); |
rv->is_dll = -1; |
rv->base_address = (bfd_vma) -1; |
rv->stack_reserve = rv->stack_commit = -1; |
rv->heap_reserve = rv->heap_commit = -1; |
rv->version_major = rv->version_minor = -1; |
return rv; |
} |
def_file * |
def_file_parse (const char *filename, def_file *add_to) |
{ |
struct directive *d; |
the_file = fopen (filename, "r"); |
def_filename = filename; |
linenumber = 1; |
if (!the_file) |
{ |
//perror (filename); |
printf("Error %s\n", filename); |
return 0; |
} |
if (add_to) |
{ |
def = add_to; |
} |
else |
{ |
def = def_file_empty (); |
} |
saw_newline = 1; |
if (def_parse ()) |
{ |
def_file_free (def); |
fclose (the_file); |
def_pool_free (); |
return 0; |
} |
fclose (the_file); |
while ((d = directives) != NULL) |
{ |
#if TRACE |
printf ("Adding directive %08x `%s'\n", d->name, d->name); |
#endif |
def_file_add_directive (def, d->name, d->len); |
directives = d->next; |
free (d->name); |
free (d); |
} |
def_pool_free (); |
return def; |
} |
void |
def_file_free (def_file *fdef) |
{ |
int i; |
if (!fdef) |
return; |
if (fdef->name) |
free (fdef->name); |
if (fdef->description) |
free (fdef->description); |
if (fdef->section_defs) |
{ |
for (i = 0; i < fdef->num_section_defs; i++) |
{ |
if (fdef->section_defs[i].name) |
free (fdef->section_defs[i].name); |
if (fdef->section_defs[i].class) |
free (fdef->section_defs[i].class); |
} |
free (fdef->section_defs); |
} |
if (fdef->exports) |
{ |
for (i = 0; i < fdef->num_exports; i++) |
{ |
if (fdef->exports[i].internal_name |
&& fdef->exports[i].internal_name != fdef->exports[i].name) |
free (fdef->exports[i].internal_name); |
if (fdef->exports[i].name) |
free (fdef->exports[i].name); |
if (fdef->exports[i].its_name) |
free (fdef->exports[i].its_name); |
} |
free (fdef->exports); |
} |
if (fdef->imports) |
{ |
for (i = 0; i < fdef->num_imports; i++) |
{ |
if (fdef->imports[i].internal_name |
&& fdef->imports[i].internal_name != fdef->imports[i].name) |
free (fdef->imports[i].internal_name); |
if (fdef->imports[i].name) |
free (fdef->imports[i].name); |
if (fdef->imports[i].its_name) |
free (fdef->imports[i].its_name); |
} |
free (fdef->imports); |
} |
while (fdef->modules) |
{ |
def_file_module *m = fdef->modules; |
fdef->modules = fdef->modules->next; |
free (m); |
} |
while (fdef->aligncomms) |
{ |
def_file_aligncomm *c = fdef->aligncomms; |
fdef->aligncomms = fdef->aligncomms->next; |
free (c->symbol_name); |
free (c); |
} |
free (fdef); |
} |
#ifdef DEF_FILE_PRINT |
void |
def_file_print (FILE *file, def_file *fdef) |
{ |
int i; |
fprintf (file, ">>>> def_file at 0x%08x\n", fdef); |
if (fdef->name) |
fprintf (file, " name: %s\n", fdef->name ? fdef->name : "(unspecified)"); |
if (fdef->is_dll != -1) |
fprintf (file, " is dll: %s\n", fdef->is_dll ? "yes" : "no"); |
if (fdef->base_address != (bfd_vma) -1) |
{ |
fprintf (file, " base address: 0x"); |
fprintf_vma (file, fdef->base_address); |
fprintf (file, "\n"); |
} |
if (fdef->description) |
fprintf (file, " description: `%s'\n", fdef->description); |
if (fdef->stack_reserve != -1) |
fprintf (file, " stack reserve: 0x%08x\n", fdef->stack_reserve); |
if (fdef->stack_commit != -1) |
fprintf (file, " stack commit: 0x%08x\n", fdef->stack_commit); |
if (fdef->heap_reserve != -1) |
fprintf (file, " heap reserve: 0x%08x\n", fdef->heap_reserve); |
if (fdef->heap_commit != -1) |
fprintf (file, " heap commit: 0x%08x\n", fdef->heap_commit); |
if (fdef->num_section_defs > 0) |
{ |
fprintf (file, " section defs:\n"); |
for (i = 0; i < fdef->num_section_defs; i++) |
{ |
fprintf (file, " name: `%s', class: `%s', flags:", |
fdef->section_defs[i].name, fdef->section_defs[i].class); |
if (fdef->section_defs[i].flag_read) |
fprintf (file, " R"); |
if (fdef->section_defs[i].flag_write) |
fprintf (file, " W"); |
if (fdef->section_defs[i].flag_execute) |
fprintf (file, " X"); |
if (fdef->section_defs[i].flag_shared) |
fprintf (file, " S"); |
fprintf (file, "\n"); |
} |
} |
if (fdef->num_exports > 0) |
{ |
fprintf (file, " exports:\n"); |
for (i = 0; i < fdef->num_exports; i++) |
{ |
fprintf (file, " name: `%s', int: `%s', ordinal: %d, flags:", |
fdef->exports[i].name, fdef->exports[i].internal_name, |
fdef->exports[i].ordinal); |
if (fdef->exports[i].flag_private) |
fprintf (file, " P"); |
if (fdef->exports[i].flag_constant) |
fprintf (file, " C"); |
if (fdef->exports[i].flag_noname) |
fprintf (file, " N"); |
if (fdef->exports[i].flag_data) |
fprintf (file, " D"); |
fprintf (file, "\n"); |
} |
} |
if (fdef->num_imports > 0) |
{ |
fprintf (file, " imports:\n"); |
for (i = 0; i < fdef->num_imports; i++) |
{ |
fprintf (file, " int: %s, from: `%s', name: `%s', ordinal: %d\n", |
fdef->imports[i].internal_name, |
fdef->imports[i].module, |
fdef->imports[i].name, |
fdef->imports[i].ordinal); |
} |
} |
if (fdef->version_major != -1) |
fprintf (file, " version: %d.%d\n", fdef->version_major, fdef->version_minor); |
fprintf (file, "<<<< def_file at 0x%08x\n", fdef); |
} |
#endif |
/* Helper routine to check for identity of string pointers, |
which might be NULL. */ |
static int |
are_names_equal (const char *s1, const char *s2) |
{ |
if (!s1 && !s2) |
return 0; |
if (!s1 || !s2) |
return (!s1 ? -1 : 1); |
return strcmp (s1, s2); |
} |
static int |
cmp_export_elem (const def_file_export *e, const char *ex_name, |
const char *in_name, const char *its_name, |
int ord) |
{ |
int r; |
if ((r = are_names_equal (ex_name, e->name)) != 0) |
return r; |
if ((r = are_names_equal (in_name, e->internal_name)) != 0) |
return r; |
if ((r = are_names_equal (its_name, e->its_name)) != 0) |
return r; |
return (ord - e->ordinal); |
} |
/* Search the position of the identical element, or returns the position |
of the next higher element. If last valid element is smaller, then MAX |
is returned. */ |
static int |
find_export_in_list (def_file_export *b, int max, |
const char *ex_name, const char *in_name, |
const char *its_name, int ord, int *is_ident) |
{ |
int e, l, r, p; |
*is_ident = 0; |
if (!max) |
return 0; |
if ((e = cmp_export_elem (b, ex_name, in_name, its_name, ord)) <= 0) |
{ |
if (!e) |
*is_ident = 1; |
return 0; |
} |
if (max == 1) |
return 1; |
if ((e = cmp_export_elem (b + (max - 1), ex_name, in_name, its_name, ord)) > 0) |
return max; |
else if (!e || max == 2) |
{ |
if (!e) |
*is_ident = 1; |
return max - 1; |
} |
l = 0; r = max - 1; |
while (l < r) |
{ |
p = (l + r) / 2; |
e = cmp_export_elem (b + p, ex_name, in_name, its_name, ord); |
if (!e) |
{ |
*is_ident = 1; |
return p; |
} |
else if (e < 0) |
r = p - 1; |
else if (e > 0) |
l = p + 1; |
} |
if ((e = cmp_export_elem (b + l, ex_name, in_name, its_name, ord)) > 0) |
++l; |
else if (!e) |
*is_ident = 1; |
return l; |
} |
def_file_export * |
def_file_add_export (def_file *fdef, |
const char *external_name, |
const char *internal_name, |
int ordinal, |
const char *its_name, |
int *is_dup) |
{ |
def_file_export *e; |
int pos; |
int max_exports = ROUND_UP(fdef->num_exports, 32); |
if (internal_name && !external_name) |
external_name = internal_name; |
if (external_name && !internal_name) |
internal_name = external_name; |
/* We need to avoid duplicates. */ |
*is_dup = 0; |
pos = find_export_in_list (fdef->exports, fdef->num_exports, |
external_name, internal_name, |
its_name, ordinal, is_dup); |
if (*is_dup != 0) |
return (fdef->exports + pos); |
if (fdef->num_exports >= max_exports) |
{ |
max_exports = ROUND_UP(fdef->num_exports + 1, 32); |
if (fdef->exports) |
fdef->exports = xrealloc (fdef->exports, |
max_exports * sizeof (def_file_export)); |
else |
fdef->exports = xmalloc (max_exports * sizeof (def_file_export)); |
} |
e = fdef->exports + pos; |
if (pos != fdef->num_exports) |
memmove (&e[1], e, (sizeof (def_file_export) * (fdef->num_exports - pos))); |
memset (e, 0, sizeof (def_file_export)); |
e->name = xstrdup (external_name); |
e->internal_name = xstrdup (internal_name); |
e->its_name = (its_name ? xstrdup (its_name) : NULL); |
e->ordinal = ordinal; |
fdef->num_exports++; |
return e; |
} |
def_file_module * |
def_get_module (def_file *fdef, const char *name) |
{ |
def_file_module *s; |
for (s = fdef->modules; s; s = s->next) |
if (strcmp (s->name, name) == 0) |
return s; |
return NULL; |
} |
static def_file_module * |
def_stash_module (def_file *fdef, const char *name) |
{ |
def_file_module *s; |
if ((s = def_get_module (fdef, name)) != NULL) |
return s; |
s = xmalloc (sizeof (def_file_module) + strlen (name)); |
s->next = fdef->modules; |
fdef->modules = s; |
s->user_data = 0; |
strcpy (s->name, name); |
return s; |
} |
static int |
cmp_import_elem (const def_file_import *e, const char *ex_name, |
const char *in_name, const char *module, |
int ord) |
{ |
int r; |
if ((r = are_names_equal (module, (e->module ? e->module->name : NULL)))) |
return r; |
if ((r = are_names_equal (ex_name, e->name)) != 0) |
return r; |
if ((r = are_names_equal (in_name, e->internal_name)) != 0) |
return r; |
if (ord != e->ordinal) |
return (ord < e->ordinal ? -1 : 1); |
return 0; |
} |
/* Search the position of the identical element, or returns the position |
of the next higher element. If last valid element is smaller, then MAX |
is returned. */ |
static int |
find_import_in_list (def_file_import *b, int max, |
const char *ex_name, const char *in_name, |
const char *module, int ord, int *is_ident) |
{ |
int e, l, r, p; |
*is_ident = 0; |
if (!max) |
return 0; |
if ((e = cmp_import_elem (b, ex_name, in_name, module, ord)) <= 0) |
{ |
if (!e) |
*is_ident = 1; |
return 0; |
} |
if (max == 1) |
return 1; |
if ((e = cmp_import_elem (b + (max - 1), ex_name, in_name, module, ord)) > 0) |
return max; |
else if (!e || max == 2) |
{ |
if (!e) |
*is_ident = 1; |
return max - 1; |
} |
l = 0; r = max - 1; |
while (l < r) |
{ |
p = (l + r) / 2; |
e = cmp_import_elem (b + p, ex_name, in_name, module, ord); |
if (!e) |
{ |
*is_ident = 1; |
return p; |
} |
else if (e < 0) |
r = p - 1; |
else if (e > 0) |
l = p + 1; |
} |
if ((e = cmp_import_elem (b + l, ex_name, in_name, module, ord)) > 0) |
++l; |
else if (!e) |
*is_ident = 1; |
return l; |
} |
def_file_import * |
def_file_add_import (def_file *fdef, |
const char *name, |
const char *module, |
int ordinal, |
const char *internal_name, |
const char *its_name, |
int *is_dup) |
{ |
def_file_import *i; |
int pos; |
int max_imports = ROUND_UP (fdef->num_imports, 16); |
/* We need to avoid here duplicates. */ |
*is_dup = 0; |
pos = find_import_in_list (fdef->imports, fdef->num_imports, |
name, |
(!internal_name ? name : internal_name), |
module, ordinal, is_dup); |
if (*is_dup != 0) |
return fdef->imports + pos; |
if (fdef->num_imports >= max_imports) |
{ |
max_imports = ROUND_UP (fdef->num_imports+1, 16); |
if (fdef->imports) |
fdef->imports = xrealloc (fdef->imports, |
max_imports * sizeof (def_file_import)); |
else |
fdef->imports = xmalloc (max_imports * sizeof (def_file_import)); |
} |
i = fdef->imports + pos; |
if (pos != fdef->num_imports) |
memmove (&i[1], i, (sizeof (def_file_import) * (fdef->num_imports - pos))); |
memset (i, 0, sizeof (def_file_import)); |
if (name) |
i->name = xstrdup (name); |
if (module) |
i->module = def_stash_module (fdef, module); |
i->ordinal = ordinal; |
if (internal_name) |
i->internal_name = xstrdup (internal_name); |
else |
i->internal_name = i->name; |
i->its_name = (its_name ? xstrdup (its_name) : NULL); |
fdef->num_imports++; |
return i; |
} |
struct |
{ |
char *param; |
int token; |
} |
diropts[] = |
{ |
{ "-heap", HEAPSIZE }, |
{ "-stack", STACKSIZE_K }, |
{ "-attr", SECTIONS }, |
{ "-export", EXPORTS }, |
{ "-aligncomm", ALIGNCOMM }, |
{ 0, 0 } |
}; |
void |
def_file_add_directive (def_file *my_def, const char *param, int len) |
{ |
def_file *save_def = def; |
const char *pend = param + len; |
char * tend = (char *) param; |
int i; |
def = my_def; |
while (param < pend) |
{ |
while (param < pend |
&& (ISSPACE (*param) || *param == '\n' || *param == 0)) |
param++; |
if (param == pend) |
break; |
/* Scan forward until we encounter any of: |
- the end of the buffer |
- the start of a new option |
- a newline seperating options |
- a NUL seperating options. */ |
for (tend = (char *) (param + 1); |
(tend < pend |
&& !(ISSPACE (tend[-1]) && *tend == '-') |
&& *tend != '\n' && *tend != 0); |
tend++) |
; |
for (i = 0; diropts[i].param; i++) |
{ |
len = strlen (diropts[i].param); |
if (tend - param >= len |
&& strncmp (param, diropts[i].param, len) == 0 |
&& (param[len] == ':' || param[len] == ' ')) |
{ |
lex_parse_string_end = tend; |
lex_parse_string = param + len + 1; |
lex_forced_token = diropts[i].token; |
saw_newline = 0; |
if (def_parse ()) |
continue; |
break; |
} |
} |
if (!diropts[i].param) |
{ |
if (tend < pend) |
{ |
char saved; |
saved = * tend; |
* tend = 0; |
/* xgettext:c-format */ |
einfo (_("Warning: .drectve `%s' unrecognized\n"), param); |
* tend = saved; |
} |
else |
{ |
einfo (_("Warning: corrupt .drectve at end of def file\n")); |
} |
} |
lex_parse_string = 0; |
param = tend; |
} |
def = save_def; |
def_pool_free (); |
} |
/* Parser Callbacks. */ |
static void |
def_image_name (const char *name, bfd_vma base, int is_dll) |
{ |
/* If a LIBRARY or NAME statement is specified without a name, there is nothing |
to do here. We retain the output filename specified on command line. */ |
if (*name) |
{ |
const char* image_name = lbasename (name); |
if (image_name != name) |
einfo ("%s:%d: Warning: path components stripped from %s, '%s'\n", |
def_filename, linenumber, is_dll ? "LIBRARY" : "NAME", |
name); |
if (def->name) |
free (def->name); |
/* Append the default suffix, if none specified. */ |
if (strchr (image_name, '.') == 0) |
{ |
const char * suffix = is_dll ? ".dll" : ".exe"; |
def->name = xmalloc (strlen (image_name) + strlen (suffix) + 1); |
sprintf (def->name, "%s%s", image_name, suffix); |
} |
else |
def->name = xstrdup (image_name); |
} |
/* Honor a BASE address statement, even if LIBRARY string is empty. */ |
def->base_address = base; |
def->is_dll = is_dll; |
} |
static void |
def_description (const char *text) |
{ |
int len = def->description ? strlen (def->description) : 0; |
len += strlen (text) + 1; |
if (def->description) |
{ |
def->description = xrealloc (def->description, len); |
strcat (def->description, text); |
} |
else |
{ |
def->description = xmalloc (len); |
strcpy (def->description, text); |
} |
} |
static void |
def_stacksize (int reserve, int commit) |
{ |
def->stack_reserve = reserve; |
def->stack_commit = commit; |
} |
static void |
def_heapsize (int reserve, int commit) |
{ |
def->heap_reserve = reserve; |
def->heap_commit = commit; |
} |
static void |
def_section (const char *name, int attr) |
{ |
def_file_section *s; |
int max_sections = ROUND_UP (def->num_section_defs, 4); |
if (def->num_section_defs >= max_sections) |
{ |
max_sections = ROUND_UP (def->num_section_defs+1, 4); |
if (def->section_defs) |
def->section_defs = xrealloc (def->section_defs, |
max_sections * sizeof (def_file_import)); |
else |
def->section_defs = xmalloc (max_sections * sizeof (def_file_import)); |
} |
s = def->section_defs + def->num_section_defs; |
memset (s, 0, sizeof (def_file_section)); |
s->name = xstrdup (name); |
if (attr & 1) |
s->flag_read = 1; |
if (attr & 2) |
s->flag_write = 1; |
if (attr & 4) |
s->flag_execute = 1; |
if (attr & 8) |
s->flag_shared = 1; |
def->num_section_defs++; |
} |
static void |
def_section_alt (const char *name, const char *attr) |
{ |
int aval = 0; |
for (; *attr; attr++) |
{ |
switch (*attr) |
{ |
case 'R': |
case 'r': |
aval |= 1; |
break; |
case 'W': |
case 'w': |
aval |= 2; |
break; |
case 'X': |
case 'x': |
aval |= 4; |
break; |
case 'S': |
case 's': |
aval |= 8; |
break; |
} |
} |
def_section (name, aval); |
} |
static void |
def_exports (const char *external_name, |
const char *internal_name, |
int ordinal, |
int flags, |
const char *its_name) |
{ |
def_file_export *dfe; |
int is_dup = 0; |
if (!internal_name && external_name) |
internal_name = external_name; |
#if TRACE |
printf ("def_exports, ext=%s int=%s\n", external_name, internal_name); |
#endif |
dfe = def_file_add_export (def, external_name, internal_name, ordinal, |
its_name, &is_dup); |
/* We might check here for flag redefinition and warn. For now we |
ignore duplicates silently. */ |
if (is_dup) |
return; |
if (flags & 1) |
dfe->flag_noname = 1; |
if (flags & 2) |
dfe->flag_constant = 1; |
if (flags & 4) |
dfe->flag_data = 1; |
if (flags & 8) |
dfe->flag_private = 1; |
} |
static void |
def_import (const char *internal_name, |
const char *module, |
const char *dllext, |
const char *name, |
int ordinal, |
const char *its_name) |
{ |
char *buf = 0; |
const char *ext = dllext ? dllext : "dll"; |
int is_dup = 0; |
buf = xmalloc (strlen (module) + strlen (ext) + 2); |
sprintf (buf, "%s.%s", module, ext); |
module = buf; |
def_file_add_import (def, name, module, ordinal, internal_name, its_name, |
&is_dup); |
free (buf); |
} |
static void |
def_version (int major, int minor) |
{ |
def->version_major = major; |
def->version_minor = minor; |
} |
static void |
def_directive (char *str) |
{ |
struct directive *d = xmalloc (sizeof (struct directive)); |
d->next = directives; |
directives = d; |
d->name = xstrdup (str); |
d->len = strlen (str); |
} |
static void |
def_aligncomm (char *str, int align) |
{ |
def_file_aligncomm *c, *p; |
p = NULL; |
c = def->aligncomms; |
while (c != NULL) |
{ |
int e = strcmp (c->symbol_name, str); |
if (!e) |
{ |
/* Not sure if we want to allow here duplicates with |
different alignments, but for now we keep them. */ |
e = (int) c->alignment - align; |
if (!e) |
return; |
} |
if (e > 0) |
break; |
c = (p = c)->next; |
} |
c = xmalloc (sizeof (def_file_aligncomm)); |
c->symbol_name = xstrdup (str); |
c->alignment = (unsigned int) align; |
if (!p) |
{ |
c->next = def->aligncomms; |
def->aligncomms = c; |
} |
else |
{ |
c->next = p->next; |
p->next = c; |
} |
} |
static int |
def_error (const char *err) |
{ |
einfo ("%P: %s:%d: %s\n", |
def_filename ? def_filename : "<unknown-file>", linenumber, err); |
return 0; |
} |
/* Lexical Scanner. */ |
#undef TRACE |
#define TRACE 0 |
/* Never freed, but always reused as needed, so no real leak. */ |
static char *buffer = 0; |
static int buflen = 0; |
static int bufptr = 0; |
static void |
put_buf (char c) |
{ |
if (bufptr == buflen) |
{ |
buflen += 50; /* overly reasonable, eh? */ |
if (buffer) |
buffer = xrealloc (buffer, buflen + 1); |
else |
buffer = xmalloc (buflen + 1); |
} |
buffer[bufptr++] = c; |
buffer[bufptr] = 0; /* not optimal, but very convenient. */ |
} |
static struct |
{ |
char *name; |
int token; |
} |
tokens[] = |
{ |
{ "BASE", BASE }, |
{ "CODE", CODE }, |
{ "CONSTANT", CONSTANTU }, |
{ "constant", CONSTANTL }, |
{ "DATA", DATAU }, |
{ "data", DATAL }, |
{ "DESCRIPTION", DESCRIPTION }, |
{ "DIRECTIVE", DIRECTIVE }, |
{ "EXECUTE", EXECUTE }, |
{ "EXPORTS", EXPORTS }, |
{ "HEAPSIZE", HEAPSIZE }, |
{ "IMPORTS", IMPORTS }, |
{ "LIBRARY", LIBRARY }, |
{ "NAME", NAME }, |
{ "NONAME", NONAMEU }, |
{ "noname", NONAMEL }, |
{ "PRIVATE", PRIVATEU }, |
{ "private", PRIVATEL }, |
{ "READ", READ }, |
{ "SECTIONS", SECTIONS }, |
{ "SEGMENTS", SECTIONS }, |
{ "SHARED", SHARED }, |
{ "STACKSIZE", STACKSIZE_K }, |
{ "VERSION", VERSIONK }, |
{ "WRITE", WRITE }, |
{ 0, 0 } |
}; |
static int |
def_getc (void) |
{ |
int rv; |
if (lex_parse_string) |
{ |
if (lex_parse_string >= lex_parse_string_end) |
rv = EOF; |
else |
rv = *lex_parse_string++; |
} |
else |
{ |
rv = fgetc (the_file); |
} |
if (rv == '\n') |
saw_newline = 1; |
return rv; |
} |
static int |
def_ungetc (int c) |
{ |
if (lex_parse_string) |
{ |
lex_parse_string--; |
return c; |
} |
else |
return ungetc (c, the_file); |
} |
static int |
def_lex (void) |
{ |
int c, i, q; |
if (lex_forced_token) |
{ |
i = lex_forced_token; |
lex_forced_token = 0; |
#if TRACE |
printf ("lex: forcing token %d\n", i); |
#endif |
return i; |
} |
c = def_getc (); |
/* Trim leading whitespace. */ |
while (c != EOF && (c == ' ' || c == '\t') && saw_newline) |
c = def_getc (); |
if (c == EOF) |
{ |
#if TRACE |
printf ("lex: EOF\n"); |
#endif |
return 0; |
} |
if (saw_newline && c == ';') |
{ |
do |
{ |
c = def_getc (); |
} |
while (c != EOF && c != '\n'); |
if (c == '\n') |
return def_lex (); |
return 0; |
} |
/* Must be something else. */ |
saw_newline = 0; |
if (ISDIGIT (c)) |
{ |
bufptr = 0; |
while (c != EOF && (ISXDIGIT (c) || (c == 'x'))) |
{ |
put_buf (c); |
c = def_getc (); |
} |
if (c != EOF) |
def_ungetc (c); |
yylval.digits = def_pool_strdup (buffer); |
#if TRACE |
printf ("lex: `%s' returns DIGITS\n", buffer); |
#endif |
return DIGITS; |
} |
if (ISALPHA (c) || strchr ("$:-_?@", c)) |
{ |
bufptr = 0; |
q = c; |
put_buf (c); |
c = def_getc (); |
if (q == '@') |
{ |
if (ISBLANK (c) ) /* '@' followed by whitespace. */ |
return (q); |
else if (ISDIGIT (c)) /* '@' followed by digit. */ |
{ |
def_ungetc (c); |
return (q); |
} |
#if TRACE |
printf ("lex: @ returns itself\n"); |
#endif |
} |
while (c != EOF && (ISALNUM (c) || strchr ("$:-_?/@<>", c))) |
{ |
put_buf (c); |
c = def_getc (); |
} |
if (c != EOF) |
def_ungetc (c); |
if (ISALPHA (q)) /* Check for tokens. */ |
{ |
for (i = 0; tokens[i].name; i++) |
if (strcmp (tokens[i].name, buffer) == 0) |
{ |
#if TRACE |
printf ("lex: `%s' is a string token\n", buffer); |
#endif |
return tokens[i].token; |
} |
} |
#if TRACE |
printf ("lex: `%s' returns ID\n", buffer); |
#endif |
yylval.id = def_pool_strdup (buffer); |
return ID; |
} |
if (c == '\'' || c == '"') |
{ |
q = c; |
c = def_getc (); |
bufptr = 0; |
while (c != EOF && c != q) |
{ |
put_buf (c); |
c = def_getc (); |
} |
yylval.id = def_pool_strdup (buffer); |
#if TRACE |
printf ("lex: `%s' returns ID\n", buffer); |
#endif |
return ID; |
} |
if ( c == '=') |
{ |
c = def_getc (); |
if (c == '=') |
{ |
#if TRACE |
printf ("lex: `==' returns EQUAL\n"); |
#endif |
return EQUAL; |
} |
def_ungetc (c); |
#if TRACE |
printf ("lex: `=' returns itself\n"); |
#endif |
return '='; |
} |
if (c == '.' || c == ',') |
{ |
#if TRACE |
printf ("lex: `%c' returns itself\n", c); |
#endif |
return c; |
} |
if (c == '\n') |
{ |
linenumber++; |
saw_newline = 1; |
} |
/*printf ("lex: 0x%02x ignored\n", c); */ |
return def_lex (); |
} |
static char * |
def_pool_alloc (size_t sz) |
{ |
def_pool_str *e; |
e = (def_pool_str *) xmalloc (sizeof (def_pool_str) + sz); |
e->next = pool_strs; |
pool_strs = e; |
return e->data; |
} |
static char * |
def_pool_strdup (const char *str) |
{ |
char *s; |
size_t len; |
if (!str) |
return NULL; |
len = strlen (str) + 1; |
s = def_pool_alloc (len); |
memcpy (s, str, len); |
return s; |
} |
static void |
def_pool_free (void) |
{ |
def_pool_str *p; |
while ((p = pool_strs) != NULL) |
{ |
pool_strs = p->next; |
free (p); |
} |
} |
/contrib/toolchain/binutils/ld/ei386pe.c |
---|
0,0 → 1,3832 |
/* Copyright 1995-2013 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* For WINDOWS_NT */ |
/* The original file generated returned different default scripts depending |
on whether certain switches were set, but these switches pertain to the |
Linux system and that particular version of coff. In the NT case, we |
only determine if the subsystem is console or windows in order to select |
the correct entry point by default. */ |
#define TARGET_IS_i386pe |
/* Do this before including bfd.h, so we prototype the right functions. */ |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) |
#define bfd_arm_allocate_interworking_sections bfd_i386pe_allocate_interworking_sections |
#define bfd_arm_get_bfd_for_interworking bfd_i386pe_get_bfd_for_interworking |
#define bfd_arm_process_before_allocation bfd_i386pe_process_before_allocation |
#endif |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "getopt.h" |
#include "libiberty.h" |
#include "filenames.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldmisc.h" |
#include "ldctor.h" |
#include "coff/internal.h" |
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific |
header in generic PE code. */ |
#include "coff/i386.h" |
#include "coff/pe.h" |
/* FIXME: This is a BFD internal header file, and we should not be |
using it here. */ |
#include "../bfd/libcoff.h" |
#include "deffile.h" |
#include "pe-dll.h" |
#include "safe-ctype.h" |
/* Permit the emulation parameters to override the default section |
alignment by setting OVERRIDE_SECTION_ALIGNMENT. FIXME: This makes |
it seem that include/coff/internal.h should not define |
PE_DEF_SECTION_ALIGNMENT. */ |
#if PE_DEF_SECTION_ALIGNMENT != PE_DEF_SECTION_ALIGNMENT |
#undef PE_DEF_SECTION_ALIGNMENT |
#define PE_DEF_SECTION_ALIGNMENT |
#endif |
#if defined(TARGET_IS_i386pe) || defined(TARGET_IS_shpe) || defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) |
#define DLL_SUPPORT |
#endif |
#if defined(TARGET_IS_i386pe) |
#define DEFAULT_PSEUDO_RELOC_VERSION 2 |
#else |
#define DEFAULT_PSEUDO_RELOC_VERSION 1 |
#endif |
#if defined(TARGET_IS_i386pe) || ! defined(DLL_SUPPORT) |
#define PE_DEF_SUBSYSTEM 3 |
#else |
#undef NT_EXE_IMAGE_BASE |
#undef PE_DEF_SECTION_ALIGNMENT |
#undef PE_DEF_FILE_ALIGNMENT |
#define NT_EXE_IMAGE_BASE 0x00010000 |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_wince_pe) |
#define PE_DEF_SECTION_ALIGNMENT 0x00001000 |
#define PE_DEF_SUBSYSTEM 9 |
#else |
#define PE_DEF_SECTION_ALIGNMENT 0x00000400 |
#define PE_DEF_SUBSYSTEM 2 |
#endif |
#define PE_DEF_FILE_ALIGNMENT 0x00000200 |
#endif |
static struct internal_extra_pe_aouthdr pe; |
static int dll; |
static int pe_subsystem = PE_DEF_SUBSYSTEM; |
static flagword real_flags = 0; |
static int support_old_code = 0; |
static char * thumb_entry_symbol = NULL; |
static lang_assignment_statement_type *image_base_statement = 0; |
static unsigned short pe_dll_characteristics = 0; |
static bfd_boolean insert_timestamp = FALSE; |
#ifdef DLL_SUPPORT |
static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */ |
static char *pe_out_def_filename = NULL; |
static char *pe_implib_filename = NULL; |
static int pe_enable_auto_image_base = 0; |
static char *pe_dll_search_prefix = NULL; |
#endif |
extern const char *output_filename; |
static int is_underscoring (void) |
{ |
int u = 0; |
if (pe_leading_underscore != -1) |
return pe_leading_underscore; |
if (!bfd_get_target_info ("pei-i386", NULL, NULL, &u, NULL)) |
bfd_get_target_info ("pe-i386", NULL, NULL, &u, NULL); |
if (u == -1) |
abort (); |
pe_leading_underscore = (u != 0 ? 1 : 0); |
return pe_leading_underscore; |
} |
static void |
gld_i386pe_before_parse (void) |
{ |
is_underscoring (); |
ldfile_set_output_arch ("i386", bfd_arch_i386); |
output_filename = "a.exe"; |
#ifdef DLL_SUPPORT |
input_flags.dynamic = TRUE; |
config.has_shared = 1; |
link_info.pei386_auto_import = 1; |
/* Use by default version. */ |
link_info.pei386_runtime_pseudo_reloc = DEFAULT_PSEUDO_RELOC_VERSION; |
#endif |
} |
/* Indicates if RDATA shall be merged into DATA when pseudo-relocation |
version 2 is used and auto-import is enabled. */ |
#define MERGE_RDATA_V2 0 |
/* PE format extra command line options. */ |
/* Used for setting flags in the PE header. */ |
#define OPTION_BASE_FILE (300 + 1) |
#define OPTION_DLL (OPTION_BASE_FILE + 1) |
#define OPTION_FILE_ALIGNMENT (OPTION_DLL + 1) |
#define OPTION_IMAGE_BASE (OPTION_FILE_ALIGNMENT + 1) |
#define OPTION_MAJOR_IMAGE_VERSION (OPTION_IMAGE_BASE + 1) |
#define OPTION_MAJOR_OS_VERSION (OPTION_MAJOR_IMAGE_VERSION + 1) |
#define OPTION_MAJOR_SUBSYSTEM_VERSION (OPTION_MAJOR_OS_VERSION + 1) |
#define OPTION_MINOR_IMAGE_VERSION (OPTION_MAJOR_SUBSYSTEM_VERSION + 1) |
#define OPTION_MINOR_OS_VERSION (OPTION_MINOR_IMAGE_VERSION + 1) |
#define OPTION_MINOR_SUBSYSTEM_VERSION (OPTION_MINOR_OS_VERSION + 1) |
#define OPTION_SECTION_ALIGNMENT (OPTION_MINOR_SUBSYSTEM_VERSION + 1) |
#define OPTION_STACK (OPTION_SECTION_ALIGNMENT + 1) |
#define OPTION_SUBSYSTEM (OPTION_STACK + 1) |
#define OPTION_HEAP (OPTION_SUBSYSTEM + 1) |
#define OPTION_SUPPORT_OLD_CODE (OPTION_HEAP + 1) |
#define OPTION_OUT_DEF (OPTION_SUPPORT_OLD_CODE + 1) |
#define OPTION_EXPORT_ALL (OPTION_OUT_DEF + 1) |
#define OPTION_EXCLUDE_SYMBOLS (OPTION_EXPORT_ALL + 1) |
#define OPTION_EXCLUDE_ALL_SYMBOLS (OPTION_EXCLUDE_SYMBOLS + 1) |
#define OPTION_KILL_ATS (OPTION_EXCLUDE_ALL_SYMBOLS + 1) |
#define OPTION_STDCALL_ALIASES (OPTION_KILL_ATS + 1) |
#define OPTION_ENABLE_STDCALL_FIXUP (OPTION_STDCALL_ALIASES + 1) |
#define OPTION_DISABLE_STDCALL_FIXUP (OPTION_ENABLE_STDCALL_FIXUP + 1) |
#define OPTION_IMPLIB_FILENAME (OPTION_DISABLE_STDCALL_FIXUP + 1) |
#define OPTION_THUMB_ENTRY (OPTION_IMPLIB_FILENAME + 1) |
#define OPTION_WARN_DUPLICATE_EXPORTS (OPTION_THUMB_ENTRY + 1) |
#define OPTION_IMP_COMPAT (OPTION_WARN_DUPLICATE_EXPORTS + 1) |
#define OPTION_ENABLE_AUTO_IMAGE_BASE (OPTION_IMP_COMPAT + 1) |
#define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1) |
#define OPTION_DLL_SEARCH_PREFIX (OPTION_DISABLE_AUTO_IMAGE_BASE + 1) |
#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_DLL_SEARCH_PREFIX + 1) |
#define OPTION_DLL_ENABLE_AUTO_IMPORT (OPTION_NO_DEFAULT_EXCLUDES + 1) |
#define OPTION_DLL_DISABLE_AUTO_IMPORT (OPTION_DLL_ENABLE_AUTO_IMPORT + 1) |
#define OPTION_ENABLE_EXTRA_PE_DEBUG (OPTION_DLL_DISABLE_AUTO_IMPORT + 1) |
#define OPTION_EXCLUDE_LIBS (OPTION_ENABLE_EXTRA_PE_DEBUG + 1) |
#define OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC (OPTION_EXCLUDE_LIBS + 1) |
#define OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC + 1) |
#define OPTION_LARGE_ADDRESS_AWARE (OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC + 1) |
#define OPTION_DISABLE_LARGE_ADDRESS_AWARE (OPTION_LARGE_ADDRESS_AWARE + 1) |
#define OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1 (OPTION_DISABLE_LARGE_ADDRESS_AWARE + 1) |
#define OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2 (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1 + 1) |
#define OPTION_EXCLUDE_MODULES_FOR_IMPLIB (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2 + 1) |
#define OPTION_USE_NUL_PREFIXED_IMPORT_TABLES (OPTION_EXCLUDE_MODULES_FOR_IMPLIB + 1) |
#define OPTION_NO_LEADING_UNDERSCORE (OPTION_USE_NUL_PREFIXED_IMPORT_TABLES + 1) |
#define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1) |
#define OPTION_ENABLE_LONG_SECTION_NAMES (OPTION_LEADING_UNDERSCORE + 1) |
#define OPTION_DISABLE_LONG_SECTION_NAMES (OPTION_ENABLE_LONG_SECTION_NAMES + 1) |
/* DLLCharacteristics flags. */ |
#define OPTION_DYNAMIC_BASE (OPTION_DISABLE_LONG_SECTION_NAMES + 1) |
#define OPTION_FORCE_INTEGRITY (OPTION_DYNAMIC_BASE + 1) |
#define OPTION_NX_COMPAT (OPTION_FORCE_INTEGRITY + 1) |
#define OPTION_NO_ISOLATION (OPTION_NX_COMPAT + 1) |
#define OPTION_NO_SEH (OPTION_NO_ISOLATION + 1) |
#define OPTION_NO_BIND (OPTION_NO_SEH + 1) |
#define OPTION_WDM_DRIVER (OPTION_NO_BIND + 1) |
#define OPTION_TERMINAL_SERVER_AWARE (OPTION_WDM_DRIVER + 1) |
/* Determinism. */ |
#define OPTION_INSERT_TIMESTAMP (OPTION_TERMINAL_SERVER_AWARE + 1) |
static void |
gldi386pe_add_options |
(int ns ATTRIBUTE_UNUSED, |
char **shortopts ATTRIBUTE_UNUSED, |
int nl, |
struct option **longopts, |
int nrl ATTRIBUTE_UNUSED, |
struct option **really_longopts ATTRIBUTE_UNUSED) |
{ |
static const struct option xtra_long[] = |
{ |
/* PE options. */ |
{"base-file", required_argument, NULL, OPTION_BASE_FILE}, |
{"dll", no_argument, NULL, OPTION_DLL}, |
{"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT}, |
{"heap", required_argument, NULL, OPTION_HEAP}, |
{"image-base", required_argument, NULL, OPTION_IMAGE_BASE}, |
{"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION}, |
{"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION}, |
{"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION}, |
{"minor-image-version", required_argument, NULL, OPTION_MINOR_IMAGE_VERSION}, |
{"minor-os-version", required_argument, NULL, OPTION_MINOR_OS_VERSION}, |
{"minor-subsystem-version", required_argument, NULL, OPTION_MINOR_SUBSYSTEM_VERSION}, |
{"section-alignment", required_argument, NULL, OPTION_SECTION_ALIGNMENT}, |
{"stack", required_argument, NULL, OPTION_STACK}, |
{"subsystem", required_argument, NULL, OPTION_SUBSYSTEM}, |
{"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, |
{"thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY}, |
{"use-nul-prefixed-import-tables", no_argument, NULL, |
OPTION_USE_NUL_PREFIXED_IMPORT_TABLES}, |
{"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE}, |
{"leading-underscore", no_argument, NULL, OPTION_LEADING_UNDERSCORE}, |
{"insert-timestamp", no_argument, NULL, OPTION_INSERT_TIMESTAMP}, |
#ifdef DLL_SUPPORT |
/* getopt allows abbreviations, so we do this to stop it |
from treating -o as an abbreviation for this option. */ |
{"output-def", required_argument, NULL, OPTION_OUT_DEF}, |
{"output-def", required_argument, NULL, OPTION_OUT_DEF}, |
{"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL}, |
{"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMBOLS}, |
{"exclude-all-symbols", no_argument, NULL, OPTION_EXCLUDE_ALL_SYMBOLS}, |
{"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, |
{"exclude-modules-for-implib", required_argument, NULL, OPTION_EXCLUDE_MODULES_FOR_IMPLIB}, |
{"kill-at", no_argument, NULL, OPTION_KILL_ATS}, |
{"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES}, |
{"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP}, |
{"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP}, |
{"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME}, |
{"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS}, |
/* getopt() allows abbreviations, so we do this to stop it from |
treating -c as an abbreviation for these --compat-implib. */ |
{"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, |
{"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, |
{"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, |
{"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE}, |
{"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX}, |
{"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES}, |
{"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT}, |
{"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT}, |
{"enable-extra-pe-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG}, |
{"enable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC}, |
{"disable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC}, |
{"enable-runtime-pseudo-reloc-v1", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1}, |
{"enable-runtime-pseudo-reloc-v2", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2}, |
#endif |
{"large-address-aware", no_argument, NULL, OPTION_LARGE_ADDRESS_AWARE}, |
{"disable-large-address-aware", no_argument, NULL, OPTION_DISABLE_LARGE_ADDRESS_AWARE}, |
{"enable-long-section-names", no_argument, NULL, OPTION_ENABLE_LONG_SECTION_NAMES}, |
{"disable-long-section-names", no_argument, NULL, OPTION_DISABLE_LONG_SECTION_NAMES}, |
{"dynamicbase",no_argument, NULL, OPTION_DYNAMIC_BASE}, |
{"forceinteg", no_argument, NULL, OPTION_FORCE_INTEGRITY}, |
{"nxcompat", no_argument, NULL, OPTION_NX_COMPAT}, |
{"no-isolation", no_argument, NULL, OPTION_NO_ISOLATION}, |
{"no-seh", no_argument, NULL, OPTION_NO_SEH}, |
{"no-bind", no_argument, NULL, OPTION_NO_BIND}, |
{"wdmdriver", no_argument, NULL, OPTION_WDM_DRIVER}, |
{"tsaware", no_argument, NULL, OPTION_TERMINAL_SERVER_AWARE}, |
{NULL, no_argument, NULL, 0} |
}; |
*longopts |
= xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); |
memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); |
} |
/* PE/WIN32; added routines to get the subsystem type, heap and/or stack |
parameters which may be input from the command line. */ |
typedef struct |
{ |
void *ptr; |
int size; |
int value; |
char *symbol; |
int inited; |
/* FALSE for an assembly level symbol and TRUE for a C visible symbol. |
C visible symbols can be prefixed by underscore dependent to target's |
settings. */ |
bfd_boolean is_c_symbol; |
} definfo; |
/* Get symbol name dependent to kind and C visible state of |
underscore. */ |
#define GET_INIT_SYMBOL_NAME(IDX) (init[(IDX)].symbol + ((init[(IDX)].is_c_symbol == FALSE || (is_underscoring () != 0)) ? 0 : 1)) |
/* Decorates the C visible symbol by underscore, if target requires. */ |
#define U(CSTR) ((is_underscoring () == 0) ? CSTR : "_" CSTR) |
/* Get size of constant string for a possible underscore prefixed |
C visible symbol. */ |
#define U_SIZE(CSTR) (sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1)) |
#define D(field,symbol,def,usc) {&pe.field,sizeof(pe.field), def, symbol, 0, usc} |
static definfo init[] = |
{ |
/* imagebase must be first */ |
#define IMAGEBASEOFF 0 |
D(ImageBase,"__image_base__", NT_EXE_IMAGE_BASE, FALSE), |
#define DLLOFF 1 |
{&dll, sizeof(dll), 0, "__dll__", 0, FALSE}, |
#define MSIMAGEBASEOFF 2 |
D(ImageBase, "___ImageBase", NT_EXE_IMAGE_BASE, TRUE), |
D(SectionAlignment,"__section_alignment__", PE_DEF_SECTION_ALIGNMENT, FALSE), |
D(FileAlignment,"__file_alignment__", PE_DEF_FILE_ALIGNMENT, FALSE), |
D(MajorOperatingSystemVersion,"__major_os_version__", 4, FALSE), |
D(MinorOperatingSystemVersion,"__minor_os_version__", 0, FALSE), |
D(MajorImageVersion,"__major_image_version__", 1, FALSE), |
D(MinorImageVersion,"__minor_image_version__", 0, FALSE), |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_wince_pe) |
D(MajorSubsystemVersion,"__major_subsystem_version__", 3, FALSE), |
#else |
D(MajorSubsystemVersion,"__major_subsystem_version__", 4, FALSE), |
#endif |
D(MinorSubsystemVersion,"__minor_subsystem_version__", 0, FALSE), |
D(Subsystem,"__subsystem__", PE_DEF_SUBSYSTEM, FALSE), |
D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x200000, FALSE), |
D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000, FALSE), |
D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000, FALSE), |
D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000, FALSE), |
D(LoaderFlags,"__loader_flags__", 0x0, FALSE), |
D(DllCharacteristics, "__dll_characteristics__", 0x0, FALSE), |
{ NULL, 0, 0, NULL, 0 , FALSE} |
}; |
static void |
gld_i386pe_list_options (FILE *file) |
{ |
fprintf (file, _(" --base_file <basefile> Generate a base file for relocatable DLLs\n")); |
fprintf (file, _(" --dll Set image base to the default for DLLs\n")); |
fprintf (file, _(" --file-alignment <size> Set file alignment\n")); |
fprintf (file, _(" --heap <size> Set initial size of the heap\n")); |
fprintf (file, _(" --image-base <address> Set start address of the executable\n")); |
fprintf (file, _(" --major-image-version <number> Set version number of the executable\n")); |
fprintf (file, _(" --major-os-version <number> Set minimum required OS version\n")); |
fprintf (file, _(" --major-subsystem-version <number> Set minimum required OS subsystem version\n")); |
fprintf (file, _(" --minor-image-version <number> Set revision number of the executable\n")); |
fprintf (file, _(" --minor-os-version <number> Set minimum required OS revision\n")); |
fprintf (file, _(" --minor-subsystem-version <number> Set minimum required OS subsystem revision\n")); |
fprintf (file, _(" --section-alignment <size> Set section alignment\n")); |
fprintf (file, _(" --stack <size> Set size of the initial stack\n")); |
fprintf (file, _(" --subsystem <name>[:<version>] Set required OS subsystem [& version]\n")); |
fprintf (file, _(" --support-old-code Support interworking with old code\n")); |
fprintf (file, _(" --[no-]leading-underscore Set explicit symbol underscore prefix mode\n")); |
fprintf (file, _(" --thumb-entry=<symbol> Set the entry point to be Thumb <symbol>\n")); |
fprintf (file, _(" --insert-timestamp Use a real timestamp rather than zero.\n")); |
fprintf (file, _(" This makes binaries non-deterministic\n")); |
#ifdef DLL_SUPPORT |
fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n")); |
fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n")); |
fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n")); |
fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n")); |
fprintf (file, _(" --exclude-all-symbols Exclude all symbols from automatic export\n")); |
fprintf (file, _(" --exclude-libs lib,lib,... Exclude libraries from automatic export\n")); |
fprintf (file, _(" --exclude-modules-for-implib mod,mod,...\n")); |
fprintf (file, _(" Exclude objects, archive members from auto\n")); |
fprintf (file, _(" export, place into import library instead.\n")); |
fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n")); |
fprintf (file, _(" --kill-at Remove @nn from exported symbols\n")); |
fprintf (file, _(" --out-implib <file> Generate import library\n")); |
fprintf (file, _(" --output-def <file> Generate a .DEF file for the built DLL\n")); |
fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports.\n")); |
fprintf (file, _(" --compat-implib Create backward compatible import libs;\n create __imp_<SYMBOL> as well.\n")); |
fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n unless user specifies one\n")); |
fprintf (file, _(" --disable-auto-image-base Do not auto-choose image base. (default)\n")); |
fprintf (file, _(" --dll-search-prefix=<string> When linking dynamically to a dll without\n an importlib, use <string><basename>.dll\n in preference to lib<basename>.dll \n")); |
fprintf (file, _(" --enable-auto-import Do sophisticated linking of _sym to\n __imp_sym for DATA references\n")); |
fprintf (file, _(" --disable-auto-import Do not auto-import DATA items from DLLs\n")); |
fprintf (file, _(" --enable-runtime-pseudo-reloc Work around auto-import limitations by\n adding pseudo-relocations resolved at\n runtime.\n")); |
fprintf (file, _(" --disable-runtime-pseudo-reloc Do not add runtime pseudo-relocations for\n auto-imported DATA.\n")); |
fprintf (file, _(" --enable-extra-pe-debug Enable verbose debug output when building\n or linking to DLLs (esp. auto-import)\n")); |
#endif |
fprintf (file, _(" --large-address-aware Executable supports virtual addresses\n greater than 2 gigabytes\n")); |
fprintf (file, _(" --disable-large-address-aware Executable does not support virtual\n addresses greater than 2 gigabytes\n")); |
fprintf (file, _(" --enable-long-section-names Use long COFF section names even in\n executable image files\n")); |
fprintf (file, _(" --disable-long-section-names Never use long COFF section names, even\n in object files\n")); |
fprintf (file, _(" --dynamicbase Image base address may be relocated using\n address space layout randomization (ASLR)\n")); |
fprintf (file, _(" --forceinteg Code integrity checks are enforced\n")); |
fprintf (file, _(" --nxcompat Image is compatible with data execution prevention\n")); |
fprintf (file, _(" --no-isolation Image understands isolation but do not isolate the image\n")); |
fprintf (file, _(" --no-seh Image does not use SEH. No SE handler may\n be called in this image\n")); |
fprintf (file, _(" --no-bind Do not bind this image\n")); |
fprintf (file, _(" --wdmdriver Driver uses the WDM model\n")); |
fprintf (file, _(" --tsaware Image is Terminal Server aware\n")); |
} |
static void |
set_pe_name (char *name, long val) |
{ |
int i; |
is_underscoring (); |
/* Find the name and set it. */ |
for (i = 0; init[i].ptr; i++) |
{ |
if (strcmp (name, GET_INIT_SYMBOL_NAME (i)) == 0) |
{ |
init[i].value = val; |
init[i].inited = 1; |
if (strcmp (name,"__image_base__") == 0) |
set_pe_name (U ("__ImageBase"), val); |
return; |
} |
} |
abort (); |
} |
static void |
set_entry_point (void) |
{ |
const char *entry; |
const char *initial_symbol_char; |
int i; |
static const struct |
{ |
const int value; |
const char *entry; |
} |
v[] = |
{ |
{ 1, "NtProcessStartup" }, |
{ 2, "WinMainCRTStartup" }, |
{ 3, "mainCRTStartup" }, |
{ 7, "__PosixProcessStartup"}, |
{ 9, "WinMainCRTStartup" }, |
{14, "mainCRTStartup" }, |
{ 0, NULL } |
}; |
/* Entry point name for arbitrary subsystem numbers. */ |
static const char default_entry[] = "mainCRTStartup"; |
if (link_info.shared || dll) |
{ |
#if defined (TARGET_IS_i386pe) |
entry = "DllMainCRTStartup@12"; |
#else |
entry = "DllMainCRTStartup"; |
#endif |
} |
else |
{ |
for (i = 0; v[i].entry; i++) |
if (v[i].value == pe_subsystem) |
break; |
/* If no match, use the default. */ |
if (v[i].entry != NULL) |
entry = v[i].entry; |
else |
entry = default_entry; |
} |
initial_symbol_char = (is_underscoring () != 0 ? "_" : ""); |
if (*initial_symbol_char != '\0') |
{ |
char *alc_entry; |
/* lang_default_entry expects its argument to be permanently |
allocated, so we don't free this string. */ |
alc_entry = xmalloc (strlen (initial_symbol_char) |
+ strlen (entry) |
+ 1); |
strcpy (alc_entry, initial_symbol_char); |
strcat (alc_entry, entry); |
entry = alc_entry; |
} |
lang_default_entry (entry); |
} |
static void |
set_pe_subsystem (void) |
{ |
const char *sver; |
char *end; |
int len; |
int i; |
unsigned long temp_subsystem; |
static const struct |
{ |
const char *name; |
const int value; |
} |
v[] = |
{ |
{ "native", 1}, |
{ "windows", 2}, |
{ "console", 3}, |
{ "posix", 7}, |
{ "wince", 9}, |
{ "xbox", 14}, |
{ NULL, 0 } |
}; |
/* Check for the presence of a version number. */ |
sver = strchr (optarg, ':'); |
if (sver == NULL) |
len = strlen (optarg); |
else |
{ |
len = sver - optarg; |
set_pe_name ("__major_subsystem_version__", |
strtoul (sver + 1, &end, 0)); |
if (*end == '.') |
set_pe_name ("__minor_subsystem_version__", |
strtoul (end + 1, &end, 0)); |
if (*end != '\0') |
einfo (_("%P: warning: bad version number in -subsystem option\n")); |
} |
/* Check for numeric subsystem. */ |
temp_subsystem = strtoul (optarg, & end, 0); |
if ((*end == ':' || *end == '\0') && (temp_subsystem < 65536)) |
{ |
/* Search list for a numeric match to use its entry point. */ |
for (i = 0; v[i].name; i++) |
if (v[i].value == (int) temp_subsystem) |
break; |
/* Use this subsystem. */ |
pe_subsystem = (int) temp_subsystem; |
} |
else |
{ |
/* Search for subsystem by name. */ |
for (i = 0; v[i].name; i++) |
if (strncmp (optarg, v[i].name, len) == 0 |
&& v[i].name[len] == '\0') |
break; |
if (v[i].name == NULL) |
{ |
einfo (_("%P%F: invalid subsystem type %s\n"), optarg); |
return; |
} |
pe_subsystem = v[i].value; |
} |
set_pe_name ("__subsystem__", pe_subsystem); |
return; |
} |
static void |
set_pe_value (char *name) |
{ |
char *end; |
set_pe_name (name, strtoul (optarg, &end, 0)); |
if (end == optarg) |
einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); |
optarg = end; |
} |
static void |
set_pe_stack_heap (char *resname, char *comname) |
{ |
set_pe_value (resname); |
if (*optarg == ',') |
{ |
optarg++; |
set_pe_value (comname); |
} |
else if (*optarg) |
einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); |
} |
static bfd_boolean |
gldi386pe_handle_option (int optc) |
{ |
switch (optc) |
{ |
default: |
return FALSE; |
case OPTION_BASE_FILE: |
link_info.base_file = fopen (optarg, FOPEN_WB); |
if (link_info.base_file == NULL) |
einfo (_("%F%P: cannot open base file %s\n"), optarg); |
break; |
/* PE options. */ |
case OPTION_HEAP: |
set_pe_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); |
break; |
case OPTION_STACK: |
set_pe_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); |
break; |
case OPTION_SUBSYSTEM: |
set_pe_subsystem (); |
break; |
case OPTION_MAJOR_OS_VERSION: |
set_pe_value ("__major_os_version__"); |
break; |
case OPTION_MINOR_OS_VERSION: |
set_pe_value ("__minor_os_version__"); |
break; |
case OPTION_MAJOR_SUBSYSTEM_VERSION: |
set_pe_value ("__major_subsystem_version__"); |
break; |
case OPTION_MINOR_SUBSYSTEM_VERSION: |
set_pe_value ("__minor_subsystem_version__"); |
break; |
case OPTION_MAJOR_IMAGE_VERSION: |
set_pe_value ("__major_image_version__"); |
break; |
case OPTION_MINOR_IMAGE_VERSION: |
set_pe_value ("__minor_image_version__"); |
break; |
case OPTION_FILE_ALIGNMENT: |
set_pe_value ("__file_alignment__"); |
break; |
case OPTION_SECTION_ALIGNMENT: |
set_pe_value ("__section_alignment__"); |
break; |
case OPTION_DLL: |
set_pe_name ("__dll__", 1); |
break; |
case OPTION_IMAGE_BASE: |
set_pe_value ("__image_base__"); |
break; |
case OPTION_SUPPORT_OLD_CODE: |
support_old_code = 1; |
break; |
case OPTION_THUMB_ENTRY: |
thumb_entry_symbol = optarg; |
break; |
case OPTION_USE_NUL_PREFIXED_IMPORT_TABLES: |
pe_use_nul_prefixed_import_tables = TRUE; |
break; |
case OPTION_NO_LEADING_UNDERSCORE: |
pe_leading_underscore = 0; |
break; |
case OPTION_LEADING_UNDERSCORE: |
pe_leading_underscore = 1; |
break; |
case OPTION_INSERT_TIMESTAMP: |
insert_timestamp = TRUE; |
break; |
#ifdef DLL_SUPPORT |
case OPTION_OUT_DEF: |
pe_out_def_filename = xstrdup (optarg); |
break; |
case OPTION_EXPORT_ALL: |
pe_dll_export_everything = 1; |
break; |
case OPTION_EXCLUDE_SYMBOLS: |
pe_dll_add_excludes (optarg, EXCLUDESYMS); |
break; |
case OPTION_EXCLUDE_ALL_SYMBOLS: |
pe_dll_exclude_all_symbols = 1; |
break; |
case OPTION_EXCLUDE_LIBS: |
pe_dll_add_excludes (optarg, EXCLUDELIBS); |
break; |
case OPTION_EXCLUDE_MODULES_FOR_IMPLIB: |
pe_dll_add_excludes (optarg, EXCLUDEFORIMPLIB); |
break; |
case OPTION_KILL_ATS: |
pe_dll_kill_ats = 1; |
break; |
case OPTION_STDCALL_ALIASES: |
pe_dll_stdcall_aliases = 1; |
break; |
case OPTION_ENABLE_STDCALL_FIXUP: |
pe_enable_stdcall_fixup = 1; |
break; |
case OPTION_DISABLE_STDCALL_FIXUP: |
pe_enable_stdcall_fixup = 0; |
break; |
case OPTION_IMPLIB_FILENAME: |
pe_implib_filename = xstrdup (optarg); |
break; |
case OPTION_WARN_DUPLICATE_EXPORTS: |
pe_dll_warn_dup_exports = 1; |
break; |
case OPTION_IMP_COMPAT: |
pe_dll_compat_implib = 1; |
break; |
case OPTION_ENABLE_AUTO_IMAGE_BASE: |
pe_enable_auto_image_base = 1; |
break; |
case OPTION_DISABLE_AUTO_IMAGE_BASE: |
pe_enable_auto_image_base = 0; |
break; |
case OPTION_DLL_SEARCH_PREFIX: |
pe_dll_search_prefix = xstrdup (optarg); |
break; |
case OPTION_NO_DEFAULT_EXCLUDES: |
pe_dll_do_default_excludes = 0; |
break; |
case OPTION_DLL_ENABLE_AUTO_IMPORT: |
link_info.pei386_auto_import = 1; |
break; |
case OPTION_DLL_DISABLE_AUTO_IMPORT: |
link_info.pei386_auto_import = 0; |
break; |
case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC: |
link_info.pei386_runtime_pseudo_reloc = |
DEFAULT_PSEUDO_RELOC_VERSION; |
break; |
case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1: |
link_info.pei386_runtime_pseudo_reloc = 1; |
break; |
case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2: |
link_info.pei386_runtime_pseudo_reloc = 2; |
break; |
case OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC: |
link_info.pei386_runtime_pseudo_reloc = 0; |
break; |
case OPTION_ENABLE_EXTRA_PE_DEBUG: |
pe_dll_extra_pe_debug = 1; |
break; |
#endif |
case OPTION_LARGE_ADDRESS_AWARE: |
real_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE; |
break; |
case OPTION_DISABLE_LARGE_ADDRESS_AWARE: |
real_flags &= ~ IMAGE_FILE_LARGE_ADDRESS_AWARE; |
break; |
case OPTION_ENABLE_LONG_SECTION_NAMES: |
pe_use_coff_long_section_names = 1; |
break; |
case OPTION_DISABLE_LONG_SECTION_NAMES: |
pe_use_coff_long_section_names = 0; |
break; |
/* Get DLLCharacteristics bits */ |
case OPTION_DYNAMIC_BASE: |
pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; |
break; |
case OPTION_FORCE_INTEGRITY: |
pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; |
break; |
case OPTION_NX_COMPAT: |
pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; |
break; |
case OPTION_NO_ISOLATION: |
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION; |
break; |
case OPTION_NO_SEH: |
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_SEH; |
break; |
case OPTION_NO_BIND: |
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_BIND; |
break; |
case OPTION_WDM_DRIVER: |
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_WDM_DRIVER; |
break; |
case OPTION_TERMINAL_SERVER_AWARE: |
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; |
break; |
} |
/* Set DLLCharacteristics bits */ |
set_pe_name ("__dll_characteristics__", pe_dll_characteristics); |
return TRUE; |
} |
#ifdef DLL_SUPPORT |
static unsigned long |
strhash (const char *str) |
{ |
const unsigned char *s; |
unsigned long hash; |
unsigned int c; |
unsigned int len; |
hash = 0; |
len = 0; |
s = (const unsigned char *) str; |
while ((c = *s++) != '\0') |
{ |
hash += c + (c << 17); |
hash ^= hash >> 2; |
++len; |
} |
hash += len + (len << 17); |
hash ^= hash >> 2; |
return hash; |
} |
/* Use the output file to create a image base for relocatable DLLs. */ |
static unsigned long |
compute_dll_image_base (const char *ofile) |
{ |
unsigned long hash = strhash (ofile); |
return 0x61300000 + ((hash << 16) & 0x0FFC0000); |
} |
#endif |
/* Assign values to the special symbols before the linker script is |
read. */ |
static void |
gld_i386pe_set_symbols (void) |
{ |
/* Run through and invent symbols for all the |
names and insert the defaults. */ |
int j; |
is_underscoring (); |
if (!init[IMAGEBASEOFF].inited) |
{ |
if (link_info.relocatable) |
init[IMAGEBASEOFF].value = 0; |
else if (init[DLLOFF].value || (link_info.shared && !link_info.pie)) |
{ |
#ifdef DLL_SUPPORT |
init[IMAGEBASEOFF].value = (pe_enable_auto_image_base |
? compute_dll_image_base (output_filename) |
: NT_DLL_IMAGE_BASE); |
#else |
init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE; |
#endif |
} |
else |
init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE; |
init[MSIMAGEBASEOFF].value = init[IMAGEBASEOFF].value; |
} |
/* Don't do any symbol assignments if this is a relocatable link. */ |
if (link_info.relocatable) |
return; |
/* Glue the assignments into the abs section. */ |
push_stat_ptr (&abs_output_section->children); |
for (j = 0; init[j].ptr; j++) |
{ |
long val = init[j].value; |
lang_assignment_statement_type *rv; |
rv = lang_add_assignment (exp_assign (GET_INIT_SYMBOL_NAME (j), |
exp_intop (val), FALSE)); |
if (init[j].size == sizeof (short)) |
*(short *) init[j].ptr = val; |
else if (init[j].size == sizeof (int)) |
*(int *) init[j].ptr = val; |
else if (init[j].size == sizeof (long)) |
*(long *) init[j].ptr = val; |
/* This might be a long long or other special type. */ |
else if (init[j].size == sizeof (bfd_vma)) |
*(bfd_vma *) init[j].ptr = val; |
else abort (); |
if (j == IMAGEBASEOFF) |
image_base_statement = rv; |
} |
/* Restore the pointer. */ |
pop_stat_ptr (); |
if (pe.FileAlignment > pe.SectionAlignment) |
{ |
einfo (_("%P: warning, file alignment > section alignment.\n")); |
} |
} |
/* This is called after the linker script and the command line options |
have been read. */ |
static void |
gld_i386pe_after_parse (void) |
{ |
/* PR ld/6744: Warn the user if they have used an ELF-only |
option hoping it will work on PE. */ |
if (link_info.export_dynamic) |
einfo (_("%P: warning: --export-dynamic is not supported for PE " |
"targets, did you mean --export-all-symbols?\n")); |
set_entry_point (); |
after_parse_default (); |
} |
/* pe-dll.c directly accesses pe_data_import_dll, |
so it must be defined outside of #ifdef DLL_SUPPORT. |
Note - this variable is deliberately not initialised. |
This allows it to be treated as a common varaible, and only |
exist in one incarnation in a multiple target enabled linker. */ |
char * pe_data_import_dll; |
#ifdef DLL_SUPPORT |
static struct bfd_link_hash_entry *pe_undef_found_sym; |
static bfd_boolean |
pe_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf) |
{ |
int sl; |
char *string = inf; |
const char *hs = h->root.string; |
sl = strlen (string); |
if (h->type == bfd_link_hash_defined |
&& ((*hs == '@' && *string == '_' |
&& strncmp (hs + 1, string + 1, sl - 1) == 0) |
|| strncmp (hs, string, sl) == 0) |
&& h->root.string[sl] == '@') |
{ |
pe_undef_found_sym = h; |
return FALSE; |
} |
return TRUE; |
} |
static void |
pe_fixup_stdcalls (void) |
{ |
static int gave_warning_message = 0; |
struct bfd_link_hash_entry *undef, *sym; |
if (pe_dll_extra_pe_debug) |
printf ("%s\n", __FUNCTION__); |
for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) |
if (undef->type == bfd_link_hash_undefined) |
{ |
char* at = strchr (undef->root.string, '@'); |
int lead_at = (*undef->root.string == '@'); |
if (lead_at) |
at = strchr (undef->root.string + 1, '@'); |
if (at || lead_at) |
{ |
/* The symbol is a stdcall symbol, so let's look for a |
cdecl symbol with the same name and resolve to that. */ |
char *cname = xstrdup (undef->root.string); |
if (lead_at) |
*cname = '_'; |
at = strchr (cname, '@'); |
if (at) |
*at = 0; |
sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); |
if (sym && sym->type == bfd_link_hash_defined) |
{ |
undef->type = bfd_link_hash_defined; |
undef->u.def.value = sym->u.def.value; |
undef->u.def.section = sym->u.def.section; |
if (pe_enable_stdcall_fixup == -1) |
{ |
einfo (_("Warning: resolving %s by linking to %s\n"), |
undef->root.string, cname); |
if (! gave_warning_message) |
{ |
gave_warning_message = 1; |
einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); |
einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); |
} |
} |
} |
} |
else |
{ |
/* The symbol is a cdecl symbol, so we look for stdcall |
symbols - which means scanning the whole symbol table. */ |
pe_undef_found_sym = 0; |
bfd_link_hash_traverse (link_info.hash, pe_undef_cdecl_match, |
(char *) undef->root.string); |
sym = pe_undef_found_sym; |
if (sym) |
{ |
undef->type = bfd_link_hash_defined; |
undef->u.def.value = sym->u.def.value; |
undef->u.def.section = sym->u.def.section; |
if (pe_enable_stdcall_fixup == -1) |
{ |
einfo (_("Warning: resolving %s by linking to %s\n"), |
undef->root.string, sym->root.string); |
if (! gave_warning_message) |
{ |
gave_warning_message = 1; |
einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); |
einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); |
} |
} |
} |
} |
} |
} |
static int |
make_import_fixup (arelent *rel, asection *s) |
{ |
struct bfd_symbol *sym = *rel->sym_ptr_ptr; |
char addend[4]; |
if (pe_dll_extra_pe_debug) |
printf ("arelent: %s@%#lx: add=%li\n", sym->name, |
(unsigned long) rel->address, (long) rel->addend); |
if (! bfd_get_section_contents (s->owner, s, addend, rel->address, sizeof (addend))) |
einfo (_("%C: Cannot get section contents - auto-import exception\n"), |
s->owner, s, rel->address); |
pe_create_import_fixup (rel, s, bfd_get_32 (s->owner, addend)); |
return 1; |
} |
static void |
pe_find_data_imports (void) |
{ |
struct bfd_link_hash_entry *undef, *sym; |
if (link_info.pei386_auto_import == 0) |
return; |
for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) |
{ |
if (undef->type == bfd_link_hash_undefined) |
{ |
/* C++ symbols are *long*. */ |
char buf[4096]; |
if (pe_dll_extra_pe_debug) |
printf ("%s:%s\n", __FUNCTION__, undef->root.string); |
sprintf (buf, "__imp_%s", undef->root.string); |
sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); |
if (sym && sym->type == bfd_link_hash_defined) |
{ |
bfd *b = sym->u.def.section->owner; |
asymbol **symbols; |
int nsyms, i; |
if (link_info.pei386_auto_import == -1) |
{ |
static bfd_boolean warned = FALSE; |
info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), |
undef->root.string, buf); |
/* PR linker/4844. */ |
if (! warned) |
{ |
warned = TRUE; |
einfo (_("%P: warning: auto-importing has been activated without --enable-auto-import specified on the command line.\nThis should work unless it involves constant data structures referencing symbols from auto-imported DLLs.\n")); |
} |
} |
if (!bfd_generic_link_read_symbols (b)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), b); |
return; |
} |
symbols = bfd_get_outsymbols (b); |
nsyms = bfd_get_symcount (b); |
for (i = 0; i < nsyms; i++) |
{ |
if (! CONST_STRNEQ (symbols[i]->name, |
U ("_head_"))) |
continue; |
if (pe_dll_extra_pe_debug) |
printf ("->%s\n", symbols[i]->name); |
pe_data_import_dll = (char *) (symbols[i]->name |
+ U_SIZE ("_head_") - 1); |
break; |
} |
pe_walk_relocs_of_symbol (&link_info, undef->root.string, |
make_import_fixup); |
/* Let's differentiate it somehow from defined. */ |
undef->type = bfd_link_hash_defweak; |
/* We replace original name with __imp_ prefixed, this |
1) may trash memory 2) leads to duplicate symbol generation. |
Still, IMHO it's better than having name poluted. */ |
undef->root.string = sym->root.string; |
undef->u.def.value = sym->u.def.value; |
undef->u.def.section = sym->u.def.section; |
} |
} |
} |
} |
static bfd_boolean |
pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) |
{ |
printf ("+%s\n", h->string); |
return TRUE; |
} |
#endif /* DLL_SUPPORT */ |
static void |
debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj) |
{ |
int *found = (int *) obj; |
if (strncmp (".debug_", sect->name, sizeof (".debug_") - 1) == 0) |
*found = 1; |
} |
static void |
gld_i386pe_after_open (void) |
{ |
after_open_default (); |
#ifdef DLL_SUPPORT |
if (pe_dll_extra_pe_debug) |
{ |
bfd *a; |
struct bfd_link_hash_entry *sym; |
printf ("%s()\n", __FUNCTION__); |
for (sym = link_info.hash->undefs; sym; sym=sym->u.undef.next) |
printf ("-%s\n", sym->root.string); |
bfd_hash_traverse (&link_info.hash->table, pr_sym, NULL); |
for (a = link_info.input_bfds; a; a = a->link_next) |
printf ("*%s\n",a->filename); |
} |
#endif |
/* Pass the wacky PE command line options into the output bfd. |
FIXME: This should be done via a function, rather than by |
including an internal BFD header. */ |
if (coff_data (link_info.output_bfd) == NULL |
|| coff_data (link_info.output_bfd)->pe == 0) |
einfo (_("%F%P: cannot perform PE operations on non PE output file '%B'.\n"), |
link_info.output_bfd); |
pe_data (link_info.output_bfd)->pe_opthdr = pe; |
pe_data (link_info.output_bfd)->dll = init[DLLOFF].value; |
pe_data (link_info.output_bfd)->real_flags |= real_flags; |
pe_data (link_info.output_bfd)->insert_timestamp = insert_timestamp; |
/* At this point we must decide whether to use long section names |
in the output or not. If the user hasn't explicitly specified |
on the command line, we leave it to the default for the format |
(object files yes, image files no), except if there is debug |
information present; GDB relies on the long section names to |
find it, so enable it in that case. */ |
if (pe_use_coff_long_section_names < 0 && link_info.strip == strip_none) |
{ |
/* Iterate over all sections of all input BFDs, checking |
for any that begin 'debug_' and are long names. */ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
int found_debug = 0; |
bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug); |
if (found_debug) |
{ |
pe_use_coff_long_section_names = 1; |
break; |
} |
} |
} |
pe_output_file_set_long_section_names (link_info.output_bfd); |
#ifdef DLL_SUPPORT |
if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */ |
pe_fixup_stdcalls (); |
pe_process_import_defs (link_info.output_bfd, &link_info); |
pe_find_data_imports (); |
/* As possibly new symbols are added by imports, we rerun |
stdcall/fastcall fixup here. */ |
if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */ |
pe_fixup_stdcalls (); |
#if defined (TARGET_IS_i386pe) || defined (TARGET_IS_armpe) || defined (TARGET_IS_arm_epoc_pe) || defined (TARGET_IS_arm_wince_pe) |
if (!link_info.relocatable) |
pe_dll_build_sections (link_info.output_bfd, &link_info); |
#else |
if (link_info.shared) |
pe_dll_build_sections (link_info.output_bfd, &link_info); |
else |
pe_exe_build_sections (link_info.output_bfd, &link_info); |
#endif |
#endif /* DLL_SUPPORT */ |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) |
if (strstr (bfd_get_target (link_info.output_bfd), "arm") == NULL) |
{ |
/* The arm backend needs special fields in the output hash structure. |
These will only be created if the output format is an arm format, |
hence we do not support linking and changing output formats at the |
same time. Use a link followed by objcopy to change output formats. */ |
einfo ("%F%X%P: error: cannot change output format whilst linking ARM binaries\n"); |
return; |
} |
{ |
/* Find a BFD that can hold the interworking stubs. */ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (bfd_arm_get_bfd_for_interworking (is->the_bfd, & link_info)) |
break; |
} |
} |
#endif |
{ |
/* This next chunk of code tries to detect the case where you have |
two import libraries for the same DLL (specifically, |
symbolically linking libm.a and libc.a in cygwin to |
libcygwin.a). In those cases, it's possible for function |
thunks from the second implib to be used but without the |
head/tail objects, causing an improper import table. We detect |
those cases and rename the "other" import libraries to match |
the one the head/tail come from, so that the linker will sort |
things nicely and produce a valid import table. */ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (is->the_bfd->my_archive) |
{ |
int idata2 = 0, reloc_count=0, is_imp = 0; |
asection *sec; |
/* See if this is an import library thunk. */ |
for (sec = is->the_bfd->sections; sec; sec = sec->next) |
{ |
if (strcmp (sec->name, ".idata$2") == 0) |
idata2 = 1; |
if (CONST_STRNEQ (sec->name, ".idata$")) |
is_imp = 1; |
reloc_count += sec->reloc_count; |
} |
if (is_imp && !idata2 && reloc_count) |
{ |
/* It is, look for the reference to head and see if it's |
from our own library. */ |
for (sec = is->the_bfd->sections; sec; sec = sec->next) |
{ |
int i; |
long relsize; |
asymbol **symbols; |
arelent **relocs; |
int nrelocs; |
relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec); |
if (relsize < 1) |
break; |
if (!bfd_generic_link_read_symbols (is->the_bfd)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), |
is->the_bfd); |
return; |
} |
symbols = bfd_get_outsymbols (is->the_bfd); |
relocs = xmalloc ((size_t) relsize); |
nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec, |
relocs, symbols); |
if (nrelocs < 0) |
{ |
free (relocs); |
einfo ("%X%P: unable to process relocs: %E\n"); |
return; |
} |
for (i = 0; i < nrelocs; i++) |
{ |
struct bfd_symbol *s; |
struct bfd_link_hash_entry * blhe; |
char *other_bfd_filename; |
char *n; |
s = (relocs[i]->sym_ptr_ptr)[0]; |
if (s->flags & BSF_LOCAL) |
continue; |
/* Thunk section with reloc to another bfd. */ |
blhe = bfd_link_hash_lookup (link_info.hash, |
s->name, |
FALSE, FALSE, TRUE); |
if (blhe == NULL |
|| blhe->type != bfd_link_hash_defined) |
continue; |
other_bfd_filename |
= blhe->u.def.section->owner->my_archive |
? bfd_get_filename (blhe->u.def.section->owner->my_archive) |
: bfd_get_filename (blhe->u.def.section->owner); |
if (filename_cmp (bfd_get_filename |
(is->the_bfd->my_archive), |
other_bfd_filename) == 0) |
continue; |
/* Rename this implib to match the other one. */ |
n = xmalloc (strlen (other_bfd_filename) + 1); |
strcpy (n, other_bfd_filename); |
is->the_bfd->my_archive->filename = n; |
} |
free (relocs); |
/* Note - we do not free the symbols, |
they are now cached in the BFD. */ |
} |
} |
} |
} |
} |
{ |
int is_ms_arch = 0; |
bfd *cur_arch = 0; |
lang_input_statement_type *is2; |
lang_input_statement_type *is3; |
/* Careful - this is a shell script. Watch those dollar signs! */ |
/* Microsoft import libraries have every member named the same, |
and not in the right order for us to link them correctly. We |
must detect these and rename the members so that they'll link |
correctly. There are three types of objects: the head, the |
thunks, and the sentinel(s). The head is easy; it's the one |
with idata2. We assume that the sentinels won't have relocs, |
and the thunks will. It's easier than checking the symbol |
table for external references. */ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (is->the_bfd->my_archive) |
{ |
char *pnt; |
bfd *arch = is->the_bfd->my_archive; |
if (cur_arch != arch) |
{ |
cur_arch = arch; |
is_ms_arch = 1; |
for (is3 = is; |
is3 && is3->the_bfd->my_archive == arch; |
is3 = (lang_input_statement_type *) is3->next) |
{ |
/* A MS dynamic import library can also contain static |
members, so look for the first element with a .dll |
extension, and use that for the remainder of the |
comparisons. */ |
pnt = strrchr (is3->the_bfd->filename, '.'); |
if (pnt != NULL && filename_cmp (pnt, ".dll") == 0) |
break; |
} |
if (is3 == NULL) |
is_ms_arch = 0; |
else |
{ |
/* OK, found one. Now look to see if the remaining |
(dynamic import) members use the same name. */ |
for (is2 = is; |
is2 && is2->the_bfd->my_archive == arch; |
is2 = (lang_input_statement_type *) is2->next) |
{ |
/* Skip static members, ie anything with a .obj |
extension. */ |
pnt = strrchr (is2->the_bfd->filename, '.'); |
if (pnt != NULL && filename_cmp (pnt, ".obj") == 0) |
continue; |
if (filename_cmp (is3->the_bfd->filename, |
is2->the_bfd->filename)) |
{ |
is_ms_arch = 0; |
break; |
} |
} |
} |
} |
/* This fragment might have come from an .obj file in a Microsoft |
import, and not an actual import record. If this is the case, |
then leave the filename alone. */ |
pnt = strrchr (is->the_bfd->filename, '.'); |
if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0)) |
{ |
int idata2 = 0, reloc_count=0; |
asection *sec; |
char *new_name, seq; |
for (sec = is->the_bfd->sections; sec; sec = sec->next) |
{ |
if (strcmp (sec->name, ".idata$2") == 0) |
idata2 = 1; |
reloc_count += sec->reloc_count; |
} |
if (idata2) /* .idata2 is the TOC */ |
seq = 'a'; |
else if (reloc_count > 0) /* thunks */ |
seq = 'b'; |
else /* sentinel */ |
seq = 'c'; |
new_name = xmalloc (strlen (is->the_bfd->filename) + 3); |
sprintf (new_name, "%s.%c", is->the_bfd->filename, seq); |
is->the_bfd->filename = new_name; |
new_name = xmalloc (strlen (is->filename) + 3); |
sprintf (new_name, "%s.%c", is->filename, seq); |
is->filename = new_name; |
} |
} |
} |
} |
{ |
/* The following chunk of code tries to identify jump stubs in |
import libraries which are dead code and eliminates them |
from the final link. For each exported symbol <sym>, there |
is a object file in the import library with a .text section |
and several .idata$* sections. The .text section contains the |
symbol definition for <sym> which is a jump stub of the form |
jmp *__imp_<sym>. The .idata$5 contains the symbol definition |
for __imp_<sym> which is the address of the slot for <sym> in |
the import address table. When a symbol is imported explicitly |
using __declspec(dllimport) declaration, the compiler generates |
a reference to __imp_<sym> which directly resolves to the |
symbol in .idata$5, in which case the jump stub code is not |
needed. The following code tries to identify jump stub sections |
in import libraries which are not referred to by anyone and |
marks them for exclusion from the final link. */ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (is->the_bfd->my_archive) |
{ |
int is_imp = 0; |
asection *sec, *stub_sec = NULL; |
/* See if this is an import library thunk. */ |
for (sec = is->the_bfd->sections; sec; sec = sec->next) |
{ |
if (strncmp (sec->name, ".idata$", 7) == 0) |
is_imp = 1; |
/* The section containing the jmp stub has code |
and has a reloc. */ |
if ((sec->flags & SEC_CODE) && sec->reloc_count) |
stub_sec = sec; |
} |
if (is_imp && stub_sec) |
{ |
asymbol **symbols; |
long nsyms, src_count; |
struct bfd_link_hash_entry * blhe; |
if (!bfd_generic_link_read_symbols (is->the_bfd)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), |
is->the_bfd); |
return; |
} |
symbols = bfd_get_outsymbols (is->the_bfd); |
nsyms = bfd_get_symcount (is->the_bfd); |
for (src_count = 0; src_count < nsyms; src_count++) |
{ |
if (symbols[src_count]->section->id == stub_sec->id) |
{ |
/* This symbol belongs to the section containing |
the stub. */ |
blhe = bfd_link_hash_lookup (link_info.hash, |
symbols[src_count]->name, |
FALSE, FALSE, TRUE); |
/* If the symbol in the stub section has no other |
undefined references, exclude the stub section |
from the final link. */ |
if (blhe != NULL |
&& blhe->type == bfd_link_hash_defined |
&& blhe->u.undef.next == NULL |
&& blhe != link_info.hash->undefs_tail) |
stub_sec->flags |= SEC_EXCLUDE; |
} |
} |
} |
} |
} |
} |
} |
static void |
gld_i386pe_before_allocation (void) |
{ |
#ifdef TARGET_IS_ppcpe |
/* Here we rummage through the found bfds to collect toc information. */ |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (!ppc_process_before_allocation (is->the_bfd, &link_info)) |
{ |
/* xgettext:c-format */ |
einfo (_("Errors encountered processing file %s\n"), is->filename); |
} |
} |
} |
/* We have seen it all. Allocate it, and carry on. */ |
ppc_allocate_toc_section (&link_info); |
#endif /* TARGET_IS_ppcpe */ |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) |
/* FIXME: we should be able to set the size of the interworking stub |
section. |
Here we rummage through the found bfds to collect glue |
information. FIXME: should this be based on a command line |
option? krk@cygnus.com. */ |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
if (! bfd_arm_process_before_allocation |
(is->the_bfd, & link_info, support_old_code)) |
{ |
/* xgettext:c-format */ |
einfo (_("Errors encountered processing file %s for interworking\n"), |
is->filename); |
} |
} |
} |
/* We have seen it all. Allocate it, and carry on. */ |
bfd_arm_allocate_interworking_sections (& link_info); |
#endif /* TARGET_IS_armpe || TARGET_IS_arm_epoc_pe || TARGET_IS_arm_wince_pe */ |
before_allocation_default (); |
} |
#ifdef DLL_SUPPORT |
/* This is called when an input file isn't recognized as a BFD. We |
check here for .DEF files and pull them in automatically. */ |
static int |
saw_option (char *option) |
{ |
int i; |
for (i = 0; init[i].ptr; i++) |
if (strcmp (GET_INIT_SYMBOL_NAME (i), option) == 0) |
return init[i].inited; |
return 0; |
} |
#endif /* DLL_SUPPORT */ |
static bfd_boolean |
gld_i386pe_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) |
{ |
#ifdef DLL_SUPPORT |
const char *ext = entry->filename + strlen (entry->filename) - 4; |
if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0) |
{ |
pe_def_file = def_file_parse (entry->filename, pe_def_file); |
if (pe_def_file) |
{ |
int i, buflen=0, len; |
char *buf; |
for (i = 0; i < pe_def_file->num_exports; i++) |
{ |
len = strlen (pe_def_file->exports[i].internal_name); |
if (buflen < len + 2) |
buflen = len + 2; |
} |
buf = xmalloc (buflen); |
for (i = 0; i < pe_def_file->num_exports; i++) |
{ |
struct bfd_link_hash_entry *h; |
sprintf (buf, "%s%s", U (""), |
pe_def_file->exports[i].internal_name); |
h = bfd_link_hash_lookup (link_info.hash, buf, TRUE, TRUE, TRUE); |
if (h == (struct bfd_link_hash_entry *) NULL) |
einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); |
if (h->type == bfd_link_hash_new) |
{ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = NULL; |
bfd_link_add_undef (link_info.hash, h); |
} |
} |
free (buf); |
/* def_file_print (stdout, pe_def_file); */ |
if (pe_def_file->is_dll == 1) |
link_info.shared = 1; |
if (pe_def_file->base_address != (bfd_vma)(-1)) |
{ |
pe.ImageBase |
= pe_data (link_info.output_bfd)->pe_opthdr.ImageBase |
= init[IMAGEBASEOFF].value |
= pe_def_file->base_address; |
init[IMAGEBASEOFF].inited = 1; |
if (image_base_statement) |
image_base_statement->exp |
= exp_assign ("__image_base__", exp_intop (pe.ImageBase), |
FALSE); |
} |
if (pe_def_file->stack_reserve != -1 |
&& ! saw_option ("__size_of_stack_reserve__")) |
{ |
pe.SizeOfStackReserve = pe_def_file->stack_reserve; |
if (pe_def_file->stack_commit != -1) |
pe.SizeOfStackCommit = pe_def_file->stack_commit; |
} |
if (pe_def_file->heap_reserve != -1 |
&& ! saw_option ("__size_of_heap_reserve__")) |
{ |
pe.SizeOfHeapReserve = pe_def_file->heap_reserve; |
if (pe_def_file->heap_commit != -1) |
pe.SizeOfHeapCommit = pe_def_file->heap_commit; |
} |
return TRUE; |
} |
} |
#endif |
return FALSE; |
} |
static bfd_boolean |
gld_i386pe_recognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) |
{ |
#ifdef DLL_SUPPORT |
#ifdef TARGET_IS_i386pe |
pe_dll_id_target ("pei-i386"); |
#endif |
#ifdef TARGET_IS_shpe |
pe_dll_id_target ("pei-shl"); |
#endif |
#ifdef TARGET_IS_armpe |
pe_dll_id_target ("pei-arm-little"); |
#endif |
#ifdef TARGET_IS_arm_epoc_pe |
pe_dll_id_target ("epoc-pei-arm-little"); |
#endif |
#ifdef TARGET_IS_arm_wince_pe |
pe_dll_id_target ("pei-arm-wince-little"); |
#endif |
if (pe_bfd_is_dll (entry->the_bfd)) |
return pe_implied_import_dll (entry->filename); |
#endif |
return FALSE; |
} |
static void |
gld_i386pe_finish (void) |
{ |
#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) |
struct bfd_link_hash_entry * h; |
if (thumb_entry_symbol != NULL) |
{ |
h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, |
FALSE, FALSE, TRUE); |
if (h != (struct bfd_link_hash_entry *) NULL |
&& (h->type == bfd_link_hash_defined |
|| h->type == bfd_link_hash_defweak) |
&& h->u.def.section->output_section != NULL) |
{ |
static char buffer[32]; |
bfd_vma val; |
/* Special procesing is required for a Thumb entry symbol. The |
bottom bit of its address must be set. */ |
val = (h->u.def.value |
+ bfd_get_section_vma (link_info.output_bfd, |
h->u.def.section->output_section) |
+ h->u.def.section->output_offset); |
val |= 1; |
/* Now convert this value into a string and store it in entry_symbol |
where the lang_finish() function will pick it up. */ |
buffer[0] = '0'; |
buffer[1] = 'x'; |
sprintf_vma (buffer + 2, val); |
if (entry_symbol.name != NULL && entry_from_cmdline) |
einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), |
thumb_entry_symbol, entry_symbol.name); |
entry_symbol.name = buffer; |
} |
else |
einfo (_("%P: warning: cannot find thumb start symbol %s\n"), thumb_entry_symbol); |
} |
#endif /* defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) */ |
finish_default (); |
#ifdef DLL_SUPPORT |
if (link_info.shared |
#if !defined(TARGET_IS_shpe) |
|| (!link_info.relocatable && pe_def_file->num_exports != 0) |
#endif |
) |
{ |
pe_dll_fill_sections (link_info.output_bfd, &link_info); |
if (pe_implib_filename) |
pe_dll_generate_implib (pe_def_file, pe_implib_filename, &link_info); |
} |
#if defined(TARGET_IS_shpe) |
/* ARM doesn't need relocs. */ |
else |
{ |
pe_exe_fill_sections (link_info.output_bfd, &link_info); |
} |
#endif |
if (pe_out_def_filename) |
pe_dll_generate_def_file (pe_out_def_filename); |
#endif /* DLL_SUPPORT */ |
/* I don't know where .idata gets set as code, but it shouldn't be. */ |
{ |
asection *asec = bfd_get_section_by_name (link_info.output_bfd, ".idata"); |
if (asec) |
{ |
asec->flags &= ~SEC_CODE; |
asec->flags |= SEC_DATA; |
} |
} |
} |
/* Place an orphan section. |
We use this to put sections in a reasonable place in the file, and |
to ensure that they are aligned as required. |
We handle grouped sections here as well. A section named .foo$nn |
goes into the output section .foo. All grouped sections are sorted |
by name. |
Grouped sections for the default sections are handled by the |
default linker script using wildcards, and are sorted by |
sort_sections. */ |
static lang_output_section_statement_type * |
gld_i386pe_place_orphan (asection *s, |
const char *secname, |
int constraint) |
{ |
const char *orig_secname = secname; |
char *dollar = NULL; |
lang_output_section_statement_type *os; |
lang_statement_list_type add_child; |
lang_output_section_statement_type *match_by_name = NULL; |
lang_statement_union_type **pl; |
/* Look through the script to see where to place this section. */ |
if (!link_info.relocatable |
&& (dollar = strchr (secname, '$')) != NULL) |
{ |
size_t len = dollar - secname; |
char *newname = xmalloc (len + 1); |
memcpy (newname, secname, len); |
newname[len] = '\0'; |
secname = newname; |
} |
lang_list_init (&add_child); |
os = NULL; |
if (constraint == 0) |
for (os = lang_output_section_find (secname); |
os != NULL; |
os = next_matching_output_section_statement (os, 0)) |
{ |
/* If we don't match an existing output section, tell |
lang_insert_orphan to create a new output section. */ |
constraint = SPECIAL; |
if (os->bfd_section != NULL |
&& (os->bfd_section->flags == 0 |
|| ((s->flags ^ os->bfd_section->flags) |
& (SEC_LOAD | SEC_ALLOC)) == 0)) |
{ |
/* We already have an output section statement with this |
name, and its bfd section has compatible flags. |
If the section already exists but does not have any flags set, |
then it has been created by the linker, probably as a result of |
a --section-start command line switch. */ |
lang_add_section (&add_child, s, NULL, os); |
break; |
} |
/* Save unused output sections in case we can match them |
against orphans later. */ |
if (os->bfd_section == NULL) |
match_by_name = os; |
} |
/* If we didn't match an active output section, see if we matched an |
unused one and use that. */ |
if (os == NULL && match_by_name) |
{ |
lang_add_section (&match_by_name->children, s, NULL, match_by_name); |
return match_by_name; |
} |
if (os == NULL) |
{ |
static struct orphan_save hold[] = |
{ |
{ ".text", |
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, |
0, 0, 0, 0 }, |
{ ".idata", |
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, |
0, 0, 0, 0 }, |
{ ".rdata", |
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, |
0, 0, 0, 0 }, |
{ ".data", |
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, |
0, 0, 0, 0 }, |
{ ".bss", |
SEC_ALLOC, |
0, 0, 0, 0 } |
}; |
enum orphan_save_index |
{ |
orphan_text = 0, |
orphan_idata, |
orphan_rodata, |
orphan_data, |
orphan_bss |
}; |
static int orphan_init_done = 0; |
struct orphan_save *place; |
lang_output_section_statement_type *after; |
etree_type *address; |
if (!orphan_init_done) |
{ |
struct orphan_save *ho; |
for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) |
if (ho->name != NULL) |
{ |
ho->os = lang_output_section_find (ho->name); |
if (ho->os != NULL && ho->os->flags == 0) |
ho->os->flags = ho->flags; |
} |
orphan_init_done = 1; |
} |
/* Try to put the new output section in a reasonable place based |
on the section name and section flags. */ |
place = NULL; |
if ((s->flags & SEC_ALLOC) == 0) |
; |
else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) |
place = &hold[orphan_bss]; |
else if ((s->flags & SEC_READONLY) == 0) |
place = &hold[orphan_data]; |
else if ((s->flags & SEC_CODE) == 0) |
{ |
place = (!strncmp (secname, ".idata$", 7) ? &hold[orphan_idata] |
: &hold[orphan_rodata]); |
} |
else |
place = &hold[orphan_text]; |
after = NULL; |
if (place != NULL) |
{ |
if (place->os == NULL) |
place->os = lang_output_section_find (place->name); |
after = place->os; |
if (after == NULL) |
after = lang_output_section_find_by_flags (s, &place->os, NULL); |
if (after == NULL) |
/* *ABS* is always the first output section statement. */ |
after = (&lang_output_section_statement.head |
->output_section_statement); |
} |
/* All sections in an executable must be aligned to a page boundary. |
In a relocatable link, just preserve the incoming alignment; the |
address is discarded by lang_insert_orphan in that case, anyway. */ |
address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); |
os = lang_insert_orphan (s, secname, constraint, after, place, address, |
&add_child); |
if (link_info.relocatable) |
{ |
os->section_alignment = s->alignment_power; |
os->bfd_section->alignment_power = s->alignment_power; |
} |
} |
/* If the section name has a '$', sort it with the other '$' |
sections. */ |
for (pl = &os->children.head; *pl != NULL; pl = &(*pl)->header.next) |
{ |
lang_input_section_type *ls; |
const char *lname; |
if ((*pl)->header.type != lang_input_section_enum) |
continue; |
ls = &(*pl)->input_section; |
lname = bfd_get_section_name (ls->section->owner, ls->section); |
if (strchr (lname, '$') != NULL |
&& (dollar == NULL || strcmp (orig_secname, lname) < 0)) |
break; |
} |
if (add_child.head != NULL) |
{ |
*add_child.tail = *pl; |
*pl = add_child.head; |
} |
return os; |
} |
static bfd_boolean |
gld_i386pe_open_dynamic_archive |
(const char *arch ATTRIBUTE_UNUSED, |
search_dirs_type *search, |
lang_input_statement_type *entry) |
{ |
static const struct |
{ |
const char * format; |
bfd_boolean use_prefix; |
} |
libname_fmt [] = |
{ |
/* Preferred explicit import library for dll's. */ |
{ "lib%s.dll.a", FALSE }, |
/* Alternate explicit import library for dll's. */ |
{ "%s.dll.a", FALSE }, |
/* "libfoo.a" could be either an import lib or a static lib. |
For backwards compatibility, libfoo.a needs to precede |
libfoo.dll and foo.dll in the search. */ |
{ "lib%s.a", FALSE }, |
/* The 'native' spelling of an import lib name is "foo.lib". */ |
{ "%s.lib", FALSE }, |
#ifdef DLL_SUPPORT |
/* Try "<prefix>foo.dll" (preferred dll name, if specified). */ |
{ "%s%s.dll", TRUE }, |
#endif |
/* Try "libfoo.dll" (default preferred dll name). */ |
{ "lib%s.dll", FALSE }, |
/* Finally try 'native' dll name "foo.dll". */ |
{ "%s.dll", FALSE }, |
/* Note: If adding more formats to this table, make sure to check to |
see if their length is longer than libname_fmt[0].format, and if |
so, update the call to xmalloc() below. */ |
{ NULL, FALSE } |
}; |
static unsigned int format_max_len = 0; |
const char * filename; |
char * full_string; |
char * base_string; |
unsigned int i; |
if (! entry->flags.maybe_archive) |
return FALSE; |
filename = entry->filename; |
if (format_max_len == 0) |
/* We need to allow space in the memory that we are going to allocate |
for the characters in the format string. Since the format array is |
static we only need to calculate this information once. In theory |
this value could also be computed statically, but this introduces |
the possibility for a discrepancy and hence a possible memory |
corruption. The lengths we compute here will be too long because |
they will include any formating characters (%s) in the strings, but |
this will not matter. */ |
for (i = 0; libname_fmt[i].format; i++) |
if (format_max_len < strlen (libname_fmt[i].format)) |
format_max_len = strlen (libname_fmt[i].format); |
full_string = xmalloc (strlen (search->name) |
+ strlen (filename) |
+ format_max_len |
#ifdef DLL_SUPPORT |
+ (pe_dll_search_prefix |
? strlen (pe_dll_search_prefix) : 0) |
#endif |
/* Allow for the terminating NUL and for the path |
separator character that is inserted between |
search->name and the start of the format string. */ |
+ 2); |
sprintf (full_string, "%s/", search->name); |
base_string = full_string + strlen (full_string); |
for (i = 0; libname_fmt[i].format; i++) |
{ |
#ifdef DLL_SUPPORT |
if (libname_fmt[i].use_prefix) |
{ |
if (!pe_dll_search_prefix) |
continue; |
sprintf (base_string, libname_fmt[i].format, pe_dll_search_prefix, filename); |
} |
else |
#endif |
sprintf (base_string, libname_fmt[i].format, filename); |
if (ldfile_try_open_bfd (full_string, entry)) |
break; |
} |
if (!libname_fmt[i].format) |
{ |
free (full_string); |
return FALSE; |
} |
entry->filename = full_string; |
return TRUE; |
} |
static int |
gld_i386pe_find_potential_libraries |
(char *name, lang_input_statement_type *entry) |
{ |
return ldfile_open_file_search (name, entry, "", ".lib"); |
} |
static char * |
gld_i386pe_get_script (int *isfile) |
{ |
*isfile = 0; |
if (link_info.relocatable && config.build_constructors) |
return |
"/* Script for ld -Ur: link w/out relocation, do create constructors */\n\ |
OUTPUT_FORMAT(pe-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
.text :\n\ |
{\n\ |
*(.text)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;\n\ |
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);\n\ |
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;\n\ |
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data :\n\ |
{\n\ |
*(.data)\n\ |
*(.data2)\n" |
" *(.jcr)\n\ |
}\n\ |
.rdata :\n\ |
{\n\ |
*(.rdata)\n\ |
*(.rdata_runtime_pseudo_reloc)\n\ |
}\n\ |
.eh_frame :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss :\n\ |
{\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
}\n\ |
.edata :\n\ |
{\n\ |
*(.edata)\n\ |
}\n\ |
/DISCARD/ :\n" |
" {\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n\ |
*(.drectve)\n\ |
}\n\ |
.idata :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
}\n\ |
.CRT :\n\ |
{\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls :\n\ |
{\n\ |
}\n\ |
.endjunk :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n" |
" }\n\ |
.rsrc :\n\ |
{\n\ |
*(.rsrc)\n\ |
}\n\ |
.reloc :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges :\n\ |
{\n\ |
*(.debug_aranges)\n" |
" }\n\ |
.zdebug_aranges :\n\ |
{\n\ |
*(.zdebug_aranges)\n\ |
}\n\ |
.debug_pubnames :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info :\n\ |
{\n\ |
*(.debug_info)\n\ |
}\n\ |
.zdebug_info :\n\ |
{\n\ |
*(.zdebug_info)\n\ |
}\n\ |
.debug_abbrev :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types :\n\ |
{\n\ |
*(.debug_types)\n\ |
}\n\ |
.zdebug_types :\n\ |
{\n\ |
*(.zdebug_types)\n\ |
}\n\ |
}\n\n" |
; else if (link_info.relocatable) return |
"/* Script for ld -r: link without relocation */\n\ |
OUTPUT_FORMAT(pe-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
.text :\n\ |
{\n\ |
*(.text)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data :\n\ |
{\n\ |
*(.data)\n\ |
*(.data2)\n\ |
*(.jcr)\n\ |
}\n\ |
.rdata :\n\ |
{\n" |
" *(.rdata)\n\ |
*(.rdata_runtime_pseudo_reloc)\n\ |
}\n\ |
.eh_frame :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss :\n\ |
{\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
}\n\ |
.edata :\n\ |
{\n\ |
*(.edata)\n\ |
}\n\ |
/DISCARD/ :\n\ |
{\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n" |
" *(.drectve)\n\ |
}\n\ |
.idata :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
}\n\ |
.CRT :\n\ |
{\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls :\n\ |
{\n\ |
}\n\ |
.endjunk :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n\ |
}\n\ |
.rsrc :\n\ |
{\n\ |
*(.rsrc)\n" |
" }\n\ |
.reloc :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges :\n\ |
{\n\ |
*(.debug_aranges)\n\ |
}\n\ |
.zdebug_aranges :\n\ |
{\n\ |
*(.zdebug_aranges)\n" |
" }\n\ |
.debug_pubnames :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info :\n\ |
{\n\ |
*(.debug_info)\n\ |
}\n\ |
.zdebug_info :\n\ |
{\n\ |
*(.zdebug_info)\n\ |
}\n\ |
.debug_abbrev :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types :\n\ |
{\n\ |
*(.debug_types)\n\ |
}\n\ |
.zdebug_types :\n\ |
{\n\ |
*(.zdebug_types)\n\ |
}\n\ |
}\n\n" |
; else if (!config.text_read_only) return |
"/* Script for -N: mix text and data on same page; don't align data */\n\ |
OUTPUT_FORMAT(pei-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
/* Make the virtual address and file offset synced if the alignment is\n\ |
lower than the target page size. */\n\ |
. = SIZEOF_HEADERS;\n\ |
. = ALIGN(__section_alignment__);\n\ |
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :\n\ |
{\n\ |
*(.init)\n\ |
*(.text)\n\ |
*(SORT(.text$*))\n\ |
*(.text.*)\n\ |
*(.gnu.linkonce.t.*)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;\n\ |
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);\n\ |
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;\n\ |
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);\n\ |
*(.fini)\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
*(.gcc_exc)\n" |
" PROVIDE (etext = .);\n\ |
PROVIDE (_etext = .);\n\ |
*(.gcc_except_table)\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data BLOCK(__section_alignment__) :\n\ |
{\n\ |
__data_start__ = . ;\n\ |
*(.data)\n\ |
*(.data2)\n\ |
*(SORT(.data$*))\n\ |
*(.jcr)\n\ |
__data_end__ = . ;\n\ |
*(.data_cygwin_nocopy)\n\ |
}\n\ |
.rdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rdata)\n\ |
*(SORT(.rdata$*))\n\ |
__rt_psrelocs_start = .;\n\ |
*(.rdata_runtime_pseudo_reloc)\n" |
" __rt_psrelocs_end = .;\n\ |
}\n\ |
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
.eh_frame BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss BLOCK(__section_alignment__) :\n\ |
{\n\ |
__bss_start__ = . ;\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
__bss_end__ = . ;\n\ |
}\n\ |
.edata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.edata)\n" |
" }\n\ |
/DISCARD/ :\n\ |
{\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n\ |
*(.drectve)\n\ |
*(.note.GNU-stack)\n\ |
*(.gnu.lto_*)\n\ |
}\n\ |
.idata BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
SORT(*)(.idata$2)\n\ |
SORT(*)(.idata$3)\n\ |
/* These zeroes mark the end of the import list. */\n\ |
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);\n\ |
SORT(*)(.idata$4)\n\ |
__IAT_start__ = .;\n\ |
SORT(*)(.idata$5)\n\ |
__IAT_end__ = .;\n\ |
SORT(*)(.idata$6)\n\ |
SORT(*)(.idata$7)\n\ |
}\n" |
" .CRT BLOCK(__section_alignment__) :\n\ |
{\n\ |
___crt_xc_start__ = . ;\n\ |
*(SORT(.CRT$XC*)) /* C initialization */\n\ |
___crt_xc_end__ = . ;\n\ |
___crt_xi_start__ = . ;\n\ |
*(SORT(.CRT$XI*)) /* C++ initialization */\n\ |
___crt_xi_end__ = . ;\n\ |
___crt_xl_start__ = . ;\n\ |
*(SORT(.CRT$XL*)) /* TLS callbacks */\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
___crt_xp_start__ = . ;\n\ |
*(SORT(.CRT$XP*)) /* Pre-termination */\n\ |
___crt_xp_end__ = . ;\n\ |
___crt_xt_start__ = . ;\n\ |
*(SORT(.CRT$XT*)) /* Termination */\n\ |
___crt_xt_end__ = . ;\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls BLOCK(__section_alignment__) :\n\ |
{\n\ |
___tls_start__ = . ;\n\ |
*(.tls$AAA)\n\ |
*(.tls)\n\ |
*(.tls$)\n\ |
*(SORT(.tls$*))\n\ |
*(.tls$ZZZ)\n\ |
___tls_end__ = . ;\n\ |
}\n\ |
.endjunk BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n\ |
PROVIDE (end = .);\n\ |
PROVIDE ( _end = .);\n\ |
__end__ = .;\n\ |
}\n\ |
.rsrc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rsrc)\n\ |
*(SORT(.rsrc$*))\n\ |
}\n\ |
.reloc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_aranges)\n\ |
}\n\ |
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_aranges)\n\ |
}\n\ |
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_info .gnu.linkonce.wi.*)\n\ |
}\n\ |
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)\n\ |
}\n\ |
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
}\n\n" |
; else if (!config.magic_demand_paged) return |
"/* Script for -n: mix text and data on same page */\n\ |
OUTPUT_FORMAT(pei-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
/* Make the virtual address and file offset synced if the alignment is\n\ |
lower than the target page size. */\n\ |
. = SIZEOF_HEADERS;\n\ |
. = ALIGN(__section_alignment__);\n\ |
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :\n\ |
{\n\ |
*(.init)\n\ |
*(.text)\n\ |
*(SORT(.text$*))\n\ |
*(.text.*)\n\ |
*(.gnu.linkonce.t.*)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;\n\ |
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);\n\ |
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;\n\ |
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);\n\ |
*(.fini)\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
*(.gcc_exc)\n" |
" PROVIDE (etext = .);\n\ |
PROVIDE (_etext = .);\n\ |
*(.gcc_except_table)\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data BLOCK(__section_alignment__) :\n\ |
{\n\ |
__data_start__ = . ;\n\ |
*(.data)\n\ |
*(.data2)\n\ |
*(SORT(.data$*))\n\ |
*(.jcr)\n\ |
__data_end__ = . ;\n\ |
*(.data_cygwin_nocopy)\n\ |
}\n\ |
.rdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rdata)\n\ |
*(SORT(.rdata$*))\n\ |
__rt_psrelocs_start = .;\n\ |
*(.rdata_runtime_pseudo_reloc)\n" |
" __rt_psrelocs_end = .;\n\ |
}\n\ |
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
.eh_frame BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss BLOCK(__section_alignment__) :\n\ |
{\n\ |
__bss_start__ = . ;\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
__bss_end__ = . ;\n\ |
}\n\ |
.edata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.edata)\n" |
" }\n\ |
/DISCARD/ :\n\ |
{\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n\ |
*(.drectve)\n\ |
*(.note.GNU-stack)\n\ |
*(.gnu.lto_*)\n\ |
}\n\ |
.idata BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
SORT(*)(.idata$2)\n\ |
SORT(*)(.idata$3)\n\ |
/* These zeroes mark the end of the import list. */\n\ |
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);\n\ |
SORT(*)(.idata$4)\n\ |
__IAT_start__ = .;\n\ |
SORT(*)(.idata$5)\n\ |
__IAT_end__ = .;\n\ |
SORT(*)(.idata$6)\n\ |
SORT(*)(.idata$7)\n\ |
}\n" |
" .CRT BLOCK(__section_alignment__) :\n\ |
{\n\ |
___crt_xc_start__ = . ;\n\ |
*(SORT(.CRT$XC*)) /* C initialization */\n\ |
___crt_xc_end__ = . ;\n\ |
___crt_xi_start__ = . ;\n\ |
*(SORT(.CRT$XI*)) /* C++ initialization */\n\ |
___crt_xi_end__ = . ;\n\ |
___crt_xl_start__ = . ;\n\ |
*(SORT(.CRT$XL*)) /* TLS callbacks */\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
___crt_xp_start__ = . ;\n\ |
*(SORT(.CRT$XP*)) /* Pre-termination */\n\ |
___crt_xp_end__ = . ;\n\ |
___crt_xt_start__ = . ;\n\ |
*(SORT(.CRT$XT*)) /* Termination */\n\ |
___crt_xt_end__ = . ;\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls BLOCK(__section_alignment__) :\n\ |
{\n\ |
___tls_start__ = . ;\n\ |
*(.tls$AAA)\n\ |
*(.tls)\n\ |
*(.tls$)\n\ |
*(SORT(.tls$*))\n\ |
*(.tls$ZZZ)\n\ |
___tls_end__ = . ;\n\ |
}\n\ |
.endjunk BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n\ |
PROVIDE (end = .);\n\ |
PROVIDE ( _end = .);\n\ |
__end__ = .;\n\ |
}\n\ |
.rsrc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rsrc)\n\ |
*(SORT(.rsrc$*))\n\ |
}\n\ |
.reloc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_aranges)\n\ |
}\n\ |
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_aranges)\n\ |
}\n\ |
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_info .gnu.linkonce.wi.*)\n\ |
}\n\ |
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)\n\ |
}\n\ |
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
}\n\n" |
; else if (link_info.pei386_auto_import == 1 && (MERGE_RDATA_V2 || link_info.pei386_runtime_pseudo_reloc != 2)) return |
"/* Script for ld --enable-auto-import: Like the default script except read only data is placed into .data */\n\ |
OUTPUT_FORMAT(pei-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
/* Make the virtual address and file offset synced if the alignment is\n\ |
lower than the target page size. */\n\ |
. = SIZEOF_HEADERS;\n\ |
. = ALIGN(__section_alignment__);\n\ |
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :\n\ |
{\n\ |
*(.init)\n\ |
*(.text)\n\ |
*(SORT(.text$*))\n\ |
*(.text.*)\n\ |
*(.gnu.linkonce.t.*)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;\n\ |
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);\n\ |
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;\n\ |
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);\n\ |
*(.fini)\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
*(.gcc_exc)\n" |
" PROVIDE (etext = .);\n\ |
PROVIDE (_etext = .);\n\ |
*(.gcc_except_table)\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data BLOCK(__section_alignment__) :\n\ |
{\n\ |
__data_start__ = . ;\n\ |
*(.data)\n\ |
*(.data2)\n\ |
*(SORT(.data$*))\n\ |
*(.rdata)\n\ |
*(SORT(.rdata$*))\n\ |
*(.jcr)\n\ |
__data_end__ = . ;\n\ |
*(.data_cygwin_nocopy)\n\ |
}\n\ |
.rdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
__rt_psrelocs_start = .;\n\ |
*(.rdata_runtime_pseudo_reloc)\n" |
" __rt_psrelocs_end = .;\n\ |
}\n\ |
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
.eh_frame BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss BLOCK(__section_alignment__) :\n\ |
{\n\ |
__bss_start__ = . ;\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
__bss_end__ = . ;\n\ |
}\n\ |
.edata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.edata)\n" |
" }\n\ |
/DISCARD/ :\n\ |
{\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n\ |
*(.drectve)\n\ |
*(.note.GNU-stack)\n\ |
*(.gnu.lto_*)\n\ |
}\n\ |
.idata BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
SORT(*)(.idata$2)\n\ |
SORT(*)(.idata$3)\n\ |
/* These zeroes mark the end of the import list. */\n\ |
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);\n\ |
SORT(*)(.idata$4)\n\ |
__IAT_start__ = .;\n\ |
SORT(*)(.idata$5)\n\ |
__IAT_end__ = .;\n\ |
SORT(*)(.idata$6)\n\ |
SORT(*)(.idata$7)\n\ |
}\n" |
" .CRT BLOCK(__section_alignment__) :\n\ |
{\n\ |
___crt_xc_start__ = . ;\n\ |
*(SORT(.CRT$XC*)) /* C initialization */\n\ |
___crt_xc_end__ = . ;\n\ |
___crt_xi_start__ = . ;\n\ |
*(SORT(.CRT$XI*)) /* C++ initialization */\n\ |
___crt_xi_end__ = . ;\n\ |
___crt_xl_start__ = . ;\n\ |
*(SORT(.CRT$XL*)) /* TLS callbacks */\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
___crt_xp_start__ = . ;\n\ |
*(SORT(.CRT$XP*)) /* Pre-termination */\n\ |
___crt_xp_end__ = . ;\n\ |
___crt_xt_start__ = . ;\n\ |
*(SORT(.CRT$XT*)) /* Termination */\n\ |
___crt_xt_end__ = . ;\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls BLOCK(__section_alignment__) :\n\ |
{\n\ |
___tls_start__ = . ;\n\ |
*(.tls$AAA)\n\ |
*(.tls)\n\ |
*(.tls$)\n\ |
*(SORT(.tls$*))\n\ |
*(.tls$ZZZ)\n\ |
___tls_end__ = . ;\n\ |
}\n\ |
.endjunk BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n\ |
PROVIDE (end = .);\n\ |
PROVIDE ( _end = .);\n\ |
__end__ = .;\n\ |
}\n\ |
.rsrc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rsrc)\n\ |
*(SORT(.rsrc$*))\n\ |
}\n\ |
.reloc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_aranges)\n\ |
}\n\ |
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_aranges)\n\ |
}\n\ |
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_info .gnu.linkonce.wi.*)\n\ |
}\n\ |
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)\n\ |
}\n\ |
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
}\n\n" |
; else return |
"/* Default linker script, for normal executables */\n\ |
OUTPUT_FORMAT(pei-i386)\n\ |
SEARCH_DIR(\"=/usr/local/lib\"); SEARCH_DIR(\"=/lib\"); SEARCH_DIR(\"=/usr/lib\");\n\ |
SECTIONS\n\ |
{\n\ |
/* Make the virtual address and file offset synced if the alignment is\n\ |
lower than the target page size. */\n\ |
. = SIZEOF_HEADERS;\n\ |
. = ALIGN(__section_alignment__);\n\ |
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :\n\ |
{\n\ |
*(.init)\n\ |
*(.text)\n\ |
*(SORT(.text$*))\n\ |
*(.text.*)\n\ |
*(.gnu.linkonce.t.*)\n\ |
*(.glue_7t)\n\ |
*(.glue_7)\n\ |
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;\n\ |
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);\n\ |
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;\n\ |
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);\n\ |
*(.fini)\n\ |
/* ??? Why is .gcc_exc here? */\n\ |
*(.gcc_exc)\n" |
" PROVIDE (etext = .);\n\ |
PROVIDE (_etext = .);\n\ |
*(.gcc_except_table)\n\ |
}\n\ |
/* The Cygwin32 library uses a section to avoid copying certain data\n\ |
on fork. This used to be named \".data\". The linker used\n\ |
to include this between __data_start__ and __data_end__, but that\n\ |
breaks building the cygwin32 dll. Instead, we name the section\n\ |
\".data_cygwin_nocopy\" and explicitly include it after __data_end__. */\n\ |
.data BLOCK(__section_alignment__) :\n\ |
{\n\ |
__data_start__ = . ;\n\ |
*(.data)\n\ |
*(.data2)\n\ |
*(SORT(.data$*))\n\ |
*(.jcr)\n\ |
__data_end__ = . ;\n\ |
*(.data_cygwin_nocopy)\n\ |
}\n\ |
.rdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rdata)\n\ |
*(SORT(.rdata$*))\n\ |
__rt_psrelocs_start = .;\n\ |
*(.rdata_runtime_pseudo_reloc)\n" |
" __rt_psrelocs_end = .;\n\ |
}\n\ |
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;\n\ |
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;\n\ |
.eh_frame BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.eh_frame*)\n\ |
}\n\ |
.pdata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.pdata)\n\ |
}\n\ |
.bss BLOCK(__section_alignment__) :\n\ |
{\n\ |
__bss_start__ = . ;\n\ |
*(.bss)\n\ |
*(COMMON)\n\ |
__bss_end__ = . ;\n\ |
}\n\ |
.edata BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.edata)\n" |
" }\n\ |
/DISCARD/ :\n\ |
{\n\ |
*(.debug$S)\n\ |
*(.debug$T)\n\ |
*(.debug$F)\n\ |
*(.drectve)\n\ |
*(.note.GNU-stack)\n\ |
*(.gnu.lto_*)\n\ |
}\n\ |
.idata BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* This cannot currently be handled with grouped sections.\n\ |
See pe.em:sort_sections. */\n\ |
SORT(*)(.idata$2)\n\ |
SORT(*)(.idata$3)\n\ |
/* These zeroes mark the end of the import list. */\n\ |
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);\n\ |
SORT(*)(.idata$4)\n\ |
__IAT_start__ = .;\n\ |
SORT(*)(.idata$5)\n\ |
__IAT_end__ = .;\n\ |
SORT(*)(.idata$6)\n\ |
SORT(*)(.idata$7)\n\ |
}\n" |
" .CRT BLOCK(__section_alignment__) :\n\ |
{\n\ |
___crt_xc_start__ = . ;\n\ |
*(SORT(.CRT$XC*)) /* C initialization */\n\ |
___crt_xc_end__ = . ;\n\ |
___crt_xi_start__ = . ;\n\ |
*(SORT(.CRT$XI*)) /* C++ initialization */\n\ |
___crt_xi_end__ = . ;\n\ |
___crt_xl_start__ = . ;\n\ |
*(SORT(.CRT$XL*)) /* TLS callbacks */\n\ |
/* ___crt_xl_end__ is defined in the TLS Directory support code */\n\ |
___crt_xp_start__ = . ;\n\ |
*(SORT(.CRT$XP*)) /* Pre-termination */\n\ |
___crt_xp_end__ = . ;\n\ |
___crt_xt_start__ = . ;\n\ |
*(SORT(.CRT$XT*)) /* Termination */\n\ |
___crt_xt_end__ = . ;\n\ |
}\n\ |
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be\n\ |
at the end of section. This is important because _tls_start MUST\n\ |
be at the beginning of the section to enable SECREL32 relocations with TLS\n\ |
data. */\n\ |
.tls BLOCK(__section_alignment__) :\n\ |
{\n\ |
___tls_start__ = . ;\n\ |
*(.tls$AAA)\n\ |
*(.tls)\n\ |
*(.tls$)\n\ |
*(SORT(.tls$*))\n\ |
*(.tls$ZZZ)\n\ |
___tls_end__ = . ;\n\ |
}\n\ |
.endjunk BLOCK(__section_alignment__) :\n\ |
{\n\ |
/* end is deprecated, don't use it */\n\ |
PROVIDE (end = .);\n\ |
PROVIDE ( _end = .);\n\ |
__end__ = .;\n\ |
}\n\ |
.rsrc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.rsrc)\n\ |
*(SORT(.rsrc$*))\n\ |
}\n\ |
.reloc BLOCK(__section_alignment__) :\n\ |
{\n\ |
*(.reloc)\n\ |
}\n\ |
.stab BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stab)\n\ |
}\n\ |
.stabstr BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.stabstr)\n\ |
}\n\ |
/* DWARF debug sections.\n\ |
Symbols in the DWARF debugging sections are relative to the beginning\n\ |
of the section. Unlike other targets that fake this by putting the\n\ |
section VMA at 0, the PE format will not allow it. */\n\ |
/* DWARF 1.1 and DWARF 2. */\n\ |
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_aranges)\n\ |
}\n\ |
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_aranges)\n\ |
}\n\ |
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubnames)\n\ |
}\n\ |
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubnames)\n\ |
}\n\ |
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_pubtypes)\n\ |
}\n\ |
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_pubtypes)\n\ |
}\n\ |
/* DWARF 2. */\n\ |
.debug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_info .gnu.linkonce.wi.*)\n\ |
}\n\ |
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)\n\ |
}\n\ |
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_abbrev)\n\ |
}\n\ |
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_abbrev)\n\ |
}\n\ |
.debug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_line)\n\ |
}\n\ |
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_line)\n\ |
}\n\ |
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_frame*)\n\ |
}\n\ |
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_frame*)\n\ |
}\n\ |
.debug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_str)\n\ |
}\n\ |
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_str)\n\ |
}\n\ |
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_loc)\n\ |
}\n\ |
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_loc)\n\ |
}\n\ |
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macinfo)\n\ |
}\n\ |
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macinfo)\n\ |
}\n\ |
/* SGI/MIPS DWARF 2 extensions. */\n\ |
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_weaknames)\n\ |
}\n\ |
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_weaknames)\n\ |
}\n\ |
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_funcnames)\n\ |
}\n\ |
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_funcnames)\n\ |
}\n\ |
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_typenames)\n\ |
}\n\ |
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_typenames)\n\ |
}\n\ |
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_varnames)\n\ |
}\n\ |
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_varnames)\n\ |
}\n\ |
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_macro)\n\ |
}\n\ |
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_macro)\n\ |
}\n\ |
/* DWARF 3. */\n\ |
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_ranges)\n\ |
}\n\ |
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_ranges)\n\ |
}\n\ |
/* DWARF 4. */\n\ |
.debug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.debug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :\n\ |
{\n\ |
*(.zdebug_types .gnu.linkonce.wt.*)\n\ |
}\n\ |
}\n\n" |
; } |
struct ld_emulation_xfer_struct ld_i386pe_emulation = |
{ |
gld_i386pe_before_parse, |
syslib_default, |
hll_default, |
gld_i386pe_after_parse, |
gld_i386pe_after_open, |
after_allocation_default, |
set_output_arch_default, |
ldemul_default_target, |
gld_i386pe_before_allocation, |
gld_i386pe_get_script, |
"i386pe", |
"pei-i386", |
gld_i386pe_finish, |
NULL, /* Create output section statements. */ |
gld_i386pe_open_dynamic_archive, |
gld_i386pe_place_orphan, |
gld_i386pe_set_symbols, |
NULL, /* parse_args */ |
gldi386pe_add_options, |
gldi386pe_handle_option, |
gld_i386pe_unrecognized_file, |
gld_i386pe_list_options, |
gld_i386pe_recognized_file, |
gld_i386pe_find_potential_libraries, |
NULL /* new_vers_pattern. */ |
}; |
/contrib/toolchain/binutils/ld/ld.h |
---|
0,0 → 1,321 |
/* ld.h -- general linker header file |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LD_H |
#define LD_H |
#ifdef HAVE_LOCALE_H |
#endif |
#ifndef SEEK_CUR |
#define SEEK_CUR 1 |
#endif |
#ifndef SEEK_END |
#define SEEK_END 2 |
#endif |
#ifdef HAVE_LOCALE_H |
# ifndef ENABLE_NLS |
/* The Solaris version of locale.h always includes libintl.h. If we have |
been configured with --disable-nls then ENABLE_NLS will not be defined |
and the dummy definitions of bindtextdomain (et al) below will conflict |
with the defintions in libintl.h. So we define these values to prevent |
the bogus inclusion of libintl.h. */ |
# define _LIBINTL_H |
# define _LIBGETTEXT_H |
# endif |
# include <locale.h> |
#endif |
#ifdef ENABLE_NLS |
# include <libintl.h> |
# define _(String) gettext (String) |
# ifdef gettext_noop |
# define N_(String) gettext_noop (String) |
# else |
# define N_(String) (String) |
# endif |
#else |
# define gettext(Msgid) (Msgid) |
# define dgettext(Domainname, Msgid) (Msgid) |
# define dcgettext(Domainname, Msgid, Category) (Msgid) |
# define textdomain(Domainname) while (0) /* nothing */ |
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ |
# define _(String) (String) |
# define N_(String) (String) |
#endif |
/* Look in this environment name for the linker to pretend to be */ |
#define EMULATION_ENVIRON "LDEMULATION" |
/* If in there look for the strings: */ |
/* Look in this variable for a target format */ |
#define TARGET_ENVIRON "GNUTARGET" |
/* Input sections which are put in a section of this name are actually |
discarded. */ |
#define DISCARD_SECTION_NAME "/DISCARD/" |
/* A file name list */ |
typedef struct name_list { |
const char *name; |
struct name_list *next; |
} |
name_list; |
typedef enum {sort_none, sort_ascending, sort_descending} sort_order; |
/* A wildcard specification. */ |
typedef enum { |
none, by_name, by_alignment, by_name_alignment, by_alignment_name, |
by_none, by_init_priority |
} sort_type; |
extern sort_type sort_section; |
struct wildcard_spec { |
const char *name; |
struct name_list *exclude_name_list; |
sort_type sorted; |
struct flag_info *section_flag_list; |
}; |
struct wildcard_list { |
struct wildcard_list *next; |
struct wildcard_spec spec; |
}; |
struct map_symbol_def { |
struct bfd_link_hash_entry *entry; |
struct map_symbol_def *next; |
}; |
/* The initial part of fat_user_section_struct has to be idential with |
lean_user_section_struct. */ |
typedef struct fat_user_section_struct { |
/* For input sections, when writing a map file: head / tail of a linked |
list of hash table entries for symbols defined in this section. */ |
struct map_symbol_def *map_symbol_def_head; |
struct map_symbol_def **map_symbol_def_tail; |
unsigned long map_symbol_def_count; |
} fat_section_userdata_type; |
#define get_userdata(x) ((x)->userdata) |
#define BYTE_SIZE (1) |
#define SHORT_SIZE (2) |
#define LONG_SIZE (4) |
#define QUAD_SIZE (8) |
enum endian_enum { ENDIAN_UNSET = 0, ENDIAN_BIG, ENDIAN_LITTLE }; |
enum symbolic_enum |
{ |
symbolic_unset = 0, |
symbolic, |
symbolic_functions, |
}; |
enum dynamic_list_enum |
{ |
dynamic_list_unset = 0, |
dynamic_list_data, |
dynamic_list |
}; |
typedef struct { |
/* 1 => assign space to common symbols even if `relocatable_output'. */ |
bfd_boolean force_common_definition; |
/* 1 => do not assign addresses to common symbols. */ |
bfd_boolean inhibit_common_definition; |
/* If TRUE, build MIPS embedded PIC relocation tables in the output |
file. */ |
bfd_boolean embedded_relocs; |
/* If TRUE, force generation of a file with a .exe file. */ |
bfd_boolean force_exe_suffix; |
/* If TRUE, generate a cross reference report. */ |
bfd_boolean cref; |
/* If TRUE (which is the default), warn about mismatched input |
files. */ |
bfd_boolean warn_mismatch; |
/* Warn on attempting to open an incompatible library during a library |
search. */ |
bfd_boolean warn_search_mismatch; |
/* If non-zero check section addresses, once computed, |
for overlaps. Relocatable links only check when this is > 0. */ |
signed char check_section_addresses; |
/* If TRUE allow the linking of input files in an unknown architecture |
assuming that the user knows what they are doing. This was the old |
behaviour of the linker. The new default behaviour is to reject such |
input files. */ |
bfd_boolean accept_unknown_input_arch; |
/* If TRUE we'll just print the default output on stdout. */ |
bfd_boolean print_output_format; |
/* Big or little endian as set on command line. */ |
enum endian_enum endian; |
/* -Bsymbolic and -Bsymbolic-functions, as set on command line. */ |
enum symbolic_enum symbolic; |
/* --dynamic-list, --dynamic-list-cpp-new, --dynamic-list-cpp-typeinfo |
and --dynamic-list FILE, as set on command line. */ |
enum dynamic_list_enum dynamic_list; |
/* Name of runtime interpreter to invoke. */ |
char *interpreter; |
/* Name to give runtime libary from the -soname argument. */ |
char *soname; |
/* Runtime library search path from the -rpath argument. */ |
char *rpath; |
/* Link time runtime library search path from the -rpath-link |
argument. */ |
char *rpath_link; |
/* Name of shared object whose symbol table should be filtered with |
this shared object. From the --filter option. */ |
char *filter_shlib; |
/* Name of shared object for whose symbol table this shared object |
is an auxiliary filter. From the --auxiliary option. */ |
char **auxiliary_filters; |
/* A version symbol to be applied to the symbol names found in the |
.exports sections. */ |
char *version_exports_section; |
/* Default linker script. */ |
char *default_script; |
} args_type; |
extern args_type command_line; |
typedef int token_code_type; |
typedef struct { |
bfd_boolean magic_demand_paged; |
bfd_boolean make_executable; |
/* If TRUE, -shared is supported. */ |
/* ??? A better way to do this is perhaps to define this in the |
ld_emulation_xfer_struct since this is really a target dependent |
parameter. */ |
bfd_boolean has_shared; |
/* If TRUE, build constructors. */ |
bfd_boolean build_constructors; |
/* If TRUE, warn about any constructors. */ |
bfd_boolean warn_constructors; |
/* If TRUE, warn about merging common symbols with others. */ |
bfd_boolean warn_common; |
/* If TRUE, only warn once about a particular undefined symbol. */ |
bfd_boolean warn_once; |
/* If TRUE, warn if multiple global-pointers are needed (Alpha |
only). */ |
bfd_boolean warn_multiple_gp; |
/* If TRUE, warn if the starting address of an output section |
changes due to the alignment of an input section. */ |
bfd_boolean warn_section_align; |
/* If TRUE, warning messages are fatal */ |
bfd_boolean fatal_warnings; |
sort_order sort_common; |
bfd_boolean text_read_only; |
bfd_boolean stats; |
/* If set, orphan input sections will be mapped to separate output |
sections. */ |
bfd_boolean unique_orphan_sections; |
/* If set, only search library directories explicitly selected |
on the command line. */ |
bfd_boolean only_cmd_line_lib_dirs; |
/* If set, numbers and absolute symbols are simply treated as |
numbers everywhere. */ |
bfd_boolean sane_expr; |
/* If set, code and non-code sections should never be in one segment. */ |
bfd_boolean separate_code; |
/* The rpath separation character. Usually ':'. */ |
char rpath_separator; |
char *map_filename; |
FILE *map_file; |
unsigned int split_by_reloc; |
bfd_size_type split_by_file; |
bfd_size_type specified_data_size; |
/* The size of the hash table to use. */ |
unsigned long hash_table_size; |
/* The maximum page size for ELF. */ |
bfd_vma maxpagesize; |
/* The common page size for ELF. */ |
bfd_vma commonpagesize; |
} ld_config_type; |
extern ld_config_type config; |
extern FILE * saved_script_handle; |
extern bfd_boolean force_make_executable; |
extern int yyparse (void); |
extern void add_cref (const char *, bfd *, asection *, bfd_vma); |
extern bfd_boolean handle_asneeded_cref (bfd *, enum notice_asneeded_action); |
extern void output_cref (FILE *); |
extern void check_nocrossrefs (void); |
extern void ld_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; |
/* If gcc >= 2.6, we can give a function name, too. */ |
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) |
#define __PRETTY_FUNCTION__ NULL |
#endif |
#undef abort |
#define abort() ld_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) |
#endif |
/contrib/toolchain/binutils/ld/ld.lnk |
---|
0,0 → 1,4 |
-static -nostdlib --stack 0x200000 -T/kolibrios/contrib/sdk/sources/newlib/app.lds |
--image-base 0 -L/kolibrios/contrib/sdk/lib -o ld-new deffilep.o ei386pe.o ldcref.o ldctor.o ldemul.o ldexp.o ldfile.o ldgram.o |
ldlang.o ldlex-wrapper.o ldmain.o ldmisc.o ldver.o ldwrite.o lexsup.o mri.o pe-dll.o |
-lbfd -liberty -lz -lgcc -lc.dll -lapp |
/contrib/toolchain/binutils/ld/ldcref.c |
---|
0,0 → 1,704 |
/* ldcref.c -- output a cross reference table |
Copyright 1996-2013 Free Software Foundation, Inc. |
Written by Ian Lance Taylor <ian@cygnus.com> |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This file holds routines that manage the cross reference table. |
The table is used to generate cross reference reports. It is also |
used to implement the NOCROSSREFS command in the linker script. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libiberty.h" |
#include "demangle.h" |
#include "objalloc.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
/* We keep an instance of this structure for each reference to a |
symbol from a given object. */ |
struct cref_ref { |
/* The next reference. */ |
struct cref_ref *next; |
/* The object. */ |
bfd *abfd; |
/* True if the symbol is defined. */ |
unsigned int def : 1; |
/* True if the symbol is common. */ |
unsigned int common : 1; |
/* True if the symbol is undefined. */ |
unsigned int undef : 1; |
}; |
/* We keep a hash table of symbols. Each entry looks like this. */ |
struct cref_hash_entry { |
struct bfd_hash_entry root; |
/* The demangled name. */ |
const char *demangled; |
/* References to and definitions of this symbol. */ |
struct cref_ref *refs; |
}; |
/* This is what the hash table looks like. */ |
struct cref_hash_table { |
struct bfd_hash_table root; |
}; |
/* Forward declarations. */ |
static void output_one_cref (FILE *, struct cref_hash_entry *); |
static void check_local_sym_xref (lang_input_statement_type *); |
static bfd_boolean check_nocrossref (struct cref_hash_entry *, void *); |
static void check_refs (const char *, bfd_boolean, asection *, bfd *, |
struct lang_nocrossrefs *); |
static void check_reloc_refs (bfd *, asection *, void *); |
/* Look up an entry in the cref hash table. */ |
#define cref_hash_lookup(table, string, create, copy) \ |
((struct cref_hash_entry *) \ |
bfd_hash_lookup (&(table)->root, (string), (create), (copy))) |
/* Traverse the cref hash table. */ |
#define cref_hash_traverse(table, func, info) \ |
(bfd_hash_traverse \ |
(&(table)->root, \ |
(bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func), \ |
(info))) |
/* The cref hash table. */ |
static struct cref_hash_table cref_table; |
/* Whether the cref hash table has been initialized. */ |
static bfd_boolean cref_initialized; |
/* The number of symbols seen so far. */ |
static size_t cref_symcount; |
/* Used to take a snapshot of the cref hash table when starting to |
add syms from an as-needed library. */ |
static struct bfd_hash_entry **old_table; |
static unsigned int old_size; |
static unsigned int old_count; |
static void *old_tab; |
static void *alloc_mark; |
static size_t tabsize, entsize, refsize; |
static size_t old_symcount; |
/* Create an entry in a cref hash table. */ |
static struct bfd_hash_entry * |
cref_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct cref_hash_entry *ret = (struct cref_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == NULL) |
ret = ((struct cref_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct cref_hash_entry))); |
if (ret == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
ret = ((struct cref_hash_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); |
if (ret != NULL) |
{ |
/* Set local fields. */ |
ret->demangled = NULL; |
ret->refs = NULL; |
/* Keep a count of the number of entries created in the hash |
table. */ |
++cref_symcount; |
} |
return &ret->root; |
} |
/* Add a symbol to the cref hash table. This is called for every |
global symbol that is seen during the link. */ |
void |
add_cref (const char *name, |
bfd *abfd, |
asection *section, |
bfd_vma value ATTRIBUTE_UNUSED) |
{ |
struct cref_hash_entry *h; |
struct cref_ref *r; |
if (! cref_initialized) |
{ |
if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc, |
sizeof (struct cref_hash_entry))) |
einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n")); |
cref_initialized = TRUE; |
} |
h = cref_hash_lookup (&cref_table, name, TRUE, FALSE); |
if (h == NULL) |
einfo (_("%X%P: cref_hash_lookup failed: %E\n")); |
for (r = h->refs; r != NULL; r = r->next) |
if (r->abfd == abfd) |
break; |
if (r == NULL) |
{ |
r = (struct cref_ref *) bfd_hash_allocate (&cref_table.root, sizeof *r); |
if (r == NULL) |
einfo (_("%X%P: cref alloc failed: %E\n")); |
r->next = h->refs; |
h->refs = r; |
r->abfd = abfd; |
r->def = FALSE; |
r->common = FALSE; |
r->undef = FALSE; |
} |
if (bfd_is_und_section (section)) |
r->undef = TRUE; |
else if (bfd_is_com_section (section)) |
r->common = TRUE; |
else |
r->def = TRUE; |
} |
/* Called before loading an as-needed library to take a snapshot of |
the cref hash table, and after we have loaded or found that the |
library was not needed. */ |
bfd_boolean |
handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED, |
enum notice_asneeded_action act) |
{ |
unsigned int i; |
if (!cref_initialized) |
return TRUE; |
if (act == notice_as_needed) |
{ |
char *old_ent, *old_ref; |
for (i = 0; i < cref_table.root.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct cref_hash_entry *c; |
struct cref_ref *r; |
for (p = cref_table.root.table[i]; p != NULL; p = p->next) |
{ |
entsize += cref_table.root.entsize; |
c = (struct cref_hash_entry *) p; |
for (r = c->refs; r != NULL; r = r->next) |
refsize += sizeof (struct cref_ref); |
} |
} |
tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *); |
old_tab = xmalloc (tabsize + entsize + refsize); |
alloc_mark = bfd_hash_allocate (&cref_table.root, 1); |
if (alloc_mark == NULL) |
return FALSE; |
memcpy (old_tab, cref_table.root.table, tabsize); |
old_ent = (char *) old_tab + tabsize; |
old_ref = (char *) old_ent + entsize; |
old_table = cref_table.root.table; |
old_size = cref_table.root.size; |
old_count = cref_table.root.count; |
old_symcount = cref_symcount; |
for (i = 0; i < cref_table.root.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct cref_hash_entry *c; |
struct cref_ref *r; |
for (p = cref_table.root.table[i]; p != NULL; p = p->next) |
{ |
memcpy (old_ent, p, cref_table.root.entsize); |
old_ent = (char *) old_ent + cref_table.root.entsize; |
c = (struct cref_hash_entry *) p; |
for (r = c->refs; r != NULL; r = r->next) |
{ |
memcpy (old_ref, r, sizeof (struct cref_ref)); |
old_ref = (char *) old_ref + sizeof (struct cref_ref); |
} |
} |
} |
return TRUE; |
} |
if (act == notice_not_needed) |
{ |
char *old_ent, *old_ref; |
if (old_tab == NULL) |
{ |
/* The only way old_tab can be NULL is if the cref hash table |
had not been initialised when notice_as_needed. */ |
bfd_hash_table_free (&cref_table.root); |
cref_initialized = FALSE; |
return TRUE; |
} |
old_ent = (char *) old_tab + tabsize; |
old_ref = (char *) old_ent + entsize; |
cref_table.root.table = old_table; |
cref_table.root.size = old_size; |
cref_table.root.count = old_count; |
memcpy (cref_table.root.table, old_tab, tabsize); |
cref_symcount = old_symcount; |
for (i = 0; i < cref_table.root.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct cref_hash_entry *c; |
struct cref_ref *r; |
for (p = cref_table.root.table[i]; p != NULL; p = p->next) |
{ |
memcpy (p, old_ent, cref_table.root.entsize); |
old_ent = (char *) old_ent + cref_table.root.entsize; |
c = (struct cref_hash_entry *) p; |
for (r = c->refs; r != NULL; r = r->next) |
{ |
memcpy (r, old_ref, sizeof (struct cref_ref)); |
old_ref = (char *) old_ref + sizeof (struct cref_ref); |
} |
} |
} |
objalloc_free_block ((struct objalloc *) cref_table.root.memory, |
alloc_mark); |
} |
else if (act != notice_needed) |
return FALSE; |
free (old_tab); |
old_tab = NULL; |
return TRUE; |
} |
/* Copy the addresses of the hash table entries into an array. This |
is called via cref_hash_traverse. We also fill in the demangled |
name. */ |
static bfd_boolean |
cref_fill_array (struct cref_hash_entry *h, void *data) |
{ |
struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data; |
ASSERT (h->demangled == NULL); |
h->demangled = bfd_demangle (link_info.output_bfd, h->root.string, |
DMGL_ANSI | DMGL_PARAMS); |
if (h->demangled == NULL) |
h->demangled = h->root.string; |
**pph = h; |
++*pph; |
return TRUE; |
} |
/* Sort an array of cref hash table entries by name. */ |
static int |
cref_sort_array (const void *a1, const void *a2) |
{ |
const struct cref_hash_entry * const *p1 = |
(const struct cref_hash_entry * const *) a1; |
const struct cref_hash_entry * const *p2 = |
(const struct cref_hash_entry * const *) a2; |
return strcmp ((*p1)->demangled, (*p2)->demangled); |
} |
/* Write out the cref table. */ |
#define FILECOL (50) |
void |
output_cref (FILE *fp) |
{ |
int len; |
struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end; |
const char *msg; |
fprintf (fp, _("\nCross Reference Table\n\n")); |
msg = _("Symbol"); |
fprintf (fp, "%s", msg); |
len = strlen (msg); |
while (len < FILECOL) |
{ |
putc (' ', fp); |
++len; |
} |
fprintf (fp, _("File\n")); |
if (! cref_initialized) |
{ |
fprintf (fp, _("No symbols\n")); |
return; |
} |
csyms = (struct cref_hash_entry **) xmalloc (cref_symcount * sizeof (*csyms)); |
csym_fill = csyms; |
cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill); |
ASSERT ((size_t) (csym_fill - csyms) == cref_symcount); |
qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array); |
csym_end = csyms + cref_symcount; |
for (csym = csyms; csym < csym_end; csym++) |
output_one_cref (fp, *csym); |
} |
/* Output one entry in the cross reference table. */ |
static void |
output_one_cref (FILE *fp, struct cref_hash_entry *h) |
{ |
int len; |
struct bfd_link_hash_entry *hl; |
struct cref_ref *r; |
hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, |
FALSE, TRUE); |
if (hl == NULL) |
einfo ("%P: symbol `%T' missing from main hash table\n", |
h->root.string); |
else |
{ |
/* If this symbol is defined in a dynamic object but never |
referenced by a normal object, then don't print it. */ |
if (hl->type == bfd_link_hash_defined) |
{ |
if (hl->u.def.section->output_section == NULL) |
return; |
if (hl->u.def.section->owner != NULL |
&& (hl->u.def.section->owner->flags & DYNAMIC) != 0) |
{ |
for (r = h->refs; r != NULL; r = r->next) |
if ((r->abfd->flags & DYNAMIC) == 0) |
break; |
if (r == NULL) |
return; |
} |
} |
} |
fprintf (fp, "%s ", h->demangled); |
len = strlen (h->demangled) + 1; |
for (r = h->refs; r != NULL; r = r->next) |
{ |
if (r->def) |
{ |
while (len < FILECOL) |
{ |
putc (' ', fp); |
++len; |
} |
lfinfo (fp, "%B\n", r->abfd); |
len = 0; |
} |
} |
for (r = h->refs; r != NULL; r = r->next) |
{ |
if (r->common) |
{ |
while (len < FILECOL) |
{ |
putc (' ', fp); |
++len; |
} |
lfinfo (fp, "%B\n", r->abfd); |
len = 0; |
} |
} |
for (r = h->refs; r != NULL; r = r->next) |
{ |
if (! r->def && ! r->common) |
{ |
while (len < FILECOL) |
{ |
putc (' ', fp); |
++len; |
} |
lfinfo (fp, "%B\n", r->abfd); |
len = 0; |
} |
} |
ASSERT (len == 0); |
} |
/* Check for prohibited cross references. */ |
void |
check_nocrossrefs (void) |
{ |
if (! cref_initialized) |
return; |
cref_hash_traverse (&cref_table, check_nocrossref, NULL); |
lang_for_each_file (check_local_sym_xref); |
} |
/* Check for prohibited cross references to local and section symbols. */ |
static void |
check_local_sym_xref (lang_input_statement_type *statement) |
{ |
bfd *abfd; |
asymbol **syms; |
abfd = statement->the_bfd; |
if (abfd == NULL) |
return; |
if (!bfd_generic_link_read_symbols (abfd)) |
einfo (_("%B%F: could not read symbols: %E\n"), abfd); |
for (syms = bfd_get_outsymbols (abfd); *syms; ++syms) |
{ |
asymbol *sym = *syms; |
if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE)) |
continue; |
if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0 |
&& sym->section->output_section != NULL) |
{ |
const char *outsecname, *symname; |
struct lang_nocrossrefs *ncrs; |
struct lang_nocrossref *ncr; |
outsecname = sym->section->output_section->name; |
symname = NULL; |
if ((sym->flags & BSF_SECTION_SYM) == 0) |
symname = sym->name; |
for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) |
for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) |
if (strcmp (ncr->name, outsecname) == 0) |
check_refs (symname, FALSE, sym->section, abfd, ncrs); |
} |
} |
} |
/* Check one symbol to see if it is a prohibited cross reference. */ |
static bfd_boolean |
check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED) |
{ |
struct bfd_link_hash_entry *hl; |
asection *defsec; |
const char *defsecname; |
struct lang_nocrossrefs *ncrs; |
struct lang_nocrossref *ncr; |
struct cref_ref *ref; |
hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, |
FALSE, TRUE); |
if (hl == NULL) |
{ |
einfo (_("%P: symbol `%T' missing from main hash table\n"), |
h->root.string); |
return TRUE; |
} |
if (hl->type != bfd_link_hash_defined |
&& hl->type != bfd_link_hash_defweak) |
return TRUE; |
defsec = hl->u.def.section->output_section; |
if (defsec == NULL) |
return TRUE; |
defsecname = bfd_get_section_name (defsec->owner, defsec); |
for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) |
for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) |
if (strcmp (ncr->name, defsecname) == 0) |
for (ref = h->refs; ref != NULL; ref = ref->next) |
check_refs (hl->root.string, TRUE, hl->u.def.section, |
ref->abfd, ncrs); |
return TRUE; |
} |
/* The struct is used to pass information from check_refs to |
check_reloc_refs through bfd_map_over_sections. */ |
struct check_refs_info { |
const char *sym_name; |
asection *defsec; |
struct lang_nocrossrefs *ncrs; |
asymbol **asymbols; |
bfd_boolean global; |
}; |
/* This function is called for each symbol defined in a section which |
prohibits cross references. We need to look through all references |
to this symbol, and ensure that the references are not from |
prohibited sections. */ |
static void |
check_refs (const char *name, |
bfd_boolean global, |
asection *sec, |
bfd *abfd, |
struct lang_nocrossrefs *ncrs) |
{ |
struct check_refs_info info; |
/* We need to look through the relocations for this BFD, to see |
if any of the relocations which refer to this symbol are from |
a prohibited section. Note that we need to do this even for |
the BFD in which the symbol is defined, since even a single |
BFD might contain a prohibited cross reference. */ |
if (!bfd_generic_link_read_symbols (abfd)) |
einfo (_("%B%F: could not read symbols: %E\n"), abfd); |
info.sym_name = name; |
info.global = global; |
info.defsec = sec; |
info.ncrs = ncrs; |
info.asymbols = bfd_get_outsymbols (abfd); |
bfd_map_over_sections (abfd, check_reloc_refs, &info); |
} |
/* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol |
defined in INFO->DEFSECNAME. If this section maps into any of the |
sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we |
look through the relocations. If any of the relocations are to |
INFO->SYM_NAME, then we report a prohibited cross reference error. */ |
static void |
check_reloc_refs (bfd *abfd, asection *sec, void *iarg) |
{ |
struct check_refs_info *info = (struct check_refs_info *) iarg; |
asection *outsec; |
const char *outsecname; |
asection *outdefsec; |
const char *outdefsecname; |
struct lang_nocrossref *ncr; |
const char *symname; |
bfd_boolean global; |
long relsize; |
arelent **relpp; |
long relcount; |
arelent **p, **pend; |
outsec = sec->output_section; |
outsecname = bfd_get_section_name (outsec->owner, outsec); |
outdefsec = info->defsec->output_section; |
outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec); |
/* The section where the symbol is defined is permitted. */ |
if (strcmp (outsecname, outdefsecname) == 0) |
return; |
for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next) |
if (strcmp (outsecname, ncr->name) == 0) |
break; |
if (ncr == NULL) |
return; |
/* This section is one for which cross references are prohibited. |
Look through the relocations, and see if any of them are to |
INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations |
against the section symbol. If INFO->GLOBAL is TRUE, the |
definition is global, check for relocations against the global |
symbols. Otherwise check for relocations against the local and |
section symbols. */ |
symname = info->sym_name; |
global = info->global; |
relsize = bfd_get_reloc_upper_bound (abfd, sec); |
if (relsize < 0) |
einfo (_("%B%F: could not read relocs: %E\n"), abfd); |
if (relsize == 0) |
return; |
relpp = (arelent **) xmalloc (relsize); |
relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols); |
if (relcount < 0) |
einfo (_("%B%F: could not read relocs: %E\n"), abfd); |
p = relpp; |
pend = p + relcount; |
for (; p < pend && *p != NULL; p++) |
{ |
arelent *q = *p; |
if (q->sym_ptr_ptr != NULL |
&& *q->sym_ptr_ptr != NULL |
&& ((global |
&& (bfd_is_und_section (bfd_get_section (*q->sym_ptr_ptr)) |
|| bfd_is_com_section (bfd_get_section (*q->sym_ptr_ptr)) |
|| ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL |
| BSF_WEAK)) != 0)) |
|| (!global |
&& ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL |
| BSF_SECTION_SYM)) != 0 |
&& bfd_get_section (*q->sym_ptr_ptr) == info->defsec)) |
&& (symname != NULL |
? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0 |
: ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0)) |
{ |
/* We found a reloc for the symbol. The symbol is defined |
in OUTSECNAME. This reloc is from a section which is |
mapped into a section from which references to OUTSECNAME |
are prohibited. We must report an error. */ |
einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"), |
abfd, sec, q->address, outsecname, |
bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname); |
} |
} |
free (relpp); |
} |
/contrib/toolchain/binutils/ld/ldctor.c |
---|
0,0 → 1,378 |
/* ldctor.c -- constructor support routines |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 |
Free Software Foundation, Inc. |
By Steve Chamberlain <sac@cygnus.com> |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "safe-ctype.h" |
#include "ld.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldmisc.h" |
#include <ldgram.h> |
#include "ldmain.h" |
#include "ldctor.h" |
/* The list of statements needed to handle constructors. These are |
invoked by the command CONSTRUCTORS in the linker script. */ |
lang_statement_list_type constructor_list; |
/* Whether the constructors should be sorted. Note that this is |
global for the entire link; we assume that there is only a single |
CONSTRUCTORS command in the linker script. */ |
bfd_boolean constructors_sorted; |
/* The sets we have seen. */ |
struct set_info *sets; |
/* Add an entry to a set. H is the entry in the linker hash table. |
RELOC is the relocation to use for an entry in the set. SECTION |
and VALUE are the value to add. This is called during the first |
phase of the link, when we are still gathering symbols together. |
We just record the information now. The ldctor_build_sets |
function will construct the sets. */ |
void |
ldctor_add_set_entry (struct bfd_link_hash_entry *h, |
bfd_reloc_code_real_type reloc, |
const char *name, |
asection *section, |
bfd_vma value) |
{ |
struct set_info *p; |
struct set_element *e; |
struct set_element **epp; |
for (p = sets; p != NULL; p = p->next) |
if (p->h == h) |
break; |
if (p == NULL) |
{ |
p = (struct set_info *) xmalloc (sizeof (struct set_info)); |
p->next = sets; |
sets = p; |
p->h = h; |
p->reloc = reloc; |
p->count = 0; |
p->elements = NULL; |
} |
else |
{ |
if (p->reloc != reloc) |
{ |
einfo (_("%P%X: Different relocs used in set %s\n"), |
h->root.string); |
return; |
} |
/* Don't permit a set to be constructed from different object |
file formats. The same reloc may have different results. We |
actually could sometimes handle this, but the case is |
unlikely to ever arise. Sometimes constructor symbols are in |
unusual sections, such as the absolute section--this appears |
to be the case in Linux a.out--and in such cases we just |
assume everything is OK. */ |
if (p->elements != NULL |
&& section->owner != NULL |
&& p->elements->section->owner != NULL |
&& strcmp (bfd_get_target (section->owner), |
bfd_get_target (p->elements->section->owner)) != 0) |
{ |
einfo (_("%P%X: Different object file formats composing set %s\n"), |
h->root.string); |
return; |
} |
} |
e = (struct set_element *) xmalloc (sizeof (struct set_element)); |
e->next = NULL; |
e->name = name; |
e->section = section; |
e->value = value; |
for (epp = &p->elements; *epp != NULL; epp = &(*epp)->next) |
; |
*epp = e; |
++p->count; |
} |
/* Get the priority of a g++ global constructor or destructor from the |
symbol name. */ |
static int |
ctor_prio (const char *name) |
{ |
/* The name will look something like _GLOBAL_$I$65535$test02__Fv. |
There might be extra leading underscores, and the $ characters |
might be something else. The I might be a D. */ |
while (*name == '_') |
++name; |
if (! CONST_STRNEQ (name, "GLOBAL_")) |
return -1; |
name += sizeof "GLOBAL_" - 1; |
if (name[0] != name[2]) |
return -1; |
if (name[1] != 'I' && name[1] != 'D') |
return -1; |
if (! ISDIGIT (name[3])) |
return -1; |
return atoi (name + 3); |
} |
/* This function is used to sort constructor elements by priority. It |
is called via qsort. */ |
static int |
ctor_cmp (const void *p1, const void *p2) |
{ |
const struct set_element * const *pe1 = |
(const struct set_element * const *) p1; |
const struct set_element * const *pe2 = |
(const struct set_element * const *) p2; |
const char *n1; |
const char *n2; |
int prio1; |
int prio2; |
n1 = (*pe1)->name; |
if (n1 == NULL) |
n1 = ""; |
n2 = (*pe2)->name; |
if (n2 == NULL) |
n2 = ""; |
/* We need to sort in reverse order by priority. When two |
constructors have the same priority, we should maintain their |
current relative position. */ |
prio1 = ctor_prio (n1); |
prio2 = ctor_prio (n2); |
/* We sort in reverse order because that is what g++ expects. */ |
if (prio1 < prio2) |
return 1; |
else if (prio1 > prio2) |
return -1; |
/* Force a stable sort. */ |
if (pe1 < pe2) |
return -1; |
else if (pe1 > pe2) |
return 1; |
else |
return 0; |
} |
/* This function is called after the first phase of the link and |
before the second phase. At this point all set information has |
been gathered. We now put the statements to build the sets |
themselves into constructor_list. */ |
void |
ldctor_build_sets (void) |
{ |
static bfd_boolean called; |
bfd_boolean header_printed; |
struct set_info *p; |
/* The emulation code may call us directly, but we only want to do |
this once. */ |
if (called) |
return; |
called = TRUE; |
if (constructors_sorted) |
{ |
for (p = sets; p != NULL; p = p->next) |
{ |
int c, i; |
struct set_element *e; |
struct set_element **array; |
if (p->elements == NULL) |
continue; |
c = 0; |
for (e = p->elements; e != NULL; e = e->next) |
++c; |
array = (struct set_element **) xmalloc (c * sizeof *array); |
i = 0; |
for (e = p->elements; e != NULL; e = e->next) |
{ |
array[i] = e; |
++i; |
} |
qsort (array, c, sizeof *array, ctor_cmp); |
e = array[0]; |
p->elements = e; |
for (i = 0; i < c - 1; i++) |
array[i]->next = array[i + 1]; |
array[i]->next = NULL; |
free (array); |
} |
} |
lang_list_init (&constructor_list); |
push_stat_ptr (&constructor_list); |
header_printed = FALSE; |
for (p = sets; p != NULL; p = p->next) |
{ |
struct set_element *e; |
reloc_howto_type *howto; |
int reloc_size, size; |
/* If the symbol is defined, we may have been invoked from |
collect, and the sets may already have been built, so we do |
not do anything. */ |
if (p->h->type == bfd_link_hash_defined |
|| p->h->type == bfd_link_hash_defweak) |
continue; |
/* For each set we build: |
set: |
.long number_of_elements |
.long element0 |
... |
.long elementN |
.long 0 |
except that we use the right size instead of .long. When |
generating relocatable output, we generate relocs instead of |
addresses. */ |
howto = bfd_reloc_type_lookup (link_info.output_bfd, p->reloc); |
if (howto == NULL) |
{ |
if (link_info.relocatable) |
{ |
einfo (_("%P%X: %s does not support reloc %s for set %s\n"), |
bfd_get_target (link_info.output_bfd), |
bfd_get_reloc_code_name (p->reloc), |
p->h->root.string); |
continue; |
} |
/* If this is not a relocatable link, all we need is the |
size, which we can get from the input BFD. */ |
if (p->elements->section->owner != NULL) |
howto = bfd_reloc_type_lookup (p->elements->section->owner, |
p->reloc); |
if (howto == NULL) |
{ |
einfo (_("%P%X: %s does not support reloc %s for set %s\n"), |
bfd_get_target (p->elements->section->owner), |
bfd_get_reloc_code_name (p->reloc), |
p->h->root.string); |
continue; |
} |
} |
reloc_size = bfd_get_reloc_size (howto); |
switch (reloc_size) |
{ |
case 1: size = BYTE; break; |
case 2: size = SHORT; break; |
case 4: size = LONG; break; |
case 8: |
if (howto->complain_on_overflow == complain_overflow_signed) |
size = SQUAD; |
else |
size = QUAD; |
break; |
default: |
einfo (_("%P%X: Unsupported size %d for set %s\n"), |
bfd_get_reloc_size (howto), p->h->root.string); |
size = LONG; |
break; |
} |
lang_add_assignment (exp_assign (".", |
exp_unop (ALIGN_K, |
exp_intop (reloc_size)), |
FALSE)); |
lang_add_assignment (exp_assign (p->h->root.string, |
exp_nameop (NAME, "."), |
FALSE)); |
lang_add_data (size, exp_intop (p->count)); |
for (e = p->elements; e != NULL; e = e->next) |
{ |
if (config.map_file != NULL) |
{ |
int len; |
if (! header_printed) |
{ |
minfo (_("\nSet Symbol\n\n")); |
header_printed = TRUE; |
} |
minfo ("%s", p->h->root.string); |
len = strlen (p->h->root.string); |
if (len >= 19) |
{ |
print_nl (); |
len = 0; |
} |
while (len < 20) |
{ |
print_space (); |
++len; |
} |
if (e->name != NULL) |
minfo ("%T\n", e->name); |
else |
minfo ("%G\n", e->section->owner, e->section, e->value); |
} |
/* Need SEC_KEEP for --gc-sections. */ |
if (! bfd_is_abs_section (e->section)) |
e->section->flags |= SEC_KEEP; |
if (link_info.relocatable) |
lang_add_reloc (p->reloc, howto, e->section, e->name, |
exp_intop (e->value)); |
else |
lang_add_data (size, exp_relop (e->section, e->value)); |
} |
lang_add_data (size, exp_intop (0)); |
} |
pop_stat_ptr (); |
} |
/contrib/toolchain/binutils/ld/ldctor.h |
---|
0,0 → 1,60 |
/* ldctor.h - linker constructor support |
Copyright 1991, 1992, 1993, 1994, 1995, 1998, 2000, 2002, 2003, 2005, |
2007, 2008 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDCTOR_H |
#define LDCTOR_H |
/* List of statements needed to handle constructors */ |
extern lang_statement_list_type constructor_list; |
/* Whether the constructors should be sorted. Note that this is |
global for the entire link; we assume that there is only a single |
CONSTRUCTORS command in the linker script. */ |
extern bfd_boolean constructors_sorted; |
/* We keep a list of these structures for each set we build. */ |
struct set_info { |
struct set_info *next; /* Next set. */ |
struct bfd_link_hash_entry *h; /* Hash table entry. */ |
bfd_reloc_code_real_type reloc; /* Reloc to use for an entry. */ |
size_t count; /* Number of elements. */ |
struct set_element *elements; /* Elements in set. */ |
}; |
struct set_element { |
struct set_element *next; /* Next element. */ |
const char *name; /* Name in set (may be NULL). */ |
asection *section; /* Section of value in set. */ |
bfd_vma value; /* Value in set. */ |
}; |
/* The sets we have seen. */ |
extern struct set_info *sets; |
extern void ldctor_add_set_entry |
(struct bfd_link_hash_entry *, bfd_reloc_code_real_type, const char *, |
asection *, bfd_vma); |
extern void ldctor_build_sets |
(void); |
#endif |
/contrib/toolchain/binutils/ld/ldemul-list.h |
---|
0,0 → 1,6 |
/* This file is automatically generated. DO NOT EDIT! */ |
extern ld_emulation_xfer_type ld_i386pe_emulation; |
#define EMULATION_LIST \ |
&ld_i386pe_emulation, \ |
0 |
/contrib/toolchain/binutils/ld/ldemul.c |
---|
0,0 → 1,352 |
/* ldemul.c -- clearing house for ld emulation states |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
2001, 2002, 2003, 2005, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "getopt.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "ldmain.h" |
#include "ldemul-list.h" |
static ld_emulation_xfer_type *ld_emulation; |
void |
ldemul_hll (char *name) |
{ |
ld_emulation->hll (name); |
} |
void |
ldemul_syslib (char *name) |
{ |
ld_emulation->syslib (name); |
} |
void |
ldemul_after_parse (void) |
{ |
ld_emulation->after_parse (); |
} |
void |
ldemul_before_parse (void) |
{ |
ld_emulation->before_parse (); |
} |
void |
ldemul_after_open (void) |
{ |
ld_emulation->after_open (); |
} |
void |
ldemul_after_allocation (void) |
{ |
ld_emulation->after_allocation (); |
} |
void |
ldemul_before_allocation (void) |
{ |
ld_emulation->before_allocation (); |
} |
void |
ldemul_set_output_arch (void) |
{ |
ld_emulation->set_output_arch (); |
} |
void |
ldemul_finish (void) |
{ |
ld_emulation->finish (); |
} |
void |
ldemul_set_symbols (void) |
{ |
if (ld_emulation->set_symbols) |
ld_emulation->set_symbols (); |
} |
void |
ldemul_create_output_section_statements (void) |
{ |
if (ld_emulation->create_output_section_statements) |
ld_emulation->create_output_section_statements (); |
} |
char * |
ldemul_get_script (int *isfile) |
{ |
return ld_emulation->get_script (isfile); |
} |
bfd_boolean |
ldemul_open_dynamic_archive (const char *arch, search_dirs_type *search, |
lang_input_statement_type *entry) |
{ |
if (ld_emulation->open_dynamic_archive) |
return (*ld_emulation->open_dynamic_archive) (arch, search, entry); |
return FALSE; |
} |
lang_output_section_statement_type * |
ldemul_place_orphan (asection *s, const char *name, int constraint) |
{ |
if (ld_emulation->place_orphan) |
return (*ld_emulation->place_orphan) (s, name, constraint); |
return NULL; |
} |
void |
ldemul_add_options (int ns, char **shortopts, int nl, |
struct option **longopts, int nrl, |
struct option **really_longopts) |
{ |
if (ld_emulation->add_options) |
(*ld_emulation->add_options) (ns, shortopts, nl, longopts, |
nrl, really_longopts); |
} |
bfd_boolean |
ldemul_handle_option (int optc) |
{ |
if (ld_emulation->handle_option) |
return (*ld_emulation->handle_option) (optc); |
return FALSE; |
} |
bfd_boolean |
ldemul_parse_args (int argc, char **argv) |
{ |
/* Try and use the emulation parser if there is one. */ |
if (ld_emulation->parse_args) |
return (*ld_emulation->parse_args) (argc, argv); |
return FALSE; |
} |
/* Let the emulation code handle an unrecognized file. */ |
bfd_boolean |
ldemul_unrecognized_file (lang_input_statement_type *entry) |
{ |
if (ld_emulation->unrecognized_file) |
return (*ld_emulation->unrecognized_file) (entry); |
return FALSE; |
} |
/* Let the emulation code handle a recognized file. */ |
bfd_boolean |
ldemul_recognized_file (lang_input_statement_type *entry) |
{ |
if (ld_emulation->recognized_file) |
return (*ld_emulation->recognized_file) (entry); |
return FALSE; |
} |
char * |
ldemul_choose_target (int argc, char **argv) |
{ |
return ld_emulation->choose_target (argc, argv); |
} |
/* The default choose_target function. */ |
char * |
ldemul_default_target (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) |
{ |
char *from_outside = getenv (TARGET_ENVIRON); |
if (from_outside != (char *) NULL) |
return from_outside; |
return ld_emulation->target_name; |
} |
/* If the entry point was not specified as an address, then add the |
symbol as undefined. This will cause ld to extract an archive |
element defining the entry if ld is linking against such an archive. |
We don't do this when generating shared libraries unless given -e |
on the command line, because most shared libs are not designed to |
be run as an executable. However, some are, eg. glibc ld.so and |
may rely on the default linker script supplying ENTRY. So we can't |
remove the ENTRY from the script, but would rather not insert |
undefined _start syms. */ |
void |
after_parse_default (void) |
{ |
if (entry_symbol.name != NULL |
&& (link_info.executable || entry_from_cmdline)) |
{ |
bfd_boolean is_vma = FALSE; |
if (entry_from_cmdline) |
{ |
const char *send; |
bfd_scan_vma (entry_symbol.name, &send, 0); |
is_vma = *send == '\0'; |
} |
if (!is_vma) |
ldlang_add_undef (entry_symbol.name, entry_from_cmdline); |
} |
} |
void |
after_open_default (void) |
{ |
} |
void |
after_allocation_default (void) |
{ |
lang_relax_sections (FALSE); |
} |
void |
before_allocation_default (void) |
{ |
if (!link_info.relocatable) |
strip_excluded_output_sections (); |
} |
void |
finish_default (void) |
{ |
if (!link_info.relocatable) |
_bfd_fix_excluded_sec_syms (link_info.output_bfd, &link_info); |
} |
void |
set_output_arch_default (void) |
{ |
/* Set the output architecture and machine if possible. */ |
bfd_set_arch_mach (link_info.output_bfd, |
ldfile_output_architecture, ldfile_output_machine); |
bfd_emul_set_maxpagesize (output_target, config.maxpagesize); |
bfd_emul_set_commonpagesize (output_target, config.commonpagesize); |
} |
void |
syslib_default (char *ignore ATTRIBUTE_UNUSED) |
{ |
info_msg (_("%S SYSLIB ignored\n"), NULL); |
} |
void |
hll_default (char *ignore ATTRIBUTE_UNUSED) |
{ |
info_msg (_("%S HLL ignored\n"), NULL); |
} |
ld_emulation_xfer_type *ld_emulations[] = { EMULATION_LIST }; |
void |
ldemul_choose_mode (char *target) |
{ |
ld_emulation_xfer_type **eptr = ld_emulations; |
/* Ignore "gld" prefix. */ |
if (target[0] == 'g' && target[1] == 'l' && target[2] == 'd') |
target += 3; |
for (; *eptr; eptr++) |
{ |
if (strcmp (target, (*eptr)->emulation_name) == 0) |
{ |
ld_emulation = *eptr; |
return; |
} |
} |
einfo (_("%P: unrecognised emulation mode: %s\n"), target); |
einfo (_("Supported emulations: ")); |
ldemul_list_emulations (stderr); |
einfo ("%F\n"); |
} |
void |
ldemul_list_emulations (FILE *f) |
{ |
ld_emulation_xfer_type **eptr = ld_emulations; |
bfd_boolean first = TRUE; |
for (; *eptr; eptr++) |
{ |
if (first) |
first = FALSE; |
else |
fprintf (f, " "); |
fprintf (f, "%s", (*eptr)->emulation_name); |
} |
} |
void |
ldemul_list_emulation_options (FILE *f) |
{ |
ld_emulation_xfer_type **eptr; |
int options_found = 0; |
for (eptr = ld_emulations; *eptr; eptr++) |
{ |
ld_emulation_xfer_type *emul = *eptr; |
if (emul->list_options) |
{ |
fprintf (f, "%s: \n", emul->emulation_name); |
emul->list_options (f); |
options_found = 1; |
} |
} |
if (! options_found) |
fprintf (f, _(" no emulation specific options.\n")); |
} |
int |
ldemul_find_potential_libraries (char *name, lang_input_statement_type *entry) |
{ |
if (ld_emulation->find_potential_libraries) |
return ld_emulation->find_potential_libraries (name, entry); |
return 0; |
} |
struct bfd_elf_version_expr * |
ldemul_new_vers_pattern (struct bfd_elf_version_expr *entry) |
{ |
if (ld_emulation->new_vers_pattern) |
entry = (*ld_emulation->new_vers_pattern) (entry); |
return entry; |
} |
/contrib/toolchain/binutils/ld/ldemul.h |
---|
0,0 → 1,209 |
/* ld-emul.h - Linker emulation header file |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, |
2002, 2003, 2004, 2005, 2007, 2008 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDEMUL_H |
#define LDEMUL_H |
/* Forward declaration for ldemul_add_options() and others. */ |
struct option; |
extern void ldemul_hll |
(char *); |
extern void ldemul_syslib |
(char *); |
extern void ldemul_after_parse |
(void); |
extern void ldemul_before_parse |
(void); |
extern void ldemul_after_open |
(void); |
extern void ldemul_after_allocation |
(void); |
extern void ldemul_before_allocation |
(void); |
extern void ldemul_set_output_arch |
(void); |
extern char *ldemul_choose_target |
(int, char**); |
extern void ldemul_choose_mode |
(char *); |
extern void ldemul_list_emulations |
(FILE *); |
extern void ldemul_list_emulation_options |
(FILE *); |
extern char *ldemul_get_script |
(int *isfile); |
extern void ldemul_finish |
(void); |
extern void ldemul_set_symbols |
(void); |
extern void ldemul_create_output_section_statements |
(void); |
extern lang_output_section_statement_type *ldemul_place_orphan |
(asection *, const char *, int); |
extern bfd_boolean ldemul_parse_args |
(int, char **); |
extern void ldemul_add_options |
(int, char **, int, struct option **, int, struct option **); |
extern bfd_boolean ldemul_handle_option |
(int); |
extern bfd_boolean ldemul_unrecognized_file |
(struct lang_input_statement_struct *); |
extern bfd_boolean ldemul_recognized_file |
(struct lang_input_statement_struct *); |
extern bfd_boolean ldemul_open_dynamic_archive |
(const char *, struct search_dirs *, struct lang_input_statement_struct *); |
extern char *ldemul_default_target |
(int, char**); |
extern void after_parse_default |
(void); |
extern void after_open_default |
(void); |
extern void after_allocation_default |
(void); |
extern void before_allocation_default |
(void); |
extern void finish_default |
(void); |
extern void finish_default |
(void); |
extern void set_output_arch_default |
(void); |
extern void syslib_default |
(char*); |
extern void hll_default |
(char*); |
extern int ldemul_find_potential_libraries |
(char *, struct lang_input_statement_struct *); |
extern struct bfd_elf_version_expr *ldemul_new_vers_pattern |
(struct bfd_elf_version_expr *); |
typedef struct ld_emulation_xfer_struct { |
/* Run before parsing the command line and script file. |
Set the architecture, maybe other things. */ |
void (*before_parse) (void); |
/* Handle the SYSLIB (low level library) script command. */ |
void (*syslib) (char *); |
/* Handle the HLL (high level library) script command. */ |
void (*hll) (char *); |
/* Run after parsing the command line and script file. */ |
void (*after_parse) (void); |
/* Run after opening all input files, and loading the symbols. */ |
void (*after_open) (void); |
/* Run after allocating output sections. */ |
void (*after_allocation) (void); |
/* Set the output architecture and machine if possible. */ |
void (*set_output_arch) (void); |
/* Decide which target name to use. */ |
char * (*choose_target) (int, char**); |
/* Run before allocating output sections. */ |
void (*before_allocation) (void); |
/* Return the appropriate linker script. */ |
char * (*get_script) (int *isfile); |
/* The name of this emulation. */ |
char *emulation_name; |
/* The output format. */ |
char *target_name; |
/* Run after assigning values from the script. */ |
void (*finish) (void); |
/* Create any output sections needed by the target. */ |
void (*create_output_section_statements) (void); |
/* Try to open a dynamic library. ARCH is an architecture name, and |
is normally the empty string. ENTRY is the lang_input_statement |
that should be opened. */ |
bfd_boolean (*open_dynamic_archive) |
(const char *arch, struct search_dirs *, |
struct lang_input_statement_struct *entry); |
/* Place an orphan section. Return TRUE if it was placed, FALSE if |
the default action should be taken. This field may be NULL, in |
which case the default action will always be taken. */ |
lang_output_section_statement_type *(*place_orphan) |
(asection *, const char *, int); |
/* Run after assigning parsing with the args, but before |
reading the script. Used to initialize symbols used in the script. */ |
void (*set_symbols) (void); |
/* Parse args which the base linker doesn't understand. |
Return TRUE if the arg needs no further processing. */ |
bfd_boolean (*parse_args) (int, char **); |
/* Hook to add options to parameters passed by the base linker to |
getopt_long and getopt_long_only calls. */ |
void (*add_options) |
(int, char **, int, struct option **, int, struct option **); |
/* Companion to the above to handle an option. Returns TRUE if it is |
one of our options. */ |
bfd_boolean (*handle_option) (int); |
/* Run to handle files which are not recognized as object files or |
archives. Return TRUE if the file was handled. */ |
bfd_boolean (*unrecognized_file) |
(struct lang_input_statement_struct *); |
/* Run to list the command line options which parse_args handles. */ |
void (* list_options) (FILE *); |
/* Run to specially handle files which *are* recognized as object |
files or archives. Return TRUE if the file was handled. */ |
bfd_boolean (*recognized_file) |
(struct lang_input_statement_struct *); |
/* Called when looking for libraries in a directory specified |
via a linker command line option or linker script option. |
Files that match the pattern "lib*.a" have already been scanned. |
(For VMS files matching ":lib*.a" have also been scanned). */ |
int (* find_potential_libraries) |
(char *, struct lang_input_statement_struct *); |
/* Called when adding a new version pattern. PowerPC64-ELF uses |
this hook to add a pattern matching ".foo" for every "foo". */ |
struct bfd_elf_version_expr * (*new_vers_pattern) |
(struct bfd_elf_version_expr *); |
} ld_emulation_xfer_type; |
typedef enum { |
intel_ic960_ld_mode_enum, |
default_mode_enum, |
intel_gld960_ld_mode_enum |
} lang_emulation_mode_enum_type; |
extern ld_emulation_xfer_type *ld_emulations[]; |
#endif |
/contrib/toolchain/binutils/ld/ldexp.c |
---|
0,0 → 1,1357 |
/* This module handles expression trees. |
Copyright 1991-2013 Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This module is in charge of working out the contents of expressions. |
It has to keep track of the relative/absness of a symbol etc. This |
is done by keeping all values in a struct (an etree_value_type) |
which contains a value, a section to which it is relative and a |
valid bit. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlex.h" |
#include <ldgram.h> |
#include "ldlang.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
static void exp_fold_tree_1 (etree_type *); |
static bfd_vma align_n (bfd_vma, bfd_vma); |
segment_type *segments; |
struct ldexp_control expld; |
/* Print the string representation of the given token. Surround it |
with spaces if INFIX_P is TRUE. */ |
static void |
exp_print_token (token_code_type code, int infix_p) |
{ |
static const struct |
{ |
token_code_type code; |
const char * name; |
} |
table[] = |
{ |
{ INT, "int" }, |
{ NAME, "NAME" }, |
{ PLUSEQ, "+=" }, |
{ MINUSEQ, "-=" }, |
{ MULTEQ, "*=" }, |
{ DIVEQ, "/=" }, |
{ LSHIFTEQ, "<<=" }, |
{ RSHIFTEQ, ">>=" }, |
{ ANDEQ, "&=" }, |
{ OREQ, "|=" }, |
{ OROR, "||" }, |
{ ANDAND, "&&" }, |
{ EQ, "==" }, |
{ NE, "!=" }, |
{ LE, "<=" }, |
{ GE, ">=" }, |
{ LSHIFT, "<<" }, |
{ RSHIFT, ">>" }, |
{ LOG2CEIL, "LOG2CEIL" }, |
{ ALIGN_K, "ALIGN" }, |
{ BLOCK, "BLOCK" }, |
{ QUAD, "QUAD" }, |
{ SQUAD, "SQUAD" }, |
{ LONG, "LONG" }, |
{ SHORT, "SHORT" }, |
{ BYTE, "BYTE" }, |
{ SECTIONS, "SECTIONS" }, |
{ SIZEOF_HEADERS, "SIZEOF_HEADERS" }, |
{ MEMORY, "MEMORY" }, |
{ DEFINED, "DEFINED" }, |
{ TARGET_K, "TARGET" }, |
{ SEARCH_DIR, "SEARCH_DIR" }, |
{ MAP, "MAP" }, |
{ ENTRY, "ENTRY" }, |
{ NEXT, "NEXT" }, |
{ ALIGNOF, "ALIGNOF" }, |
{ SIZEOF, "SIZEOF" }, |
{ ADDR, "ADDR" }, |
{ LOADADDR, "LOADADDR" }, |
{ CONSTANT, "CONSTANT" }, |
{ ABSOLUTE, "ABSOLUTE" }, |
{ MAX_K, "MAX" }, |
{ MIN_K, "MIN" }, |
{ ASSERT_K, "ASSERT" }, |
{ REL, "relocatable" }, |
{ DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" }, |
{ DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" }, |
{ DATA_SEGMENT_END, "DATA_SEGMENT_END" }, |
{ ORIGIN, "ORIGIN" }, |
{ LENGTH, "LENGTH" }, |
{ SEGMENT_START, "SEGMENT_START" } |
}; |
unsigned int idx; |
for (idx = 0; idx < ARRAY_SIZE (table); idx++) |
if (table[idx].code == code) |
break; |
if (infix_p) |
fputc (' ', config.map_file); |
if (idx < ARRAY_SIZE (table)) |
fputs (table[idx].name, config.map_file); |
else if (code < 127) |
fputc (code, config.map_file); |
else |
fprintf (config.map_file, "<code %d>", code); |
if (infix_p) |
fputc (' ', config.map_file); |
} |
static void |
make_log2ceil (void) |
{ |
bfd_vma value = expld.result.value; |
bfd_vma result = -1; |
bfd_boolean round_up = FALSE; |
do |
{ |
result++; |
/* If more than one bit is set in the value we will need to round up. */ |
if ((value > 1) && (value & 1)) |
round_up = TRUE; |
} |
while (value >>= 1); |
if (round_up) |
result += 1; |
expld.result.section = NULL; |
expld.result.value = result; |
} |
static void |
make_abs (void) |
{ |
if (expld.result.section != NULL) |
expld.result.value += expld.result.section->vma; |
expld.result.section = bfd_abs_section_ptr; |
} |
static void |
new_abs (bfd_vma value) |
{ |
expld.result.valid_p = TRUE; |
expld.result.section = bfd_abs_section_ptr; |
expld.result.value = value; |
expld.result.str = NULL; |
} |
etree_type * |
exp_intop (bfd_vma value) |
{ |
etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value)); |
new_e->type.node_code = INT; |
new_e->type.filename = ldlex_filename (); |
new_e->type.lineno = lineno; |
new_e->value.value = value; |
new_e->value.str = NULL; |
new_e->type.node_class = etree_value; |
return new_e; |
} |
etree_type * |
exp_bigintop (bfd_vma value, char *str) |
{ |
etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value)); |
new_e->type.node_code = INT; |
new_e->type.filename = ldlex_filename (); |
new_e->type.lineno = lineno; |
new_e->value.value = value; |
new_e->value.str = str; |
new_e->type.node_class = etree_value; |
return new_e; |
} |
/* Build an expression representing an unnamed relocatable value. */ |
etree_type * |
exp_relop (asection *section, bfd_vma value) |
{ |
etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->rel)); |
new_e->type.node_code = REL; |
new_e->type.filename = ldlex_filename (); |
new_e->type.lineno = lineno; |
new_e->type.node_class = etree_rel; |
new_e->rel.section = section; |
new_e->rel.value = value; |
return new_e; |
} |
static void |
new_number (bfd_vma value) |
{ |
expld.result.valid_p = TRUE; |
expld.result.value = value; |
expld.result.str = NULL; |
expld.result.section = NULL; |
} |
static void |
new_rel (bfd_vma value, asection *section) |
{ |
expld.result.valid_p = TRUE; |
expld.result.value = value; |
expld.result.str = NULL; |
expld.result.section = section; |
} |
static void |
new_rel_from_abs (bfd_vma value) |
{ |
asection *s = expld.section; |
if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum) |
s = section_for_dot (); |
expld.result.valid_p = TRUE; |
expld.result.value = value - s->vma; |
expld.result.str = NULL; |
expld.result.section = s; |
} |
static void |
fold_unary (etree_type *tree) |
{ |
exp_fold_tree_1 (tree->unary.child); |
if (expld.result.valid_p) |
{ |
switch (tree->type.node_code) |
{ |
case ALIGN_K: |
if (expld.phase != lang_first_phase_enum) |
new_rel_from_abs (align_n (expld.dot, expld.result.value)); |
else |
expld.result.valid_p = FALSE; |
break; |
case ABSOLUTE: |
make_abs (); |
break; |
case LOG2CEIL: |
make_log2ceil (); |
break; |
case '~': |
expld.result.value = ~expld.result.value; |
break; |
case '!': |
expld.result.value = !expld.result.value; |
break; |
case '-': |
expld.result.value = -expld.result.value; |
break; |
case NEXT: |
/* Return next place aligned to value. */ |
if (expld.phase != lang_first_phase_enum) |
{ |
make_abs (); |
expld.result.value = align_n (expld.dot, expld.result.value); |
} |
else |
expld.result.valid_p = FALSE; |
break; |
case DATA_SEGMENT_END: |
if (expld.phase == lang_first_phase_enum |
|| expld.section != bfd_abs_section_ptr) |
{ |
expld.result.valid_p = FALSE; |
} |
else if (expld.dataseg.phase == exp_dataseg_align_seen |
|| expld.dataseg.phase == exp_dataseg_relro_seen) |
{ |
expld.dataseg.phase = exp_dataseg_end_seen; |
expld.dataseg.end = expld.result.value; |
} |
else if (expld.dataseg.phase == exp_dataseg_done |
|| expld.dataseg.phase == exp_dataseg_adjust |
|| expld.dataseg.phase == exp_dataseg_relro_adjust) |
{ |
/* OK. */ |
} |
else |
expld.result.valid_p = FALSE; |
break; |
default: |
FAIL (); |
break; |
} |
} |
} |
static void |
fold_binary (etree_type *tree) |
{ |
etree_value_type lhs; |
exp_fold_tree_1 (tree->binary.lhs); |
/* The SEGMENT_START operator is special because its first |
operand is a string, not the name of a symbol. Note that the |
operands have been swapped, so binary.lhs is second (default) |
operand, binary.rhs is first operand. */ |
if (expld.result.valid_p && tree->type.node_code == SEGMENT_START) |
{ |
const char *segment_name; |
segment_type *seg; |
/* Check to see if the user has overridden the default |
value. */ |
segment_name = tree->binary.rhs->name.name; |
for (seg = segments; seg; seg = seg->next) |
if (strcmp (seg->name, segment_name) == 0) |
{ |
if (!seg->used |
&& config.magic_demand_paged |
&& (seg->value % config.maxpagesize) != 0) |
einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"), |
segment_name); |
seg->used = TRUE; |
new_rel_from_abs (seg->value); |
break; |
} |
return; |
} |
lhs = expld.result; |
exp_fold_tree_1 (tree->binary.rhs); |
expld.result.valid_p &= lhs.valid_p; |
if (expld.result.valid_p) |
{ |
if (lhs.section != expld.result.section) |
{ |
/* If the values are from different sections, and neither is |
just a number, make both the source arguments absolute. */ |
if (expld.result.section != NULL |
&& lhs.section != NULL) |
{ |
make_abs (); |
lhs.value += lhs.section->vma; |
lhs.section = bfd_abs_section_ptr; |
} |
/* If the rhs is just a number, keep the lhs section. */ |
else if (expld.result.section == NULL) |
{ |
expld.result.section = lhs.section; |
/* Make this NULL so that we know one of the operands |
was just a number, for later tests. */ |
lhs.section = NULL; |
} |
} |
/* At this point we know that both operands have the same |
section, or at least one of them is a plain number. */ |
switch (tree->type.node_code) |
{ |
/* Arithmetic operators, bitwise AND, bitwise OR and XOR |
keep the section of one of their operands only when the |
other operand is a plain number. Losing the section when |
operating on two symbols, ie. a result of a plain number, |
is required for subtraction and XOR. It's justifiable |
for the other operations on the grounds that adding, |
multiplying etc. two section relative values does not |
really make sense unless they are just treated as |
numbers. |
The same argument could be made for many expressions |
involving one symbol and a number. For example, |
"1 << x" and "100 / x" probably should not be given the |
section of x. The trouble is that if we fuss about such |
things the rules become complex and it is onerous to |
document ld expression evaluation. */ |
#define BOP(x, y) \ |
case x: \ |
expld.result.value = lhs.value y expld.result.value; \ |
if (expld.result.section == lhs.section) \ |
expld.result.section = NULL; \ |
break; |
/* Comparison operators, logical AND, and logical OR always |
return a plain number. */ |
#define BOPN(x, y) \ |
case x: \ |
expld.result.value = lhs.value y expld.result.value; \ |
expld.result.section = NULL; \ |
break; |
BOP ('+', +); |
BOP ('*', *); |
BOP ('-', -); |
BOP (LSHIFT, <<); |
BOP (RSHIFT, >>); |
BOP ('&', &); |
BOP ('^', ^); |
BOP ('|', |); |
BOPN (EQ, ==); |
BOPN (NE, !=); |
BOPN ('<', <); |
BOPN ('>', >); |
BOPN (LE, <=); |
BOPN (GE, >=); |
BOPN (ANDAND, &&); |
BOPN (OROR, ||); |
case '%': |
if (expld.result.value != 0) |
expld.result.value = ((bfd_signed_vma) lhs.value |
% (bfd_signed_vma) expld.result.value); |
else if (expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S %% by zero\n"), tree->binary.rhs); |
if (expld.result.section == lhs.section) |
expld.result.section = NULL; |
break; |
case '/': |
if (expld.result.value != 0) |
expld.result.value = ((bfd_signed_vma) lhs.value |
/ (bfd_signed_vma) expld.result.value); |
else if (expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S / by zero\n"), tree->binary.rhs); |
if (expld.result.section == lhs.section) |
expld.result.section = NULL; |
break; |
case MAX_K: |
if (lhs.value > expld.result.value) |
expld.result.value = lhs.value; |
break; |
case MIN_K: |
if (lhs.value < expld.result.value) |
expld.result.value = lhs.value; |
break; |
case ALIGN_K: |
expld.result.value = align_n (lhs.value, expld.result.value); |
break; |
case DATA_SEGMENT_ALIGN: |
expld.dataseg.relro = exp_dataseg_relro_start; |
if (expld.phase == lang_first_phase_enum |
|| expld.section != bfd_abs_section_ptr) |
expld.result.valid_p = FALSE; |
else |
{ |
bfd_vma maxpage = lhs.value; |
bfd_vma commonpage = expld.result.value; |
expld.result.value = align_n (expld.dot, maxpage); |
if (expld.dataseg.phase == exp_dataseg_relro_adjust) |
expld.result.value = expld.dataseg.base; |
else if (expld.dataseg.phase == exp_dataseg_adjust) |
{ |
if (commonpage < maxpage) |
expld.result.value += ((expld.dot + commonpage - 1) |
& (maxpage - commonpage)); |
} |
else |
{ |
expld.result.value += expld.dot & (maxpage - 1); |
if (expld.dataseg.phase == exp_dataseg_done) |
{ |
/* OK. */ |
} |
else if (expld.dataseg.phase == exp_dataseg_none) |
{ |
expld.dataseg.phase = exp_dataseg_align_seen; |
expld.dataseg.min_base = expld.dot; |
expld.dataseg.base = expld.result.value; |
expld.dataseg.pagesize = commonpage; |
expld.dataseg.maxpagesize = maxpage; |
expld.dataseg.relro_end = 0; |
} |
else |
expld.result.valid_p = FALSE; |
} |
} |
break; |
case DATA_SEGMENT_RELRO_END: |
expld.dataseg.relro = exp_dataseg_relro_end; |
if (expld.phase == lang_first_phase_enum |
|| expld.section != bfd_abs_section_ptr) |
expld.result.valid_p = FALSE; |
else if (expld.dataseg.phase == exp_dataseg_align_seen |
|| expld.dataseg.phase == exp_dataseg_adjust |
|| expld.dataseg.phase == exp_dataseg_relro_adjust |
|| expld.dataseg.phase == exp_dataseg_done) |
{ |
if (expld.dataseg.phase == exp_dataseg_align_seen |
|| expld.dataseg.phase == exp_dataseg_relro_adjust) |
expld.dataseg.relro_end = lhs.value + expld.result.value; |
if (expld.dataseg.phase == exp_dataseg_relro_adjust |
&& (expld.dataseg.relro_end |
& (expld.dataseg.pagesize - 1))) |
{ |
expld.dataseg.relro_end += expld.dataseg.pagesize - 1; |
expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1); |
expld.result.value = (expld.dataseg.relro_end |
- expld.result.value); |
} |
else |
expld.result.value = lhs.value; |
if (expld.dataseg.phase == exp_dataseg_align_seen) |
expld.dataseg.phase = exp_dataseg_relro_seen; |
} |
else |
expld.result.valid_p = FALSE; |
break; |
default: |
FAIL (); |
} |
} |
} |
static void |
fold_trinary (etree_type *tree) |
{ |
exp_fold_tree_1 (tree->trinary.cond); |
if (expld.result.valid_p) |
exp_fold_tree_1 (expld.result.value |
? tree->trinary.lhs |
: tree->trinary.rhs); |
} |
static void |
fold_name (etree_type *tree) |
{ |
memset (&expld.result, 0, sizeof (expld.result)); |
switch (tree->type.node_code) |
{ |
case SIZEOF_HEADERS: |
if (expld.phase != lang_first_phase_enum) |
{ |
bfd_vma hdr_size = 0; |
/* Don't find the real header size if only marking sections; |
The bfd function may cache incorrect data. */ |
if (expld.phase != lang_mark_phase_enum) |
hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info); |
new_number (hdr_size); |
} |
break; |
case DEFINED: |
if (expld.phase == lang_first_phase_enum) |
lang_track_definedness (tree->name.name); |
else |
{ |
struct bfd_link_hash_entry *h; |
int def_iteration |
= lang_symbol_definition_iteration (tree->name.name); |
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, |
&link_info, |
tree->name.name, |
FALSE, FALSE, TRUE); |
new_number (h != NULL |
&& (h->type == bfd_link_hash_defined |
|| h->type == bfd_link_hash_defweak |
|| h->type == bfd_link_hash_common) |
&& (def_iteration == lang_statement_iteration |
|| def_iteration == -1)); |
} |
break; |
case NAME: |
if (expld.assign_name != NULL |
&& strcmp (expld.assign_name, tree->name.name) == 0) |
expld.assign_name = NULL; |
if (expld.phase == lang_first_phase_enum) |
; |
else if (tree->name.name[0] == '.' && tree->name.name[1] == 0) |
new_rel_from_abs (expld.dot); |
else |
{ |
struct bfd_link_hash_entry *h; |
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, |
&link_info, |
tree->name.name, |
TRUE, FALSE, TRUE); |
if (!h) |
einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); |
else if (h->type == bfd_link_hash_defined |
|| h->type == bfd_link_hash_defweak) |
{ |
asection *output_section; |
output_section = h->u.def.section->output_section; |
if (output_section == NULL) |
{ |
if (expld.phase == lang_mark_phase_enum) |
new_rel (h->u.def.value, h->u.def.section); |
else |
einfo (_("%X%S: unresolvable symbol `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
} |
else if (output_section == bfd_abs_section_ptr |
&& (expld.section != bfd_abs_section_ptr |
|| config.sane_expr)) |
new_number (h->u.def.value + h->u.def.section->output_offset); |
else |
new_rel (h->u.def.value + h->u.def.section->output_offset, |
output_section); |
} |
else if (expld.phase == lang_final_phase_enum |
|| (expld.phase != lang_mark_phase_enum |
&& expld.assigning_to_dot)) |
einfo (_("%F%S: undefined symbol `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
else if (h->type == bfd_link_hash_new) |
{ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = NULL; |
if (h->u.undef.next == NULL && h != link_info.hash->undefs_tail) |
bfd_link_add_undef (link_info.hash, h); |
} |
} |
break; |
case ADDR: |
if (expld.phase != lang_first_phase_enum) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_find (tree->name.name); |
if (os == NULL) |
{ |
if (expld.phase == lang_final_phase_enum) |
einfo (_("%F%S: undefined section `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
} |
else if (os->processed_vma) |
new_rel (0, os->bfd_section); |
} |
break; |
case LOADADDR: |
if (expld.phase != lang_first_phase_enum) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_find (tree->name.name); |
if (os == NULL) |
{ |
if (expld.phase == lang_final_phase_enum) |
einfo (_("%F%S: undefined section `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
} |
else if (os->processed_lma) |
{ |
if (os->load_base == NULL) |
new_abs (os->bfd_section->lma); |
else |
{ |
exp_fold_tree_1 (os->load_base); |
if (expld.result.valid_p) |
make_abs (); |
} |
} |
} |
break; |
case SIZEOF: |
case ALIGNOF: |
if (expld.phase != lang_first_phase_enum) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_find (tree->name.name); |
if (os == NULL) |
{ |
if (expld.phase == lang_final_phase_enum) |
einfo (_("%F%S: undefined section `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
new_number (0); |
} |
else if (os->bfd_section != NULL) |
{ |
bfd_vma val; |
if (tree->type.node_code == SIZEOF) |
val = (os->bfd_section->size |
/ bfd_octets_per_byte (link_info.output_bfd)); |
else |
val = (bfd_vma)1 << os->bfd_section->alignment_power; |
new_number (val); |
} |
else |
new_number (0); |
} |
break; |
case LENGTH: |
{ |
lang_memory_region_type *mem; |
mem = lang_memory_region_lookup (tree->name.name, FALSE); |
if (mem != NULL) |
new_number (mem->length); |
else |
einfo (_("%F%S: undefined MEMORY region `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
} |
break; |
case ORIGIN: |
if (expld.phase != lang_first_phase_enum) |
{ |
lang_memory_region_type *mem; |
mem = lang_memory_region_lookup (tree->name.name, FALSE); |
if (mem != NULL) |
new_rel_from_abs (mem->origin); |
else |
einfo (_("%F%S: undefined MEMORY region `%s'" |
" referenced in expression\n"), |
tree, tree->name.name); |
} |
break; |
case CONSTANT: |
if (strcmp (tree->name.name, "MAXPAGESIZE") == 0) |
new_number (config.maxpagesize); |
else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0) |
new_number (config.commonpagesize); |
else |
einfo (_("%F%S: unknown constant `%s' referenced in expression\n"), |
tree, tree->name.name); |
break; |
default: |
FAIL (); |
break; |
} |
} |
static void |
exp_fold_tree_1 (etree_type *tree) |
{ |
if (tree == NULL) |
{ |
memset (&expld.result, 0, sizeof (expld.result)); |
return; |
} |
switch (tree->type.node_class) |
{ |
case etree_value: |
if (expld.section == bfd_abs_section_ptr |
&& !config.sane_expr) |
new_abs (tree->value.value); |
else |
new_number (tree->value.value); |
expld.result.str = tree->value.str; |
break; |
case etree_rel: |
if (expld.phase != lang_first_phase_enum) |
{ |
asection *output_section = tree->rel.section->output_section; |
new_rel (tree->rel.value + tree->rel.section->output_offset, |
output_section); |
} |
else |
memset (&expld.result, 0, sizeof (expld.result)); |
break; |
case etree_assert: |
exp_fold_tree_1 (tree->assert_s.child); |
if (expld.phase == lang_final_phase_enum && !expld.result.value) |
einfo ("%X%P: %s\n", tree->assert_s.message); |
break; |
case etree_unary: |
fold_unary (tree); |
break; |
case etree_binary: |
fold_binary (tree); |
break; |
case etree_trinary: |
fold_trinary (tree); |
break; |
case etree_assign: |
case etree_provide: |
case etree_provided: |
if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) |
{ |
if (tree->type.node_class != etree_assign) |
einfo (_("%F%S can not PROVIDE assignment to" |
" location counter\n"), tree); |
if (expld.phase != lang_first_phase_enum) |
{ |
/* Notify the folder that this is an assignment to dot. */ |
expld.assigning_to_dot = TRUE; |
exp_fold_tree_1 (tree->assign.src); |
expld.assigning_to_dot = FALSE; |
if (!expld.result.valid_p) |
{ |
if (expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S invalid assignment to" |
" location counter\n"), tree); |
} |
else if (expld.dotp == NULL) |
einfo (_("%F%S assignment to location counter" |
" invalid outside of SECTIONS\n"), tree); |
/* After allocation, assignment to dot should not be |
done inside an output section since allocation adds a |
padding statement that effectively duplicates the |
assignment. */ |
else if (expld.phase <= lang_allocating_phase_enum |
|| expld.section == bfd_abs_section_ptr) |
{ |
bfd_vma nextdot; |
nextdot = expld.result.value; |
if (expld.result.section != NULL) |
nextdot += expld.result.section->vma; |
else |
nextdot += expld.section->vma; |
if (nextdot < expld.dot |
&& expld.section != bfd_abs_section_ptr) |
einfo (_("%F%S cannot move location counter backwards" |
" (from %V to %V)\n"), |
tree, expld.dot, nextdot); |
else |
{ |
expld.dot = nextdot; |
*expld.dotp = nextdot; |
} |
} |
} |
else |
memset (&expld.result, 0, sizeof (expld.result)); |
} |
else |
{ |
struct bfd_link_hash_entry *h = NULL; |
if (tree->type.node_class == etree_provide) |
{ |
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, |
FALSE, FALSE, TRUE); |
if (h == NULL |
|| (h->type != bfd_link_hash_new |
&& h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common)) |
{ |
/* Do nothing. The symbol was never referenced, or was |
defined by some object. */ |
break; |
} |
} |
expld.assign_name = tree->assign.dst; |
exp_fold_tree_1 (tree->assign.src); |
/* expld.assign_name remaining equal to tree->assign.dst |
below indicates the evaluation of tree->assign.src did |
not use the value of tree->assign.dst. We don't allow |
self assignment until the final phase for two reasons: |
1) Expressions are evaluated multiple times. With |
relaxation, the number of times may vary. |
2) Section relative symbol values cannot be correctly |
converted to absolute values, as is required by many |
expressions, until final section sizing is complete. */ |
if ((expld.result.valid_p |
&& (expld.phase == lang_final_phase_enum |
|| expld.assign_name != NULL)) |
|| (expld.phase <= lang_mark_phase_enum |
&& tree->type.node_class == etree_assign |
&& tree->assign.defsym)) |
{ |
if (h == NULL) |
{ |
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, |
TRUE, FALSE, TRUE); |
if (h == NULL) |
einfo (_("%P%F:%s: hash creation failed\n"), |
tree->assign.dst); |
} |
/* FIXME: Should we worry if the symbol is already |
defined? */ |
lang_update_definedness (tree->assign.dst, h); |
h->type = bfd_link_hash_defined; |
h->u.def.value = expld.result.value; |
if (expld.result.section == NULL) |
expld.result.section = expld.section; |
h->u.def.section = expld.result.section; |
if (tree->type.node_class == etree_provide) |
tree->type.node_class = etree_provided; |
/* Copy the symbol type if this is a simple assignment of |
one symbol to another. This could be more general |
(e.g. a ?: operator with NAMEs in each branch). */ |
if (tree->assign.src->type.node_class == etree_name) |
{ |
struct bfd_link_hash_entry *hsrc; |
hsrc = bfd_link_hash_lookup (link_info.hash, |
tree->assign.src->name.name, |
FALSE, FALSE, TRUE); |
if (hsrc) |
bfd_copy_link_hash_symbol_type (link_info.output_bfd, h, |
hsrc); |
} |
} |
else if (expld.phase == lang_final_phase_enum) |
{ |
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, |
FALSE, FALSE, TRUE); |
if (h != NULL |
&& h->type == bfd_link_hash_new) |
h->type = bfd_link_hash_undefined; |
} |
expld.assign_name = NULL; |
} |
break; |
case etree_name: |
fold_name (tree); |
break; |
default: |
FAIL (); |
memset (&expld.result, 0, sizeof (expld.result)); |
break; |
} |
} |
void |
exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp) |
{ |
expld.dot = *dotp; |
expld.dotp = dotp; |
expld.section = current_section; |
exp_fold_tree_1 (tree); |
} |
void |
exp_fold_tree_no_dot (etree_type *tree) |
{ |
expld.dot = 0; |
expld.dotp = NULL; |
expld.section = bfd_abs_section_ptr; |
exp_fold_tree_1 (tree); |
} |
etree_type * |
exp_binop (int code, etree_type *lhs, etree_type *rhs) |
{ |
etree_type value, *new_e; |
value.type.node_code = code; |
value.type.filename = lhs->type.filename; |
value.type.lineno = lhs->type.lineno; |
value.binary.lhs = lhs; |
value.binary.rhs = rhs; |
value.type.node_class = etree_binary; |
exp_fold_tree_no_dot (&value); |
if (expld.result.valid_p) |
return exp_intop (expld.result.value); |
new_e = (etree_type *) stat_alloc (sizeof (new_e->binary)); |
memcpy (new_e, &value, sizeof (new_e->binary)); |
return new_e; |
} |
etree_type * |
exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs) |
{ |
etree_type value, *new_e; |
value.type.node_code = code; |
value.type.filename = cond->type.filename; |
value.type.lineno = cond->type.lineno; |
value.trinary.lhs = lhs; |
value.trinary.cond = cond; |
value.trinary.rhs = rhs; |
value.type.node_class = etree_trinary; |
exp_fold_tree_no_dot (&value); |
if (expld.result.valid_p) |
return exp_intop (expld.result.value); |
new_e = (etree_type *) stat_alloc (sizeof (new_e->trinary)); |
memcpy (new_e, &value, sizeof (new_e->trinary)); |
return new_e; |
} |
etree_type * |
exp_unop (int code, etree_type *child) |
{ |
etree_type value, *new_e; |
value.unary.type.node_code = code; |
value.unary.type.filename = child->type.filename; |
value.unary.type.lineno = child->type.lineno; |
value.unary.child = child; |
value.unary.type.node_class = etree_unary; |
exp_fold_tree_no_dot (&value); |
if (expld.result.valid_p) |
return exp_intop (expld.result.value); |
new_e = (etree_type *) stat_alloc (sizeof (new_e->unary)); |
memcpy (new_e, &value, sizeof (new_e->unary)); |
return new_e; |
} |
etree_type * |
exp_nameop (int code, const char *name) |
{ |
etree_type value, *new_e; |
value.name.type.node_code = code; |
value.name.type.filename = ldlex_filename (); |
value.name.type.lineno = lineno; |
value.name.name = name; |
value.name.type.node_class = etree_name; |
exp_fold_tree_no_dot (&value); |
if (expld.result.valid_p) |
return exp_intop (expld.result.value); |
new_e = (etree_type *) stat_alloc (sizeof (new_e->name)); |
memcpy (new_e, &value, sizeof (new_e->name)); |
return new_e; |
} |
static etree_type * |
exp_assop (const char *dst, |
etree_type *src, |
enum node_tree_enum class, |
bfd_boolean defsym, |
bfd_boolean hidden) |
{ |
etree_type *n; |
n = (etree_type *) stat_alloc (sizeof (n->assign)); |
n->assign.type.node_code = '='; |
n->assign.type.filename = src->type.filename; |
n->assign.type.lineno = src->type.lineno; |
n->assign.type.node_class = class; |
n->assign.src = src; |
n->assign.dst = dst; |
n->assign.defsym = defsym; |
n->assign.hidden = hidden; |
return n; |
} |
/* Handle linker script assignments and HIDDEN. */ |
etree_type * |
exp_assign (const char *dst, etree_type *src, bfd_boolean hidden) |
{ |
return exp_assop (dst, src, etree_assign, FALSE, hidden); |
} |
/* Handle --defsym command-line option. */ |
etree_type * |
exp_defsym (const char *dst, etree_type *src) |
{ |
return exp_assop (dst, src, etree_assign, TRUE, FALSE); |
} |
/* Handle PROVIDE. */ |
etree_type * |
exp_provide (const char *dst, etree_type *src, bfd_boolean hidden) |
{ |
return exp_assop (dst, src, etree_provide, FALSE, hidden); |
} |
/* Handle ASSERT. */ |
etree_type * |
exp_assert (etree_type *exp, const char *message) |
{ |
etree_type *n; |
n = (etree_type *) stat_alloc (sizeof (n->assert_s)); |
n->assert_s.type.node_code = '!'; |
n->assert_s.type.filename = exp->type.filename; |
n->assert_s.type.lineno = exp->type.lineno; |
n->assert_s.type.node_class = etree_assert; |
n->assert_s.child = exp; |
n->assert_s.message = message; |
return n; |
} |
void |
exp_print_tree (etree_type *tree) |
{ |
bfd_boolean function_like; |
if (config.map_file == NULL) |
config.map_file = stderr; |
if (tree == NULL) |
{ |
minfo ("NULL TREE\n"); |
return; |
} |
switch (tree->type.node_class) |
{ |
case etree_value: |
minfo ("0x%v", tree->value.value); |
return; |
case etree_rel: |
if (tree->rel.section->owner != NULL) |
minfo ("%B:", tree->rel.section->owner); |
minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value); |
return; |
case etree_assign: |
fputs (tree->assign.dst, config.map_file); |
exp_print_token (tree->type.node_code, TRUE); |
exp_print_tree (tree->assign.src); |
break; |
case etree_provide: |
case etree_provided: |
fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst); |
exp_print_tree (tree->assign.src); |
fputc (')', config.map_file); |
break; |
case etree_binary: |
function_like = FALSE; |
switch (tree->type.node_code) |
{ |
case MAX_K: |
case MIN_K: |
case ALIGN_K: |
case DATA_SEGMENT_ALIGN: |
case DATA_SEGMENT_RELRO_END: |
function_like = TRUE; |
break; |
case SEGMENT_START: |
/* Special handling because arguments are in reverse order and |
the segment name is quoted. */ |
exp_print_token (tree->type.node_code, FALSE); |
fputs (" (\"", config.map_file); |
exp_print_tree (tree->binary.rhs); |
fputs ("\", ", config.map_file); |
exp_print_tree (tree->binary.lhs); |
fputc (')', config.map_file); |
return; |
} |
if (function_like) |
{ |
exp_print_token (tree->type.node_code, FALSE); |
fputc (' ', config.map_file); |
} |
fputc ('(', config.map_file); |
exp_print_tree (tree->binary.lhs); |
if (function_like) |
fprintf (config.map_file, ", "); |
else |
exp_print_token (tree->type.node_code, TRUE); |
exp_print_tree (tree->binary.rhs); |
fputc (')', config.map_file); |
break; |
case etree_trinary: |
exp_print_tree (tree->trinary.cond); |
fputc ('?', config.map_file); |
exp_print_tree (tree->trinary.lhs); |
fputc (':', config.map_file); |
exp_print_tree (tree->trinary.rhs); |
break; |
case etree_unary: |
exp_print_token (tree->unary.type.node_code, FALSE); |
if (tree->unary.child) |
{ |
fprintf (config.map_file, " ("); |
exp_print_tree (tree->unary.child); |
fputc (')', config.map_file); |
} |
break; |
case etree_assert: |
fprintf (config.map_file, "ASSERT ("); |
exp_print_tree (tree->assert_s.child); |
fprintf (config.map_file, ", %s)", tree->assert_s.message); |
break; |
case etree_name: |
if (tree->type.node_code == NAME) |
fputs (tree->name.name, config.map_file); |
else |
{ |
exp_print_token (tree->type.node_code, FALSE); |
if (tree->name.name) |
fprintf (config.map_file, " (%s)", tree->name.name); |
} |
break; |
default: |
FAIL (); |
break; |
} |
} |
bfd_vma |
exp_get_vma (etree_type *tree, bfd_vma def, char *name) |
{ |
if (tree != NULL) |
{ |
exp_fold_tree_no_dot (tree); |
if (expld.result.valid_p) |
return expld.result.value; |
else if (name != NULL && expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S: nonconstant expression for %s\n"), |
tree, name); |
} |
return def; |
} |
int |
exp_get_value_int (etree_type *tree, int def, char *name) |
{ |
return exp_get_vma (tree, def, name); |
} |
fill_type * |
exp_get_fill (etree_type *tree, fill_type *def, char *name) |
{ |
fill_type *fill; |
size_t len; |
unsigned int val; |
if (tree == NULL) |
return def; |
exp_fold_tree_no_dot (tree); |
if (!expld.result.valid_p) |
{ |
if (name != NULL && expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S: nonconstant expression for %s\n"), |
tree, name); |
return def; |
} |
if (expld.result.str != NULL && (len = strlen (expld.result.str)) != 0) |
{ |
unsigned char *dst; |
unsigned char *s; |
fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1); |
fill->size = (len + 1) / 2; |
dst = fill->data; |
s = (unsigned char *) expld.result.str; |
val = 0; |
do |
{ |
unsigned int digit; |
digit = *s++ - '0'; |
if (digit > 9) |
digit = (digit - 'A' + '0' + 10) & 0xf; |
val <<= 4; |
val += digit; |
--len; |
if ((len & 1) == 0) |
{ |
*dst++ = val; |
val = 0; |
} |
} |
while (len != 0); |
} |
else |
{ |
fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1); |
val = expld.result.value; |
fill->data[0] = (val >> 24) & 0xff; |
fill->data[1] = (val >> 16) & 0xff; |
fill->data[2] = (val >> 8) & 0xff; |
fill->data[3] = (val >> 0) & 0xff; |
fill->size = 4; |
} |
return fill; |
} |
bfd_vma |
exp_get_abs_int (etree_type *tree, int def, char *name) |
{ |
if (tree != NULL) |
{ |
exp_fold_tree_no_dot (tree); |
if (expld.result.valid_p) |
{ |
if (expld.result.section != NULL) |
expld.result.value += expld.result.section->vma; |
return expld.result.value; |
} |
else if (name != NULL && expld.phase != lang_mark_phase_enum) |
{ |
einfo (_("%F%S: nonconstant expression for %s\n"), |
tree, name); |
} |
} |
return def; |
} |
static bfd_vma |
align_n (bfd_vma value, bfd_vma align) |
{ |
if (align <= 1) |
return value; |
value = (value + align - 1) / align; |
return value * align; |
} |
/contrib/toolchain/binutils/ld/ldexp.h |
---|
0,0 → 1,226 |
/* ldexp.h - |
Copyright 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2007, 2011, 2012 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDEXP_H |
#define LDEXP_H |
/* The result of an expression tree */ |
typedef struct { |
bfd_vma value; |
char *str; |
asection *section; |
bfd_boolean valid_p; |
} etree_value_type; |
enum node_tree_enum { |
etree_binary, |
etree_trinary, |
etree_unary, |
etree_name, |
etree_assign, |
etree_provide, |
etree_provided, |
etree_value, |
etree_assert, |
etree_rel |
}; |
typedef struct { |
int node_code; |
unsigned int lineno; |
const char *filename; |
enum node_tree_enum node_class; |
} node_type; |
typedef union etree_union { |
node_type type; |
struct { |
node_type type; |
union etree_union *lhs; |
union etree_union *rhs; |
} binary; |
struct { |
node_type type; |
union etree_union *cond; |
union etree_union *lhs; |
union etree_union *rhs; |
} trinary; |
struct { |
node_type type; |
const char *dst; |
union etree_union *src; |
bfd_boolean defsym; |
bfd_boolean hidden; |
} assign; |
struct { |
node_type type; |
union etree_union *child; |
} unary; |
struct { |
node_type type; |
const char *name; |
} name; |
struct { |
node_type type; |
bfd_vma value; |
char *str; |
} value; |
struct { |
node_type type; |
asection *section; |
bfd_vma value; |
} rel; |
struct { |
node_type type; |
union etree_union *child; |
const char *message; |
} assert_s; |
} etree_type; |
/* Expression evaluation control. */ |
typedef enum |
{ |
/* Parsing linker script. Will only return "valid" for expressions |
that evaluate to a constant. */ |
lang_first_phase_enum, |
/* Prior to section sizing. */ |
lang_mark_phase_enum, |
/* During section sizing. */ |
lang_allocating_phase_enum, |
/* During assignment of symbol values when relaxation in progress. */ |
lang_assigning_phase_enum, |
/* Final assignment of symbol values. */ |
lang_final_phase_enum |
} lang_phase_type; |
union lang_statement_union; |
enum phase_enum { |
/* We step through the first four states here as we see the |
associated linker script tokens. */ |
exp_dataseg_none, |
exp_dataseg_align_seen, |
exp_dataseg_relro_seen, |
exp_dataseg_end_seen, |
/* The last three states are final, and affect the value returned |
by DATA_SEGMENT_ALIGN. */ |
exp_dataseg_relro_adjust, |
exp_dataseg_adjust, |
exp_dataseg_done |
}; |
enum relro_enum { |
exp_dataseg_relro_none, |
exp_dataseg_relro_start, |
exp_dataseg_relro_end, |
}; |
struct ldexp_control { |
/* Modify expression evaluation depending on this. */ |
lang_phase_type phase; |
/* Principally used for diagnostics. */ |
bfd_boolean assigning_to_dot; |
/* If evaluating an assignment, the destination. Cleared if an |
etree_name NAME matches this, to signal a self-assignment. |
Note that an etree_name DEFINED does not clear this field, nor |
does the false branch of a trinary expression. */ |
const char *assign_name; |
/* Working results. */ |
etree_value_type result; |
bfd_vma dot; |
/* Current dot and section passed to ldexp folder. */ |
bfd_vma *dotp; |
asection *section; |
/* State machine and results for DATASEG. */ |
struct { |
enum phase_enum phase; |
bfd_vma base, min_base, relro_end, end, pagesize, maxpagesize; |
enum relro_enum relro; |
union lang_statement_union *relro_start_stat; |
union lang_statement_union *relro_end_stat; |
} dataseg; |
}; |
extern struct ldexp_control expld; |
/* A maps from a segment name to a base address. */ |
typedef struct segment_struct { |
/* The next segment in the linked list. */ |
struct segment_struct *next; |
/* The name of the sgement. */ |
const char *name; |
/* The base address for the segment. */ |
bfd_vma value; |
/* True if a SEGMENT_START directive corresponding to this segment |
has been seen. */ |
bfd_boolean used; |
} segment_type; |
/* The segments specified by the user on the command-line. */ |
extern segment_type *segments; |
typedef struct _fill_type fill_type; |
etree_type *exp_intop |
(bfd_vma); |
etree_type *exp_bigintop |
(bfd_vma, char *); |
etree_type *exp_relop |
(asection *, bfd_vma); |
void exp_fold_tree |
(etree_type *, asection *, bfd_vma *); |
void exp_fold_tree_no_dot |
(etree_type *); |
etree_type *exp_binop |
(int, etree_type *, etree_type *); |
etree_type *exp_trinop |
(int,etree_type *, etree_type *, etree_type *); |
etree_type *exp_unop |
(int, etree_type *); |
etree_type *exp_nameop |
(int, const char *); |
etree_type *exp_assign |
(const char *, etree_type *, bfd_boolean); |
etree_type *exp_defsym |
(const char *, etree_type *); |
etree_type *exp_provide |
(const char *, etree_type *, bfd_boolean); |
etree_type *exp_assert |
(etree_type *, const char *); |
void exp_print_tree |
(etree_type *); |
bfd_vma exp_get_vma |
(etree_type *, bfd_vma, char *); |
int exp_get_value_int |
(etree_type *, int, char *); |
fill_type *exp_get_fill |
(etree_type *, fill_type *, char *); |
bfd_vma exp_get_abs_int |
(etree_type *, int, char *); |
#endif |
/contrib/toolchain/binutils/ld/ldfile.c |
---|
0,0 → 1,672 |
/* Linker file opening and searching. |
Copyright 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "safe-ctype.h" |
#include "ld.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "ldmain.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldemul.h" |
#include "libiberty.h" |
#include "filenames.h" |
#ifdef ENABLE_PLUGINS |
#include "plugin-api.h" |
#include "plugin.h" |
#endif /* ENABLE_PLUGINS */ |
bfd_boolean ldfile_assumed_script = FALSE; |
const char * ldfile_output_machine_name = ""; |
unsigned long ldfile_output_machine; |
enum bfd_architecture ldfile_output_architecture; |
search_dirs_type * search_head; |
#ifdef VMS |
static char * slash = ""; |
#else |
#if defined (_WIN32) && ! defined (__CYGWIN32__) |
static char * slash = "\\"; |
#else |
static char * slash = "/"; |
#endif |
#endif |
typedef struct search_arch |
{ |
char *name; |
struct search_arch *next; |
} search_arch_type; |
static search_dirs_type **search_tail_ptr = &search_head; |
static search_arch_type *search_arch_head; |
static search_arch_type **search_arch_tail_ptr = &search_arch_head; |
/* Test whether a pathname, after canonicalization, is the same or a |
sub-directory of the sysroot directory. */ |
static bfd_boolean |
is_sysrooted_pathname (const char *name) |
{ |
char *realname; |
int len; |
bfd_boolean result; |
if (ld_canon_sysroot == NULL) |
return FALSE; |
realname = lrealpath (name); |
len = strlen (realname); |
result = FALSE; |
if (len > ld_canon_sysroot_len |
&& IS_DIR_SEPARATOR (realname[ld_canon_sysroot_len])) |
{ |
realname[ld_canon_sysroot_len] = '\0'; |
result = FILENAME_CMP (ld_canon_sysroot, realname) == 0; |
} |
free (realname); |
return result; |
} |
/* Adds NAME to the library search path. |
Makes a copy of NAME using xmalloc(). */ |
void |
ldfile_add_library_path (const char *name, bfd_boolean cmdline) |
{ |
search_dirs_type *new_dirs; |
if (!cmdline && config.only_cmd_line_lib_dirs) |
return; |
new_dirs = (search_dirs_type *) xmalloc (sizeof (search_dirs_type)); |
new_dirs->next = NULL; |
new_dirs->cmdline = cmdline; |
*search_tail_ptr = new_dirs; |
search_tail_ptr = &new_dirs->next; |
/* If a directory is marked as honoring sysroot, prepend the sysroot path |
now. */ |
if (name[0] == '=') |
new_dirs->name = concat (ld_sysroot, name + 1, (const char *) NULL); |
else |
new_dirs->name = xstrdup (name); |
} |
/* Try to open a BFD for a lang_input_statement. */ |
bfd_boolean |
ldfile_try_open_bfd (const char *attempt, |
lang_input_statement_type *entry) |
{ |
entry->the_bfd = bfd_openr (attempt, entry->target); |
if (verbose) |
{ |
if (entry->the_bfd == NULL) |
info_msg (_("attempt to open %s failed\n"), attempt); |
else |
info_msg (_("attempt to open %s succeeded\n"), attempt); |
} |
if (entry->the_bfd == NULL) |
{ |
if (bfd_get_error () == bfd_error_invalid_target) |
einfo (_("%F%P: invalid BFD target `%s'\n"), entry->target); |
return FALSE; |
} |
/* Linker needs to decompress sections. */ |
entry->the_bfd->flags |= BFD_DECOMPRESS; |
/* If we are searching for this file, see if the architecture is |
compatible with the output file. If it isn't, keep searching. |
If we can't open the file as an object file, stop the search |
here. If we are statically linking, ensure that we don't link |
a dynamic object. |
In the code below, it's OK to exit early if the check fails, |
closing the checked BFD and returning FALSE, but if the BFD |
checks out compatible, do not exit early returning TRUE, or |
the plugins will not get a chance to claim the file. */ |
if (entry->flags.search_dirs || !entry->flags.dynamic) |
{ |
bfd *check; |
if (bfd_check_format (entry->the_bfd, bfd_archive)) |
check = bfd_openr_next_archived_file (entry->the_bfd, NULL); |
else |
check = entry->the_bfd; |
if (check != NULL) |
{ |
if (! bfd_check_format (check, bfd_object)) |
{ |
if (check == entry->the_bfd |
&& entry->flags.search_dirs |
&& bfd_get_error () == bfd_error_file_not_recognized |
&& ! ldemul_unrecognized_file (entry)) |
{ |
int token, skip = 0; |
char *arg, *arg1, *arg2, *arg3; |
extern FILE *yyin; |
/* Try to interpret the file as a linker script. */ |
ldfile_open_command_file (attempt); |
ldfile_assumed_script = TRUE; |
parser_input = input_selected; |
ldlex_both (); |
token = INPUT_SCRIPT; |
while (token != 0) |
{ |
switch (token) |
{ |
case OUTPUT_FORMAT: |
if ((token = yylex ()) != '(') |
continue; |
if ((token = yylex ()) != NAME) |
continue; |
arg1 = yylval.name; |
arg2 = NULL; |
arg3 = NULL; |
token = yylex (); |
if (token == ',') |
{ |
if ((token = yylex ()) != NAME) |
{ |
free (arg1); |
continue; |
} |
arg2 = yylval.name; |
if ((token = yylex ()) != ',' |
|| (token = yylex ()) != NAME) |
{ |
free (arg1); |
free (arg2); |
continue; |
} |
arg3 = yylval.name; |
token = yylex (); |
} |
if (token == ')') |
{ |
switch (command_line.endian) |
{ |
default: |
case ENDIAN_UNSET: |
arg = arg1; break; |
case ENDIAN_BIG: |
arg = arg2 ? arg2 : arg1; break; |
case ENDIAN_LITTLE: |
arg = arg3 ? arg3 : arg1; break; |
} |
if (strcmp (arg, lang_get_output_target ()) != 0) |
skip = 1; |
} |
free (arg1); |
if (arg2) free (arg2); |
if (arg3) free (arg3); |
break; |
case NAME: |
case LNAME: |
case VERS_IDENTIFIER: |
case VERS_TAG: |
free (yylval.name); |
break; |
case INT: |
if (yylval.bigint.str) |
free (yylval.bigint.str); |
break; |
} |
token = yylex (); |
} |
ldlex_popstate (); |
ldfile_assumed_script = FALSE; |
fclose (yyin); |
yyin = NULL; |
if (skip) |
{ |
if (command_line.warn_search_mismatch) |
einfo (_("%P: skipping incompatible %s " |
"when searching for %s\n"), |
attempt, entry->local_sym_name); |
bfd_close (entry->the_bfd); |
entry->the_bfd = NULL; |
return FALSE; |
} |
} |
goto success; |
} |
if (!entry->flags.dynamic && (entry->the_bfd->flags & DYNAMIC) != 0) |
{ |
einfo (_("%F%P: attempted static link of dynamic object `%s'\n"), |
attempt); |
bfd_close (entry->the_bfd); |
entry->the_bfd = NULL; |
return FALSE; |
} |
if (entry->flags.search_dirs |
&& !bfd_arch_get_compatible (check, link_info.output_bfd, |
command_line.accept_unknown_input_arch) |
/* XCOFF archives can have 32 and 64 bit objects. */ |
&& ! (bfd_get_flavour (check) == bfd_target_xcoff_flavour |
&& bfd_get_flavour (link_info.output_bfd) == bfd_target_xcoff_flavour |
&& bfd_check_format (entry->the_bfd, bfd_archive))) |
{ |
if (command_line.warn_search_mismatch) |
einfo (_("%P: skipping incompatible %s " |
"when searching for %s\n"), |
attempt, entry->local_sym_name); |
bfd_close (entry->the_bfd); |
entry->the_bfd = NULL; |
return FALSE; |
} |
} |
} |
success: |
#ifdef ENABLE_PLUGINS |
/* If plugins are active, they get first chance to claim |
any successfully-opened input file. We skip archives |
here; the plugin wants us to offer it the individual |
members when we enumerate them, not the whole file. We |
also ignore corefiles, because that's just weird. It is |
a needed side-effect of calling bfd_check_format with |
bfd_object that it sets the bfd's arch and mach, which |
will be needed when and if we want to bfd_create a new |
one using this one as a template. */ |
if (bfd_check_format (entry->the_bfd, bfd_object) |
&& plugin_active_plugins_p () |
&& !no_more_claiming) |
{ |
int fd = open (attempt, O_RDONLY | O_BINARY); |
if (fd >= 0) |
{ |
struct ld_plugin_input_file file; |
file.name = attempt; |
file.offset = 0; |
file.filesize = lseek (fd, 0, SEEK_END); |
file.fd = fd; |
plugin_maybe_claim (&file, entry); |
} |
} |
#endif /* ENABLE_PLUGINS */ |
/* It opened OK, the format checked out, and the plugins have had |
their chance to claim it, so this is success. */ |
return TRUE; |
} |
/* Search for and open the file specified by ENTRY. If it is an |
archive, use ARCH, LIB and SUFFIX to modify the file name. */ |
bfd_boolean |
ldfile_open_file_search (const char *arch, |
lang_input_statement_type *entry, |
const char *lib, |
const char *suffix) |
{ |
search_dirs_type *search; |
/* If this is not an archive, try to open it in the current |
directory first. */ |
if (! entry->flags.maybe_archive) |
{ |
if (entry->flags.sysrooted && IS_ABSOLUTE_PATH (entry->filename)) |
{ |
char *name = concat (ld_sysroot, entry->filename, |
(const char *) NULL); |
if (ldfile_try_open_bfd (name, entry)) |
{ |
entry->filename = name; |
return TRUE; |
} |
free (name); |
} |
else if (ldfile_try_open_bfd (entry->filename, entry)) |
return TRUE; |
if (IS_ABSOLUTE_PATH (entry->filename)) |
return FALSE; |
} |
for (search = search_head; search != NULL; search = search->next) |
{ |
char *string; |
if (entry->flags.dynamic && ! link_info.relocatable) |
{ |
if (ldemul_open_dynamic_archive (arch, search, entry)) |
return TRUE; |
} |
if (entry->flags.maybe_archive) |
string = concat (search->name, slash, lib, entry->filename, |
arch, suffix, (const char *) NULL); |
else |
string = concat (search->name, slash, entry->filename, |
(const char *) 0); |
if (ldfile_try_open_bfd (string, entry)) |
{ |
entry->filename = string; |
return TRUE; |
} |
free (string); |
} |
return FALSE; |
} |
/* Open the input file specified by ENTRY. |
PR 4437: Do not stop on the first missing file, but |
continue processing other input files in case there |
are more errors to report. */ |
void |
ldfile_open_file (lang_input_statement_type *entry) |
{ |
if (entry->the_bfd != NULL) |
return; |
printf("%s %s\n", __FUNCTION__, entry->filename); |
if (! entry->flags.search_dirs) |
{ |
if (ldfile_try_open_bfd (entry->filename, entry)) |
return; |
if (filename_cmp (entry->filename, entry->local_sym_name) != 0) |
einfo (_("%P: cannot find %s (%s): %E\n"), |
entry->filename, entry->local_sym_name); |
else |
einfo (_("%P: cannot find %s: %E\n"), entry->local_sym_name); |
entry->flags.missing_file = TRUE; |
input_flags.missing_file = TRUE; |
} |
else |
{ |
search_arch_type *arch; |
bfd_boolean found = FALSE; |
/* Try to open <filename><suffix> or lib<filename><suffix>.a */ |
for (arch = search_arch_head; arch != NULL; arch = arch->next) |
{ |
found = ldfile_open_file_search (arch->name, entry, "lib", ".a"); |
if (found) |
break; |
#ifdef VMS |
found = ldfile_open_file_search (arch->name, entry, ":lib", ".a"); |
if (found) |
break; |
#endif |
found = ldemul_find_potential_libraries (arch->name, entry); |
if (found) |
break; |
} |
/* If we have found the file, we don't need to search directories |
again. */ |
if (found) |
entry->flags.search_dirs = FALSE; |
else |
{ |
if (entry->flags.sysrooted |
&& ld_sysroot |
&& IS_ABSOLUTE_PATH (entry->local_sym_name)) |
einfo (_("%P: cannot find %s inside %s\n"), |
entry->local_sym_name, ld_sysroot); |
else |
einfo (_("%P: cannot find %s\n"), entry->local_sym_name); |
entry->flags.missing_file = TRUE; |
input_flags.missing_file = TRUE; |
} |
} |
} |
/* Try to open NAME. */ |
static FILE * |
try_open (const char *name, bfd_boolean *sysrooted) |
{ |
FILE *result; |
result = fopen (name, "r"); |
if (result != NULL) |
*sysrooted = is_sysrooted_pathname (name); |
if (verbose) |
{ |
if (result == NULL) |
info_msg (_("cannot find script file %s\n"), name); |
else |
info_msg (_("opened script file %s\n"), name); |
} |
return result; |
} |
/* Return TRUE iff directory DIR contains an "ldscripts" subdirectory. */ |
static bfd_boolean |
check_for_scripts_dir (char *dir) |
{ |
char *buf; |
struct stat s; |
bfd_boolean res; |
buf = concat (dir, "/ldscripts", (const char *) NULL); |
res = stat (buf, &s) == 0 && S_ISDIR (s.st_mode); |
free (buf); |
return res; |
} |
/* Return the default directory for finding script files. |
We look for the "ldscripts" directory in: |
SCRIPTDIR (passed from Makefile) |
(adjusted according to the current location of the binary) |
the dir where this program is (for using it from the build tree). */ |
static char * |
find_scripts_dir (void) |
{ |
char *dir; |
dir = make_relative_prefix (program_name, BINDIR, SCRIPTDIR); |
if (dir) |
{ |
if (check_for_scripts_dir (dir)) |
return dir; |
free (dir); |
} |
dir = make_relative_prefix (program_name, TOOLBINDIR, SCRIPTDIR); |
if (dir) |
{ |
if (check_for_scripts_dir (dir)) |
return dir; |
free (dir); |
} |
/* Look for "ldscripts" in the dir where our binary is. */ |
dir = make_relative_prefix (program_name, ".", "."); |
if (dir) |
{ |
if (check_for_scripts_dir (dir)) |
return dir; |
free (dir); |
} |
return NULL; |
} |
/* If DEFAULT_ONLY is false, try to open NAME; if that fails, look for |
it in directories specified with -L, then in the default script |
directory. If DEFAULT_ONLY is true, the search is restricted to |
the default script location. */ |
static FILE * |
ldfile_find_command_file (const char *name, |
bfd_boolean default_only, |
bfd_boolean *sysrooted) |
{ |
search_dirs_type *search; |
FILE *result = NULL; |
char *path; |
static search_dirs_type *script_search; |
if (!default_only) |
{ |
/* First try raw name. */ |
result = try_open (name, sysrooted); |
if (result != NULL) |
return result; |
} |
if (!script_search) |
{ |
char *script_dir = find_scripts_dir (); |
if (script_dir) |
{ |
search_dirs_type **save_tail_ptr = search_tail_ptr; |
search_tail_ptr = &script_search; |
ldfile_add_library_path (script_dir, TRUE); |
search_tail_ptr = save_tail_ptr; |
} |
} |
/* Temporarily append script_search to the path list so that the |
paths specified with -L will be searched first. */ |
*search_tail_ptr = script_search; |
/* Try now prefixes. */ |
for (search = default_only ? script_search : search_head; |
search != NULL; |
search = search->next) |
{ |
path = concat (search->name, slash, name, (const char *) NULL); |
result = try_open (path, sysrooted); |
free (path); |
if (result) |
break; |
} |
/* Restore the original path list. */ |
*search_tail_ptr = NULL; |
return result; |
} |
/* Open command file NAME. */ |
static void |
ldfile_open_command_file_1 (const char *name, bfd_boolean default_only) |
{ |
FILE *ldlex_input_stack; |
bfd_boolean sysrooted; |
ldlex_input_stack = ldfile_find_command_file (name, default_only, &sysrooted); |
if (ldlex_input_stack == NULL) |
{ |
bfd_set_error (bfd_error_system_call); |
einfo (_("%P%F: cannot open linker script file %s: %E\n"), name); |
return; |
} |
lex_push_file (ldlex_input_stack, name, sysrooted); |
lineno = 1; |
saved_script_handle = ldlex_input_stack; |
} |
/* Open command file NAME in the current directory, -L directories, |
the default script location, in that order. */ |
void |
ldfile_open_command_file (const char *name) |
{ |
ldfile_open_command_file_1 (name, FALSE); |
} |
/* Open command file NAME at the default script location. */ |
void |
ldfile_open_default_command_file (const char *name) |
{ |
ldfile_open_command_file_1 (name, TRUE); |
} |
void |
ldfile_add_arch (const char *in_name) |
{ |
char *name = xstrdup (in_name); |
search_arch_type *new_arch = (search_arch_type *) |
xmalloc (sizeof (search_arch_type)); |
ldfile_output_machine_name = in_name; |
new_arch->name = name; |
new_arch->next = NULL; |
while (*name) |
{ |
*name = TOLOWER (*name); |
name++; |
} |
*search_arch_tail_ptr = new_arch; |
search_arch_tail_ptr = &new_arch->next; |
} |
/* Set the output architecture. */ |
void |
ldfile_set_output_arch (const char *string, enum bfd_architecture defarch) |
{ |
const bfd_arch_info_type *arch = bfd_scan_arch (string); |
if (arch) |
{ |
ldfile_output_architecture = arch->arch; |
ldfile_output_machine = arch->mach; |
ldfile_output_machine_name = arch->printable_name; |
} |
else if (defarch != bfd_arch_unknown) |
ldfile_output_architecture = defarch; |
else |
einfo (_("%P%F: cannot represent machine `%s'\n"), string); |
} |
/contrib/toolchain/binutils/ld/ldfile.h |
---|
0,0 → 1,62 |
/* ldfile.h - |
Copyright 1991, 1992, 1993, 1994, 1995, 2000, 2002, 2003, 2004, 2005, |
2007, 2012 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDFILE_H |
#define LDFILE_H |
extern bfd_boolean ldfile_assumed_script; |
extern unsigned long ldfile_output_machine; |
extern enum bfd_architecture ldfile_output_architecture; |
extern const char *ldfile_output_machine_name; |
/* Structure used to hold the list of directories to search for |
libraries. */ |
typedef struct search_dirs { |
/* Next directory on list. */ |
struct search_dirs *next; |
/* Name of directory. */ |
const char *name; |
/* TRUE if this is from the command line. */ |
bfd_boolean cmdline; |
} search_dirs_type; |
extern search_dirs_type *search_head; |
extern void ldfile_add_arch |
(const char *); |
extern void ldfile_add_library_path |
(const char *, bfd_boolean cmdline); |
extern void ldfile_open_command_file |
(const char *name); |
extern void ldfile_open_default_command_file |
(const char *name); |
extern void ldfile_open_file |
(struct lang_input_statement_struct *); |
extern bfd_boolean ldfile_try_open_bfd |
(const char *, struct lang_input_statement_struct *); |
extern void ldfile_set_output_arch |
(const char *, enum bfd_architecture); |
extern bfd_boolean ldfile_open_file_search |
(const char *arch, struct lang_input_statement_struct *, |
const char *lib, const char *suffix); |
#endif |
/contrib/toolchain/binutils/ld/ldgram.c |
---|
0,0 → 1,4717 |
/* A Bison parser, made by GNU Bison 2.3. */ |
/* Skeleton implementation for Bison's Yacc-like parsers in C |
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 |
Free Software Foundation, Inc. |
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, Inc., 51 Franklin Street, Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* As a special exception, you may create a larger work that contains |
part or all of the Bison parser skeleton and distribute that work |
under terms of your choice, so long as that work isn't itself a |
parser generator using the skeleton or a modified version thereof |
as a parser skeleton. Alternatively, if you modify or redistribute |
the parser skeleton itself, you may (at your option) remove this |
special exception, which will cause the skeleton and the resulting |
Bison output files to be licensed under the GNU General Public |
License without this special exception. |
This special exception was added by the Free Software Foundation in |
version 2.2 of Bison. */ |
/* C LALR(1) parser skeleton written by Richard Stallman, by |
simplifying the original so-called "semantic" parser. */ |
/* All symbols defined below should begin with yy or YY, to avoid |
infringing on user name space. This should be done even for local |
variables, as they might otherwise be expanded by user macros. |
There are some unavoidable exceptions within include files to |
define necessary library symbols; they are noted "INFRINGES ON |
USER NAME SPACE" below. */ |
/* Identify Bison output. */ |
#define YYBISON 1 |
/* Bison version. */ |
#define YYBISON_VERSION "2.3" |
/* Skeleton name. */ |
#define YYSKELETON_NAME "yacc.c" |
/* Pure parsers. */ |
#define YYPURE 0 |
/* Using locations. */ |
#define YYLSP_NEEDED 0 |
/* Tokens. */ |
#ifndef YYTOKENTYPE |
# define YYTOKENTYPE |
/* Put the tokens into the symbol table, so that GDB and other debuggers |
know about them. */ |
enum yytokentype { |
INT = 258, |
NAME = 259, |
LNAME = 260, |
OREQ = 261, |
ANDEQ = 262, |
RSHIFTEQ = 263, |
LSHIFTEQ = 264, |
DIVEQ = 265, |
MULTEQ = 266, |
MINUSEQ = 267, |
PLUSEQ = 268, |
OROR = 269, |
ANDAND = 270, |
NE = 271, |
EQ = 272, |
GE = 273, |
LE = 274, |
RSHIFT = 275, |
LSHIFT = 276, |
UNARY = 277, |
END = 278, |
ALIGN_K = 279, |
BLOCK = 280, |
BIND = 281, |
QUAD = 282, |
SQUAD = 283, |
LONG = 284, |
SHORT = 285, |
BYTE = 286, |
SECTIONS = 287, |
PHDRS = 288, |
INSERT_K = 289, |
AFTER = 290, |
BEFORE = 291, |
DATA_SEGMENT_ALIGN = 292, |
DATA_SEGMENT_RELRO_END = 293, |
DATA_SEGMENT_END = 294, |
SORT_BY_NAME = 295, |
SORT_BY_ALIGNMENT = 296, |
SORT_NONE = 297, |
SORT_BY_INIT_PRIORITY = 298, |
SIZEOF_HEADERS = 299, |
OUTPUT_FORMAT = 300, |
FORCE_COMMON_ALLOCATION = 301, |
OUTPUT_ARCH = 302, |
INHIBIT_COMMON_ALLOCATION = 303, |
SEGMENT_START = 304, |
INCLUDE = 305, |
MEMORY = 306, |
REGION_ALIAS = 307, |
LD_FEATURE = 308, |
NOLOAD = 309, |
DSECT = 310, |
COPY = 311, |
INFO = 312, |
OVERLAY = 313, |
DEFINED = 314, |
TARGET_K = 315, |
SEARCH_DIR = 316, |
MAP = 317, |
ENTRY = 318, |
NEXT = 319, |
SIZEOF = 320, |
ALIGNOF = 321, |
ADDR = 322, |
LOADADDR = 323, |
MAX_K = 324, |
MIN_K = 325, |
STARTUP = 326, |
HLL = 327, |
SYSLIB = 328, |
FLOAT = 329, |
NOFLOAT = 330, |
NOCROSSREFS = 331, |
ORIGIN = 332, |
FILL = 333, |
LENGTH = 334, |
CREATE_OBJECT_SYMBOLS = 335, |
INPUT = 336, |
GROUP = 337, |
OUTPUT = 338, |
CONSTRUCTORS = 339, |
ALIGNMOD = 340, |
AT = 341, |
SUBALIGN = 342, |
HIDDEN = 343, |
PROVIDE = 344, |
PROVIDE_HIDDEN = 345, |
AS_NEEDED = 346, |
CHIP = 347, |
LIST = 348, |
SECT = 349, |
ABSOLUTE = 350, |
LOAD = 351, |
NEWLINE = 352, |
ENDWORD = 353, |
ORDER = 354, |
NAMEWORD = 355, |
ASSERT_K = 356, |
LOG2CEIL = 357, |
FORMAT = 358, |
PUBLIC = 359, |
DEFSYMEND = 360, |
BASE = 361, |
ALIAS = 362, |
TRUNCATE = 363, |
REL = 364, |
INPUT_SCRIPT = 365, |
INPUT_MRI_SCRIPT = 366, |
INPUT_DEFSYM = 367, |
CASE = 368, |
EXTERN = 369, |
START = 370, |
VERS_TAG = 371, |
VERS_IDENTIFIER = 372, |
GLOBAL = 373, |
LOCAL = 374, |
VERSIONK = 375, |
INPUT_VERSION_SCRIPT = 376, |
KEEP = 377, |
ONLY_IF_RO = 378, |
ONLY_IF_RW = 379, |
SPECIAL = 380, |
INPUT_SECTION_FLAGS = 381, |
ALIGN_WITH_INPUT = 382, |
EXCLUDE_FILE = 383, |
CONSTANT = 384, |
INPUT_DYNAMIC_LIST = 385 |
}; |
#endif |
/* Tokens. */ |
#define INT 258 |
#define NAME 259 |
#define LNAME 260 |
#define OREQ 261 |
#define ANDEQ 262 |
#define RSHIFTEQ 263 |
#define LSHIFTEQ 264 |
#define DIVEQ 265 |
#define MULTEQ 266 |
#define MINUSEQ 267 |
#define PLUSEQ 268 |
#define OROR 269 |
#define ANDAND 270 |
#define NE 271 |
#define EQ 272 |
#define GE 273 |
#define LE 274 |
#define RSHIFT 275 |
#define LSHIFT 276 |
#define UNARY 277 |
#define END 278 |
#define ALIGN_K 279 |
#define BLOCK 280 |
#define BIND 281 |
#define QUAD 282 |
#define SQUAD 283 |
#define LONG 284 |
#define SHORT 285 |
#define BYTE 286 |
#define SECTIONS 287 |
#define PHDRS 288 |
#define INSERT_K 289 |
#define AFTER 290 |
#define BEFORE 291 |
#define DATA_SEGMENT_ALIGN 292 |
#define DATA_SEGMENT_RELRO_END 293 |
#define DATA_SEGMENT_END 294 |
#define SORT_BY_NAME 295 |
#define SORT_BY_ALIGNMENT 296 |
#define SORT_NONE 297 |
#define SORT_BY_INIT_PRIORITY 298 |
#define SIZEOF_HEADERS 299 |
#define OUTPUT_FORMAT 300 |
#define FORCE_COMMON_ALLOCATION 301 |
#define OUTPUT_ARCH 302 |
#define INHIBIT_COMMON_ALLOCATION 303 |
#define SEGMENT_START 304 |
#define INCLUDE 305 |
#define MEMORY 306 |
#define REGION_ALIAS 307 |
#define LD_FEATURE 308 |
#define NOLOAD 309 |
#define DSECT 310 |
#define COPY 311 |
#define INFO 312 |
#define OVERLAY 313 |
#define DEFINED 314 |
#define TARGET_K 315 |
#define SEARCH_DIR 316 |
#define MAP 317 |
#define ENTRY 318 |
#define NEXT 319 |
#define SIZEOF 320 |
#define ALIGNOF 321 |
#define ADDR 322 |
#define LOADADDR 323 |
#define MAX_K 324 |
#define MIN_K 325 |
#define STARTUP 326 |
#define HLL 327 |
#define SYSLIB 328 |
#define FLOAT 329 |
#define NOFLOAT 330 |
#define NOCROSSREFS 331 |
#define ORIGIN 332 |
#define FILL 333 |
#define LENGTH 334 |
#define CREATE_OBJECT_SYMBOLS 335 |
#define INPUT 336 |
#define GROUP 337 |
#define OUTPUT 338 |
#define CONSTRUCTORS 339 |
#define ALIGNMOD 340 |
#define AT 341 |
#define SUBALIGN 342 |
#define HIDDEN 343 |
#define PROVIDE 344 |
#define PROVIDE_HIDDEN 345 |
#define AS_NEEDED 346 |
#define CHIP 347 |
#define LIST 348 |
#define SECT 349 |
#define ABSOLUTE 350 |
#define LOAD 351 |
#define NEWLINE 352 |
#define ENDWORD 353 |
#define ORDER 354 |
#define NAMEWORD 355 |
#define ASSERT_K 356 |
#define LOG2CEIL 357 |
#define FORMAT 358 |
#define PUBLIC 359 |
#define DEFSYMEND 360 |
#define BASE 361 |
#define ALIAS 362 |
#define TRUNCATE 363 |
#define REL 364 |
#define INPUT_SCRIPT 365 |
#define INPUT_MRI_SCRIPT 366 |
#define INPUT_DEFSYM 367 |
#define CASE 368 |
#define EXTERN 369 |
#define START 370 |
#define VERS_TAG 371 |
#define VERS_IDENTIFIER 372 |
#define GLOBAL 373 |
#define LOCAL 374 |
#define VERSIONK 375 |
#define INPUT_VERSION_SCRIPT 376 |
#define KEEP 377 |
#define ONLY_IF_RO 378 |
#define ONLY_IF_RW 379 |
#define SPECIAL 380 |
#define INPUT_SECTION_FLAGS 381 |
#define ALIGN_WITH_INPUT 382 |
#define EXCLUDE_FILE 383 |
#define CONSTANT 384 |
#define INPUT_DYNAMIC_LIST 385 |
/* Copy the first part of user declarations. */ |
#line 22 "ldgram.y" |
/* |
*/ |
#define DONTDECLARE_MALLOC |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldexp.h" |
#include "ldver.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "ldmisc.h" |
#include "ldmain.h" |
#include "mri.h" |
#include "ldctor.h" |
#include "ldlex.h" |
#ifndef YYDEBUG |
#define YYDEBUG 1 |
#endif |
static enum section_type sectype; |
static lang_memory_region_type *region; |
bfd_boolean ldgram_had_keep = FALSE; |
char *ldgram_vers_current_lang = NULL; |
#define ERROR_NAME_MAX 20 |
static char *error_names[ERROR_NAME_MAX]; |
static int error_index; |
#define PUSH_ERROR(x) if (error_index < ERROR_NAME_MAX) error_names[error_index] = x; error_index++; |
#define POP_ERROR() error_index--; |
/* Enabling traces. */ |
#ifndef YYDEBUG |
# define YYDEBUG 0 |
#endif |
/* Enabling verbose error messages. */ |
#ifdef YYERROR_VERBOSE |
# undef YYERROR_VERBOSE |
# define YYERROR_VERBOSE 1 |
#else |
# define YYERROR_VERBOSE 0 |
#endif |
/* Enabling the token table. */ |
#ifndef YYTOKEN_TABLE |
# define YYTOKEN_TABLE 0 |
#endif |
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED |
typedef union YYSTYPE |
#line 60 "ldgram.y" |
{ |
bfd_vma integer; |
struct big_int |
{ |
bfd_vma integer; |
char *str; |
} bigint; |
fill_type *fill; |
char *name; |
const char *cname; |
struct wildcard_spec wildcard; |
struct wildcard_list *wildcard_list; |
struct name_list *name_list; |
struct flag_info_list *flag_info_list; |
struct flag_info *flag_info; |
int token; |
union etree_union *etree; |
struct phdr_info |
{ |
bfd_boolean filehdr; |
bfd_boolean phdrs; |
union etree_union *at; |
union etree_union *flags; |
} phdr; |
struct lang_nocrossref *nocrossref; |
struct lang_output_section_phdr_list *section_phdr; |
struct bfd_elf_version_deps *deflist; |
struct bfd_elf_version_expr *versyms; |
struct bfd_elf_version_tree *versnode; |
} |
/* Line 193 of yacc.c. */ |
#line 426 "ldgram.c" |
YYSTYPE; |
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ |
# define YYSTYPE_IS_DECLARED 1 |
# define YYSTYPE_IS_TRIVIAL 1 |
#endif |
/* Copy the second part of user declarations. */ |
/* Line 216 of yacc.c. */ |
#line 439 "ldgram.c" |
#ifdef short |
# undef short |
#endif |
#ifdef YYTYPE_UINT8 |
typedef YYTYPE_UINT8 yytype_uint8; |
#else |
typedef unsigned char yytype_uint8; |
#endif |
#ifdef YYTYPE_INT8 |
typedef YYTYPE_INT8 yytype_int8; |
#elif (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
typedef signed char yytype_int8; |
#else |
typedef short int yytype_int8; |
#endif |
#ifdef YYTYPE_UINT16 |
typedef YYTYPE_UINT16 yytype_uint16; |
#else |
typedef unsigned short int yytype_uint16; |
#endif |
#ifdef YYTYPE_INT16 |
typedef YYTYPE_INT16 yytype_int16; |
#else |
typedef short int yytype_int16; |
#endif |
#ifndef YYSIZE_T |
# ifdef __SIZE_TYPE__ |
# define YYSIZE_T __SIZE_TYPE__ |
# elif defined size_t |
# define YYSIZE_T size_t |
# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ |
# define YYSIZE_T size_t |
# else |
# define YYSIZE_T unsigned int |
# endif |
#endif |
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) |
#ifndef YY_ |
# if defined YYENABLE_NLS && YYENABLE_NLS |
# if ENABLE_NLS |
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ |
# define YY_(msgid) dgettext ("bison-runtime", msgid) |
# endif |
# endif |
# ifndef YY_ |
# define YY_(msgid) msgid |
# endif |
#endif |
/* Suppress unused-variable warnings by "using" E. */ |
#if ! defined lint || defined __GNUC__ |
# define YYUSE(e) ((void) (e)) |
#else |
# define YYUSE(e) /* empty */ |
#endif |
/* Identity function, used to suppress warnings about constant conditions. */ |
#ifndef lint |
# define YYID(n) (n) |
#else |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static int |
YYID (int i) |
#else |
static int |
YYID (i) |
int i; |
#endif |
{ |
return i; |
} |
#endif |
#if ! defined yyoverflow || YYERROR_VERBOSE |
/* The parser invokes alloca or malloc; define the necessary symbols. */ |
# ifdef YYSTACK_USE_ALLOCA |
# if YYSTACK_USE_ALLOCA |
# ifdef __GNUC__ |
# define YYSTACK_ALLOC __builtin_alloca |
# elif defined __BUILTIN_VA_ARG_INCR |
# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ |
# elif defined _AIX |
# define YYSTACK_ALLOC __alloca |
# elif defined _MSC_VER |
# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ |
# define alloca _alloca |
# else |
# define YYSTACK_ALLOC alloca |
# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ |
# ifndef _STDLIB_H |
# define _STDLIB_H 1 |
# endif |
# endif |
# endif |
# endif |
# endif |
# ifdef YYSTACK_ALLOC |
/* Pacify GCC's `empty if-body' warning. */ |
# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) |
# ifndef YYSTACK_ALLOC_MAXIMUM |
/* The OS might guarantee only one guard page at the bottom of the stack, |
and a page size can be as small as 4096 bytes. So we cannot safely |
invoke alloca (N) if N exceeds 4096. Use a slightly smaller number |
to allow for a few compiler-allocated temporary stack slots. */ |
# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ |
# endif |
# else |
# define YYSTACK_ALLOC YYMALLOC |
# define YYSTACK_FREE YYFREE |
# ifndef YYSTACK_ALLOC_MAXIMUM |
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM |
# endif |
# if (defined __cplusplus && ! defined _STDLIB_H \ |
&& ! ((defined YYMALLOC || defined malloc) \ |
&& (defined YYFREE || defined free))) |
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ |
# ifndef _STDLIB_H |
# define _STDLIB_H 1 |
# endif |
# endif |
# ifndef YYMALLOC |
# define YYMALLOC malloc |
# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ |
# endif |
# endif |
# ifndef YYFREE |
# define YYFREE free |
# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
void free (void *); /* INFRINGES ON USER NAME SPACE */ |
# endif |
# endif |
# endif |
#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ |
#if (! defined yyoverflow \ |
&& (! defined __cplusplus \ |
|| (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) |
/* A type that is properly aligned for any stack member. */ |
union yyalloc |
{ |
yytype_int16 yyss; |
YYSTYPE yyvs; |
}; |
/* The size of the maximum gap between one aligned stack and the next. */ |
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) |
/* The size of an array large to enough to hold all stacks, each with |
N elements. */ |
# define YYSTACK_BYTES(N) \ |
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ |
+ YYSTACK_GAP_MAXIMUM) |
/* Copy COUNT objects from FROM to TO. The source and destination do |
not overlap. */ |
# ifndef YYCOPY |
# if defined __GNUC__ && 1 < __GNUC__ |
# define YYCOPY(To, From, Count) \ |
__builtin_memcpy (To, From, (Count) * sizeof (*(From))) |
# else |
# define YYCOPY(To, From, Count) \ |
do \ |
{ \ |
YYSIZE_T yyi; \ |
for (yyi = 0; yyi < (Count); yyi++) \ |
(To)[yyi] = (From)[yyi]; \ |
} \ |
while (YYID (0)) |
# endif |
# endif |
/* Relocate STACK from its old location to the new one. The |
local variables YYSIZE and YYSTACKSIZE give the old and new number of |
elements in the stack, and YYPTR gives the new location of the |
stack. Advance YYPTR to a properly aligned location for the next |
stack. */ |
# define YYSTACK_RELOCATE(Stack) \ |
do \ |
{ \ |
YYSIZE_T yynewbytes; \ |
YYCOPY (&yyptr->Stack, Stack, yysize); \ |
Stack = &yyptr->Stack; \ |
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ |
yyptr += yynewbytes / sizeof (*yyptr); \ |
} \ |
while (YYID (0)) |
#endif |
/* YYFINAL -- State number of the termination state. */ |
#define YYFINAL 17 |
/* YYLAST -- Last index in YYTABLE. */ |
#define YYLAST 1999 |
/* YYNTOKENS -- Number of terminals. */ |
#define YYNTOKENS 154 |
/* YYNNTS -- Number of nonterminals. */ |
#define YYNNTS 129 |
/* YYNRULES -- Number of rules. */ |
#define YYNRULES 369 |
/* YYNRULES -- Number of states. */ |
#define YYNSTATES 803 |
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ |
#define YYUNDEFTOK 2 |
#define YYMAXUTOK 385 |
#define YYTRANSLATE(YYX) \ |
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) |
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ |
static const yytype_uint8 yytranslate[] = |
{ |
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 152, 2, 2, 2, 34, 21, 2, |
37, 149, 32, 30, 147, 31, 2, 33, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 16, 148, |
24, 6, 25, 15, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 150, 2, 151, 20, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 58, 19, 59, 153, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
2, 2, 2, 2, 2, 2, 1, 2, 3, 4, |
5, 7, 8, 9, 10, 11, 12, 13, 14, 17, |
18, 22, 23, 26, 27, 28, 29, 35, 36, 38, |
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
49, 50, 51, 52, 53, 54, 55, 56, 57, 60, |
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, |
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, |
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, |
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, |
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, |
111, 112, 113, 114, 115, 116, 117, 118, 119, 120, |
121, 122, 123, 124, 125, 126, 127, 128, 129, 130, |
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, |
141, 142, 143, 144, 145, 146 |
}; |
#if YYDEBUG |
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in |
YYRHS. */ |
static const yytype_uint16 yyprhs[] = |
{ |
0, 0, 3, 6, 9, 12, 15, 18, 20, 21, |
26, 27, 30, 34, 35, 38, 43, 45, 47, 50, |
52, 57, 62, 66, 69, 74, 78, 83, 88, 93, |
98, 103, 106, 109, 112, 117, 122, 125, 128, 131, |
134, 135, 141, 144, 145, 149, 152, 153, 155, 159, |
161, 165, 166, 168, 172, 173, 176, 178, 181, 185, |
186, 189, 192, 193, 195, 197, 199, 201, 203, 205, |
207, 209, 211, 213, 218, 223, 228, 233, 242, 247, |
249, 251, 256, 257, 263, 268, 269, 275, 280, 285, |
289, 293, 300, 305, 307, 311, 314, 316, 320, 323, |
324, 330, 331, 339, 340, 347, 352, 355, 358, 359, |
364, 367, 368, 376, 378, 380, 382, 384, 390, 395, |
400, 405, 413, 421, 429, 437, 446, 451, 453, 457, |
462, 465, 467, 471, 473, 475, 478, 482, 487, 492, |
498, 500, 501, 507, 510, 512, 514, 516, 521, 523, |
528, 533, 534, 543, 544, 550, 553, 555, 556, 558, |
560, 562, 564, 566, 568, 570, 573, 574, 576, 578, |
580, 582, 584, 586, 588, 590, 592, 594, 598, 602, |
609, 616, 623, 625, 626, 631, 633, 634, 638, 640, |
641, 649, 650, 656, 660, 664, 665, 669, 671, 674, |
676, 679, 684, 689, 693, 697, 699, 704, 708, 709, |
711, 713, 714, 717, 721, 722, 725, 728, 732, 737, |
740, 743, 746, 750, 754, 758, 762, 766, 770, 774, |
778, 782, 786, 790, 794, 798, 802, 806, 810, 816, |
820, 824, 829, 831, 833, 838, 843, 848, 853, 858, |
863, 868, 875, 882, 889, 894, 901, 906, 908, 915, |
922, 929, 934, 939, 944, 948, 949, 954, 955, 960, |
961, 963, 964, 969, 970, 972, 974, 976, 977, 978, |
979, 980, 981, 982, 1003, 1004, 1005, 1006, 1007, 1008, |
1027, 1028, 1029, 1037, 1038, 1044, 1046, 1048, 1050, 1052, |
1054, 1058, 1059, 1062, 1066, 1069, 1076, 1087, 1090, 1092, |
1093, 1095, 1098, 1099, 1100, 1104, 1105, 1106, 1107, 1108, |
1120, 1125, 1126, 1129, 1130, 1131, 1138, 1140, 1141, 1145, |
1151, 1152, 1156, 1157, 1160, 1162, 1165, 1170, 1173, 1174, |
1177, 1178, 1184, 1186, 1189, 1194, 1200, 1207, 1209, 1212, |
1213, 1216, 1221, 1226, 1235, 1237, 1239, 1243, 1247, 1248, |
1258, 1259, 1267, 1269, 1273, 1275, 1279, 1281, 1285, 1286 |
}; |
/* YYRHS -- A `-1'-separated list of the rules' RHS. */ |
static const yytype_int16 yyrhs[] = |
{ |
155, 0, -1, 126, 171, -1, 127, 159, -1, 137, |
271, -1, 146, 266, -1, 128, 157, -1, 4, -1, |
-1, 158, 4, 6, 226, -1, -1, 160, 161, -1, |
161, 162, 113, -1, -1, 108, 226, -1, 108, 226, |
147, 226, -1, 4, -1, 109, -1, 115, 164, -1, |
114, -1, 120, 4, 6, 226, -1, 120, 4, 147, |
226, -1, 120, 4, 226, -1, 119, 4, -1, 110, |
4, 147, 226, -1, 110, 4, 226, -1, 110, 4, |
6, 226, -1, 38, 4, 6, 226, -1, 38, 4, |
147, 226, -1, 101, 4, 6, 226, -1, 101, 4, |
147, 226, -1, 111, 166, -1, 112, 165, -1, 116, |
4, -1, 123, 4, 147, 4, -1, 123, 4, 147, |
3, -1, 122, 226, -1, 124, 3, -1, 129, 167, |
-1, 130, 168, -1, -1, 66, 156, 163, 161, 36, |
-1, 131, 4, -1, -1, 164, 147, 4, -1, 164, |
4, -1, -1, 4, -1, 165, 147, 4, -1, 4, |
-1, 166, 147, 4, -1, -1, 4, -1, 167, 147, |
4, -1, -1, 169, 170, -1, 4, -1, 170, 4, |
-1, 170, 147, 4, -1, -1, 172, 173, -1, 173, |
174, -1, -1, 206, -1, 181, -1, 258, -1, 217, |
-1, 218, -1, 220, -1, 222, -1, 183, -1, 273, |
-1, 148, -1, 76, 37, 4, 149, -1, 77, 37, |
156, 149, -1, 99, 37, 156, 149, -1, 61, 37, |
4, 149, -1, 61, 37, 4, 147, 4, 147, 4, |
149, -1, 63, 37, 4, 149, -1, 62, -1, 64, |
-1, 97, 37, 177, 149, -1, -1, 98, 175, 37, |
177, 149, -1, 78, 37, 156, 149, -1, -1, 66, |
156, 176, 173, 36, -1, 92, 37, 223, 149, -1, |
130, 37, 168, 149, -1, 48, 49, 4, -1, 48, |
50, 4, -1, 68, 37, 4, 147, 4, 149, -1, |
69, 37, 4, 149, -1, 4, -1, 177, 147, 4, |
-1, 177, 4, -1, 5, -1, 177, 147, 5, -1, |
177, 5, -1, -1, 107, 37, 178, 177, 149, -1, |
-1, 177, 147, 107, 37, 179, 177, 149, -1, -1, |
177, 107, 37, 180, 177, 149, -1, 46, 58, 182, |
59, -1, 182, 233, -1, 182, 183, -1, -1, 79, |
37, 4, 149, -1, 204, 203, -1, -1, 117, 184, |
37, 226, 147, 4, 149, -1, 4, -1, 32, -1, |
15, -1, 185, -1, 144, 37, 189, 149, 185, -1, |
54, 37, 185, 149, -1, 55, 37, 185, 149, -1, |
56, 37, 185, 149, -1, 54, 37, 55, 37, 185, |
149, 149, -1, 54, 37, 54, 37, 185, 149, 149, |
-1, 55, 37, 54, 37, 185, 149, 149, -1, 55, |
37, 55, 37, 185, 149, 149, -1, 54, 37, 144, |
37, 189, 149, 185, 149, -1, 57, 37, 185, 149, |
-1, 4, -1, 187, 21, 4, -1, 142, 37, 187, |
149, -1, 189, 185, -1, 185, -1, 190, 205, 186, |
-1, 186, -1, 4, -1, 188, 4, -1, 150, 190, |
151, -1, 188, 150, 190, 151, -1, 186, 37, 190, |
149, -1, 188, 186, 37, 190, 149, -1, 191, -1, |
-1, 138, 37, 193, 191, 149, -1, 204, 203, -1, |
96, -1, 148, -1, 100, -1, 54, 37, 100, 149, |
-1, 192, -1, 199, 37, 224, 149, -1, 94, 37, |
200, 149, -1, -1, 117, 195, 37, 226, 147, 4, |
149, 203, -1, -1, 66, 156, 196, 198, 36, -1, |
197, 194, -1, 194, -1, -1, 197, -1, 41, -1, |
42, -1, 43, -1, 44, -1, 45, -1, 224, -1, |
6, 200, -1, -1, 14, -1, 13, -1, 12, -1, |
11, -1, 10, -1, 9, -1, 8, -1, 7, -1, |
148, -1, 147, -1, 4, 6, 224, -1, 4, 202, |
224, -1, 104, 37, 4, 6, 224, 149, -1, 105, |
37, 4, 6, 224, 149, -1, 106, 37, 4, 6, |
224, 149, -1, 147, -1, -1, 67, 58, 207, 59, |
-1, 208, -1, -1, 208, 205, 209, -1, 209, -1, |
-1, 4, 210, 214, 16, 212, 205, 213, -1, -1, |
66, 156, 211, 207, 36, -1, 93, 6, 224, -1, |
95, 6, 224, -1, -1, 37, 215, 149, -1, 216, |
-1, 215, 216, -1, 4, -1, 152, 4, -1, 87, |
37, 156, 149, -1, 88, 37, 219, 149, -1, 88, |
37, 149, -1, 219, 205, 156, -1, 156, -1, 89, |
37, 221, 149, -1, 221, 205, 156, -1, -1, 90, |
-1, 91, -1, -1, 4, 223, -1, 4, 147, 223, |
-1, -1, 225, 226, -1, 31, 226, -1, 37, 226, |
149, -1, 80, 37, 226, 149, -1, 152, 226, -1, |
30, 226, -1, 153, 226, -1, 226, 32, 226, -1, |
226, 33, 226, -1, 226, 34, 226, -1, 226, 30, |
226, -1, 226, 31, 226, -1, 226, 29, 226, -1, |
226, 28, 226, -1, 226, 23, 226, -1, 226, 22, |
226, -1, 226, 27, 226, -1, 226, 26, 226, -1, |
226, 24, 226, -1, 226, 25, 226, -1, 226, 21, |
226, -1, 226, 20, 226, -1, 226, 19, 226, -1, |
226, 15, 226, 16, 226, -1, 226, 18, 226, -1, |
226, 17, 226, -1, 75, 37, 4, 149, -1, 3, |
-1, 60, -1, 82, 37, 4, 149, -1, 81, 37, |
4, 149, -1, 83, 37, 4, 149, -1, 84, 37, |
4, 149, -1, 145, 37, 4, 149, -1, 111, 37, |
226, 149, -1, 38, 37, 226, 149, -1, 38, 37, |
226, 147, 226, 149, -1, 51, 37, 226, 147, 226, |
149, -1, 52, 37, 226, 147, 226, 149, -1, 53, |
37, 226, 149, -1, 65, 37, 4, 147, 226, 149, |
-1, 39, 37, 226, 149, -1, 4, -1, 85, 37, |
226, 147, 226, 149, -1, 86, 37, 226, 147, 226, |
149, -1, 117, 37, 226, 147, 4, 149, -1, 93, |
37, 4, 149, -1, 95, 37, 4, 149, -1, 118, |
37, 226, 149, -1, 102, 25, 4, -1, -1, 102, |
37, 226, 149, -1, -1, 38, 37, 226, 149, -1, |
-1, 143, -1, -1, 103, 37, 226, 149, -1, -1, |
139, -1, 140, -1, 141, -1, -1, -1, -1, -1, |
-1, -1, 4, 234, 249, 228, 229, 230, 231, 235, |
232, 58, 236, 198, 59, 237, 252, 227, 253, 201, |
238, 205, -1, -1, -1, -1, -1, -1, 74, 239, |
250, 251, 228, 231, 240, 58, 241, 254, 59, 242, |
252, 227, 253, 201, 243, 205, -1, -1, -1, 98, |
244, 249, 245, 58, 182, 59, -1, -1, 66, 156, |
246, 182, 36, -1, 70, -1, 71, -1, 72, -1, |
73, -1, 74, -1, 37, 247, 149, -1, -1, 37, |
149, -1, 226, 248, 16, -1, 248, 16, -1, 40, |
37, 226, 149, 248, 16, -1, 40, 37, 226, 149, |
39, 37, 226, 149, 248, 16, -1, 226, 16, -1, |
16, -1, -1, 92, -1, 25, 4, -1, -1, -1, |
253, 16, 4, -1, -1, -1, -1, -1, 254, 4, |
255, 58, 198, 59, 256, 253, 201, 257, 205, -1, |
47, 58, 259, 59, -1, -1, 259, 260, -1, -1, |
-1, 4, 261, 263, 264, 262, 148, -1, 226, -1, |
-1, 4, 265, 264, -1, 102, 37, 226, 149, 264, |
-1, -1, 37, 226, 149, -1, -1, 267, 268, -1, |
269, -1, 268, 269, -1, 58, 270, 59, 148, -1, |
279, 148, -1, -1, 272, 275, -1, -1, 274, 136, |
58, 275, 59, -1, 276, -1, 275, 276, -1, 58, |
278, 59, 148, -1, 132, 58, 278, 59, 148, -1, |
132, 58, 278, 59, 277, 148, -1, 132, -1, 277, |
132, -1, -1, 279, 148, -1, 134, 16, 279, 148, |
-1, 135, 16, 279, 148, -1, 134, 16, 279, 148, |
135, 16, 279, 148, -1, 133, -1, 4, -1, 279, |
148, 133, -1, 279, 148, 4, -1, -1, 279, 148, |
130, 4, 58, 280, 279, 282, 59, -1, -1, 130, |
4, 58, 281, 279, 282, 59, -1, 134, -1, 279, |
148, 134, -1, 135, -1, 279, 148, 135, -1, 130, |
-1, 279, 148, 130, -1, -1, 148, -1 |
}; |
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ |
static const yytype_uint16 yyrline[] = |
{ |
0, 166, 166, 167, 168, 169, 170, 174, 178, 178, |
188, 188, 201, 202, 206, 207, 208, 211, 214, 215, |
216, 218, 220, 222, 224, 226, 228, 230, 232, 234, |
236, 238, 239, 240, 242, 244, 246, 248, 250, 251, |
253, 252, 256, 258, 262, 263, 264, 268, 270, 274, |
276, 281, 282, 283, 288, 288, 293, 295, 297, 302, |
302, 308, 309, 314, 315, 316, 317, 318, 319, 320, |
321, 322, 323, 324, 326, 328, 330, 333, 335, 337, |
339, 341, 343, 342, 346, 349, 348, 352, 356, 357, |
359, 361, 363, 368, 371, 374, 377, 380, 383, 387, |
386, 392, 391, 397, 396, 404, 408, 409, 410, 414, |
416, 417, 417, 425, 429, 433, 440, 447, 454, 461, |
468, 475, 482, 489, 496, 503, 510, 519, 537, 558, |
571, 580, 591, 600, 611, 620, 629, 633, 642, 646, |
654, 656, 655, 662, 663, 667, 668, 673, 678, 679, |
684, 688, 688, 692, 691, 698, 699, 702, 704, 708, |
710, 712, 714, 716, 721, 728, 730, 734, 736, 738, |
740, 742, 744, 746, 748, 753, 753, 758, 762, 770, |
774, 778, 786, 786, 790, 793, 793, 796, 797, 802, |
801, 807, 806, 813, 821, 829, 830, 834, 835, 839, |
841, 846, 851, 852, 857, 859, 865, 867, 869, 873, |
875, 881, 884, 893, 904, 904, 910, 912, 914, 916, |
918, 920, 923, 925, 927, 929, 931, 933, 935, 937, |
939, 941, 943, 945, 947, 949, 951, 953, 955, 957, |
959, 961, 963, 965, 968, 970, 972, 974, 976, 978, |
980, 982, 984, 986, 988, 990, 999, 1001, 1003, 1005, |
1007, 1009, 1011, 1013, 1019, 1020, 1024, 1025, 1029, 1030, |
1034, 1035, 1039, 1040, 1044, 1045, 1046, 1047, 1050, 1055, |
1058, 1064, 1066, 1050, 1073, 1075, 1077, 1082, 1084, 1072, |
1094, 1096, 1094, 1102, 1101, 1108, 1109, 1110, 1111, 1112, |
1116, 1117, 1118, 1122, 1123, 1128, 1129, 1134, 1135, 1140, |
1141, 1146, 1148, 1153, 1156, 1169, 1173, 1178, 1180, 1171, |
1188, 1191, 1193, 1197, 1198, 1197, 1207, 1252, 1255, 1268, |
1277, 1280, 1287, 1287, 1299, 1300, 1304, 1308, 1317, 1317, |
1331, 1331, 1341, 1342, 1346, 1350, 1354, 1361, 1365, 1373, |
1376, 1380, 1384, 1388, 1395, 1399, 1403, 1407, 1412, 1411, |
1425, 1424, 1434, 1438, 1442, 1446, 1450, 1454, 1460, 1462 |
}; |
#endif |
#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE |
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. |
First, the terminals, then, starting at YYNTOKENS, nonterminals. */ |
static const char *const yytname[] = |
{ |
"$end", "error", "$undefined", "INT", "NAME", "LNAME", "'='", "OREQ", |
"ANDEQ", "RSHIFTEQ", "LSHIFTEQ", "DIVEQ", "MULTEQ", "MINUSEQ", "PLUSEQ", |
"'?'", "':'", "OROR", "ANDAND", "'|'", "'^'", "'&'", "NE", "EQ", "'<'", |
"'>'", "GE", "LE", "RSHIFT", "LSHIFT", "'+'", "'-'", "'*'", "'/'", "'%'", |
"UNARY", "END", "'('", "ALIGN_K", "BLOCK", "BIND", "QUAD", "SQUAD", |
"LONG", "SHORT", "BYTE", "SECTIONS", "PHDRS", "INSERT_K", "AFTER", |
"BEFORE", "DATA_SEGMENT_ALIGN", "DATA_SEGMENT_RELRO_END", |
"DATA_SEGMENT_END", "SORT_BY_NAME", "SORT_BY_ALIGNMENT", "SORT_NONE", |
"SORT_BY_INIT_PRIORITY", "'{'", "'}'", "SIZEOF_HEADERS", "OUTPUT_FORMAT", |
"FORCE_COMMON_ALLOCATION", "OUTPUT_ARCH", "INHIBIT_COMMON_ALLOCATION", |
"SEGMENT_START", "INCLUDE", "MEMORY", "REGION_ALIAS", "LD_FEATURE", |
"NOLOAD", "DSECT", "COPY", "INFO", "OVERLAY", "DEFINED", "TARGET_K", |
"SEARCH_DIR", "MAP", "ENTRY", "NEXT", "SIZEOF", "ALIGNOF", "ADDR", |
"LOADADDR", "MAX_K", "MIN_K", "STARTUP", "HLL", "SYSLIB", "FLOAT", |
"NOFLOAT", "NOCROSSREFS", "ORIGIN", "FILL", "LENGTH", |
"CREATE_OBJECT_SYMBOLS", "INPUT", "GROUP", "OUTPUT", "CONSTRUCTORS", |
"ALIGNMOD", "AT", "SUBALIGN", "HIDDEN", "PROVIDE", "PROVIDE_HIDDEN", |
"AS_NEEDED", "CHIP", "LIST", "SECT", "ABSOLUTE", "LOAD", "NEWLINE", |
"ENDWORD", "ORDER", "NAMEWORD", "ASSERT_K", "LOG2CEIL", "FORMAT", |
"PUBLIC", "DEFSYMEND", "BASE", "ALIAS", "TRUNCATE", "REL", |
"INPUT_SCRIPT", "INPUT_MRI_SCRIPT", "INPUT_DEFSYM", "CASE", "EXTERN", |
"START", "VERS_TAG", "VERS_IDENTIFIER", "GLOBAL", "LOCAL", "VERSIONK", |
"INPUT_VERSION_SCRIPT", "KEEP", "ONLY_IF_RO", "ONLY_IF_RW", "SPECIAL", |
"INPUT_SECTION_FLAGS", "ALIGN_WITH_INPUT", "EXCLUDE_FILE", "CONSTANT", |
"INPUT_DYNAMIC_LIST", "','", "';'", "')'", "'['", "']'", "'!'", "'~'", |
"$accept", "file", "filename", "defsym_expr", "@1", "mri_script_file", |
"@2", "mri_script_lines", "mri_script_command", "@3", "ordernamelist", |
"mri_load_name_list", "mri_abs_name_list", "casesymlist", |
"extern_name_list", "@4", "extern_name_list_body", "script_file", "@5", |
"ifile_list", "ifile_p1", "@6", "@7", "input_list", "@8", "@9", "@10", |
"sections", "sec_or_group_p1", "statement_anywhere", "@11", |
"wildcard_name", "wildcard_spec", "sect_flag_list", "sect_flags", |
"exclude_name_list", "file_NAME_list", "input_section_spec_no_keep", |
"input_section_spec", "@12", "statement", "@13", "@14", "statement_list", |
"statement_list_opt", "length", "fill_exp", "fill_opt", "assign_op", |
"end", "assignment", "opt_comma", "memory", "memory_spec_list_opt", |
"memory_spec_list", "memory_spec", "@15", "@16", "origin_spec", |
"length_spec", "attributes_opt", "attributes_list", "attributes_string", |
"startup", "high_level_library", "high_level_library_NAME_list", |
"low_level_library", "low_level_library_NAME_list", |
"floating_point_support", "nocrossref_list", "mustbe_exp", "@17", "exp", |
"memspec_at_opt", "opt_at", "opt_align", "opt_align_with_input", |
"opt_subalign", "sect_constraint", "section", "@18", "@19", "@20", "@21", |
"@22", "@23", "@24", "@25", "@26", "@27", "@28", "@29", "@30", "type", |
"atype", "opt_exp_with_type", "opt_exp_without_type", "opt_nocrossrefs", |
"memspec_opt", "phdr_opt", "overlay_section", "@31", "@32", "@33", |
"phdrs", "phdr_list", "phdr", "@34", "@35", "phdr_type", |
"phdr_qualifiers", "phdr_val", "dynamic_list_file", "@36", |
"dynamic_list_nodes", "dynamic_list_node", "dynamic_list_tag", |
"version_script_file", "@37", "version", "@38", "vers_nodes", |
"vers_node", "verdep", "vers_tag", "vers_defns", "@39", "@40", |
"opt_semicolon", 0 |
}; |
#endif |
# ifdef YYPRINT |
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to |
token YYLEX-NUM. */ |
static const yytype_uint16 yytoknum[] = |
{ |
0, 256, 257, 258, 259, 260, 61, 261, 262, 263, |
264, 265, 266, 267, 268, 63, 58, 269, 270, 124, |
94, 38, 271, 272, 60, 62, 273, 274, 275, 276, |
43, 45, 42, 47, 37, 277, 278, 40, 279, 280, |
281, 282, 283, 284, 285, 286, 287, 288, 289, 290, |
291, 292, 293, 294, 295, 296, 297, 298, 123, 125, |
299, 300, 301, 302, 303, 304, 305, 306, 307, 308, |
309, 310, 311, 312, 313, 314, 315, 316, 317, 318, |
319, 320, 321, 322, 323, 324, 325, 326, 327, 328, |
329, 330, 331, 332, 333, 334, 335, 336, 337, 338, |
339, 340, 341, 342, 343, 344, 345, 346, 347, 348, |
349, 350, 351, 352, 353, 354, 355, 356, 357, 358, |
359, 360, 361, 362, 363, 364, 365, 366, 367, 368, |
369, 370, 371, 372, 373, 374, 375, 376, 377, 378, |
379, 380, 381, 382, 383, 384, 385, 44, 59, 41, |
91, 93, 33, 126 |
}; |
# endif |
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ |
static const yytype_uint16 yyr1[] = |
{ |
0, 154, 155, 155, 155, 155, 155, 156, 158, 157, |
160, 159, 161, 161, 162, 162, 162, 162, 162, 162, |
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, |
162, 162, 162, 162, 162, 162, 162, 162, 162, 162, |
163, 162, 162, 162, 164, 164, 164, 165, 165, 166, |
166, 167, 167, 167, 169, 168, 170, 170, 170, 172, |
171, 173, 173, 174, 174, 174, 174, 174, 174, 174, |
174, 174, 174, 174, 174, 174, 174, 174, 174, 174, |
174, 174, 175, 174, 174, 176, 174, 174, 174, 174, |
174, 174, 174, 177, 177, 177, 177, 177, 177, 178, |
177, 179, 177, 180, 177, 181, 182, 182, 182, 183, |
183, 184, 183, 185, 185, 185, 186, 186, 186, 186, |
186, 186, 186, 186, 186, 186, 186, 187, 187, 188, |
189, 189, 190, 190, 191, 191, 191, 191, 191, 191, |
192, 193, 192, 194, 194, 194, 194, 194, 194, 194, |
194, 195, 194, 196, 194, 197, 197, 198, 198, 199, |
199, 199, 199, 199, 200, 201, 201, 202, 202, 202, |
202, 202, 202, 202, 202, 203, 203, 204, 204, 204, |
204, 204, 205, 205, 206, 207, 207, 208, 208, 210, |
209, 211, 209, 212, 213, 214, 214, 215, 215, 216, |
216, 217, 218, 218, 219, 219, 220, 221, 221, 222, |
222, 223, 223, 223, 225, 224, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 226, 226, |
226, 226, 226, 226, 227, 227, 228, 228, 229, 229, |
230, 230, 231, 231, 232, 232, 232, 232, 234, 235, |
236, 237, 238, 233, 239, 240, 241, 242, 243, 233, |
244, 245, 233, 246, 233, 247, 247, 247, 247, 247, |
248, 248, 248, 249, 249, 249, 249, 250, 250, 251, |
251, 252, 252, 253, 253, 254, 255, 256, 257, 254, |
258, 259, 259, 261, 262, 260, 263, 264, 264, 264, |
265, 265, 267, 266, 268, 268, 269, 270, 272, 271, |
274, 273, 275, 275, 276, 276, 276, 277, 277, 278, |
278, 278, 278, 278, 279, 279, 279, 279, 280, 279, |
281, 279, 279, 279, 279, 279, 279, 279, 282, 282 |
}; |
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ |
static const yytype_uint8 yyr2[] = |
{ |
0, 2, 2, 2, 2, 2, 2, 1, 0, 4, |
0, 2, 3, 0, 2, 4, 1, 1, 2, 1, |
4, 4, 3, 2, 4, 3, 4, 4, 4, 4, |
4, 2, 2, 2, 4, 4, 2, 2, 2, 2, |
0, 5, 2, 0, 3, 2, 0, 1, 3, 1, |
3, 0, 1, 3, 0, 2, 1, 2, 3, 0, |
2, 2, 0, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 4, 4, 4, 4, 8, 4, 1, |
1, 4, 0, 5, 4, 0, 5, 4, 4, 3, |
3, 6, 4, 1, 3, 2, 1, 3, 2, 0, |
5, 0, 7, 0, 6, 4, 2, 2, 0, 4, |
2, 0, 7, 1, 1, 1, 1, 5, 4, 4, |
4, 7, 7, 7, 7, 8, 4, 1, 3, 4, |
2, 1, 3, 1, 1, 2, 3, 4, 4, 5, |
1, 0, 5, 2, 1, 1, 1, 4, 1, 4, |
4, 0, 8, 0, 5, 2, 1, 0, 1, 1, |
1, 1, 1, 1, 1, 2, 0, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 3, 3, 6, |
6, 6, 1, 0, 4, 1, 0, 3, 1, 0, |
7, 0, 5, 3, 3, 0, 3, 1, 2, 1, |
2, 4, 4, 3, 3, 1, 4, 3, 0, 1, |
1, 0, 2, 3, 0, 2, 2, 3, 4, 2, |
2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 5, 3, |
3, 4, 1, 1, 4, 4, 4, 4, 4, 4, |
4, 6, 6, 6, 4, 6, 4, 1, 6, 6, |
6, 4, 4, 4, 3, 0, 4, 0, 4, 0, |
1, 0, 4, 0, 1, 1, 1, 0, 0, 0, |
0, 0, 0, 20, 0, 0, 0, 0, 0, 18, |
0, 0, 7, 0, 5, 1, 1, 1, 1, 1, |
3, 0, 2, 3, 2, 6, 10, 2, 1, 0, |
1, 2, 0, 0, 3, 0, 0, 0, 0, 11, |
4, 0, 2, 0, 0, 6, 1, 0, 3, 5, |
0, 3, 0, 2, 1, 2, 4, 2, 0, 2, |
0, 5, 1, 2, 4, 5, 6, 1, 2, 0, |
2, 4, 4, 8, 1, 1, 3, 3, 0, 9, |
0, 7, 1, 3, 1, 3, 1, 3, 0, 1 |
}; |
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state |
STATE-NUM when YYTABLE doesn't specify something else to do. Zero |
means the default is an error. */ |
static const yytype_uint16 yydefact[] = |
{ |
0, 59, 10, 8, 338, 332, 0, 2, 62, 3, |
13, 6, 0, 4, 0, 5, 0, 1, 60, 11, |
0, 349, 0, 339, 342, 0, 333, 334, 0, 0, |
0, 0, 0, 79, 0, 80, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 209, 210, 0, |
0, 82, 0, 0, 0, 0, 111, 0, 72, 61, |
64, 70, 0, 63, 66, 67, 68, 69, 65, 71, |
0, 16, 0, 0, 0, 0, 17, 0, 0, 0, |
19, 46, 0, 0, 0, 0, 0, 0, 51, 54, |
0, 0, 0, 355, 366, 354, 362, 364, 0, 0, |
349, 343, 362, 364, 0, 0, 335, 214, 174, 173, |
172, 171, 170, 169, 168, 167, 214, 108, 321, 0, |
0, 0, 0, 7, 85, 186, 0, 0, 0, 0, |
0, 0, 0, 0, 208, 211, 0, 0, 0, 0, |
0, 0, 0, 54, 176, 175, 110, 0, 0, 40, |
0, 242, 257, 0, 0, 0, 0, 0, 0, 0, |
0, 243, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 14, |
0, 49, 31, 47, 32, 18, 33, 23, 0, 36, |
0, 37, 52, 38, 39, 0, 42, 12, 9, 0, |
0, 0, 0, 350, 0, 0, 337, 177, 0, 178, |
0, 0, 89, 90, 0, 0, 62, 189, 0, 0, |
183, 188, 0, 0, 0, 0, 0, 0, 0, 203, |
205, 183, 183, 211, 0, 93, 96, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 13, |
0, 0, 220, 216, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 219, 221, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 25, |
0, 0, 45, 0, 0, 0, 22, 0, 0, 56, |
55, 360, 0, 0, 344, 357, 367, 356, 363, 365, |
0, 336, 215, 278, 105, 0, 284, 290, 107, 106, |
323, 320, 322, 0, 76, 78, 340, 195, 191, 184, |
182, 0, 0, 92, 73, 74, 84, 109, 201, 202, |
0, 206, 0, 211, 212, 87, 99, 95, 98, 0, |
0, 81, 0, 75, 214, 214, 214, 0, 88, 0, |
27, 28, 43, 29, 30, 217, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 240, 239, 237, |
236, 235, 230, 229, 233, 234, 232, 231, 228, 227, |
225, 226, 222, 223, 224, 15, 26, 24, 50, 48, |
44, 20, 21, 35, 34, 53, 57, 0, 0, 351, |
352, 0, 347, 345, 0, 301, 293, 0, 301, 0, |
0, 86, 0, 0, 186, 187, 0, 204, 207, 213, |
0, 103, 94, 97, 0, 83, 0, 0, 0, 0, |
341, 41, 0, 250, 256, 0, 0, 254, 0, 241, |
218, 245, 244, 246, 247, 0, 0, 261, 262, 249, |
0, 263, 248, 0, 58, 368, 365, 358, 348, 346, |
0, 0, 301, 0, 267, 108, 308, 0, 309, 291, |
326, 327, 0, 199, 0, 0, 197, 0, 0, 91, |
0, 0, 101, 179, 180, 181, 0, 0, 0, 0, |
0, 0, 0, 0, 238, 369, 0, 0, 0, 295, |
296, 297, 298, 299, 302, 0, 0, 0, 0, 304, |
0, 269, 0, 307, 310, 267, 0, 330, 0, 324, |
0, 200, 196, 198, 0, 183, 192, 100, 0, 0, |
112, 251, 252, 253, 255, 258, 259, 260, 361, 0, |
368, 300, 0, 303, 0, 0, 271, 294, 273, 108, |
0, 327, 0, 0, 77, 214, 0, 104, 0, 353, |
0, 301, 0, 0, 270, 273, 0, 285, 0, 0, |
328, 0, 325, 193, 0, 190, 102, 359, 0, 0, |
266, 0, 279, 0, 0, 292, 331, 327, 214, 0, |
305, 268, 277, 0, 286, 329, 194, 0, 274, 275, |
276, 0, 272, 315, 301, 280, 0, 0, 157, 316, |
287, 306, 134, 115, 114, 159, 160, 161, 162, 163, |
0, 0, 0, 0, 0, 0, 144, 146, 151, 0, |
0, 0, 145, 0, 116, 0, 0, 140, 148, 156, |
158, 0, 0, 0, 0, 312, 0, 0, 0, 0, |
153, 214, 0, 141, 0, 0, 113, 0, 133, 183, |
0, 135, 0, 0, 155, 281, 214, 143, 157, 0, |
265, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 157, 0, 164, 0, 0, 127, 0, 131, 0, |
0, 136, 0, 183, 183, 0, 312, 0, 0, 311, |
0, 313, 0, 0, 147, 0, 118, 0, 0, 119, |
120, 126, 0, 150, 0, 113, 0, 0, 129, 0, |
130, 132, 138, 137, 183, 265, 149, 317, 0, 166, |
0, 0, 0, 0, 0, 154, 0, 142, 128, 117, |
139, 313, 313, 264, 214, 0, 288, 0, 0, 0, |
0, 0, 0, 166, 166, 165, 314, 183, 122, 121, |
0, 123, 124, 0, 282, 318, 289, 125, 152, 183, |
183, 283, 319 |
}; |
/* YYDEFGOTO[NTERM-NUM]. */ |
static const yytype_int16 yydefgoto[] = |
{ |
-1, 6, 124, 11, 12, 9, 10, 19, 91, 249, |
185, 184, 182, 193, 194, 195, 310, 7, 8, 18, |
59, 137, 216, 238, 450, 559, 511, 60, 210, 328, |
142, 664, 665, 717, 666, 719, 689, 667, 668, 715, |
669, 682, 711, 670, 671, 672, 712, 776, 116, 146, |
62, 722, 63, 219, 220, 221, 337, 444, 555, 605, |
443, 505, 506, 64, 65, 231, 66, 232, 67, 234, |
713, 208, 254, 731, 541, 576, 595, 597, 631, 329, |
435, 622, 638, 726, 799, 437, 614, 633, 675, 787, |
438, 546, 495, 535, 493, 494, 498, 545, 700, 759, |
636, 674, 772, 800, 68, 211, 332, 439, 583, 501, |
549, 581, 15, 16, 26, 27, 104, 13, 14, 69, |
70, 23, 24, 434, 98, 99, 528, 428, 526 |
}; |
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing |
STATE-NUM. */ |
#define YYPACT_NINF -647 |
static const yytype_int16 yypact[] = |
{ |
-46, -647, -647, -647, -647, -647, 74, -647, -647, -647, |
-647, -647, 64, -647, -3, -647, 65, -647, 957, 1755, |
124, 5, 166, -3, -647, 114, 65, -647, 682, 169, |
179, 192, 105, -647, 213, -647, 259, 221, 246, 248, |
256, 258, 262, 263, 265, 266, 267, -647, -647, 268, |
276, -647, 291, 293, 295, 296, -647, 298, -647, -647, |
-647, -647, 110, -647, -647, -647, -647, -647, -647, -647, |
178, -647, 332, 259, 334, 781, -647, 336, 337, 338, |
-647, -647, 341, 342, 344, 781, 346, 348, 351, -647, |
352, 245, 781, -647, 355, -647, 345, 353, 313, 226, |
5, -647, -647, -647, 318, 230, -647, -647, -647, -647, |
-647, -647, -647, -647, -647, -647, -647, -647, -647, 375, |
376, 388, 390, -647, -647, 49, 395, 398, 405, 259, |
259, 409, 259, 4, -647, 410, 34, 378, 259, 413, |
417, 418, 386, -647, -647, -647, -647, 366, 31, -647, |
38, -647, -647, 781, 781, 781, 393, 394, 404, 407, |
408, -647, 419, 420, 422, 426, 427, 428, 430, 431, |
432, 433, 440, 444, 445, 446, 449, 781, 781, 1564, |
367, -647, 282, -647, 299, 20, -647, -647, 525, 1936, |
307, -647, -647, 340, -647, 439, -647, -647, 1936, 421, |
114, 114, 343, 121, 434, 354, 121, -647, 781, -647, |
278, 55, -647, -647, -53, 357, -647, -647, 259, 435, |
85, -647, 363, 362, 368, 372, 373, 374, 377, -647, |
-647, -4, 96, 24, 381, -647, -647, 452, 17, 34, |
383, 486, 494, 495, 781, 387, -3, 781, 781, -647, |
781, 781, -647, -647, 965, 781, 781, 781, 781, 781, |
500, 520, 781, 521, 533, 535, 536, 781, 781, 537, |
538, 781, 781, 781, 539, -647, -647, 781, 781, 781, |
781, 781, 781, 781, 781, 781, 781, 781, 781, 781, |
781, 781, 781, 781, 781, 781, 781, 781, 781, 1936, |
541, 543, -647, 544, 781, 781, 1936, 273, 545, -647, |
27, -647, 402, 403, -647, -647, 548, -647, -647, -647, |
-47, -647, 1936, 682, -647, 259, -647, -647, -647, -647, |
-647, -647, -647, 549, -647, -647, 1033, 517, -647, -647, |
-647, 49, 553, -647, -647, -647, -647, -647, -647, -647, |
259, -647, 259, 410, -647, -647, -647, -647, -647, 522, |
88, -647, 21, -647, -647, -647, -647, 1584, -647, -16, |
1936, 1936, 1779, 1936, 1936, -647, 921, 1165, 1604, 1624, |
1185, 411, 412, 1205, 416, 423, 424, 425, 1644, 1664, |
437, 438, 1225, 1695, 1245, 443, 1896, 1776, 1145, 1951, |
1965, 1278, 856, 856, 406, 406, 406, 406, 442, 442, |
167, 167, -647, -647, -647, 1936, 1936, 1936, -647, -647, |
-647, 1936, 1936, -647, -647, -647, -647, 556, 114, 277, |
121, 508, -647, -647, -37, 622, -647, 697, 622, 781, |
441, -647, 3, 551, 49, -647, 447, -647, -647, -647, |
34, -647, -647, -647, 531, -647, 448, 450, 453, 565, |
-647, -647, 781, -647, -647, 781, 781, -647, 781, -647, |
-647, -647, -647, -647, -647, 781, 781, -647, -647, -647, |
566, -647, -647, 781, -647, 455, 559, -647, -647, -647, |
236, 542, 1807, 564, 479, -647, -647, 1916, 497, -647, |
1936, 29, 589, -647, 590, 2, -647, 502, 562, -647, |
30, 34, -647, -647, -647, -647, 463, 1265, 1298, 1318, |
1338, 1358, 1378, 464, 1936, 121, 555, 114, 114, -647, |
-647, -647, -647, -647, -647, 466, 781, -22, 585, -647, |
567, 578, 392, -647, -647, 479, 561, 580, 584, -647, |
473, -647, -647, -647, 617, 477, -647, -647, 79, 34, |
-647, -647, -647, -647, -647, -647, -647, -647, -647, 489, |
455, -647, 1398, -647, 781, 601, 498, -647, 546, -647, |
781, 29, 781, 492, -647, -647, 550, -647, 84, 121, |
587, 225, 1431, 781, -647, 546, 607, -647, 429, 1451, |
-647, 1471, -647, -647, 641, -647, -647, -647, 611, 634, |
-647, 1491, -647, 781, 593, -647, -647, 29, -647, 781, |
-647, -647, 95, 1511, -647, -647, -647, 1531, -647, -647, |
-647, 596, -647, -647, 618, -647, 63, 640, 864, -647, |
-647, -647, 621, -647, -647, -647, -647, -647, -647, -647, |
620, 626, 627, 628, 259, 629, -647, -647, -647, 630, |
631, 632, -647, 311, -647, 639, 15, -647, -647, -647, |
864, 612, 642, 110, 623, 655, 94, 371, 72, 72, |
-647, -647, 646, -647, 680, 72, -647, 648, -647, -39, |
311, 649, 311, 661, -647, -647, -647, -647, 864, 695, |
608, 672, 674, 563, 677, 569, 679, 683, 570, 572, |
573, 864, 574, -647, 781, 8, -647, 11, -647, 14, |
102, -647, 311, 122, -15, 311, 655, 575, 666, -647, |
701, -647, 72, 72, -647, 72, -647, 72, 72, -647, |
-647, -647, 693, -647, 1715, 581, 582, 728, -647, 72, |
-647, -647, -647, -647, 123, 608, -647, -647, 733, 91, |
592, 594, 41, 602, 603, -647, 734, -647, -647, -647, |
-647, -647, -647, -647, -647, 738, -647, 605, 606, 72, |
609, 610, 614, 91, 91, -647, -647, 477, -647, -647, |
615, -647, -647, 110, -647, -647, -647, -647, -647, 477, |
477, -647, -647 |
}; |
/* YYPGOTO[NTERM-NUM]. */ |
static const yytype_int16 yypgoto[] = |
{ |
-647, -647, -72, -647, -647, -647, -647, 507, -647, -647, |
-647, -647, -647, -647, 625, -647, -647, -647, -647, 554, |
-647, -647, -647, -225, -647, -647, -647, -647, -459, -13, |
-647, 68, -398, -647, -647, 25, -615, 46, -647, -647, |
99, -647, -647, -647, -612, -647, -9, -493, -647, -646, |
-386, -216, -647, 322, -647, 454, -647, -647, -647, -647, |
-647, -647, 271, -647, -647, -647, -647, -647, -647, -192, |
-105, -647, -75, 16, 228, -647, -647, 191, -647, -647, |
-647, -647, -647, -647, -647, -647, -647, -647, -647, -647, |
-647, -647, -647, -647, -472, 356, -647, -647, 67, -474, |
-647, -647, -647, -647, -647, -647, -647, -647, -647, -647, |
-527, -647, -647, -647, -647, 763, -647, -647, -647, -647, |
-647, 552, -20, -647, 691, -12, -647, -647, 227 |
}; |
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If |
positive, shift that token. If negative, reduce the rule which |
number is the opposite. If zero, do what YYDEFACT says. |
If YYTABLE_NINF, syntax error. */ |
#define YYTABLE_NINF -341 |
static const yytype_int16 yytable[] = |
{ |
179, 149, 207, 101, 341, 61, 503, 503, 123, 93, |
189, 209, 745, 105, 362, 350, 352, 198, 686, 691, |
538, 357, 358, 643, 302, 357, 358, 697, 233, 643, |
643, 426, 747, 547, 357, 358, 542, 247, 235, 236, |
644, 354, 21, 460, 250, 686, 644, 644, 529, 530, |
531, 532, 533, 217, 600, 21, 643, 225, 226, 330, |
228, 230, 687, 651, 652, 653, 240, 639, 20, 687, |
651, 652, 653, 644, 17, 723, 686, 724, 252, 253, |
1, 2, 3, 357, 358, 432, 728, 643, 357, 358, |
625, 4, 452, 453, 333, 488, 334, 774, 686, 742, |
5, 433, 275, 276, 644, 299, 686, 775, 340, 643, |
754, 489, 721, 306, 331, 218, 22, 643, 93, 609, |
598, -185, 640, 25, 359, 315, 644, 534, 359, 22, |
92, 548, 340, 322, 644, 94, 753, 359, 95, 96, |
97, 237, 121, 340, -185, 349, 338, 798, 701, 702, |
660, 552, 661, 229, 504, 504, 701, 702, 663, 661, |
748, 449, 637, 749, 360, 692, 361, 303, 360, 367, |
455, 353, 370, 371, 427, 373, 374, 360, 248, 557, |
376, 377, 378, 379, 380, 251, 359, 383, 312, 313, |
779, 359, 388, 389, 703, 454, 392, 393, 394, 293, |
294, 295, 396, 397, 398, 399, 400, 401, 402, 403, |
404, 405, 406, 407, 408, 409, 410, 411, 412, 413, |
414, 415, 416, 417, 100, 510, 360, 117, 587, 421, |
422, 360, 340, 606, 628, 629, 630, 118, 704, 151, |
152, 119, 120, 340, 94, 351, 704, 95, 102, 103, |
122, 316, 673, 436, 317, 318, 319, 144, 145, 456, |
457, 458, 537, 123, 608, 688, 153, 154, 693, 340, |
340, 752, 770, 155, 156, 157, 423, 424, 447, 125, |
448, 315, 323, 126, 673, 127, 558, 158, 159, 160, |
794, 795, 688, 128, 688, 129, 161, 783, 784, 130, |
131, 162, 132, 133, 134, 135, 529, 530, 531, 532, |
533, 163, 673, 136, 147, 686, 164, 165, 166, 167, |
168, 169, 170, 61, 751, 673, 643, 688, 138, 171, |
139, 172, 140, 141, 588, 143, 148, 324, 150, 586, |
180, 181, 183, 644, 325, 186, 187, 173, 188, 101, |
190, 191, 326, 174, 175, 192, 196, 43, 197, 199, |
492, 200, 497, 492, 500, 687, 651, 652, 653, 201, |
151, 152, 202, 297, 203, 686, 327, 205, 206, 212, |
213, 176, 53, 54, 55, 534, 643, 517, 177, 178, |
518, 519, 214, 520, 215, 56, 323, 153, 154, 222, |
521, 522, 223, 644, 155, 156, 157, 316, 524, 224, |
317, 318, 486, 227, 233, 239, 485, 241, 158, 159, |
160, 242, 243, 244, 246, 706, 707, 161, 577, 300, |
255, 256, 162, 323, 289, 290, 291, 292, 293, 294, |
295, 257, 163, 309, 258, 259, 301, 164, 165, 166, |
167, 168, 169, 170, 307, 661, 260, 261, 325, 262, |
171, 572, 172, 263, 264, 265, 326, 266, 267, 268, |
269, 43, 291, 292, 293, 294, 295, 270, 173, 311, |
603, 271, 272, 273, 174, 175, 274, 308, 615, 356, |
327, 314, 364, 320, 339, 325, 53, 54, 55, 592, |
365, 366, 321, 326, 381, 599, 335, 601, 43, 56, |
342, 343, 176, 626, 298, 569, 570, 344, 611, 177, |
178, 345, 346, 347, 382, 384, 348, 327, 151, 152, |
355, 304, 363, 53, 54, 55, 368, 385, 623, 386, |
387, 390, 391, 395, 627, 418, 56, 419, 420, 425, |
429, 430, 431, 440, 442, 153, 154, 446, 468, 451, |
484, 469, 155, 156, 157, 471, 487, 507, 512, 516, |
523, 796, 472, 473, 474, 527, 158, 159, 160, 536, |
539, 540, 680, 801, 802, 161, 477, 478, 502, 544, |
162, 727, 482, 550, 551, 554, 509, 513, 556, 514, |
163, 573, 515, 525, 574, 164, 165, 166, 167, 168, |
169, 170, 560, 567, 568, 571, 575, 580, 171, 579, |
172, 582, 584, 585, 340, 151, 152, 107, 108, 109, |
110, 111, 112, 113, 114, 115, 173, 589, 593, 744, |
602, 594, 174, 175, 613, 604, 607, 618, 619, 596, |
620, 624, 153, 154, 635, 537, 641, 676, -113, 490, |
156, 157, 491, 677, 678, 679, 681, 683, 684, 685, |
176, 695, 305, 158, 159, 160, 690, 177, 178, 696, |
699, 698, 161, 714, 716, 720, -113, 162, 107, 108, |
109, 110, 111, 112, 113, 114, 115, 163, 725, 729, |
151, 152, 164, 165, 166, 167, 168, 169, 170, 732, |
730, 733, 734, 496, 735, 171, 737, 172, 736, 739, |
738, 740, 741, 743, 756, 757, 758, 153, 154, 765, |
-134, 767, 768, 173, 155, 156, 157, 773, 782, 174, |
175, 777, 786, 778, 705, 708, 709, 710, 158, 159, |
160, 780, 781, 718, 788, 789, 372, 161, 791, 792, |
762, 746, 162, 793, 797, 785, 508, 176, 245, 694, |
336, 771, 163, 578, 177, 178, 553, 164, 165, 166, |
167, 168, 169, 170, 151, 152, 612, 750, 705, 106, |
171, 204, 172, 755, 499, 445, 0, 590, 369, 0, |
760, 761, 0, 718, 0, 763, 764, 0, 173, 0, |
0, 153, 154, 0, 174, 175, 0, 769, 155, 156, |
157, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
750, 0, 158, 159, 160, 0, 0, 0, 0, 0, |
0, 161, 176, 0, 0, 0, 162, 790, 0, 177, |
178, 0, 0, 0, 0, 0, 163, 0, 0, 0, |
0, 164, 165, 166, 167, 168, 169, 170, 642, 0, |
0, 0, 0, 0, 171, 0, 172, 0, 0, 643, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 0, 173, 0, 0, 0, 644, 0, 174, 175, |
0, 0, 0, 0, 0, 645, 646, 647, 648, 649, |
0, 0, 0, 0, 0, 0, 0, 0, 650, 651, |
652, 653, 0, 0, 0, 0, 176, 0, 0, 0, |
654, 0, 0, 177, 178, 0, 277, 0, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 0, 0, 655, 0, |
656, 28, 0, 0, 657, 0, 0, 0, 53, 54, |
55, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
277, 658, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
0, 0, 659, 29, 30, 31, 660, 0, 661, 0, |
0, 0, 662, 0, 663, 0, 0, 0, 32, 33, |
34, 35, 0, 36, 37, 38, 39, 0, 0, 0, |
0, 0, 0, 40, 41, 42, 43, 28, 0, 0, |
0, 0, 0, 0, 44, 45, 46, 47, 48, 49, |
0, 0, 0, 0, 50, 51, 52, 0, 0, 0, |
0, 53, 54, 55, 0, 0, 0, 0, 462, 441, |
463, 0, 0, 0, 56, 0, 0, 0, 0, 29, |
30, 31, 0, 0, 0, 0, 0, 57, 0, 0, |
0, 0, 0, -340, 32, 33, 34, 35, 0, 36, |
37, 38, 39, 0, 0, 58, 0, 0, 0, 40, |
41, 42, 43, 0, 375, 0, 0, 0, 0, 0, |
44, 45, 46, 47, 48, 49, 0, 0, 0, 0, |
50, 51, 52, 0, 0, 0, 0, 53, 54, 55, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
56, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 57, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 58, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 0, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 0, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 0, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 0, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 0, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 464, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 467, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 470, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 479, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 481, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 277, 561, 278, 279, 280, 281, 282, |
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, |
293, 294, 295, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 277, 562, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 277, 563, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 277, 564, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 277, 565, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 277, 566, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 277, 591, 278, 279, |
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 277, |
610, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 277, |
616, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 277, |
617, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 277, |
621, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 277, |
632, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 277, |
634, 278, 279, 280, 281, 282, 283, 284, 285, 286, |
287, 288, 289, 290, 291, 292, 293, 294, 295, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
277, 296, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
277, 459, 278, 279, 280, 281, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295, |
0, 465, 0, 0, 0, 0, 0, 0, 0, 71, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 466, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 71, 0, 0, 0, 0, 0, 0, |
0, 475, 0, 72, 279, 280, 281, 282, 283, 284, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 476, 0, 0, 0, 461, 0, 72, 0, 0, |
0, 73, 277, 0, 278, 279, 280, 281, 282, 283, |
284, 285, 286, 287, 288, 289, 290, 291, 292, 293, |
294, 295, 480, 0, 537, 73, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 74, 0, 0, 0, |
0, 0, 766, 75, 76, 77, 78, 79, -43, 80, |
81, 82, 0, 0, 83, 84, 0, 85, 86, 87, |
74, 0, 0, 0, 88, 89, 90, 75, 76, 77, |
78, 79, 0, 80, 81, 82, 0, 0, 83, 84, |
0, 85, 86, 87, 0, 0, 0, 0, 88, 89, |
90, 277, 483, 278, 279, 280, 281, 282, 283, 284, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 277, 543, 278, 279, 280, 281, 282, 283, 284, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 277, 0, 278, 279, 280, 281, 282, 283, 284, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 281, 282, 283, 284, 285, 286, 287, 288, 289, |
290, 291, 292, 293, 294, 295, 282, 283, 284, 285, |
286, 287, 288, 289, 290, 291, 292, 293, 294, 295 |
}; |
static const yytype_int16 yycheck[] = |
{ |
75, 73, 107, 23, 220, 18, 4, 4, 4, 4, |
85, 116, 4, 25, 239, 231, 232, 92, 4, 4, |
492, 4, 5, 15, 4, 4, 5, 673, 4, 15, |
15, 4, 21, 4, 4, 5, 495, 6, 4, 5, |
32, 233, 58, 59, 6, 4, 32, 32, 70, 71, |
72, 73, 74, 4, 581, 58, 15, 129, 130, 4, |
132, 133, 54, 55, 56, 57, 138, 4, 4, 54, |
55, 56, 57, 32, 0, 690, 4, 692, 153, 154, |
126, 127, 128, 4, 5, 132, 698, 15, 4, 5, |
617, 137, 4, 5, 147, 132, 149, 6, 4, 711, |
146, 148, 177, 178, 32, 180, 4, 16, 147, 15, |
725, 148, 151, 188, 59, 66, 132, 15, 4, 591, |
579, 36, 59, 58, 107, 4, 32, 149, 107, 132, |
6, 102, 147, 208, 32, 130, 151, 107, 133, 134, |
135, 107, 37, 147, 59, 149, 218, 793, 54, 55, |
142, 149, 144, 149, 152, 152, 54, 55, 150, 144, |
149, 353, 634, 149, 147, 150, 149, 147, 147, 244, |
149, 147, 247, 248, 147, 250, 251, 147, 147, 149, |
255, 256, 257, 258, 259, 147, 107, 262, 200, 201, |
149, 107, 267, 268, 100, 107, 271, 272, 273, 32, |
33, 34, 277, 278, 279, 280, 281, 282, 283, 284, |
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, |
295, 296, 297, 298, 58, 450, 147, 58, 149, 304, |
305, 147, 147, 149, 139, 140, 141, 58, 144, 3, |
4, 49, 50, 147, 130, 149, 144, 133, 134, 135, |
37, 130, 638, 325, 133, 134, 135, 147, 148, 364, |
365, 366, 37, 4, 39, 663, 30, 31, 666, 147, |
147, 149, 149, 37, 38, 39, 3, 4, 350, 58, |
352, 4, 4, 37, 670, 37, 511, 51, 52, 53, |
783, 784, 690, 37, 692, 37, 60, 771, 772, 37, |
37, 65, 37, 37, 37, 37, 70, 71, 72, 73, |
74, 75, 698, 37, 136, 4, 80, 81, 82, 83, |
84, 85, 86, 336, 722, 711, 15, 725, 37, 93, |
37, 95, 37, 37, 559, 37, 4, 59, 4, 555, |
4, 4, 4, 32, 66, 4, 4, 111, 4, 369, |
4, 3, 74, 117, 118, 4, 4, 79, 113, 4, |
435, 16, 437, 438, 439, 54, 55, 56, 57, 16, |
3, 4, 59, 6, 148, 4, 98, 59, 148, 4, |
4, 145, 104, 105, 106, 149, 15, 462, 152, 153, |
465, 466, 4, 468, 4, 117, 4, 30, 31, 4, |
475, 476, 4, 32, 37, 38, 39, 130, 483, 4, |
133, 134, 135, 4, 4, 37, 428, 4, 51, 52, |
53, 4, 4, 37, 58, 54, 55, 60, 36, 147, |
37, 37, 65, 4, 28, 29, 30, 31, 32, 33, |
34, 37, 75, 4, 37, 37, 147, 80, 81, 82, |
83, 84, 85, 86, 147, 144, 37, 37, 66, 37, |
93, 536, 95, 37, 37, 37, 74, 37, 37, 37, |
37, 79, 30, 31, 32, 33, 34, 37, 111, 58, |
585, 37, 37, 37, 117, 118, 37, 147, 59, 37, |
98, 148, 6, 59, 59, 66, 104, 105, 106, 574, |
6, 6, 148, 74, 4, 580, 149, 582, 79, 117, |
147, 149, 145, 618, 147, 527, 528, 149, 593, 152, |
153, 149, 149, 149, 4, 4, 149, 98, 3, 4, |
149, 6, 149, 104, 105, 106, 149, 4, 613, 4, |
4, 4, 4, 4, 619, 4, 117, 4, 4, 4, |
148, 148, 4, 4, 37, 30, 31, 4, 147, 37, |
4, 149, 37, 38, 39, 149, 58, 16, 37, 4, |
4, 787, 149, 149, 149, 16, 51, 52, 53, 37, |
16, 102, 654, 799, 800, 60, 149, 149, 147, 92, |
65, 696, 149, 4, 4, 93, 149, 149, 36, 149, |
75, 16, 149, 148, 37, 80, 81, 82, 83, 84, |
85, 86, 149, 149, 59, 149, 38, 37, 93, 58, |
95, 37, 149, 6, 147, 3, 4, 6, 7, 8, |
9, 10, 11, 12, 13, 14, 111, 148, 37, 714, |
148, 143, 117, 118, 37, 95, 59, 6, 37, 103, |
16, 58, 30, 31, 58, 37, 16, 37, 37, 37, |
38, 39, 40, 37, 37, 37, 37, 37, 37, 37, |
145, 59, 147, 51, 52, 53, 37, 152, 153, 37, |
25, 58, 60, 37, 4, 37, 37, 65, 6, 7, |
8, 9, 10, 11, 12, 13, 14, 75, 37, 4, |
3, 4, 80, 81, 82, 83, 84, 85, 86, 37, |
102, 37, 149, 16, 37, 93, 37, 95, 149, 149, |
37, 149, 149, 149, 149, 59, 25, 30, 31, 36, |
149, 149, 4, 111, 37, 38, 39, 4, 4, 117, |
118, 149, 4, 149, 676, 677, 678, 679, 51, 52, |
53, 149, 149, 685, 149, 149, 249, 60, 149, 149, |
735, 715, 65, 149, 149, 774, 444, 145, 143, 670, |
216, 755, 75, 545, 152, 153, 505, 80, 81, 82, |
83, 84, 85, 86, 3, 4, 595, 719, 720, 26, |
93, 100, 95, 726, 438, 341, -1, 570, 246, -1, |
732, 733, -1, 735, -1, 737, 738, -1, 111, -1, |
-1, 30, 31, -1, 117, 118, -1, 749, 37, 38, |
39, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
762, -1, 51, 52, 53, -1, -1, -1, -1, -1, |
-1, 60, 145, -1, -1, -1, 65, 779, -1, 152, |
153, -1, -1, -1, -1, -1, 75, -1, -1, -1, |
-1, 80, 81, 82, 83, 84, 85, 86, 4, -1, |
-1, -1, -1, -1, 93, -1, 95, -1, -1, 15, |
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, |
34, -1, 111, -1, -1, -1, 32, -1, 117, 118, |
-1, -1, -1, -1, -1, 41, 42, 43, 44, 45, |
-1, -1, -1, -1, -1, -1, -1, -1, 54, 55, |
56, 57, -1, -1, -1, -1, 145, -1, -1, -1, |
66, -1, -1, 152, 153, -1, 15, -1, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, -1, -1, 94, -1, |
96, 4, -1, -1, 100, -1, -1, -1, 104, 105, |
106, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
15, 117, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
-1, -1, 138, 46, 47, 48, 142, -1, 144, -1, |
-1, -1, 148, -1, 150, -1, -1, -1, 61, 62, |
63, 64, -1, 66, 67, 68, 69, -1, -1, -1, |
-1, -1, -1, 76, 77, 78, 79, 4, -1, -1, |
-1, -1, -1, -1, 87, 88, 89, 90, 91, 92, |
-1, -1, -1, -1, 97, 98, 99, -1, -1, -1, |
-1, 104, 105, 106, -1, -1, -1, -1, 147, 36, |
149, -1, -1, -1, 117, -1, -1, -1, -1, 46, |
47, 48, -1, -1, -1, -1, -1, 130, -1, -1, |
-1, -1, -1, 136, 61, 62, 63, 64, -1, 66, |
67, 68, 69, -1, -1, 148, -1, -1, -1, 76, |
77, 78, 79, -1, 149, -1, -1, -1, -1, -1, |
87, 88, 89, 90, 91, 92, -1, -1, -1, -1, |
97, 98, 99, -1, -1, -1, -1, 104, 105, 106, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
117, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 130, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, 148, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, -1, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, -1, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, -1, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, -1, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, -1, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 15, 149, 17, 18, 19, 20, 21, |
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 15, 149, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, 15, |
149, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
26, 27, 28, 29, 30, 31, 32, 33, 34, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
15, 147, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
15, 147, 17, 18, 19, 20, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
-1, 147, -1, -1, -1, -1, -1, -1, -1, 4, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, 147, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 4, -1, -1, -1, -1, -1, -1, |
-1, 147, -1, 38, 18, 19, 20, 21, 22, 23, |
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, |
34, 147, -1, -1, -1, 36, -1, 38, -1, -1, |
-1, 66, 15, -1, 17, 18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, |
33, 34, 147, -1, 37, 66, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, 101, -1, -1, -1, |
-1, -1, 147, 108, 109, 110, 111, 112, 113, 114, |
115, 116, -1, -1, 119, 120, -1, 122, 123, 124, |
101, -1, -1, -1, 129, 130, 131, 108, 109, 110, |
111, 112, -1, 114, 115, 116, -1, -1, 119, 120, |
-1, 122, 123, 124, -1, -1, -1, -1, 129, 130, |
131, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, |
34, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, |
34, 15, -1, 17, 18, 19, 20, 21, 22, 23, |
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, |
34, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 21, 22, 23, 24, |
25, 26, 27, 28, 29, 30, 31, 32, 33, 34 |
}; |
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing |
symbol of state STATE-NUM. */ |
static const yytype_uint16 yystos[] = |
{ |
0, 126, 127, 128, 137, 146, 155, 171, 172, 159, |
160, 157, 158, 271, 272, 266, 267, 0, 173, 161, |
4, 58, 132, 275, 276, 58, 268, 269, 4, 46, |
47, 48, 61, 62, 63, 64, 66, 67, 68, 69, |
76, 77, 78, 79, 87, 88, 89, 90, 91, 92, |
97, 98, 99, 104, 105, 106, 117, 130, 148, 174, |
181, 183, 204, 206, 217, 218, 220, 222, 258, 273, |
274, 4, 38, 66, 101, 108, 109, 110, 111, 112, |
114, 115, 116, 119, 120, 122, 123, 124, 129, 130, |
131, 162, 6, 4, 130, 133, 134, 135, 278, 279, |
58, 276, 134, 135, 270, 279, 269, 6, 7, 8, |
9, 10, 11, 12, 13, 14, 202, 58, 58, 49, |
50, 37, 37, 4, 156, 58, 37, 37, 37, 37, |
37, 37, 37, 37, 37, 37, 37, 175, 37, 37, |
37, 37, 184, 37, 147, 148, 203, 136, 4, 156, |
4, 3, 4, 30, 31, 37, 38, 39, 51, 52, |
53, 60, 65, 75, 80, 81, 82, 83, 84, 85, |
86, 93, 95, 111, 117, 118, 145, 152, 153, 226, |
4, 4, 166, 4, 165, 164, 4, 4, 4, 226, |
4, 3, 4, 167, 168, 169, 4, 113, 226, 4, |
16, 16, 59, 148, 278, 59, 148, 224, 225, 224, |
182, 259, 4, 4, 4, 4, 176, 4, 66, 207, |
208, 209, 4, 4, 4, 156, 156, 4, 156, 149, |
156, 219, 221, 4, 223, 4, 5, 107, 177, 37, |
156, 4, 4, 4, 37, 168, 58, 6, 147, 163, |
6, 147, 226, 226, 226, 37, 37, 37, 37, 37, |
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, |
37, 37, 37, 37, 37, 226, 226, 15, 17, 18, |
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
29, 30, 31, 32, 33, 34, 147, 6, 147, 226, |
147, 147, 4, 147, 6, 147, 226, 147, 147, 4, |
170, 58, 279, 279, 148, 4, 130, 133, 134, 135, |
59, 148, 226, 4, 59, 66, 74, 98, 183, 233, |
4, 59, 260, 147, 149, 149, 173, 210, 156, 59, |
147, 205, 147, 149, 149, 149, 149, 149, 149, 149, |
205, 149, 205, 147, 223, 149, 37, 4, 5, 107, |
147, 149, 177, 149, 6, 6, 6, 226, 149, 275, |
226, 226, 161, 226, 226, 149, 226, 226, 226, 226, |
226, 4, 4, 226, 4, 4, 4, 4, 226, 226, |
4, 4, 226, 226, 226, 4, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 226, 226, |
226, 226, 226, 226, 226, 226, 226, 226, 4, 4, |
4, 226, 226, 3, 4, 4, 4, 147, 281, 148, |
148, 4, 132, 148, 277, 234, 156, 239, 244, 261, |
4, 36, 37, 214, 211, 209, 4, 156, 156, 223, |
178, 37, 4, 5, 107, 149, 224, 224, 224, 147, |
59, 36, 147, 149, 149, 147, 147, 149, 147, 149, |
149, 149, 149, 149, 149, 147, 147, 149, 149, 149, |
147, 149, 149, 16, 4, 279, 135, 58, 132, 148, |
37, 40, 226, 248, 249, 246, 16, 226, 250, 249, |
226, 263, 147, 4, 152, 215, 216, 16, 207, 149, |
177, 180, 37, 149, 149, 149, 4, 226, 226, 226, |
226, 226, 226, 4, 226, 148, 282, 16, 280, 70, |
71, 72, 73, 74, 149, 247, 37, 37, 248, 16, |
102, 228, 182, 16, 92, 251, 245, 4, 102, 264, |
4, 4, 149, 216, 93, 212, 36, 149, 177, 179, |
149, 149, 149, 149, 149, 149, 149, 149, 59, 279, |
279, 149, 226, 16, 37, 38, 229, 36, 228, 58, |
37, 265, 37, 262, 149, 6, 205, 149, 177, 148, |
282, 149, 226, 37, 143, 230, 103, 231, 182, 226, |
264, 226, 148, 224, 95, 213, 149, 59, 39, 248, |
149, 226, 231, 37, 240, 59, 149, 149, 6, 37, |
16, 149, 235, 226, 58, 264, 224, 226, 139, 140, |
141, 232, 149, 241, 149, 58, 254, 248, 236, 4, |
59, 16, 4, 15, 32, 41, 42, 43, 44, 45, |
54, 55, 56, 57, 66, 94, 96, 100, 117, 138, |
142, 144, 148, 150, 185, 186, 188, 191, 192, 194, |
197, 198, 199, 204, 255, 242, 37, 37, 37, 37, |
156, 37, 195, 37, 37, 37, 4, 54, 186, 190, |
37, 4, 150, 186, 194, 59, 37, 203, 58, 25, |
252, 54, 55, 100, 144, 185, 54, 55, 185, 185, |
185, 196, 200, 224, 37, 193, 4, 187, 185, 189, |
37, 151, 205, 190, 190, 37, 237, 224, 198, 4, |
102, 227, 37, 37, 149, 37, 149, 37, 37, 149, |
149, 149, 198, 149, 226, 4, 191, 21, 149, 149, |
185, 186, 149, 151, 190, 252, 149, 59, 25, 253, |
185, 185, 189, 185, 185, 36, 147, 149, 4, 185, |
149, 227, 256, 4, 6, 16, 201, 149, 149, 149, |
149, 149, 4, 253, 253, 200, 4, 243, 149, 149, |
185, 149, 149, 149, 201, 201, 205, 149, 203, 238, |
257, 205, 205 |
}; |
#define yyerrok (yyerrstatus = 0) |
#define yyclearin (yychar = YYEMPTY) |
#define YYEMPTY (-2) |
#define YYEOF 0 |
#define YYACCEPT goto yyacceptlab |
#define YYABORT goto yyabortlab |
#define YYERROR goto yyerrorlab |
/* Like YYERROR except do call yyerror. This remains here temporarily |
to ease the transition to the new meaning of YYERROR, for GCC. |
Once GCC version 2 has supplanted version 1, this can go. */ |
#define YYFAIL goto yyerrlab |
#define YYRECOVERING() (!!yyerrstatus) |
#define YYBACKUP(Token, Value) \ |
do \ |
if (yychar == YYEMPTY && yylen == 1) \ |
{ \ |
yychar = (Token); \ |
yylval = (Value); \ |
yytoken = YYTRANSLATE (yychar); \ |
YYPOPSTACK (1); \ |
goto yybackup; \ |
} \ |
else \ |
{ \ |
yyerror (YY_("syntax error: cannot back up")); \ |
YYERROR; \ |
} \ |
while (YYID (0)) |
#define YYTERROR 1 |
#define YYERRCODE 256 |
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. |
If N is 0, then set CURRENT to the empty location which ends |
the previous symbol: RHS[0] (always defined). */ |
#define YYRHSLOC(Rhs, K) ((Rhs)[K]) |
#ifndef YYLLOC_DEFAULT |
# define YYLLOC_DEFAULT(Current, Rhs, N) \ |
do \ |
if (YYID (N)) \ |
{ \ |
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ |
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ |
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \ |
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \ |
} \ |
else \ |
{ \ |
(Current).first_line = (Current).last_line = \ |
YYRHSLOC (Rhs, 0).last_line; \ |
(Current).first_column = (Current).last_column = \ |
YYRHSLOC (Rhs, 0).last_column; \ |
} \ |
while (YYID (0)) |
#endif |
/* YY_LOCATION_PRINT -- Print the location on the stream. |
This macro was not mandated originally: define only if we know |
we won't break user code: when these are the locations we know. */ |
#ifndef YY_LOCATION_PRINT |
# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL |
# define YY_LOCATION_PRINT(File, Loc) \ |
fprintf (File, "%d.%d-%d.%d", \ |
(Loc).first_line, (Loc).first_column, \ |
(Loc).last_line, (Loc).last_column) |
# else |
# define YY_LOCATION_PRINT(File, Loc) ((void) 0) |
# endif |
#endif |
/* YYLEX -- calling `yylex' with the right arguments. */ |
#ifdef YYLEX_PARAM |
# define YYLEX yylex (YYLEX_PARAM) |
#else |
# define YYLEX yylex () |
#endif |
/* Enable debugging if requested. */ |
#if YYDEBUG |
# ifndef YYFPRINTF |
# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ |
# define YYFPRINTF fprintf |
# endif |
# define YYDPRINTF(Args) \ |
do { \ |
if (yydebug) \ |
YYFPRINTF Args; \ |
} while (YYID (0)) |
# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ |
do { \ |
if (yydebug) \ |
{ \ |
YYFPRINTF (stderr, "%s ", Title); \ |
yy_symbol_print (stderr, \ |
Type, Value); \ |
YYFPRINTF (stderr, "\n"); \ |
} \ |
} while (YYID (0)) |
/*--------------------------------. |
| Print this symbol on YYOUTPUT. | |
`--------------------------------*/ |
/*ARGSUSED*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) |
#else |
static void |
yy_symbol_value_print (yyoutput, yytype, yyvaluep) |
FILE *yyoutput; |
int yytype; |
YYSTYPE const * const yyvaluep; |
#endif |
{ |
if (!yyvaluep) |
return; |
# ifdef YYPRINT |
if (yytype < YYNTOKENS) |
YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); |
# else |
YYUSE (yyoutput); |
# endif |
switch (yytype) |
{ |
default: |
break; |
} |
} |
/*--------------------------------. |
| Print this symbol on YYOUTPUT. | |
`--------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) |
#else |
static void |
yy_symbol_print (yyoutput, yytype, yyvaluep) |
FILE *yyoutput; |
int yytype; |
YYSTYPE const * const yyvaluep; |
#endif |
{ |
if (yytype < YYNTOKENS) |
YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); |
else |
YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); |
yy_symbol_value_print (yyoutput, yytype, yyvaluep); |
YYFPRINTF (yyoutput, ")"); |
} |
/*------------------------------------------------------------------. |
| yy_stack_print -- Print the state stack from its BOTTOM up to its | |
| TOP (included). | |
`------------------------------------------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) |
#else |
static void |
yy_stack_print (bottom, top) |
yytype_int16 *bottom; |
yytype_int16 *top; |
#endif |
{ |
YYFPRINTF (stderr, "Stack now"); |
for (; bottom <= top; ++bottom) |
YYFPRINTF (stderr, " %d", *bottom); |
YYFPRINTF (stderr, "\n"); |
} |
# define YY_STACK_PRINT(Bottom, Top) \ |
do { \ |
if (yydebug) \ |
yy_stack_print ((Bottom), (Top)); \ |
} while (YYID (0)) |
/*------------------------------------------------. |
| Report that the YYRULE is going to be reduced. | |
`------------------------------------------------*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yy_reduce_print (YYSTYPE *yyvsp, int yyrule) |
#else |
static void |
yy_reduce_print (yyvsp, yyrule) |
YYSTYPE *yyvsp; |
int yyrule; |
#endif |
{ |
int yynrhs = yyr2[yyrule]; |
int yyi; |
unsigned long int yylno = yyrline[yyrule]; |
YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", |
yyrule - 1, yylno); |
/* The symbols being reduced. */ |
for (yyi = 0; yyi < yynrhs; yyi++) |
{ |
fprintf (stderr, " $%d = ", yyi + 1); |
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], |
&(yyvsp[(yyi + 1) - (yynrhs)]) |
); |
fprintf (stderr, "\n"); |
} |
} |
# define YY_REDUCE_PRINT(Rule) \ |
do { \ |
if (yydebug) \ |
yy_reduce_print (yyvsp, Rule); \ |
} while (YYID (0)) |
/* Nonzero means print parse trace. It is left uninitialized so that |
multiple parsers can coexist. */ |
int yydebug; |
#else /* !YYDEBUG */ |
# define YYDPRINTF(Args) |
# define YY_SYMBOL_PRINT(Title, Type, Value, Location) |
# define YY_STACK_PRINT(Bottom, Top) |
# define YY_REDUCE_PRINT(Rule) |
#endif /* !YYDEBUG */ |
/* YYINITDEPTH -- initial size of the parser's stacks. */ |
#ifndef YYINITDEPTH |
# define YYINITDEPTH 200 |
#endif |
/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only |
if the built-in stack extension method is used). |
Do not make this value too large; the results are undefined if |
YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) |
evaluated with infinite-precision integer arithmetic. */ |
#ifndef YYMAXDEPTH |
# define YYMAXDEPTH 10000 |
#endif |
#if YYERROR_VERBOSE |
# ifndef yystrlen |
# if defined __GLIBC__ && defined _STRING_H |
# define yystrlen strlen |
# else |
/* Return the length of YYSTR. */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static YYSIZE_T |
yystrlen (const char *yystr) |
#else |
static YYSIZE_T |
yystrlen (yystr) |
const char *yystr; |
#endif |
{ |
YYSIZE_T yylen; |
for (yylen = 0; yystr[yylen]; yylen++) |
continue; |
return yylen; |
} |
# endif |
# endif |
# ifndef yystpcpy |
# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE |
# define yystpcpy stpcpy |
# else |
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in |
YYDEST. */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static char * |
yystpcpy (char *yydest, const char *yysrc) |
#else |
static char * |
yystpcpy (yydest, yysrc) |
char *yydest; |
const char *yysrc; |
#endif |
{ |
char *yyd = yydest; |
const char *yys = yysrc; |
while ((*yyd++ = *yys++) != '\0') |
continue; |
return yyd - 1; |
} |
# endif |
# endif |
# ifndef yytnamerr |
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary |
quotes and backslashes, so that it's suitable for yyerror. The |
heuristic is that double-quoting is unnecessary unless the string |
contains an apostrophe, a comma, or backslash (other than |
backslash-backslash). YYSTR is taken from yytname. If YYRES is |
null, do not copy; instead, return the length of what the result |
would have been. */ |
static YYSIZE_T |
yytnamerr (char *yyres, const char *yystr) |
{ |
if (*yystr == '"') |
{ |
YYSIZE_T yyn = 0; |
char const *yyp = yystr; |
for (;;) |
switch (*++yyp) |
{ |
case '\'': |
case ',': |
goto do_not_strip_quotes; |
case '\\': |
if (*++yyp != '\\') |
goto do_not_strip_quotes; |
/* Fall through. */ |
default: |
if (yyres) |
yyres[yyn] = *yyp; |
yyn++; |
break; |
case '"': |
if (yyres) |
yyres[yyn] = '\0'; |
return yyn; |
} |
do_not_strip_quotes: ; |
} |
if (! yyres) |
return yystrlen (yystr); |
return yystpcpy (yyres, yystr) - yyres; |
} |
# endif |
/* Copy into YYRESULT an error message about the unexpected token |
YYCHAR while in state YYSTATE. Return the number of bytes copied, |
including the terminating null byte. If YYRESULT is null, do not |
copy anything; just return the number of bytes that would be |
copied. As a special case, return 0 if an ordinary "syntax error" |
message will do. Return YYSIZE_MAXIMUM if overflow occurs during |
size calculation. */ |
static YYSIZE_T |
yysyntax_error (char *yyresult, int yystate, int yychar) |
{ |
int yyn = yypact[yystate]; |
if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) |
return 0; |
else |
{ |
int yytype = YYTRANSLATE (yychar); |
YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); |
YYSIZE_T yysize = yysize0; |
YYSIZE_T yysize1; |
int yysize_overflow = 0; |
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; |
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; |
int yyx; |
# if 0 |
/* This is so xgettext sees the translatable formats that are |
constructed on the fly. */ |
YY_("syntax error, unexpected %s"); |
YY_("syntax error, unexpected %s, expecting %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s or %s"); |
YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); |
# endif |
char *yyfmt; |
char const *yyf; |
static char const yyunexpected[] = "syntax error, unexpected %s"; |
static char const yyexpecting[] = ", expecting %s"; |
static char const yyor[] = " or %s"; |
char yyformat[sizeof yyunexpected |
+ sizeof yyexpecting - 1 |
+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) |
* (sizeof yyor - 1))]; |
char const *yyprefix = yyexpecting; |
/* Start YYX at -YYN if negative to avoid negative indexes in |
YYCHECK. */ |
int yyxbegin = yyn < 0 ? -yyn : 0; |
/* Stay within bounds of both yycheck and yytname. */ |
int yychecklim = YYLAST - yyn + 1; |
int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; |
int yycount = 1; |
yyarg[0] = yytname[yytype]; |
yyfmt = yystpcpy (yyformat, yyunexpected); |
for (yyx = yyxbegin; yyx < yyxend; ++yyx) |
if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) |
{ |
if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) |
{ |
yycount = 1; |
yysize = yysize0; |
yyformat[sizeof yyunexpected - 1] = '\0'; |
break; |
} |
yyarg[yycount++] = yytname[yyx]; |
yysize1 = yysize + yytnamerr (0, yytname[yyx]); |
yysize_overflow |= (yysize1 < yysize); |
yysize = yysize1; |
yyfmt = yystpcpy (yyfmt, yyprefix); |
yyprefix = yyor; |
} |
yyf = YY_(yyformat); |
yysize1 = yysize + yystrlen (yyf); |
yysize_overflow |= (yysize1 < yysize); |
yysize = yysize1; |
if (yysize_overflow) |
return YYSIZE_MAXIMUM; |
if (yyresult) |
{ |
/* Avoid sprintf, as that infringes on the user's name space. |
Don't have undefined behavior even if the translation |
produced a string with the wrong number of "%s"s. */ |
char *yyp = yyresult; |
int yyi = 0; |
while ((*yyp = *yyf) != '\0') |
{ |
if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) |
{ |
yyp += yytnamerr (yyp, yyarg[yyi++]); |
yyf += 2; |
} |
else |
{ |
yyp++; |
yyf++; |
} |
} |
} |
return yysize; |
} |
} |
#endif /* YYERROR_VERBOSE */ |
/*-----------------------------------------------. |
| Release the memory associated to this symbol. | |
`-----------------------------------------------*/ |
/*ARGSUSED*/ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
static void |
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) |
#else |
static void |
yydestruct (yymsg, yytype, yyvaluep) |
const char *yymsg; |
int yytype; |
YYSTYPE *yyvaluep; |
#endif |
{ |
YYUSE (yyvaluep); |
if (!yymsg) |
yymsg = "Deleting"; |
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); |
switch (yytype) |
{ |
default: |
break; |
} |
} |
/* Prevent warnings from -Wmissing-prototypes. */ |
#ifdef YYPARSE_PARAM |
#if defined __STDC__ || defined __cplusplus |
int yyparse (void *YYPARSE_PARAM); |
#else |
int yyparse (); |
#endif |
#else /* ! YYPARSE_PARAM */ |
#if defined __STDC__ || defined __cplusplus |
int yyparse (void); |
#else |
int yyparse (); |
#endif |
#endif /* ! YYPARSE_PARAM */ |
/* The look-ahead symbol. */ |
int yychar; |
/* The semantic value of the look-ahead symbol. */ |
YYSTYPE yylval; |
/* Number of syntax errors so far. */ |
int yynerrs; |
/*----------. |
| yyparse. | |
`----------*/ |
#ifdef YYPARSE_PARAM |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
int |
yyparse (void *YYPARSE_PARAM) |
#else |
int |
yyparse (YYPARSE_PARAM) |
void *YYPARSE_PARAM; |
#endif |
#else /* ! YYPARSE_PARAM */ |
#if (defined __STDC__ || defined __C99__FUNC__ \ |
|| defined __cplusplus || defined _MSC_VER) |
int |
yyparse (void) |
#else |
int |
yyparse () |
#endif |
#endif |
{ |
int yystate; |
int yyn; |
int yyresult; |
/* Number of tokens to shift before error messages enabled. */ |
int yyerrstatus; |
/* Look-ahead token as an internal (translated) token number. */ |
int yytoken = 0; |
#if YYERROR_VERBOSE |
/* Buffer for error messages, and its allocated size. */ |
char yymsgbuf[128]; |
char *yymsg = yymsgbuf; |
YYSIZE_T yymsg_alloc = sizeof yymsgbuf; |
#endif |
/* Three stacks and their tools: |
`yyss': related to states, |
`yyvs': related to semantic values, |
`yyls': related to locations. |
Refer to the stacks thru separate pointers, to allow yyoverflow |
to reallocate them elsewhere. */ |
/* The state stack. */ |
yytype_int16 yyssa[YYINITDEPTH]; |
yytype_int16 *yyss = yyssa; |
yytype_int16 *yyssp; |
/* The semantic value stack. */ |
YYSTYPE yyvsa[YYINITDEPTH]; |
YYSTYPE *yyvs = yyvsa; |
YYSTYPE *yyvsp; |
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) |
YYSIZE_T yystacksize = YYINITDEPTH; |
/* The variables used to return semantic value and location from the |
action routines. */ |
YYSTYPE yyval; |
/* The number of symbols on the RHS of the reduced rule. |
Keep to zero when no symbol should be popped. */ |
int yylen = 0; |
YYDPRINTF ((stderr, "Starting parse\n")); |
yystate = 0; |
yyerrstatus = 0; |
yynerrs = 0; |
yychar = YYEMPTY; /* Cause a token to be read. */ |
/* Initialize stack pointers. |
Waste one element of value and location stack |
so that they stay on the same level as the state stack. |
The wasted elements are never initialized. */ |
yyssp = yyss; |
yyvsp = yyvs; |
goto yysetstate; |
/*------------------------------------------------------------. |
| yynewstate -- Push a new state, which is found in yystate. | |
`------------------------------------------------------------*/ |
yynewstate: |
/* In all cases, when you get here, the value and location stacks |
have just been pushed. So pushing a state here evens the stacks. */ |
yyssp++; |
yysetstate: |
*yyssp = yystate; |
if (yyss + yystacksize - 1 <= yyssp) |
{ |
/* Get the current used size of the three stacks, in elements. */ |
YYSIZE_T yysize = yyssp - yyss + 1; |
#ifdef yyoverflow |
{ |
/* Give user a chance to reallocate the stack. Use copies of |
these so that the &'s don't force the real ones into |
memory. */ |
YYSTYPE *yyvs1 = yyvs; |
yytype_int16 *yyss1 = yyss; |
/* Each stack pointer address is followed by the size of the |
data in use in that stack, in bytes. This used to be a |
conditional around just the two extra args, but that might |
be undefined if yyoverflow is a macro. */ |
yyoverflow (YY_("memory exhausted"), |
&yyss1, yysize * sizeof (*yyssp), |
&yyvs1, yysize * sizeof (*yyvsp), |
&yystacksize); |
yyss = yyss1; |
yyvs = yyvs1; |
} |
#else /* no yyoverflow */ |
# ifndef YYSTACK_RELOCATE |
goto yyexhaustedlab; |
# else |
/* Extend the stack our own way. */ |
if (YYMAXDEPTH <= yystacksize) |
goto yyexhaustedlab; |
yystacksize *= 2; |
if (YYMAXDEPTH < yystacksize) |
yystacksize = YYMAXDEPTH; |
{ |
yytype_int16 *yyss1 = yyss; |
union yyalloc *yyptr = |
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); |
if (! yyptr) |
goto yyexhaustedlab; |
YYSTACK_RELOCATE (yyss); |
YYSTACK_RELOCATE (yyvs); |
# undef YYSTACK_RELOCATE |
if (yyss1 != yyssa) |
YYSTACK_FREE (yyss1); |
} |
# endif |
#endif /* no yyoverflow */ |
yyssp = yyss + yysize - 1; |
yyvsp = yyvs + yysize - 1; |
YYDPRINTF ((stderr, "Stack size increased to %lu\n", |
(unsigned long int) yystacksize)); |
if (yyss + yystacksize - 1 <= yyssp) |
YYABORT; |
} |
YYDPRINTF ((stderr, "Entering state %d\n", yystate)); |
goto yybackup; |
/*-----------. |
| yybackup. | |
`-----------*/ |
yybackup: |
/* Do appropriate processing given the current state. Read a |
look-ahead token if we need one and don't already have one. */ |
/* First try to decide what to do without reference to look-ahead token. */ |
yyn = yypact[yystate]; |
if (yyn == YYPACT_NINF) |
goto yydefault; |
/* Not known => get a look-ahead token if don't already have one. */ |
/* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ |
if (yychar == YYEMPTY) |
{ |
YYDPRINTF ((stderr, "Reading a token: ")); |
yychar = YYLEX; |
} |
if (yychar <= YYEOF) |
{ |
yychar = yytoken = YYEOF; |
YYDPRINTF ((stderr, "Now at end of input.\n")); |
} |
else |
{ |
yytoken = YYTRANSLATE (yychar); |
YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); |
} |
/* If the proper action on seeing token YYTOKEN is to reduce or to |
detect an error, take that action. */ |
yyn += yytoken; |
if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) |
goto yydefault; |
yyn = yytable[yyn]; |
if (yyn <= 0) |
{ |
if (yyn == 0 || yyn == YYTABLE_NINF) |
goto yyerrlab; |
yyn = -yyn; |
goto yyreduce; |
} |
if (yyn == YYFINAL) |
YYACCEPT; |
/* Count tokens shifted since error; after three, turn off error |
status. */ |
if (yyerrstatus) |
yyerrstatus--; |
/* Shift the look-ahead token. */ |
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); |
/* Discard the shifted token unless it is eof. */ |
if (yychar != YYEOF) |
yychar = YYEMPTY; |
yystate = yyn; |
*++yyvsp = yylval; |
goto yynewstate; |
/*-----------------------------------------------------------. |
| yydefault -- do the default action for the current state. | |
`-----------------------------------------------------------*/ |
yydefault: |
yyn = yydefact[yystate]; |
if (yyn == 0) |
goto yyerrlab; |
goto yyreduce; |
/*-----------------------------. |
| yyreduce -- Do a reduction. | |
`-----------------------------*/ |
yyreduce: |
/* yyn is the number of a rule to reduce with. */ |
yylen = yyr2[yyn]; |
/* If YYLEN is nonzero, implement the default value of the action: |
`$$ = $1'. |
Otherwise, the following line sets YYVAL to garbage. |
This behavior is undocumented and Bison |
users should not rely upon it. Assigning to YYVAL |
unconditionally makes the parser a bit smaller, and it avoids a |
GCC warning that YYVAL may be used uninitialized. */ |
yyval = yyvsp[1-yylen]; |
YY_REDUCE_PRINT (yyn); |
switch (yyn) |
{ |
case 8: |
#line 178 "ldgram.y" |
{ ldlex_defsym(); } |
break; |
case 9: |
#line 180 "ldgram.y" |
{ |
ldlex_popstate(); |
lang_add_assignment (exp_defsym ((yyvsp[(2) - (4)].name), (yyvsp[(4) - (4)].etree))); |
} |
break; |
case 10: |
#line 188 "ldgram.y" |
{ |
ldlex_mri_script (); |
PUSH_ERROR (_("MRI style script")); |
} |
break; |
case 11: |
#line 193 "ldgram.y" |
{ |
ldlex_popstate (); |
mri_draw_tree (); |
POP_ERROR (); |
} |
break; |
case 16: |
#line 208 "ldgram.y" |
{ |
einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),(yyvsp[(1) - (1)].name)); |
} |
break; |
case 17: |
#line 211 "ldgram.y" |
{ |
config.map_filename = "-"; |
} |
break; |
case 20: |
#line 217 "ldgram.y" |
{ mri_public((yyvsp[(2) - (4)].name), (yyvsp[(4) - (4)].etree)); } |
break; |
case 21: |
#line 219 "ldgram.y" |
{ mri_public((yyvsp[(2) - (4)].name), (yyvsp[(4) - (4)].etree)); } |
break; |
case 22: |
#line 221 "ldgram.y" |
{ mri_public((yyvsp[(2) - (3)].name), (yyvsp[(3) - (3)].etree)); } |
break; |
case 23: |
#line 223 "ldgram.y" |
{ mri_format((yyvsp[(2) - (2)].name)); } |
break; |
case 24: |
#line 225 "ldgram.y" |
{ mri_output_section((yyvsp[(2) - (4)].name), (yyvsp[(4) - (4)].etree));} |
break; |
case 25: |
#line 227 "ldgram.y" |
{ mri_output_section((yyvsp[(2) - (3)].name), (yyvsp[(3) - (3)].etree));} |
break; |
case 26: |
#line 229 "ldgram.y" |
{ mri_output_section((yyvsp[(2) - (4)].name), (yyvsp[(4) - (4)].etree));} |
break; |
case 27: |
#line 231 "ldgram.y" |
{ mri_align((yyvsp[(2) - (4)].name),(yyvsp[(4) - (4)].etree)); } |
break; |
case 28: |
#line 233 "ldgram.y" |
{ mri_align((yyvsp[(2) - (4)].name),(yyvsp[(4) - (4)].etree)); } |
break; |
case 29: |
#line 235 "ldgram.y" |
{ mri_alignmod((yyvsp[(2) - (4)].name),(yyvsp[(4) - (4)].etree)); } |
break; |
case 30: |
#line 237 "ldgram.y" |
{ mri_alignmod((yyvsp[(2) - (4)].name),(yyvsp[(4) - (4)].etree)); } |
break; |
case 33: |
#line 241 "ldgram.y" |
{ mri_name((yyvsp[(2) - (2)].name)); } |
break; |
case 34: |
#line 243 "ldgram.y" |
{ mri_alias((yyvsp[(2) - (4)].name),(yyvsp[(4) - (4)].name),0);} |
break; |
case 35: |
#line 245 "ldgram.y" |
{ mri_alias ((yyvsp[(2) - (4)].name), 0, (int) (yyvsp[(4) - (4)].bigint).integer); } |
break; |
case 36: |
#line 247 "ldgram.y" |
{ mri_base((yyvsp[(2) - (2)].etree)); } |
break; |
case 37: |
#line 249 "ldgram.y" |
{ mri_truncate ((unsigned int) (yyvsp[(2) - (2)].bigint).integer); } |
break; |
case 40: |
#line 253 "ldgram.y" |
{ ldlex_script (); ldfile_open_command_file((yyvsp[(2) - (2)].name)); } |
break; |
case 41: |
#line 255 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 42: |
#line 257 "ldgram.y" |
{ lang_add_entry ((yyvsp[(2) - (2)].name), FALSE); } |
break; |
case 44: |
#line 262 "ldgram.y" |
{ mri_order((yyvsp[(3) - (3)].name)); } |
break; |
case 45: |
#line 263 "ldgram.y" |
{ mri_order((yyvsp[(2) - (2)].name)); } |
break; |
case 47: |
#line 269 "ldgram.y" |
{ mri_load((yyvsp[(1) - (1)].name)); } |
break; |
case 48: |
#line 270 "ldgram.y" |
{ mri_load((yyvsp[(3) - (3)].name)); } |
break; |
case 49: |
#line 275 "ldgram.y" |
{ mri_only_load((yyvsp[(1) - (1)].name)); } |
break; |
case 50: |
#line 277 "ldgram.y" |
{ mri_only_load((yyvsp[(3) - (3)].name)); } |
break; |
case 51: |
#line 281 "ldgram.y" |
{ (yyval.name) = NULL; } |
break; |
case 54: |
#line 288 "ldgram.y" |
{ ldlex_expression (); } |
break; |
case 55: |
#line 290 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 56: |
#line 294 "ldgram.y" |
{ ldlang_add_undef ((yyvsp[(1) - (1)].name), FALSE); } |
break; |
case 57: |
#line 296 "ldgram.y" |
{ ldlang_add_undef ((yyvsp[(2) - (2)].name), FALSE); } |
break; |
case 58: |
#line 298 "ldgram.y" |
{ ldlang_add_undef ((yyvsp[(3) - (3)].name), FALSE); } |
break; |
case 59: |
#line 302 "ldgram.y" |
{ ldlex_both(); } |
break; |
case 60: |
#line 304 "ldgram.y" |
{ ldlex_popstate(); } |
break; |
case 73: |
#line 325 "ldgram.y" |
{ lang_add_target((yyvsp[(3) - (4)].name)); } |
break; |
case 74: |
#line 327 "ldgram.y" |
{ ldfile_add_library_path ((yyvsp[(3) - (4)].name), FALSE); } |
break; |
case 75: |
#line 329 "ldgram.y" |
{ lang_add_output((yyvsp[(3) - (4)].name), 1); } |
break; |
case 76: |
#line 331 "ldgram.y" |
{ lang_add_output_format ((yyvsp[(3) - (4)].name), (char *) NULL, |
(char *) NULL, 1); } |
break; |
case 77: |
#line 334 "ldgram.y" |
{ lang_add_output_format ((yyvsp[(3) - (8)].name), (yyvsp[(5) - (8)].name), (yyvsp[(7) - (8)].name), 1); } |
break; |
case 78: |
#line 336 "ldgram.y" |
{ ldfile_set_output_arch ((yyvsp[(3) - (4)].name), bfd_arch_unknown); } |
break; |
case 79: |
#line 338 "ldgram.y" |
{ command_line.force_common_definition = TRUE ; } |
break; |
case 80: |
#line 340 "ldgram.y" |
{ command_line.inhibit_common_definition = TRUE ; } |
break; |
case 82: |
#line 343 "ldgram.y" |
{ lang_enter_group (); } |
break; |
case 83: |
#line 345 "ldgram.y" |
{ lang_leave_group (); } |
break; |
case 84: |
#line 347 "ldgram.y" |
{ lang_add_map((yyvsp[(3) - (4)].name)); } |
break; |
case 85: |
#line 349 "ldgram.y" |
{ ldlex_script (); ldfile_open_command_file((yyvsp[(2) - (2)].name)); } |
break; |
case 86: |
#line 351 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 87: |
#line 353 "ldgram.y" |
{ |
lang_add_nocrossref ((yyvsp[(3) - (4)].nocrossref)); |
} |
break; |
case 89: |
#line 358 "ldgram.y" |
{ lang_add_insert ((yyvsp[(3) - (3)].name), 0); } |
break; |
case 90: |
#line 360 "ldgram.y" |
{ lang_add_insert ((yyvsp[(3) - (3)].name), 1); } |
break; |
case 91: |
#line 362 "ldgram.y" |
{ lang_memory_region_alias ((yyvsp[(3) - (6)].name), (yyvsp[(5) - (6)].name)); } |
break; |
case 92: |
#line 364 "ldgram.y" |
{ lang_ld_feature ((yyvsp[(3) - (4)].name)); } |
break; |
case 93: |
#line 369 "ldgram.y" |
{ lang_add_input_file((yyvsp[(1) - (1)].name),lang_input_file_is_search_file_enum, |
(char *)NULL); } |
break; |
case 94: |
#line 372 "ldgram.y" |
{ lang_add_input_file((yyvsp[(3) - (3)].name),lang_input_file_is_search_file_enum, |
(char *)NULL); } |
break; |
case 95: |
#line 375 "ldgram.y" |
{ lang_add_input_file((yyvsp[(2) - (2)].name),lang_input_file_is_search_file_enum, |
(char *)NULL); } |
break; |
case 96: |
#line 378 "ldgram.y" |
{ lang_add_input_file((yyvsp[(1) - (1)].name),lang_input_file_is_l_enum, |
(char *)NULL); } |
break; |
case 97: |
#line 381 "ldgram.y" |
{ lang_add_input_file((yyvsp[(3) - (3)].name),lang_input_file_is_l_enum, |
(char *)NULL); } |
break; |
case 98: |
#line 384 "ldgram.y" |
{ lang_add_input_file((yyvsp[(2) - (2)].name),lang_input_file_is_l_enum, |
(char *)NULL); } |
break; |
case 99: |
#line 387 "ldgram.y" |
{ (yyval.integer) = input_flags.add_DT_NEEDED_for_regular; |
input_flags.add_DT_NEEDED_for_regular = TRUE; } |
break; |
case 100: |
#line 390 "ldgram.y" |
{ input_flags.add_DT_NEEDED_for_regular = (yyvsp[(3) - (5)].integer); } |
break; |
case 101: |
#line 392 "ldgram.y" |
{ (yyval.integer) = input_flags.add_DT_NEEDED_for_regular; |
input_flags.add_DT_NEEDED_for_regular = TRUE; } |
break; |
case 102: |
#line 395 "ldgram.y" |
{ input_flags.add_DT_NEEDED_for_regular = (yyvsp[(5) - (7)].integer); } |
break; |
case 103: |
#line 397 "ldgram.y" |
{ (yyval.integer) = input_flags.add_DT_NEEDED_for_regular; |
input_flags.add_DT_NEEDED_for_regular = TRUE; } |
break; |
case 104: |
#line 400 "ldgram.y" |
{ input_flags.add_DT_NEEDED_for_regular = (yyvsp[(4) - (6)].integer); } |
break; |
case 109: |
#line 415 "ldgram.y" |
{ lang_add_entry ((yyvsp[(3) - (4)].name), FALSE); } |
break; |
case 111: |
#line 417 "ldgram.y" |
{ldlex_expression ();} |
break; |
case 112: |
#line 418 "ldgram.y" |
{ ldlex_popstate (); |
lang_add_assignment (exp_assert ((yyvsp[(4) - (7)].etree), (yyvsp[(6) - (7)].name))); } |
break; |
case 113: |
#line 426 "ldgram.y" |
{ |
(yyval.cname) = (yyvsp[(1) - (1)].name); |
} |
break; |
case 114: |
#line 430 "ldgram.y" |
{ |
(yyval.cname) = "*"; |
} |
break; |
case 115: |
#line 434 "ldgram.y" |
{ |
(yyval.cname) = "?"; |
} |
break; |
case 116: |
#line 441 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(1) - (1)].cname); |
(yyval.wildcard).sorted = none; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 117: |
#line 448 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(5) - (5)].cname); |
(yyval.wildcard).sorted = none; |
(yyval.wildcard).exclude_name_list = (yyvsp[(3) - (5)].name_list); |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 118: |
#line 455 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(3) - (4)].cname); |
(yyval.wildcard).sorted = by_name; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 119: |
#line 462 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(3) - (4)].cname); |
(yyval.wildcard).sorted = by_alignment; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 120: |
#line 469 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(3) - (4)].cname); |
(yyval.wildcard).sorted = by_none; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 121: |
#line 476 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(5) - (7)].cname); |
(yyval.wildcard).sorted = by_name_alignment; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 122: |
#line 483 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(5) - (7)].cname); |
(yyval.wildcard).sorted = by_name; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 123: |
#line 490 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(5) - (7)].cname); |
(yyval.wildcard).sorted = by_alignment_name; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 124: |
#line 497 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(5) - (7)].cname); |
(yyval.wildcard).sorted = by_alignment; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 125: |
#line 504 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(7) - (8)].cname); |
(yyval.wildcard).sorted = by_name; |
(yyval.wildcard).exclude_name_list = (yyvsp[(5) - (8)].name_list); |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 126: |
#line 511 "ldgram.y" |
{ |
(yyval.wildcard).name = (yyvsp[(3) - (4)].cname); |
(yyval.wildcard).sorted = by_init_priority; |
(yyval.wildcard).exclude_name_list = NULL; |
(yyval.wildcard).section_flag_list = NULL; |
} |
break; |
case 127: |
#line 520 "ldgram.y" |
{ |
struct flag_info_list *n; |
n = ((struct flag_info_list *) xmalloc (sizeof *n)); |
if ((yyvsp[(1) - (1)].name)[0] == '!') |
{ |
n->with = without_flags; |
n->name = &(yyvsp[(1) - (1)].name)[1]; |
} |
else |
{ |
n->with = with_flags; |
n->name = (yyvsp[(1) - (1)].name); |
} |
n->valid = FALSE; |
n->next = NULL; |
(yyval.flag_info_list) = n; |
} |
break; |
case 128: |
#line 538 "ldgram.y" |
{ |
struct flag_info_list *n; |
n = ((struct flag_info_list *) xmalloc (sizeof *n)); |
if ((yyvsp[(3) - (3)].name)[0] == '!') |
{ |
n->with = without_flags; |
n->name = &(yyvsp[(3) - (3)].name)[1]; |
} |
else |
{ |
n->with = with_flags; |
n->name = (yyvsp[(3) - (3)].name); |
} |
n->valid = FALSE; |
n->next = (yyvsp[(1) - (3)].flag_info_list); |
(yyval.flag_info_list) = n; |
} |
break; |
case 129: |
#line 559 "ldgram.y" |
{ |
struct flag_info *n; |
n = ((struct flag_info *) xmalloc (sizeof *n)); |
n->flag_list = (yyvsp[(3) - (4)].flag_info_list); |
n->flags_initialized = FALSE; |
n->not_with_flags = 0; |
n->only_with_flags = 0; |
(yyval.flag_info) = n; |
} |
break; |
case 130: |
#line 572 "ldgram.y" |
{ |
struct name_list *tmp; |
tmp = (struct name_list *) xmalloc (sizeof *tmp); |
tmp->name = (yyvsp[(2) - (2)].cname); |
tmp->next = (yyvsp[(1) - (2)].name_list); |
(yyval.name_list) = tmp; |
} |
break; |
case 131: |
#line 581 "ldgram.y" |
{ |
struct name_list *tmp; |
tmp = (struct name_list *) xmalloc (sizeof *tmp); |
tmp->name = (yyvsp[(1) - (1)].cname); |
tmp->next = NULL; |
(yyval.name_list) = tmp; |
} |
break; |
case 132: |
#line 592 "ldgram.y" |
{ |
struct wildcard_list *tmp; |
tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); |
tmp->next = (yyvsp[(1) - (3)].wildcard_list); |
tmp->spec = (yyvsp[(3) - (3)].wildcard); |
(yyval.wildcard_list) = tmp; |
} |
break; |
case 133: |
#line 601 "ldgram.y" |
{ |
struct wildcard_list *tmp; |
tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); |
tmp->next = NULL; |
tmp->spec = (yyvsp[(1) - (1)].wildcard); |
(yyval.wildcard_list) = tmp; |
} |
break; |
case 134: |
#line 612 "ldgram.y" |
{ |
struct wildcard_spec tmp; |
tmp.name = (yyvsp[(1) - (1)].name); |
tmp.exclude_name_list = NULL; |
tmp.sorted = none; |
tmp.section_flag_list = NULL; |
lang_add_wild (&tmp, NULL, ldgram_had_keep); |
} |
break; |
case 135: |
#line 621 "ldgram.y" |
{ |
struct wildcard_spec tmp; |
tmp.name = (yyvsp[(2) - (2)].name); |
tmp.exclude_name_list = NULL; |
tmp.sorted = none; |
tmp.section_flag_list = (yyvsp[(1) - (2)].flag_info); |
lang_add_wild (&tmp, NULL, ldgram_had_keep); |
} |
break; |
case 136: |
#line 630 "ldgram.y" |
{ |
lang_add_wild (NULL, (yyvsp[(2) - (3)].wildcard_list), ldgram_had_keep); |
} |
break; |
case 137: |
#line 634 "ldgram.y" |
{ |
struct wildcard_spec tmp; |
tmp.name = NULL; |
tmp.exclude_name_list = NULL; |
tmp.sorted = none; |
tmp.section_flag_list = (yyvsp[(1) - (4)].flag_info); |
lang_add_wild (&tmp, (yyvsp[(3) - (4)].wildcard_list), ldgram_had_keep); |
} |
break; |
case 138: |
#line 643 "ldgram.y" |
{ |
lang_add_wild (&(yyvsp[(1) - (4)].wildcard), (yyvsp[(3) - (4)].wildcard_list), ldgram_had_keep); |
} |
break; |
case 139: |
#line 647 "ldgram.y" |
{ |
(yyvsp[(2) - (5)].wildcard).section_flag_list = (yyvsp[(1) - (5)].flag_info); |
lang_add_wild (&(yyvsp[(2) - (5)].wildcard), (yyvsp[(4) - (5)].wildcard_list), ldgram_had_keep); |
} |
break; |
case 141: |
#line 656 "ldgram.y" |
{ ldgram_had_keep = TRUE; } |
break; |
case 142: |
#line 658 "ldgram.y" |
{ ldgram_had_keep = FALSE; } |
break; |
case 144: |
#line 664 "ldgram.y" |
{ |
lang_add_attribute(lang_object_symbols_statement_enum); |
} |
break; |
case 146: |
#line 669 "ldgram.y" |
{ |
lang_add_attribute(lang_constructors_statement_enum); |
} |
break; |
case 147: |
#line 674 "ldgram.y" |
{ |
constructors_sorted = TRUE; |
lang_add_attribute (lang_constructors_statement_enum); |
} |
break; |
case 149: |
#line 680 "ldgram.y" |
{ |
lang_add_data ((int) (yyvsp[(1) - (4)].integer), (yyvsp[(3) - (4)].etree)); |
} |
break; |
case 150: |
#line 685 "ldgram.y" |
{ |
lang_add_fill ((yyvsp[(3) - (4)].fill)); |
} |
break; |
case 151: |
#line 688 "ldgram.y" |
{ldlex_expression ();} |
break; |
case 152: |
#line 689 "ldgram.y" |
{ ldlex_popstate (); |
lang_add_assignment (exp_assert ((yyvsp[(4) - (8)].etree), (yyvsp[(6) - (8)].name))); } |
break; |
case 153: |
#line 692 "ldgram.y" |
{ ldlex_script (); ldfile_open_command_file((yyvsp[(2) - (2)].name)); } |
break; |
case 154: |
#line 694 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 159: |
#line 709 "ldgram.y" |
{ (yyval.integer) = (yyvsp[(1) - (1)].token); } |
break; |
case 160: |
#line 711 "ldgram.y" |
{ (yyval.integer) = (yyvsp[(1) - (1)].token); } |
break; |
case 161: |
#line 713 "ldgram.y" |
{ (yyval.integer) = (yyvsp[(1) - (1)].token); } |
break; |
case 162: |
#line 715 "ldgram.y" |
{ (yyval.integer) = (yyvsp[(1) - (1)].token); } |
break; |
case 163: |
#line 717 "ldgram.y" |
{ (yyval.integer) = (yyvsp[(1) - (1)].token); } |
break; |
case 164: |
#line 722 "ldgram.y" |
{ |
(yyval.fill) = exp_get_fill ((yyvsp[(1) - (1)].etree), 0, "fill value"); |
} |
break; |
case 165: |
#line 729 "ldgram.y" |
{ (yyval.fill) = (yyvsp[(2) - (2)].fill); } |
break; |
case 166: |
#line 730 "ldgram.y" |
{ (yyval.fill) = (fill_type *) 0; } |
break; |
case 167: |
#line 735 "ldgram.y" |
{ (yyval.token) = '+'; } |
break; |
case 168: |
#line 737 "ldgram.y" |
{ (yyval.token) = '-'; } |
break; |
case 169: |
#line 739 "ldgram.y" |
{ (yyval.token) = '*'; } |
break; |
case 170: |
#line 741 "ldgram.y" |
{ (yyval.token) = '/'; } |
break; |
case 171: |
#line 743 "ldgram.y" |
{ (yyval.token) = LSHIFT; } |
break; |
case 172: |
#line 745 "ldgram.y" |
{ (yyval.token) = RSHIFT; } |
break; |
case 173: |
#line 747 "ldgram.y" |
{ (yyval.token) = '&'; } |
break; |
case 174: |
#line 749 "ldgram.y" |
{ (yyval.token) = '|'; } |
break; |
case 177: |
#line 759 "ldgram.y" |
{ |
lang_add_assignment (exp_assign ((yyvsp[(1) - (3)].name), (yyvsp[(3) - (3)].etree), FALSE)); |
} |
break; |
case 178: |
#line 763 "ldgram.y" |
{ |
lang_add_assignment (exp_assign ((yyvsp[(1) - (3)].name), |
exp_binop ((yyvsp[(2) - (3)].token), |
exp_nameop (NAME, |
(yyvsp[(1) - (3)].name)), |
(yyvsp[(3) - (3)].etree)), FALSE)); |
} |
break; |
case 179: |
#line 771 "ldgram.y" |
{ |
lang_add_assignment (exp_assign ((yyvsp[(3) - (6)].name), (yyvsp[(5) - (6)].etree), TRUE)); |
} |
break; |
case 180: |
#line 775 "ldgram.y" |
{ |
lang_add_assignment (exp_provide ((yyvsp[(3) - (6)].name), (yyvsp[(5) - (6)].etree), FALSE)); |
} |
break; |
case 181: |
#line 779 "ldgram.y" |
{ |
lang_add_assignment (exp_provide ((yyvsp[(3) - (6)].name), (yyvsp[(5) - (6)].etree), TRUE)); |
} |
break; |
case 189: |
#line 802 "ldgram.y" |
{ region = lang_memory_region_lookup ((yyvsp[(1) - (1)].name), TRUE); } |
break; |
case 190: |
#line 805 "ldgram.y" |
{} |
break; |
case 191: |
#line 807 "ldgram.y" |
{ ldlex_script (); ldfile_open_command_file((yyvsp[(2) - (2)].name)); } |
break; |
case 192: |
#line 809 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 193: |
#line 814 "ldgram.y" |
{ |
region->origin = exp_get_vma ((yyvsp[(3) - (3)].etree), 0, "origin"); |
region->current = region->origin; |
} |
break; |
case 194: |
#line 822 "ldgram.y" |
{ |
region->length = exp_get_vma ((yyvsp[(3) - (3)].etree), -1, "length"); |
} |
break; |
case 195: |
#line 829 "ldgram.y" |
{ /* dummy action to avoid bison 1.25 error message */ } |
break; |
case 199: |
#line 840 "ldgram.y" |
{ lang_set_flags (region, (yyvsp[(1) - (1)].name), 0); } |
break; |
case 200: |
#line 842 "ldgram.y" |
{ lang_set_flags (region, (yyvsp[(2) - (2)].name), 1); } |
break; |
case 201: |
#line 847 "ldgram.y" |
{ lang_startup((yyvsp[(3) - (4)].name)); } |
break; |
case 203: |
#line 853 "ldgram.y" |
{ ldemul_hll((char *)NULL); } |
break; |
case 204: |
#line 858 "ldgram.y" |
{ ldemul_hll((yyvsp[(3) - (3)].name)); } |
break; |
case 205: |
#line 860 "ldgram.y" |
{ ldemul_hll((yyvsp[(1) - (1)].name)); } |
break; |
case 207: |
#line 868 "ldgram.y" |
{ ldemul_syslib((yyvsp[(3) - (3)].name)); } |
break; |
case 209: |
#line 874 "ldgram.y" |
{ lang_float(TRUE); } |
break; |
case 210: |
#line 876 "ldgram.y" |
{ lang_float(FALSE); } |
break; |
case 211: |
#line 881 "ldgram.y" |
{ |
(yyval.nocrossref) = NULL; |
} |
break; |
case 212: |
#line 885 "ldgram.y" |
{ |
struct lang_nocrossref *n; |
n = (struct lang_nocrossref *) xmalloc (sizeof *n); |
n->name = (yyvsp[(1) - (2)].name); |
n->next = (yyvsp[(2) - (2)].nocrossref); |
(yyval.nocrossref) = n; |
} |
break; |
case 213: |
#line 894 "ldgram.y" |
{ |
struct lang_nocrossref *n; |
n = (struct lang_nocrossref *) xmalloc (sizeof *n); |
n->name = (yyvsp[(1) - (3)].name); |
n->next = (yyvsp[(3) - (3)].nocrossref); |
(yyval.nocrossref) = n; |
} |
break; |
case 214: |
#line 904 "ldgram.y" |
{ ldlex_expression (); } |
break; |
case 215: |
#line 906 "ldgram.y" |
{ ldlex_popstate (); (yyval.etree)=(yyvsp[(2) - (2)].etree);} |
break; |
case 216: |
#line 911 "ldgram.y" |
{ (yyval.etree) = exp_unop ('-', (yyvsp[(2) - (2)].etree)); } |
break; |
case 217: |
#line 913 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(2) - (3)].etree); } |
break; |
case 218: |
#line 915 "ldgram.y" |
{ (yyval.etree) = exp_unop ((int) (yyvsp[(1) - (4)].integer),(yyvsp[(3) - (4)].etree)); } |
break; |
case 219: |
#line 917 "ldgram.y" |
{ (yyval.etree) = exp_unop ('!', (yyvsp[(2) - (2)].etree)); } |
break; |
case 220: |
#line 919 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(2) - (2)].etree); } |
break; |
case 221: |
#line 921 "ldgram.y" |
{ (yyval.etree) = exp_unop ('~', (yyvsp[(2) - (2)].etree));} |
break; |
case 222: |
#line 924 "ldgram.y" |
{ (yyval.etree) = exp_binop ('*', (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 223: |
#line 926 "ldgram.y" |
{ (yyval.etree) = exp_binop ('/', (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 224: |
#line 928 "ldgram.y" |
{ (yyval.etree) = exp_binop ('%', (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 225: |
#line 930 "ldgram.y" |
{ (yyval.etree) = exp_binop ('+', (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 226: |
#line 932 "ldgram.y" |
{ (yyval.etree) = exp_binop ('-' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 227: |
#line 934 "ldgram.y" |
{ (yyval.etree) = exp_binop (LSHIFT , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 228: |
#line 936 "ldgram.y" |
{ (yyval.etree) = exp_binop (RSHIFT , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 229: |
#line 938 "ldgram.y" |
{ (yyval.etree) = exp_binop (EQ , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 230: |
#line 940 "ldgram.y" |
{ (yyval.etree) = exp_binop (NE , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 231: |
#line 942 "ldgram.y" |
{ (yyval.etree) = exp_binop (LE , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 232: |
#line 944 "ldgram.y" |
{ (yyval.etree) = exp_binop (GE , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 233: |
#line 946 "ldgram.y" |
{ (yyval.etree) = exp_binop ('<' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 234: |
#line 948 "ldgram.y" |
{ (yyval.etree) = exp_binop ('>' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 235: |
#line 950 "ldgram.y" |
{ (yyval.etree) = exp_binop ('&' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 236: |
#line 952 "ldgram.y" |
{ (yyval.etree) = exp_binop ('^' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 237: |
#line 954 "ldgram.y" |
{ (yyval.etree) = exp_binop ('|' , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 238: |
#line 956 "ldgram.y" |
{ (yyval.etree) = exp_trinop ('?' , (yyvsp[(1) - (5)].etree), (yyvsp[(3) - (5)].etree), (yyvsp[(5) - (5)].etree)); } |
break; |
case 239: |
#line 958 "ldgram.y" |
{ (yyval.etree) = exp_binop (ANDAND , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 240: |
#line 960 "ldgram.y" |
{ (yyval.etree) = exp_binop (OROR , (yyvsp[(1) - (3)].etree), (yyvsp[(3) - (3)].etree)); } |
break; |
case 241: |
#line 962 "ldgram.y" |
{ (yyval.etree) = exp_nameop (DEFINED, (yyvsp[(3) - (4)].name)); } |
break; |
case 242: |
#line 964 "ldgram.y" |
{ (yyval.etree) = exp_bigintop ((yyvsp[(1) - (1)].bigint).integer, (yyvsp[(1) - (1)].bigint).str); } |
break; |
case 243: |
#line 966 "ldgram.y" |
{ (yyval.etree) = exp_nameop (SIZEOF_HEADERS,0); } |
break; |
case 244: |
#line 969 "ldgram.y" |
{ (yyval.etree) = exp_nameop (ALIGNOF,(yyvsp[(3) - (4)].name)); } |
break; |
case 245: |
#line 971 "ldgram.y" |
{ (yyval.etree) = exp_nameop (SIZEOF,(yyvsp[(3) - (4)].name)); } |
break; |
case 246: |
#line 973 "ldgram.y" |
{ (yyval.etree) = exp_nameop (ADDR,(yyvsp[(3) - (4)].name)); } |
break; |
case 247: |
#line 975 "ldgram.y" |
{ (yyval.etree) = exp_nameop (LOADADDR,(yyvsp[(3) - (4)].name)); } |
break; |
case 248: |
#line 977 "ldgram.y" |
{ (yyval.etree) = exp_nameop (CONSTANT,(yyvsp[(3) - (4)].name)); } |
break; |
case 249: |
#line 979 "ldgram.y" |
{ (yyval.etree) = exp_unop (ABSOLUTE, (yyvsp[(3) - (4)].etree)); } |
break; |
case 250: |
#line 981 "ldgram.y" |
{ (yyval.etree) = exp_unop (ALIGN_K,(yyvsp[(3) - (4)].etree)); } |
break; |
case 251: |
#line 983 "ldgram.y" |
{ (yyval.etree) = exp_binop (ALIGN_K,(yyvsp[(3) - (6)].etree),(yyvsp[(5) - (6)].etree)); } |
break; |
case 252: |
#line 985 "ldgram.y" |
{ (yyval.etree) = exp_binop (DATA_SEGMENT_ALIGN, (yyvsp[(3) - (6)].etree), (yyvsp[(5) - (6)].etree)); } |
break; |
case 253: |
#line 987 "ldgram.y" |
{ (yyval.etree) = exp_binop (DATA_SEGMENT_RELRO_END, (yyvsp[(5) - (6)].etree), (yyvsp[(3) - (6)].etree)); } |
break; |
case 254: |
#line 989 "ldgram.y" |
{ (yyval.etree) = exp_unop (DATA_SEGMENT_END, (yyvsp[(3) - (4)].etree)); } |
break; |
case 255: |
#line 991 "ldgram.y" |
{ /* The operands to the expression node are |
placed in the opposite order from the way |
in which they appear in the script as |
that allows us to reuse more code in |
fold_binary. */ |
(yyval.etree) = exp_binop (SEGMENT_START, |
(yyvsp[(5) - (6)].etree), |
exp_nameop (NAME, (yyvsp[(3) - (6)].name))); } |
break; |
case 256: |
#line 1000 "ldgram.y" |
{ (yyval.etree) = exp_unop (ALIGN_K,(yyvsp[(3) - (4)].etree)); } |
break; |
case 257: |
#line 1002 "ldgram.y" |
{ (yyval.etree) = exp_nameop (NAME,(yyvsp[(1) - (1)].name)); } |
break; |
case 258: |
#line 1004 "ldgram.y" |
{ (yyval.etree) = exp_binop (MAX_K, (yyvsp[(3) - (6)].etree), (yyvsp[(5) - (6)].etree) ); } |
break; |
case 259: |
#line 1006 "ldgram.y" |
{ (yyval.etree) = exp_binop (MIN_K, (yyvsp[(3) - (6)].etree), (yyvsp[(5) - (6)].etree) ); } |
break; |
case 260: |
#line 1008 "ldgram.y" |
{ (yyval.etree) = exp_assert ((yyvsp[(3) - (6)].etree), (yyvsp[(5) - (6)].name)); } |
break; |
case 261: |
#line 1010 "ldgram.y" |
{ (yyval.etree) = exp_nameop (ORIGIN, (yyvsp[(3) - (4)].name)); } |
break; |
case 262: |
#line 1012 "ldgram.y" |
{ (yyval.etree) = exp_nameop (LENGTH, (yyvsp[(3) - (4)].name)); } |
break; |
case 263: |
#line 1014 "ldgram.y" |
{ (yyval.etree) = exp_unop (LOG2CEIL, (yyvsp[(3) - (4)].etree)); } |
break; |
case 264: |
#line 1019 "ldgram.y" |
{ (yyval.name) = (yyvsp[(3) - (3)].name); } |
break; |
case 265: |
#line 1020 "ldgram.y" |
{ (yyval.name) = 0; } |
break; |
case 266: |
#line 1024 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(3) - (4)].etree); } |
break; |
case 267: |
#line 1025 "ldgram.y" |
{ (yyval.etree) = 0; } |
break; |
case 268: |
#line 1029 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(3) - (4)].etree); } |
break; |
case 269: |
#line 1030 "ldgram.y" |
{ (yyval.etree) = 0; } |
break; |
case 270: |
#line 1034 "ldgram.y" |
{ (yyval.token) = ALIGN_WITH_INPUT; } |
break; |
case 271: |
#line 1035 "ldgram.y" |
{ (yyval.token) = 0; } |
break; |
case 272: |
#line 1039 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(3) - (4)].etree); } |
break; |
case 273: |
#line 1040 "ldgram.y" |
{ (yyval.etree) = 0; } |
break; |
case 274: |
#line 1044 "ldgram.y" |
{ (yyval.token) = ONLY_IF_RO; } |
break; |
case 275: |
#line 1045 "ldgram.y" |
{ (yyval.token) = ONLY_IF_RW; } |
break; |
case 276: |
#line 1046 "ldgram.y" |
{ (yyval.token) = SPECIAL; } |
break; |
case 277: |
#line 1047 "ldgram.y" |
{ (yyval.token) = 0; } |
break; |
case 278: |
#line 1050 "ldgram.y" |
{ ldlex_expression(); } |
break; |
case 279: |
#line 1055 "ldgram.y" |
{ ldlex_popstate (); ldlex_script (); } |
break; |
case 280: |
#line 1058 "ldgram.y" |
{ |
lang_enter_output_section_statement((yyvsp[(1) - (10)].name), (yyvsp[(3) - (10)].etree), |
sectype, |
(yyvsp[(5) - (10)].etree), (yyvsp[(7) - (10)].etree), (yyvsp[(4) - (10)].etree), (yyvsp[(9) - (10)].token), (yyvsp[(6) - (10)].token)); |
} |
break; |
case 281: |
#line 1064 "ldgram.y" |
{ ldlex_popstate (); ldlex_expression (); } |
break; |
case 282: |
#line 1066 "ldgram.y" |
{ |
ldlex_popstate (); |
lang_leave_output_section_statement ((yyvsp[(18) - (18)].fill), (yyvsp[(15) - (18)].name), (yyvsp[(17) - (18)].section_phdr), (yyvsp[(16) - (18)].name)); |
} |
break; |
case 283: |
#line 1071 "ldgram.y" |
{} |
break; |
case 284: |
#line 1073 "ldgram.y" |
{ ldlex_expression (); } |
break; |
case 285: |
#line 1075 "ldgram.y" |
{ ldlex_popstate (); ldlex_script (); } |
break; |
case 286: |
#line 1077 "ldgram.y" |
{ |
lang_enter_overlay ((yyvsp[(3) - (8)].etree), (yyvsp[(6) - (8)].etree)); |
} |
break; |
case 287: |
#line 1082 "ldgram.y" |
{ ldlex_popstate (); ldlex_expression (); } |
break; |
case 288: |
#line 1084 "ldgram.y" |
{ |
ldlex_popstate (); |
lang_leave_overlay ((yyvsp[(5) - (16)].etree), (int) (yyvsp[(4) - (16)].integer), |
(yyvsp[(16) - (16)].fill), (yyvsp[(13) - (16)].name), (yyvsp[(15) - (16)].section_phdr), (yyvsp[(14) - (16)].name)); |
} |
break; |
case 290: |
#line 1094 "ldgram.y" |
{ ldlex_expression (); } |
break; |
case 291: |
#line 1096 "ldgram.y" |
{ |
ldlex_popstate (); |
lang_add_assignment (exp_assign (".", (yyvsp[(3) - (3)].etree), FALSE)); |
} |
break; |
case 293: |
#line 1102 "ldgram.y" |
{ ldlex_script (); ldfile_open_command_file((yyvsp[(2) - (2)].name)); } |
break; |
case 294: |
#line 1104 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 295: |
#line 1108 "ldgram.y" |
{ sectype = noload_section; } |
break; |
case 296: |
#line 1109 "ldgram.y" |
{ sectype = noalloc_section; } |
break; |
case 297: |
#line 1110 "ldgram.y" |
{ sectype = noalloc_section; } |
break; |
case 298: |
#line 1111 "ldgram.y" |
{ sectype = noalloc_section; } |
break; |
case 299: |
#line 1112 "ldgram.y" |
{ sectype = noalloc_section; } |
break; |
case 301: |
#line 1117 "ldgram.y" |
{ sectype = normal_section; } |
break; |
case 302: |
#line 1118 "ldgram.y" |
{ sectype = normal_section; } |
break; |
case 303: |
#line 1122 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(1) - (3)].etree); } |
break; |
case 304: |
#line 1123 "ldgram.y" |
{ (yyval.etree) = (etree_type *)NULL; } |
break; |
case 305: |
#line 1128 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(3) - (6)].etree); } |
break; |
case 306: |
#line 1130 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(3) - (10)].etree); } |
break; |
case 307: |
#line 1134 "ldgram.y" |
{ (yyval.etree) = (yyvsp[(1) - (2)].etree); } |
break; |
case 308: |
#line 1135 "ldgram.y" |
{ (yyval.etree) = (etree_type *) NULL; } |
break; |
case 309: |
#line 1140 "ldgram.y" |
{ (yyval.integer) = 0; } |
break; |
case 310: |
#line 1142 "ldgram.y" |
{ (yyval.integer) = 1; } |
break; |
case 311: |
#line 1147 "ldgram.y" |
{ (yyval.name) = (yyvsp[(2) - (2)].name); } |
break; |
case 312: |
#line 1148 "ldgram.y" |
{ (yyval.name) = DEFAULT_MEMORY_REGION; } |
break; |
case 313: |
#line 1153 "ldgram.y" |
{ |
(yyval.section_phdr) = NULL; |
} |
break; |
case 314: |
#line 1157 "ldgram.y" |
{ |
struct lang_output_section_phdr_list *n; |
n = ((struct lang_output_section_phdr_list *) |
xmalloc (sizeof *n)); |
n->name = (yyvsp[(3) - (3)].name); |
n->used = FALSE; |
n->next = (yyvsp[(1) - (3)].section_phdr); |
(yyval.section_phdr) = n; |
} |
break; |
case 316: |
#line 1173 "ldgram.y" |
{ |
ldlex_script (); |
lang_enter_overlay_section ((yyvsp[(2) - (2)].name)); |
} |
break; |
case 317: |
#line 1178 "ldgram.y" |
{ ldlex_popstate (); ldlex_expression (); } |
break; |
case 318: |
#line 1180 "ldgram.y" |
{ |
ldlex_popstate (); |
lang_leave_overlay_section ((yyvsp[(9) - (9)].fill), (yyvsp[(8) - (9)].section_phdr)); |
} |
break; |
case 323: |
#line 1197 "ldgram.y" |
{ ldlex_expression (); } |
break; |
case 324: |
#line 1198 "ldgram.y" |
{ ldlex_popstate (); } |
break; |
case 325: |
#line 1200 "ldgram.y" |
{ |
lang_new_phdr ((yyvsp[(1) - (6)].name), (yyvsp[(3) - (6)].etree), (yyvsp[(4) - (6)].phdr).filehdr, (yyvsp[(4) - (6)].phdr).phdrs, (yyvsp[(4) - (6)].phdr).at, |
(yyvsp[(4) - (6)].phdr).flags); |
} |
break; |
case 326: |
#line 1208 "ldgram.y" |
{ |
(yyval.etree) = (yyvsp[(1) - (1)].etree); |
if ((yyvsp[(1) - (1)].etree)->type.node_class == etree_name |
&& (yyvsp[(1) - (1)].etree)->type.node_code == NAME) |
{ |
const char *s; |
unsigned int i; |
static const char * const phdr_types[] = |
{ |
"PT_NULL", "PT_LOAD", "PT_DYNAMIC", |
"PT_INTERP", "PT_NOTE", "PT_SHLIB", |
"PT_PHDR", "PT_TLS" |
}; |
s = (yyvsp[(1) - (1)].etree)->name.name; |
for (i = 0; |
i < sizeof phdr_types / sizeof phdr_types[0]; |
i++) |
if (strcmp (s, phdr_types[i]) == 0) |
{ |
(yyval.etree) = exp_intop (i); |
break; |
} |
if (i == sizeof phdr_types / sizeof phdr_types[0]) |
{ |
if (strcmp (s, "PT_GNU_EH_FRAME") == 0) |
(yyval.etree) = exp_intop (0x6474e550); |
else if (strcmp (s, "PT_GNU_STACK") == 0) |
(yyval.etree) = exp_intop (0x6474e551); |
else |
{ |
einfo (_("\ |
%X%P:%S: unknown phdr type `%s' (try integer literal)\n"), |
NULL, s); |
(yyval.etree) = exp_intop (0); |
} |
} |
} |
} |
break; |
case 327: |
#line 1252 "ldgram.y" |
{ |
memset (&(yyval.phdr), 0, sizeof (struct phdr_info)); |
} |
break; |
case 328: |
#line 1256 "ldgram.y" |
{ |
(yyval.phdr) = (yyvsp[(3) - (3)].phdr); |
if (strcmp ((yyvsp[(1) - (3)].name), "FILEHDR") == 0 && (yyvsp[(2) - (3)].etree) == NULL) |
(yyval.phdr).filehdr = TRUE; |
else if (strcmp ((yyvsp[(1) - (3)].name), "PHDRS") == 0 && (yyvsp[(2) - (3)].etree) == NULL) |
(yyval.phdr).phdrs = TRUE; |
else if (strcmp ((yyvsp[(1) - (3)].name), "FLAGS") == 0 && (yyvsp[(2) - (3)].etree) != NULL) |
(yyval.phdr).flags = (yyvsp[(2) - (3)].etree); |
else |
einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"), |
NULL, (yyvsp[(1) - (3)].name)); |
} |
break; |
case 329: |
#line 1269 "ldgram.y" |
{ |
(yyval.phdr) = (yyvsp[(5) - (5)].phdr); |
(yyval.phdr).at = (yyvsp[(3) - (5)].etree); |
} |
break; |
case 330: |
#line 1277 "ldgram.y" |
{ |
(yyval.etree) = NULL; |
} |
break; |
case 331: |
#line 1281 "ldgram.y" |
{ |
(yyval.etree) = (yyvsp[(2) - (3)].etree); |
} |
break; |
case 332: |
#line 1287 "ldgram.y" |
{ |
ldlex_version_file (); |
PUSH_ERROR (_("dynamic list")); |
} |
break; |
case 333: |
#line 1292 "ldgram.y" |
{ |
ldlex_popstate (); |
POP_ERROR (); |
} |
break; |
case 337: |
#line 1309 "ldgram.y" |
{ |
lang_append_dynamic_list ((yyvsp[(1) - (2)].versyms)); |
} |
break; |
case 338: |
#line 1317 "ldgram.y" |
{ |
ldlex_version_file (); |
PUSH_ERROR (_("VERSION script")); |
} |
break; |
case 339: |
#line 1322 "ldgram.y" |
{ |
ldlex_popstate (); |
POP_ERROR (); |
} |
break; |
case 340: |
#line 1331 "ldgram.y" |
{ |
ldlex_version_script (); |
} |
break; |
case 341: |
#line 1335 "ldgram.y" |
{ |
ldlex_popstate (); |
} |
break; |
case 344: |
#line 1347 "ldgram.y" |
{ |
lang_register_vers_node (NULL, (yyvsp[(2) - (4)].versnode), NULL); |
} |
break; |
case 345: |
#line 1351 "ldgram.y" |
{ |
lang_register_vers_node ((yyvsp[(1) - (5)].name), (yyvsp[(3) - (5)].versnode), NULL); |
} |
break; |
case 346: |
#line 1355 "ldgram.y" |
{ |
lang_register_vers_node ((yyvsp[(1) - (6)].name), (yyvsp[(3) - (6)].versnode), (yyvsp[(5) - (6)].deflist)); |
} |
break; |
case 347: |
#line 1362 "ldgram.y" |
{ |
(yyval.deflist) = lang_add_vers_depend (NULL, (yyvsp[(1) - (1)].name)); |
} |
break; |
case 348: |
#line 1366 "ldgram.y" |
{ |
(yyval.deflist) = lang_add_vers_depend ((yyvsp[(1) - (2)].deflist), (yyvsp[(2) - (2)].name)); |
} |
break; |
case 349: |
#line 1373 "ldgram.y" |
{ |
(yyval.versnode) = lang_new_vers_node (NULL, NULL); |
} |
break; |
case 350: |
#line 1377 "ldgram.y" |
{ |
(yyval.versnode) = lang_new_vers_node ((yyvsp[(1) - (2)].versyms), NULL); |
} |
break; |
case 351: |
#line 1381 "ldgram.y" |
{ |
(yyval.versnode) = lang_new_vers_node ((yyvsp[(3) - (4)].versyms), NULL); |
} |
break; |
case 352: |
#line 1385 "ldgram.y" |
{ |
(yyval.versnode) = lang_new_vers_node (NULL, (yyvsp[(3) - (4)].versyms)); |
} |
break; |
case 353: |
#line 1389 "ldgram.y" |
{ |
(yyval.versnode) = lang_new_vers_node ((yyvsp[(3) - (8)].versyms), (yyvsp[(7) - (8)].versyms)); |
} |
break; |
case 354: |
#line 1396 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern (NULL, (yyvsp[(1) - (1)].name), ldgram_vers_current_lang, FALSE); |
} |
break; |
case 355: |
#line 1400 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern (NULL, (yyvsp[(1) - (1)].name), ldgram_vers_current_lang, TRUE); |
} |
break; |
case 356: |
#line 1404 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern ((yyvsp[(1) - (3)].versyms), (yyvsp[(3) - (3)].name), ldgram_vers_current_lang, FALSE); |
} |
break; |
case 357: |
#line 1408 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern ((yyvsp[(1) - (3)].versyms), (yyvsp[(3) - (3)].name), ldgram_vers_current_lang, TRUE); |
} |
break; |
case 358: |
#line 1412 "ldgram.y" |
{ |
(yyval.name) = ldgram_vers_current_lang; |
ldgram_vers_current_lang = (yyvsp[(4) - (5)].name); |
} |
break; |
case 359: |
#line 1417 "ldgram.y" |
{ |
struct bfd_elf_version_expr *pat; |
for (pat = (yyvsp[(7) - (9)].versyms); pat->next != NULL; pat = pat->next); |
pat->next = (yyvsp[(1) - (9)].versyms); |
(yyval.versyms) = (yyvsp[(7) - (9)].versyms); |
ldgram_vers_current_lang = (yyvsp[(6) - (9)].name); |
} |
break; |
case 360: |
#line 1425 "ldgram.y" |
{ |
(yyval.name) = ldgram_vers_current_lang; |
ldgram_vers_current_lang = (yyvsp[(2) - (3)].name); |
} |
break; |
case 361: |
#line 1430 "ldgram.y" |
{ |
(yyval.versyms) = (yyvsp[(5) - (7)].versyms); |
ldgram_vers_current_lang = (yyvsp[(4) - (7)].name); |
} |
break; |
case 362: |
#line 1435 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE); |
} |
break; |
case 363: |
#line 1439 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern ((yyvsp[(1) - (3)].versyms), "global", ldgram_vers_current_lang, FALSE); |
} |
break; |
case 364: |
#line 1443 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE); |
} |
break; |
case 365: |
#line 1447 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern ((yyvsp[(1) - (3)].versyms), "local", ldgram_vers_current_lang, FALSE); |
} |
break; |
case 366: |
#line 1451 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE); |
} |
break; |
case 367: |
#line 1455 "ldgram.y" |
{ |
(yyval.versyms) = lang_new_vers_pattern ((yyvsp[(1) - (3)].versyms), "extern", ldgram_vers_current_lang, FALSE); |
} |
break; |
/* Line 1267 of yacc.c. */ |
#line 4490 "ldgram.c" |
default: break; |
} |
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); |
YYPOPSTACK (yylen); |
yylen = 0; |
YY_STACK_PRINT (yyss, yyssp); |
*++yyvsp = yyval; |
/* Now `shift' the result of the reduction. Determine what state |
that goes to, based on the state we popped back to and the rule |
number reduced by. */ |
yyn = yyr1[yyn]; |
yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; |
if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) |
yystate = yytable[yystate]; |
else |
yystate = yydefgoto[yyn - YYNTOKENS]; |
goto yynewstate; |
/*------------------------------------. |
| yyerrlab -- here on detecting error | |
`------------------------------------*/ |
yyerrlab: |
/* If not already recovering from an error, report this error. */ |
if (!yyerrstatus) |
{ |
++yynerrs; |
#if ! YYERROR_VERBOSE |
yyerror (YY_("syntax error")); |
#else |
{ |
YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); |
if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) |
{ |
YYSIZE_T yyalloc = 2 * yysize; |
if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) |
yyalloc = YYSTACK_ALLOC_MAXIMUM; |
if (yymsg != yymsgbuf) |
YYSTACK_FREE (yymsg); |
yymsg = (char *) YYSTACK_ALLOC (yyalloc); |
if (yymsg) |
yymsg_alloc = yyalloc; |
else |
{ |
yymsg = yymsgbuf; |
yymsg_alloc = sizeof yymsgbuf; |
} |
} |
if (0 < yysize && yysize <= yymsg_alloc) |
{ |
(void) yysyntax_error (yymsg, yystate, yychar); |
yyerror (yymsg); |
} |
else |
{ |
yyerror (YY_("syntax error")); |
if (yysize != 0) |
goto yyexhaustedlab; |
} |
} |
#endif |
} |
if (yyerrstatus == 3) |
{ |
/* If just tried and failed to reuse look-ahead token after an |
error, discard it. */ |
if (yychar <= YYEOF) |
{ |
/* Return failure if at end of input. */ |
if (yychar == YYEOF) |
YYABORT; |
} |
else |
{ |
yydestruct ("Error: discarding", |
yytoken, &yylval); |
yychar = YYEMPTY; |
} |
} |
/* Else will try to reuse look-ahead token after shifting the error |
token. */ |
goto yyerrlab1; |
/*---------------------------------------------------. |
| yyerrorlab -- error raised explicitly by YYERROR. | |
`---------------------------------------------------*/ |
yyerrorlab: |
/* Pacify compilers like GCC when the user code never invokes |
YYERROR and the label yyerrorlab therefore never appears in user |
code. */ |
if (/*CONSTCOND*/ 0) |
goto yyerrorlab; |
/* Do not reclaim the symbols of the rule which action triggered |
this YYERROR. */ |
YYPOPSTACK (yylen); |
yylen = 0; |
YY_STACK_PRINT (yyss, yyssp); |
yystate = *yyssp; |
goto yyerrlab1; |
/*-------------------------------------------------------------. |
| yyerrlab1 -- common code for both syntax error and YYERROR. | |
`-------------------------------------------------------------*/ |
yyerrlab1: |
yyerrstatus = 3; /* Each real token shifted decrements this. */ |
for (;;) |
{ |
yyn = yypact[yystate]; |
if (yyn != YYPACT_NINF) |
{ |
yyn += YYTERROR; |
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) |
{ |
yyn = yytable[yyn]; |
if (0 < yyn) |
break; |
} |
} |
/* Pop the current state because it cannot handle the error token. */ |
if (yyssp == yyss) |
YYABORT; |
yydestruct ("Error: popping", |
yystos[yystate], yyvsp); |
YYPOPSTACK (1); |
yystate = *yyssp; |
YY_STACK_PRINT (yyss, yyssp); |
} |
if (yyn == YYFINAL) |
YYACCEPT; |
*++yyvsp = yylval; |
/* Shift the error token. */ |
YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); |
yystate = yyn; |
goto yynewstate; |
/*-------------------------------------. |
| yyacceptlab -- YYACCEPT comes here. | |
`-------------------------------------*/ |
yyacceptlab: |
yyresult = 0; |
goto yyreturn; |
/*-----------------------------------. |
| yyabortlab -- YYABORT comes here. | |
`-----------------------------------*/ |
yyabortlab: |
yyresult = 1; |
goto yyreturn; |
#ifndef yyoverflow |
/*-------------------------------------------------. |
| yyexhaustedlab -- memory exhaustion comes here. | |
`-------------------------------------------------*/ |
yyexhaustedlab: |
yyerror (YY_("memory exhausted")); |
yyresult = 2; |
/* Fall through. */ |
#endif |
yyreturn: |
if (yychar != YYEOF && yychar != YYEMPTY) |
yydestruct ("Cleanup: discarding lookahead", |
yytoken, &yylval); |
/* Do not reclaim the symbols of the rule which action triggered |
this YYABORT or YYACCEPT. */ |
YYPOPSTACK (yylen); |
YY_STACK_PRINT (yyss, yyssp); |
while (yyssp != yyss) |
{ |
yydestruct ("Cleanup: popping", |
yystos[*yyssp], yyvsp); |
YYPOPSTACK (1); |
} |
#ifndef yyoverflow |
if (yyss != yyssa) |
YYSTACK_FREE (yyss); |
#endif |
#if YYERROR_VERBOSE |
if (yymsg != yymsgbuf) |
YYSTACK_FREE (yymsg); |
#endif |
/* Make sure YYID is used. */ |
return YYID (yyresult); |
} |
#line 1465 "ldgram.y" |
void |
yyerror(arg) |
const char *arg; |
{ |
if (ldfile_assumed_script) |
einfo (_("%P:%s: file format not recognized; treating as linker script\n"), |
ldlex_filename ()); |
if (error_index > 0 && error_index < ERROR_NAME_MAX) |
einfo ("%P%F:%S: %s in %s\n", NULL, arg, error_names[error_index - 1]); |
else |
einfo ("%P%F:%S: %s\n", NULL, arg); |
} |
/contrib/toolchain/binutils/ld/ldgram.h |
---|
0,0 → 1,347 |
/* A Bison parser, made by GNU Bison 2.3. */ |
/* Skeleton interface for Bison's Yacc-like parsers in C |
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 |
Free Software Foundation, Inc. |
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, Inc., 51 Franklin Street, Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* As a special exception, you may create a larger work that contains |
part or all of the Bison parser skeleton and distribute that work |
under terms of your choice, so long as that work isn't itself a |
parser generator using the skeleton or a modified version thereof |
as a parser skeleton. Alternatively, if you modify or redistribute |
the parser skeleton itself, you may (at your option) remove this |
special exception, which will cause the skeleton and the resulting |
Bison output files to be licensed under the GNU General Public |
License without this special exception. |
This special exception was added by the Free Software Foundation in |
version 2.2 of Bison. */ |
/* Tokens. */ |
#ifndef YYTOKENTYPE |
# define YYTOKENTYPE |
/* Put the tokens into the symbol table, so that GDB and other debuggers |
know about them. */ |
enum yytokentype { |
INT = 258, |
NAME = 259, |
LNAME = 260, |
OREQ = 261, |
ANDEQ = 262, |
RSHIFTEQ = 263, |
LSHIFTEQ = 264, |
DIVEQ = 265, |
MULTEQ = 266, |
MINUSEQ = 267, |
PLUSEQ = 268, |
OROR = 269, |
ANDAND = 270, |
NE = 271, |
EQ = 272, |
GE = 273, |
LE = 274, |
RSHIFT = 275, |
LSHIFT = 276, |
UNARY = 277, |
END = 278, |
ALIGN_K = 279, |
BLOCK = 280, |
BIND = 281, |
QUAD = 282, |
SQUAD = 283, |
LONG = 284, |
SHORT = 285, |
BYTE = 286, |
SECTIONS = 287, |
PHDRS = 288, |
INSERT_K = 289, |
AFTER = 290, |
BEFORE = 291, |
DATA_SEGMENT_ALIGN = 292, |
DATA_SEGMENT_RELRO_END = 293, |
DATA_SEGMENT_END = 294, |
SORT_BY_NAME = 295, |
SORT_BY_ALIGNMENT = 296, |
SORT_NONE = 297, |
SORT_BY_INIT_PRIORITY = 298, |
SIZEOF_HEADERS = 299, |
OUTPUT_FORMAT = 300, |
FORCE_COMMON_ALLOCATION = 301, |
OUTPUT_ARCH = 302, |
INHIBIT_COMMON_ALLOCATION = 303, |
SEGMENT_START = 304, |
INCLUDE = 305, |
MEMORY = 306, |
REGION_ALIAS = 307, |
LD_FEATURE = 308, |
NOLOAD = 309, |
DSECT = 310, |
COPY = 311, |
INFO = 312, |
OVERLAY = 313, |
DEFINED = 314, |
TARGET_K = 315, |
SEARCH_DIR = 316, |
MAP = 317, |
ENTRY = 318, |
NEXT = 319, |
SIZEOF = 320, |
ALIGNOF = 321, |
ADDR = 322, |
LOADADDR = 323, |
MAX_K = 324, |
MIN_K = 325, |
STARTUP = 326, |
HLL = 327, |
SYSLIB = 328, |
FLOAT = 329, |
NOFLOAT = 330, |
NOCROSSREFS = 331, |
ORIGIN = 332, |
FILL = 333, |
LENGTH = 334, |
CREATE_OBJECT_SYMBOLS = 335, |
INPUT = 336, |
GROUP = 337, |
OUTPUT = 338, |
CONSTRUCTORS = 339, |
ALIGNMOD = 340, |
AT = 341, |
SUBALIGN = 342, |
HIDDEN = 343, |
PROVIDE = 344, |
PROVIDE_HIDDEN = 345, |
AS_NEEDED = 346, |
CHIP = 347, |
LIST = 348, |
SECT = 349, |
ABSOLUTE = 350, |
LOAD = 351, |
NEWLINE = 352, |
ENDWORD = 353, |
ORDER = 354, |
NAMEWORD = 355, |
ASSERT_K = 356, |
LOG2CEIL = 357, |
FORMAT = 358, |
PUBLIC = 359, |
DEFSYMEND = 360, |
BASE = 361, |
ALIAS = 362, |
TRUNCATE = 363, |
REL = 364, |
INPUT_SCRIPT = 365, |
INPUT_MRI_SCRIPT = 366, |
INPUT_DEFSYM = 367, |
CASE = 368, |
EXTERN = 369, |
START = 370, |
VERS_TAG = 371, |
VERS_IDENTIFIER = 372, |
GLOBAL = 373, |
LOCAL = 374, |
VERSIONK = 375, |
INPUT_VERSION_SCRIPT = 376, |
KEEP = 377, |
ONLY_IF_RO = 378, |
ONLY_IF_RW = 379, |
SPECIAL = 380, |
INPUT_SECTION_FLAGS = 381, |
ALIGN_WITH_INPUT = 382, |
EXCLUDE_FILE = 383, |
CONSTANT = 384, |
INPUT_DYNAMIC_LIST = 385 |
}; |
#endif |
/* Tokens. */ |
#define INT 258 |
#define NAME 259 |
#define LNAME 260 |
#define OREQ 261 |
#define ANDEQ 262 |
#define RSHIFTEQ 263 |
#define LSHIFTEQ 264 |
#define DIVEQ 265 |
#define MULTEQ 266 |
#define MINUSEQ 267 |
#define PLUSEQ 268 |
#define OROR 269 |
#define ANDAND 270 |
#define NE 271 |
#define EQ 272 |
#define GE 273 |
#define LE 274 |
#define RSHIFT 275 |
#define LSHIFT 276 |
#define UNARY 277 |
#define END 278 |
#define ALIGN_K 279 |
#define BLOCK 280 |
#define BIND 281 |
#define QUAD 282 |
#define SQUAD 283 |
#define LONG 284 |
#define SHORT 285 |
#define BYTE 286 |
#define SECTIONS 287 |
#define PHDRS 288 |
#define INSERT_K 289 |
#define AFTER 290 |
#define BEFORE 291 |
#define DATA_SEGMENT_ALIGN 292 |
#define DATA_SEGMENT_RELRO_END 293 |
#define DATA_SEGMENT_END 294 |
#define SORT_BY_NAME 295 |
#define SORT_BY_ALIGNMENT 296 |
#define SORT_NONE 297 |
#define SORT_BY_INIT_PRIORITY 298 |
#define SIZEOF_HEADERS 299 |
#define OUTPUT_FORMAT 300 |
#define FORCE_COMMON_ALLOCATION 301 |
#define OUTPUT_ARCH 302 |
#define INHIBIT_COMMON_ALLOCATION 303 |
#define SEGMENT_START 304 |
#define INCLUDE 305 |
#define MEMORY 306 |
#define REGION_ALIAS 307 |
#define LD_FEATURE 308 |
#define NOLOAD 309 |
#define DSECT 310 |
#define COPY 311 |
#define INFO 312 |
#define OVERLAY 313 |
#define DEFINED 314 |
#define TARGET_K 315 |
#define SEARCH_DIR 316 |
#define MAP 317 |
#define ENTRY 318 |
#define NEXT 319 |
#define SIZEOF 320 |
#define ALIGNOF 321 |
#define ADDR 322 |
#define LOADADDR 323 |
#define MAX_K 324 |
#define MIN_K 325 |
#define STARTUP 326 |
#define HLL 327 |
#define SYSLIB 328 |
#define FLOAT 329 |
#define NOFLOAT 330 |
#define NOCROSSREFS 331 |
#define ORIGIN 332 |
#define FILL 333 |
#define LENGTH 334 |
#define CREATE_OBJECT_SYMBOLS 335 |
#define INPUT 336 |
#define GROUP 337 |
#define OUTPUT 338 |
#define CONSTRUCTORS 339 |
#define ALIGNMOD 340 |
#define AT 341 |
#define SUBALIGN 342 |
#define HIDDEN 343 |
#define PROVIDE 344 |
#define PROVIDE_HIDDEN 345 |
#define AS_NEEDED 346 |
#define CHIP 347 |
#define LIST 348 |
#define SECT 349 |
#define ABSOLUTE 350 |
#define LOAD 351 |
#define NEWLINE 352 |
#define ENDWORD 353 |
#define ORDER 354 |
#define NAMEWORD 355 |
#define ASSERT_K 356 |
#define LOG2CEIL 357 |
#define FORMAT 358 |
#define PUBLIC 359 |
#define DEFSYMEND 360 |
#define BASE 361 |
#define ALIAS 362 |
#define TRUNCATE 363 |
#define REL 364 |
#define INPUT_SCRIPT 365 |
#define INPUT_MRI_SCRIPT 366 |
#define INPUT_DEFSYM 367 |
#define CASE 368 |
#define EXTERN 369 |
#define START 370 |
#define VERS_TAG 371 |
#define VERS_IDENTIFIER 372 |
#define GLOBAL 373 |
#define LOCAL 374 |
#define VERSIONK 375 |
#define INPUT_VERSION_SCRIPT 376 |
#define KEEP 377 |
#define ONLY_IF_RO 378 |
#define ONLY_IF_RW 379 |
#define SPECIAL 380 |
#define INPUT_SECTION_FLAGS 381 |
#define ALIGN_WITH_INPUT 382 |
#define EXCLUDE_FILE 383 |
#define CONSTANT 384 |
#define INPUT_DYNAMIC_LIST 385 |
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED |
typedef union YYSTYPE |
#line 60 "ldgram.y" |
{ |
bfd_vma integer; |
struct big_int |
{ |
bfd_vma integer; |
char *str; |
} bigint; |
fill_type *fill; |
char *name; |
const char *cname; |
struct wildcard_spec wildcard; |
struct wildcard_list *wildcard_list; |
struct name_list *name_list; |
struct flag_info_list *flag_info_list; |
struct flag_info *flag_info; |
int token; |
union etree_union *etree; |
struct phdr_info |
{ |
bfd_boolean filehdr; |
bfd_boolean phdrs; |
union etree_union *at; |
union etree_union *flags; |
} phdr; |
struct lang_nocrossref *nocrossref; |
struct lang_output_section_phdr_list *section_phdr; |
struct bfd_elf_version_deps *deflist; |
struct bfd_elf_version_expr *versyms; |
struct bfd_elf_version_tree *versnode; |
} |
/* Line 1529 of yacc.c. */ |
#line 340 "ldgram.h" |
YYSTYPE; |
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ |
# define YYSTYPE_IS_DECLARED 1 |
# define YYSTYPE_IS_TRIVIAL 1 |
#endif |
extern YYSTYPE yylval; |
/contrib/toolchain/binutils/ld/ldlang.c |
---|
0,0 → 1,8066 |
/* Linker command language support. |
Copyright 1991-2013 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "filenames.h" |
#include "safe-ctype.h" |
#include "obstack.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldmisc.h" |
#include "ldctor.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "fnmatch.h" |
#include "demangle.h" |
#include "hashtab.h" |
#include "libbfd.h" |
#ifdef ENABLE_PLUGINS |
#include "plugin.h" |
#endif /* ENABLE_PLUGINS */ |
#include <limits.h> |
#ifndef offsetof |
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER)) |
#endif |
/* Locals variables. */ |
static struct obstack stat_obstack; |
static struct obstack map_obstack; |
#define obstack_chunk_alloc xmalloc |
#define obstack_chunk_free free |
static const char *entry_symbol_default = "start"; |
static bfd_boolean placed_commons = FALSE; |
static bfd_boolean stripped_excluded_sections = FALSE; |
static lang_output_section_statement_type *default_common_section; |
static bfd_boolean map_option_f; |
static bfd_vma print_dot; |
static lang_input_statement_type *first_file; |
static const char *current_target; |
static lang_statement_list_type statement_list; |
static struct bfd_hash_table lang_definedness_table; |
static lang_statement_list_type *stat_save[10]; |
static lang_statement_list_type **stat_save_ptr = &stat_save[0]; |
static struct unique_sections *unique_section_list; |
/* Forward declarations. */ |
static void exp_init_os (etree_type *); |
static void init_map_userdata (bfd *, asection *, void *); |
static lang_input_statement_type *lookup_name (const char *); |
static struct bfd_hash_entry *lang_definedness_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
static void insert_undefined (const char *); |
static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *); |
static void print_statement (lang_statement_union_type *, |
lang_output_section_statement_type *); |
static void print_statement_list (lang_statement_union_type *, |
lang_output_section_statement_type *); |
static void print_statements (void); |
static void print_input_section (asection *, bfd_boolean); |
static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *); |
static void lang_record_phdrs (void); |
static void lang_do_version_exports_section (void); |
static void lang_finalize_version_expr_head |
(struct bfd_elf_version_expr_head *); |
/* Exported variables. */ |
const char *output_target; |
lang_output_section_statement_type *abs_output_section; |
lang_statement_list_type lang_output_section_statement; |
lang_statement_list_type *stat_ptr = &statement_list; |
lang_statement_list_type file_chain = { NULL, NULL }; |
lang_statement_list_type input_file_chain; |
struct bfd_sym_chain entry_symbol = { NULL, NULL }; |
const char *entry_section = ".text"; |
struct lang_input_statement_flags input_flags; |
bfd_boolean entry_from_cmdline; |
bfd_boolean undef_from_cmdline; |
bfd_boolean lang_has_input_file = FALSE; |
bfd_boolean had_output_filename = FALSE; |
bfd_boolean lang_float_flag = FALSE; |
bfd_boolean delete_output_file_on_failure = FALSE; |
struct lang_phdr *lang_phdr_list; |
struct lang_nocrossrefs *nocrossref_list; |
/* Functions that traverse the linker script and might evaluate |
DEFINED() need to increment this. */ |
int lang_statement_iteration = 0; |
etree_type *base; /* Relocation base - or null */ |
/* Return TRUE if the PATTERN argument is a wildcard pattern. |
Although backslashes are treated specially if a pattern contains |
wildcards, we do not consider the mere presence of a backslash to |
be enough to cause the pattern to be treated as a wildcard. |
That lets us handle DOS filenames more naturally. */ |
#define wildcardp(pattern) (strpbrk ((pattern), "?*[") != NULL) |
#define new_stat(x, y) \ |
(x##_type *) new_statement (x##_enum, sizeof (x##_type), y) |
#define outside_section_address(q) \ |
((q)->output_offset + (q)->output_section->vma) |
#define outside_symbol_address(q) \ |
((q)->value + outside_section_address (q->section)) |
#define SECTION_NAME_MAP_LENGTH (16) |
void * |
stat_alloc (size_t size) |
{ |
return obstack_alloc (&stat_obstack, size); |
} |
static int |
name_match (const char *pattern, const char *name) |
{ |
if (wildcardp (pattern)) |
return fnmatch (pattern, name, 0); |
return strcmp (pattern, name); |
} |
/* If PATTERN is of the form archive:file, return a pointer to the |
separator. If not, return NULL. */ |
static char * |
archive_path (const char *pattern) |
{ |
char *p = NULL; |
if (link_info.path_separator == 0) |
return p; |
p = strchr (pattern, link_info.path_separator); |
#ifdef HAVE_DOS_BASED_FILE_SYSTEM |
if (p == NULL || link_info.path_separator != ':') |
return p; |
/* Assume a match on the second char is part of drive specifier, |
as in "c:\silly.dos". */ |
if (p == pattern + 1 && ISALPHA (*pattern)) |
p = strchr (p + 1, link_info.path_separator); |
#endif |
return p; |
} |
/* Given that FILE_SPEC results in a non-NULL SEP result from archive_path, |
return whether F matches FILE_SPEC. */ |
static bfd_boolean |
input_statement_is_archive_path (const char *file_spec, char *sep, |
lang_input_statement_type *f) |
{ |
bfd_boolean match = FALSE; |
if ((*(sep + 1) == 0 |
|| name_match (sep + 1, f->filename) == 0) |
&& ((sep != file_spec) |
== (f->the_bfd != NULL && f->the_bfd->my_archive != NULL))) |
{ |
match = TRUE; |
if (sep != file_spec) |
{ |
const char *aname = f->the_bfd->my_archive->filename; |
*sep = 0; |
match = name_match (file_spec, aname) == 0; |
*sep = link_info.path_separator; |
} |
} |
return match; |
} |
static bfd_boolean |
unique_section_p (const asection *sec, |
const lang_output_section_statement_type *os) |
{ |
struct unique_sections *unam; |
const char *secnam; |
if (link_info.relocatable |
&& sec->owner != NULL |
&& bfd_is_group_section (sec->owner, sec)) |
return !(os != NULL |
&& strcmp (os->name, DISCARD_SECTION_NAME) == 0); |
secnam = sec->name; |
for (unam = unique_section_list; unam; unam = unam->next) |
if (name_match (unam->name, secnam) == 0) |
return TRUE; |
return FALSE; |
} |
/* Generic traversal routines for finding matching sections. */ |
/* Try processing a section against a wildcard. This just calls |
the callback unless the filename exclusion list is present |
and excludes the file. It's hardly ever present so this |
function is very fast. */ |
static void |
walk_wild_consider_section (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
asection *s, |
struct wildcard_list *sec, |
callback_t callback, |
void *data) |
{ |
struct name_list *list_tmp; |
/* Don't process sections from files which were excluded. */ |
for (list_tmp = sec->spec.exclude_name_list; |
list_tmp; |
list_tmp = list_tmp->next) |
{ |
char *p = archive_path (list_tmp->name); |
if (p != NULL) |
{ |
if (input_statement_is_archive_path (list_tmp->name, p, file)) |
return; |
} |
else if (name_match (list_tmp->name, file->filename) == 0) |
return; |
/* FIXME: Perhaps remove the following at some stage? Matching |
unadorned archives like this was never documented and has |
been superceded by the archive:path syntax. */ |
else if (file->the_bfd != NULL |
&& file->the_bfd->my_archive != NULL |
&& name_match (list_tmp->name, |
file->the_bfd->my_archive->filename) == 0) |
return; |
} |
(*callback) (ptr, sec, s, ptr->section_flag_list, file, data); |
} |
/* Lowest common denominator routine that can handle everything correctly, |
but slowly. */ |
static void |
walk_wild_section_general (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
asection *s; |
struct wildcard_list *sec; |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
sec = ptr->section_list; |
if (sec == NULL) |
(*callback) (ptr, sec, s, ptr->section_flag_list, file, data); |
while (sec != NULL) |
{ |
bfd_boolean skip = FALSE; |
if (sec->spec.name != NULL) |
{ |
const char *sname = bfd_get_section_name (file->the_bfd, s); |
skip = name_match (sec->spec.name, sname) != 0; |
} |
if (!skip) |
walk_wild_consider_section (ptr, file, s, sec, callback, data); |
sec = sec->next; |
} |
} |
} |
/* Routines to find a single section given its name. If there's more |
than one section with that name, we report that. */ |
typedef struct |
{ |
asection *found_section; |
bfd_boolean multiple_sections_found; |
} section_iterator_callback_data; |
static bfd_boolean |
section_iterator_callback (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *data) |
{ |
section_iterator_callback_data *d = (section_iterator_callback_data *) data; |
if (d->found_section != NULL) |
{ |
d->multiple_sections_found = TRUE; |
return TRUE; |
} |
d->found_section = s; |
return FALSE; |
} |
static asection * |
find_section (lang_input_statement_type *file, |
struct wildcard_list *sec, |
bfd_boolean *multiple_sections_found) |
{ |
section_iterator_callback_data cb_data = { NULL, FALSE }; |
bfd_get_section_by_name_if (file->the_bfd, sec->spec.name, |
section_iterator_callback, &cb_data); |
*multiple_sections_found = cb_data.multiple_sections_found; |
return cb_data.found_section; |
} |
/* Code for handling simple wildcards without going through fnmatch, |
which can be expensive because of charset translations etc. */ |
/* A simple wild is a literal string followed by a single '*', |
where the literal part is at least 4 characters long. */ |
static bfd_boolean |
is_simple_wild (const char *name) |
{ |
size_t len = strcspn (name, "*?["); |
return len >= 4 && name[len] == '*' && name[len + 1] == '\0'; |
} |
static bfd_boolean |
match_simple_wild (const char *pattern, const char *name) |
{ |
/* The first four characters of the pattern are guaranteed valid |
non-wildcard characters. So we can go faster. */ |
if (pattern[0] != name[0] || pattern[1] != name[1] |
|| pattern[2] != name[2] || pattern[3] != name[3]) |
return FALSE; |
pattern += 4; |
name += 4; |
while (*pattern != '*') |
if (*name++ != *pattern++) |
return FALSE; |
return TRUE; |
} |
/* Return the numerical value of the init_priority attribute from |
section name NAME. */ |
static unsigned long |
get_init_priority (const char *name) |
{ |
char *end; |
unsigned long init_priority; |
/* GCC uses the following section names for the init_priority |
attribute with numerical values 101 and 65535 inclusive. A |
lower value means a higher priority. |
1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the |
decimal numerical value of the init_priority attribute. |
The order of execution in .init_array is forward and |
.fini_array is backward. |
2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the |
decimal numerical value of the init_priority attribute. |
The order of execution in .ctors is backward and .dtors |
is forward. |
*/ |
if (strncmp (name, ".init_array.", 12) == 0 |
|| strncmp (name, ".fini_array.", 12) == 0) |
{ |
init_priority = strtoul (name + 12, &end, 10); |
return *end ? 0 : init_priority; |
} |
else if (strncmp (name, ".ctors.", 7) == 0 |
|| strncmp (name, ".dtors.", 7) == 0) |
{ |
init_priority = strtoul (name + 7, &end, 10); |
return *end ? 0 : 65535 - init_priority; |
} |
return 0; |
} |
/* Compare sections ASEC and BSEC according to SORT. */ |
static int |
compare_section (sort_type sort, asection *asec, asection *bsec) |
{ |
int ret; |
unsigned long ainit_priority, binit_priority; |
switch (sort) |
{ |
default: |
abort (); |
case by_init_priority: |
ainit_priority |
= get_init_priority (bfd_get_section_name (asec->owner, asec)); |
binit_priority |
= get_init_priority (bfd_get_section_name (bsec->owner, bsec)); |
if (ainit_priority == 0 || binit_priority == 0) |
goto sort_by_name; |
ret = ainit_priority - binit_priority; |
if (ret) |
break; |
else |
goto sort_by_name; |
case by_alignment_name: |
ret = (bfd_section_alignment (bsec->owner, bsec) |
- bfd_section_alignment (asec->owner, asec)); |
if (ret) |
break; |
/* Fall through. */ |
case by_name: |
sort_by_name: |
ret = strcmp (bfd_get_section_name (asec->owner, asec), |
bfd_get_section_name (bsec->owner, bsec)); |
break; |
case by_name_alignment: |
ret = strcmp (bfd_get_section_name (asec->owner, asec), |
bfd_get_section_name (bsec->owner, bsec)); |
if (ret) |
break; |
/* Fall through. */ |
case by_alignment: |
ret = (bfd_section_alignment (bsec->owner, bsec) |
- bfd_section_alignment (asec->owner, asec)); |
break; |
} |
return ret; |
} |
/* Build a Binary Search Tree to sort sections, unlike insertion sort |
used in wild_sort(). BST is considerably faster if the number of |
of sections are large. */ |
static lang_section_bst_type ** |
wild_sort_fast (lang_wild_statement_type *wild, |
struct wildcard_list *sec, |
lang_input_statement_type *file ATTRIBUTE_UNUSED, |
asection *section) |
{ |
lang_section_bst_type **tree; |
tree = &wild->tree; |
if (!wild->filenames_sorted |
&& (sec == NULL || sec->spec.sorted == none)) |
{ |
/* Append at the right end of tree. */ |
while (*tree) |
tree = &((*tree)->right); |
return tree; |
} |
while (*tree) |
{ |
/* Find the correct node to append this section. */ |
if (compare_section (sec->spec.sorted, section, (*tree)->section) < 0) |
tree = &((*tree)->left); |
else |
tree = &((*tree)->right); |
} |
return tree; |
} |
/* Use wild_sort_fast to build a BST to sort sections. */ |
static void |
output_section_callback_fast (lang_wild_statement_type *ptr, |
struct wildcard_list *sec, |
asection *section, |
struct flag_info *sflag_list ATTRIBUTE_UNUSED, |
lang_input_statement_type *file, |
void *output) |
{ |
lang_section_bst_type *node; |
lang_section_bst_type **tree; |
lang_output_section_statement_type *os; |
os = (lang_output_section_statement_type *) output; |
if (unique_section_p (section, os)) |
return; |
node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type)); |
node->left = 0; |
node->right = 0; |
node->section = section; |
tree = wild_sort_fast (ptr, sec, file, section); |
if (tree != NULL) |
*tree = node; |
} |
/* Convert a sorted sections' BST back to list form. */ |
static void |
output_section_callback_tree_to_list (lang_wild_statement_type *ptr, |
lang_section_bst_type *tree, |
void *output) |
{ |
if (tree->left) |
output_section_callback_tree_to_list (ptr, tree->left, output); |
lang_add_section (&ptr->children, tree->section, NULL, |
(lang_output_section_statement_type *) output); |
if (tree->right) |
output_section_callback_tree_to_list (ptr, tree->right, output); |
free (tree); |
} |
/* Specialized, optimized routines for handling different kinds of |
wildcards */ |
static void |
walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
/* We can just do a hash lookup for the section with the right name. |
But if that lookup discovers more than one section with the name |
(should be rare), we fall back to the general algorithm because |
we would otherwise have to sort the sections to make sure they |
get processed in the bfd's order. */ |
bfd_boolean multiple_sections_found; |
struct wildcard_list *sec0 = ptr->handler_data[0]; |
asection *s0 = find_section (file, sec0, &multiple_sections_found); |
if (multiple_sections_found) |
walk_wild_section_general (ptr, file, callback, data); |
else if (s0) |
walk_wild_consider_section (ptr, file, s0, sec0, callback, data); |
} |
static void |
walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
asection *s; |
struct wildcard_list *wildsec0 = ptr->handler_data[0]; |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
const char *sname = bfd_get_section_name (file->the_bfd, s); |
bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec0, callback, data); |
} |
} |
static void |
walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
asection *s; |
struct wildcard_list *sec0 = ptr->handler_data[0]; |
struct wildcard_list *wildsec1 = ptr->handler_data[1]; |
bfd_boolean multiple_sections_found; |
asection *s0 = find_section (file, sec0, &multiple_sections_found); |
if (multiple_sections_found) |
{ |
walk_wild_section_general (ptr, file, callback, data); |
return; |
} |
/* Note that if the section was not found, s0 is NULL and |
we'll simply never succeed the s == s0 test below. */ |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
/* Recall that in this code path, a section cannot satisfy more |
than one spec, so if s == s0 then it cannot match |
wildspec1. */ |
if (s == s0) |
walk_wild_consider_section (ptr, file, s, sec0, callback, data); |
else |
{ |
const char *sname = bfd_get_section_name (file->the_bfd, s); |
bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec1, callback, |
data); |
} |
} |
} |
static void |
walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
asection *s; |
struct wildcard_list *sec0 = ptr->handler_data[0]; |
struct wildcard_list *wildsec1 = ptr->handler_data[1]; |
struct wildcard_list *wildsec2 = ptr->handler_data[2]; |
bfd_boolean multiple_sections_found; |
asection *s0 = find_section (file, sec0, &multiple_sections_found); |
if (multiple_sections_found) |
{ |
walk_wild_section_general (ptr, file, callback, data); |
return; |
} |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
if (s == s0) |
walk_wild_consider_section (ptr, file, s, sec0, callback, data); |
else |
{ |
const char *sname = bfd_get_section_name (file->the_bfd, s); |
bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec1, callback, data); |
else |
{ |
skip = !match_simple_wild (wildsec2->spec.name, sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec2, callback, |
data); |
} |
} |
} |
} |
static void |
walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
asection *s; |
struct wildcard_list *sec0 = ptr->handler_data[0]; |
struct wildcard_list *sec1 = ptr->handler_data[1]; |
struct wildcard_list *wildsec2 = ptr->handler_data[2]; |
struct wildcard_list *wildsec3 = ptr->handler_data[3]; |
bfd_boolean multiple_sections_found; |
asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1; |
if (multiple_sections_found) |
{ |
walk_wild_section_general (ptr, file, callback, data); |
return; |
} |
s1 = find_section (file, sec1, &multiple_sections_found); |
if (multiple_sections_found) |
{ |
walk_wild_section_general (ptr, file, callback, data); |
return; |
} |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
if (s == s0) |
walk_wild_consider_section (ptr, file, s, sec0, callback, data); |
else |
if (s == s1) |
walk_wild_consider_section (ptr, file, s, sec1, callback, data); |
else |
{ |
const char *sname = bfd_get_section_name (file->the_bfd, s); |
bfd_boolean skip = !match_simple_wild (wildsec2->spec.name, |
sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec2, callback, |
data); |
else |
{ |
skip = !match_simple_wild (wildsec3->spec.name, sname); |
if (!skip) |
walk_wild_consider_section (ptr, file, s, wildsec3, |
callback, data); |
} |
} |
} |
} |
static void |
walk_wild_section (lang_wild_statement_type *ptr, |
lang_input_statement_type *file, |
callback_t callback, |
void *data) |
{ |
if (file->flags.just_syms) |
return; |
(*ptr->walk_wild_section_handler) (ptr, file, callback, data); |
} |
/* Returns TRUE when name1 is a wildcard spec that might match |
something name2 can match. We're conservative: we return FALSE |
only if the prefixes of name1 and name2 are different up to the |
first wildcard character. */ |
static bfd_boolean |
wild_spec_can_overlap (const char *name1, const char *name2) |
{ |
size_t prefix1_len = strcspn (name1, "?*["); |
size_t prefix2_len = strcspn (name2, "?*["); |
size_t min_prefix_len; |
/* Note that if there is no wildcard character, then we treat the |
terminating 0 as part of the prefix. Thus ".text" won't match |
".text." or ".text.*", for example. */ |
if (name1[prefix1_len] == '\0') |
prefix1_len++; |
if (name2[prefix2_len] == '\0') |
prefix2_len++; |
min_prefix_len = prefix1_len < prefix2_len ? prefix1_len : prefix2_len; |
return memcmp (name1, name2, min_prefix_len) == 0; |
} |
/* Select specialized code to handle various kinds of wildcard |
statements. */ |
static void |
analyze_walk_wild_section_handler (lang_wild_statement_type *ptr) |
{ |
int sec_count = 0; |
int wild_name_count = 0; |
struct wildcard_list *sec; |
int signature; |
int data_counter; |
ptr->walk_wild_section_handler = walk_wild_section_general; |
ptr->handler_data[0] = NULL; |
ptr->handler_data[1] = NULL; |
ptr->handler_data[2] = NULL; |
ptr->handler_data[3] = NULL; |
ptr->tree = NULL; |
/* Count how many wildcard_specs there are, and how many of those |
actually use wildcards in the name. Also, bail out if any of the |
wildcard names are NULL. (Can this actually happen? |
walk_wild_section used to test for it.) And bail out if any |
of the wildcards are more complex than a simple string |
ending in a single '*'. */ |
for (sec = ptr->section_list; sec != NULL; sec = sec->next) |
{ |
++sec_count; |
if (sec->spec.name == NULL) |
return; |
if (wildcardp (sec->spec.name)) |
{ |
++wild_name_count; |
if (!is_simple_wild (sec->spec.name)) |
return; |
} |
} |
/* The zero-spec case would be easy to optimize but it doesn't |
happen in practice. Likewise, more than 4 specs doesn't |
happen in practice. */ |
if (sec_count == 0 || sec_count > 4) |
return; |
/* Check that no two specs can match the same section. */ |
for (sec = ptr->section_list; sec != NULL; sec = sec->next) |
{ |
struct wildcard_list *sec2; |
for (sec2 = sec->next; sec2 != NULL; sec2 = sec2->next) |
{ |
if (wild_spec_can_overlap (sec->spec.name, sec2->spec.name)) |
return; |
} |
} |
signature = (sec_count << 8) + wild_name_count; |
switch (signature) |
{ |
case 0x0100: |
ptr->walk_wild_section_handler = walk_wild_section_specs1_wild0; |
break; |
case 0x0101: |
ptr->walk_wild_section_handler = walk_wild_section_specs1_wild1; |
break; |
case 0x0201: |
ptr->walk_wild_section_handler = walk_wild_section_specs2_wild1; |
break; |
case 0x0302: |
ptr->walk_wild_section_handler = walk_wild_section_specs3_wild2; |
break; |
case 0x0402: |
ptr->walk_wild_section_handler = walk_wild_section_specs4_wild2; |
break; |
default: |
return; |
} |
/* Now fill the data array with pointers to the specs, first the |
specs with non-wildcard names, then the specs with wildcard |
names. It's OK to process the specs in different order from the |
given order, because we've already determined that no section |
will match more than one spec. */ |
data_counter = 0; |
for (sec = ptr->section_list; sec != NULL; sec = sec->next) |
if (!wildcardp (sec->spec.name)) |
ptr->handler_data[data_counter++] = sec; |
for (sec = ptr->section_list; sec != NULL; sec = sec->next) |
if (wildcardp (sec->spec.name)) |
ptr->handler_data[data_counter++] = sec; |
} |
/* Handle a wild statement for a single file F. */ |
static void |
walk_wild_file (lang_wild_statement_type *s, |
lang_input_statement_type *f, |
callback_t callback, |
void *data) |
{ |
if (f->the_bfd == NULL |
|| ! bfd_check_format (f->the_bfd, bfd_archive)) |
walk_wild_section (s, f, callback, data); |
else |
{ |
bfd *member; |
/* This is an archive file. We must map each member of the |
archive separately. */ |
member = bfd_openr_next_archived_file (f->the_bfd, NULL); |
while (member != NULL) |
{ |
/* When lookup_name is called, it will call the add_symbols |
entry point for the archive. For each element of the |
archive which is included, BFD will call ldlang_add_file, |
which will set the usrdata field of the member to the |
lang_input_statement. */ |
if (member->usrdata != NULL) |
{ |
walk_wild_section (s, |
(lang_input_statement_type *) member->usrdata, |
callback, data); |
} |
member = bfd_openr_next_archived_file (f->the_bfd, member); |
} |
} |
} |
static void |
walk_wild (lang_wild_statement_type *s, callback_t callback, void *data) |
{ |
const char *file_spec = s->filename; |
char *p; |
if (file_spec == NULL) |
{ |
/* Perform the iteration over all files in the list. */ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
walk_wild_file (s, f, callback, data); |
} |
} |
else if ((p = archive_path (file_spec)) != NULL) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
if (input_statement_is_archive_path (file_spec, p, f)) |
walk_wild_file (s, f, callback, data); |
} |
} |
else if (wildcardp (file_spec)) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
if (fnmatch (file_spec, f->filename, 0) == 0) |
walk_wild_file (s, f, callback, data); |
} |
} |
else |
{ |
lang_input_statement_type *f; |
/* Perform the iteration over a single file. */ |
f = lookup_name (file_spec); |
if (f) |
walk_wild_file (s, f, callback, data); |
} |
} |
/* lang_for_each_statement walks the parse tree and calls the provided |
function for each node, except those inside output section statements |
with constraint set to -1. */ |
void |
lang_for_each_statement_worker (void (*func) (lang_statement_union_type *), |
lang_statement_union_type *s) |
{ |
for (; s != NULL; s = s->header.next) |
{ |
func (s); |
switch (s->header.type) |
{ |
case lang_constructors_statement_enum: |
lang_for_each_statement_worker (func, constructor_list.head); |
break; |
case lang_output_section_statement_enum: |
if (s->output_section_statement.constraint != -1) |
lang_for_each_statement_worker |
(func, s->output_section_statement.children.head); |
break; |
case lang_wild_statement_enum: |
lang_for_each_statement_worker (func, |
s->wild_statement.children.head); |
break; |
case lang_group_statement_enum: |
lang_for_each_statement_worker (func, |
s->group_statement.children.head); |
break; |
case lang_data_statement_enum: |
case lang_reloc_statement_enum: |
case lang_object_symbols_statement_enum: |
case lang_output_statement_enum: |
case lang_target_statement_enum: |
case lang_input_section_enum: |
case lang_input_statement_enum: |
case lang_assignment_statement_enum: |
case lang_padding_statement_enum: |
case lang_address_statement_enum: |
case lang_fill_statement_enum: |
case lang_insert_statement_enum: |
break; |
default: |
FAIL (); |
break; |
} |
} |
} |
void |
lang_for_each_statement (void (*func) (lang_statement_union_type *)) |
{ |
lang_for_each_statement_worker (func, statement_list.head); |
} |
/*----------------------------------------------------------------------*/ |
void |
lang_list_init (lang_statement_list_type *list) |
{ |
list->head = NULL; |
list->tail = &list->head; |
} |
void |
push_stat_ptr (lang_statement_list_type *new_ptr) |
{ |
if (stat_save_ptr >= stat_save + sizeof (stat_save) / sizeof (stat_save[0])) |
abort (); |
*stat_save_ptr++ = stat_ptr; |
stat_ptr = new_ptr; |
} |
void |
pop_stat_ptr (void) |
{ |
if (stat_save_ptr <= stat_save) |
abort (); |
stat_ptr = *--stat_save_ptr; |
} |
/* Build a new statement node for the parse tree. */ |
static lang_statement_union_type * |
new_statement (enum statement_enum type, |
size_t size, |
lang_statement_list_type *list) |
{ |
lang_statement_union_type *new_stmt; |
new_stmt = (lang_statement_union_type *) stat_alloc (size); |
new_stmt->header.type = type; |
new_stmt->header.next = NULL; |
lang_statement_append (list, new_stmt, &new_stmt->header.next); |
return new_stmt; |
} |
/* Build a new input file node for the language. There are several |
ways in which we treat an input file, eg, we only look at symbols, |
or prefix it with a -l etc. |
We can be supplied with requests for input files more than once; |
they may, for example be split over several lines like foo.o(.text) |
foo.o(.data) etc, so when asked for a file we check that we haven't |
got it already so we don't duplicate the bfd. */ |
static lang_input_statement_type * |
new_afile (const char *name, |
lang_input_file_enum_type file_type, |
const char *target, |
bfd_boolean add_to_list) |
{ |
lang_input_statement_type *p; |
lang_has_input_file = TRUE; |
if (add_to_list) |
p = (lang_input_statement_type *) new_stat (lang_input_statement, stat_ptr); |
else |
{ |
p = (lang_input_statement_type *) |
stat_alloc (sizeof (lang_input_statement_type)); |
p->header.type = lang_input_statement_enum; |
p->header.next = NULL; |
} |
memset (&p->the_bfd, 0, |
sizeof (*p) - offsetof (lang_input_statement_type, the_bfd)); |
p->target = target; |
p->flags.dynamic = input_flags.dynamic; |
p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic; |
p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular; |
p->flags.whole_archive = input_flags.whole_archive; |
p->flags.sysrooted = input_flags.sysrooted; |
if (file_type == lang_input_file_is_l_enum |
&& name[0] == ':' && name[1] != '\0') |
{ |
file_type = lang_input_file_is_search_file_enum; |
name = name + 1; |
} |
switch (file_type) |
{ |
case lang_input_file_is_symbols_only_enum: |
p->filename = name; |
p->local_sym_name = name; |
p->flags.real = TRUE; |
p->flags.just_syms = TRUE; |
break; |
case lang_input_file_is_fake_enum: |
p->filename = name; |
p->local_sym_name = name; |
break; |
case lang_input_file_is_l_enum: |
p->filename = name; |
p->local_sym_name = concat ("-l", name, (const char *) NULL); |
p->flags.maybe_archive = TRUE; |
p->flags.real = TRUE; |
p->flags.search_dirs = TRUE; |
break; |
case lang_input_file_is_marker_enum: |
p->filename = name; |
p->local_sym_name = name; |
p->flags.search_dirs = TRUE; |
break; |
case lang_input_file_is_search_file_enum: |
p->filename = name; |
p->local_sym_name = name; |
p->flags.real = TRUE; |
p->flags.search_dirs = TRUE; |
break; |
case lang_input_file_is_file_enum: |
p->filename = name; |
p->local_sym_name = name; |
p->flags.real = TRUE; |
break; |
default: |
FAIL (); |
} |
lang_statement_append (&input_file_chain, |
(lang_statement_union_type *) p, |
&p->next_real_file); |
return p; |
} |
lang_input_statement_type * |
lang_add_input_file (const char *name, |
lang_input_file_enum_type file_type, |
const char *target) |
{ |
return new_afile (name, file_type, target, TRUE); |
} |
struct out_section_hash_entry |
{ |
struct bfd_hash_entry root; |
lang_statement_union_type s; |
}; |
/* The hash table. */ |
static struct bfd_hash_table output_section_statement_table; |
/* Support routines for the hash table used by lang_output_section_find, |
initialize the table, fill in an entry and remove the table. */ |
static struct bfd_hash_entry * |
output_section_statement_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
lang_output_section_statement_type **nextp; |
struct out_section_hash_entry *ret; |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) bfd_hash_allocate (table, |
sizeof (*ret)); |
if (entry == NULL) |
return entry; |
} |
entry = bfd_hash_newfunc (entry, table, string); |
if (entry == NULL) |
return entry; |
ret = (struct out_section_hash_entry *) entry; |
memset (&ret->s, 0, sizeof (ret->s)); |
ret->s.header.type = lang_output_section_statement_enum; |
ret->s.output_section_statement.subsection_alignment = -1; |
ret->s.output_section_statement.section_alignment = -1; |
ret->s.output_section_statement.block_value = 1; |
lang_list_init (&ret->s.output_section_statement.children); |
lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next); |
/* For every output section statement added to the list, except the |
first one, lang_output_section_statement.tail points to the "next" |
field of the last element of the list. */ |
if (lang_output_section_statement.head != NULL) |
ret->s.output_section_statement.prev |
= ((lang_output_section_statement_type *) |
((char *) lang_output_section_statement.tail |
- offsetof (lang_output_section_statement_type, next))); |
/* GCC's strict aliasing rules prevent us from just casting the |
address, so we store the pointer in a variable and cast that |
instead. */ |
nextp = &ret->s.output_section_statement.next; |
lang_statement_append (&lang_output_section_statement, |
&ret->s, |
(lang_statement_union_type **) nextp); |
return &ret->root; |
} |
static void |
output_section_statement_table_init (void) |
{ |
if (!bfd_hash_table_init_n (&output_section_statement_table, |
output_section_statement_newfunc, |
sizeof (struct out_section_hash_entry), |
61)) |
einfo (_("%P%F: can not create hash table: %E\n")); |
} |
static void |
output_section_statement_table_free (void) |
{ |
bfd_hash_table_free (&output_section_statement_table); |
} |
/* Build enough state so that the parser can build its tree. */ |
void |
lang_init (void) |
{ |
obstack_begin (&stat_obstack, 1000); |
stat_ptr = &statement_list; |
output_section_statement_table_init (); |
lang_list_init (stat_ptr); |
lang_list_init (&input_file_chain); |
lang_list_init (&lang_output_section_statement); |
lang_list_init (&file_chain); |
first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum, |
NULL); |
abs_output_section = |
lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, TRUE); |
abs_output_section->bfd_section = bfd_abs_section_ptr; |
/* The value "3" is ad-hoc, somewhat related to the expected number of |
DEFINED expressions in a linker script. For most default linker |
scripts, there are none. Why a hash table then? Well, it's somewhat |
simpler to re-use working machinery than using a linked list in terms |
of code-complexity here in ld, besides the initialization which just |
looks like other code here. */ |
if (!bfd_hash_table_init_n (&lang_definedness_table, |
lang_definedness_newfunc, |
sizeof (struct lang_definedness_hash_entry), |
3)) |
einfo (_("%P%F: can not create hash table: %E\n")); |
} |
void |
lang_finish (void) |
{ |
bfd_link_hash_table_free (link_info.output_bfd, link_info.hash); |
bfd_hash_table_free (&lang_definedness_table); |
output_section_statement_table_free (); |
} |
/*---------------------------------------------------------------------- |
A region is an area of memory declared with the |
MEMORY { name:org=exp, len=exp ... } |
syntax. |
We maintain a list of all the regions here. |
If no regions are specified in the script, then the default is used |
which is created when looked up to be the entire data space. |
If create is true we are creating a region inside a MEMORY block. |
In this case it is probably an error to create a region that has |
already been created. If we are not inside a MEMORY block it is |
dubious to use an undeclared region name (except DEFAULT_MEMORY_REGION) |
and so we issue a warning. |
Each region has at least one name. The first name is either |
DEFAULT_MEMORY_REGION or the name given in the MEMORY block. You can add |
alias names to an existing region within a script with |
REGION_ALIAS (alias, region_name). Each name corresponds to at most one |
region. */ |
static lang_memory_region_type *lang_memory_region_list; |
static lang_memory_region_type **lang_memory_region_list_tail |
= &lang_memory_region_list; |
lang_memory_region_type * |
lang_memory_region_lookup (const char *const name, bfd_boolean create) |
{ |
lang_memory_region_name *n; |
lang_memory_region_type *r; |
lang_memory_region_type *new_region; |
/* NAME is NULL for LMA memspecs if no region was specified. */ |
if (name == NULL) |
return NULL; |
for (r = lang_memory_region_list; r != NULL; r = r->next) |
for (n = &r->name_list; n != NULL; n = n->next) |
if (strcmp (n->name, name) == 0) |
{ |
if (create) |
einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"), |
NULL, name); |
return r; |
} |
if (!create && strcmp (name, DEFAULT_MEMORY_REGION)) |
einfo (_("%P:%S: warning: memory region `%s' not declared\n"), |
NULL, name); |
new_region = (lang_memory_region_type *) |
stat_alloc (sizeof (lang_memory_region_type)); |
new_region->name_list.name = xstrdup (name); |
new_region->name_list.next = NULL; |
new_region->next = NULL; |
new_region->origin = 0; |
new_region->length = ~(bfd_size_type) 0; |
new_region->current = 0; |
new_region->last_os = NULL; |
new_region->flags = 0; |
new_region->not_flags = 0; |
new_region->had_full_message = FALSE; |
*lang_memory_region_list_tail = new_region; |
lang_memory_region_list_tail = &new_region->next; |
return new_region; |
} |
void |
lang_memory_region_alias (const char * alias, const char * region_name) |
{ |
lang_memory_region_name * n; |
lang_memory_region_type * r; |
lang_memory_region_type * region; |
/* The default region must be unique. This ensures that it is not necessary |
to iterate through the name list if someone wants the check if a region is |
the default memory region. */ |
if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0 |
|| strcmp (alias, DEFAULT_MEMORY_REGION) == 0) |
einfo (_("%F%P:%S: error: alias for default memory region\n"), NULL); |
/* Look for the target region and check if the alias is not already |
in use. */ |
region = NULL; |
for (r = lang_memory_region_list; r != NULL; r = r->next) |
for (n = &r->name_list; n != NULL; n = n->next) |
{ |
if (region == NULL && strcmp (n->name, region_name) == 0) |
region = r; |
if (strcmp (n->name, alias) == 0) |
einfo (_("%F%P:%S: error: redefinition of memory region " |
"alias `%s'\n"), |
NULL, alias); |
} |
/* Check if the target region exists. */ |
if (region == NULL) |
einfo (_("%F%P:%S: error: memory region `%s' " |
"for alias `%s' does not exist\n"), |
NULL, region_name, alias); |
/* Add alias to region name list. */ |
n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name)); |
n->name = xstrdup (alias); |
n->next = region->name_list.next; |
region->name_list.next = n; |
} |
static lang_memory_region_type * |
lang_memory_default (asection * section) |
{ |
lang_memory_region_type *p; |
flagword sec_flags = section->flags; |
/* Override SEC_DATA to mean a writable section. */ |
if ((sec_flags & (SEC_ALLOC | SEC_READONLY | SEC_CODE)) == SEC_ALLOC) |
sec_flags |= SEC_DATA; |
for (p = lang_memory_region_list; p != NULL; p = p->next) |
{ |
if ((p->flags & sec_flags) != 0 |
&& (p->not_flags & sec_flags) == 0) |
{ |
return p; |
} |
} |
return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); |
} |
/* Find or create an output_section_statement with the given NAME. |
If CONSTRAINT is non-zero match one with that constraint, otherwise |
match any non-negative constraint. If CREATE, always make a |
new output_section_statement for SPECIAL CONSTRAINT. */ |
lang_output_section_statement_type * |
lang_output_section_statement_lookup (const char *name, |
int constraint, |
bfd_boolean create) |
{ |
struct out_section_hash_entry *entry; |
entry = ((struct out_section_hash_entry *) |
bfd_hash_lookup (&output_section_statement_table, name, |
create, FALSE)); |
if (entry == NULL) |
{ |
if (create) |
einfo (_("%P%F: failed creating section `%s': %E\n"), name); |
return NULL; |
} |
if (entry->s.output_section_statement.name != NULL) |
{ |
/* We have a section of this name, but it might not have the correct |
constraint. */ |
struct out_section_hash_entry *last_ent; |
name = entry->s.output_section_statement.name; |
if (create && constraint == SPECIAL) |
/* Not traversing to the end reverses the order of the second |
and subsequent SPECIAL sections in the hash table chain, |
but that shouldn't matter. */ |
last_ent = entry; |
else |
do |
{ |
if (constraint == entry->s.output_section_statement.constraint |
|| (constraint == 0 |
&& entry->s.output_section_statement.constraint >= 0)) |
return &entry->s.output_section_statement; |
last_ent = entry; |
entry = (struct out_section_hash_entry *) entry->root.next; |
} |
while (entry != NULL |
&& name == entry->s.output_section_statement.name); |
if (!create) |
return NULL; |
entry |
= ((struct out_section_hash_entry *) |
output_section_statement_newfunc (NULL, |
&output_section_statement_table, |
name)); |
if (entry == NULL) |
{ |
einfo (_("%P%F: failed creating section `%s': %E\n"), name); |
return NULL; |
} |
entry->root = last_ent->root; |
last_ent->root.next = &entry->root; |
} |
entry->s.output_section_statement.name = name; |
entry->s.output_section_statement.constraint = constraint; |
return &entry->s.output_section_statement; |
} |
/* Find the next output_section_statement with the same name as OS. |
If CONSTRAINT is non-zero, find one with that constraint otherwise |
match any non-negative constraint. */ |
lang_output_section_statement_type * |
next_matching_output_section_statement (lang_output_section_statement_type *os, |
int constraint) |
{ |
/* All output_section_statements are actually part of a |
struct out_section_hash_entry. */ |
struct out_section_hash_entry *entry = (struct out_section_hash_entry *) |
((char *) os |
- offsetof (struct out_section_hash_entry, s.output_section_statement)); |
const char *name = os->name; |
ASSERT (name == entry->root.string); |
do |
{ |
entry = (struct out_section_hash_entry *) entry->root.next; |
if (entry == NULL |
|| name != entry->s.output_section_statement.name) |
return NULL; |
} |
while (constraint != entry->s.output_section_statement.constraint |
&& (constraint != 0 |
|| entry->s.output_section_statement.constraint < 0)); |
return &entry->s.output_section_statement; |
} |
/* A variant of lang_output_section_find used by place_orphan. |
Returns the output statement that should precede a new output |
statement for SEC. If an exact match is found on certain flags, |
sets *EXACT too. */ |
lang_output_section_statement_type * |
lang_output_section_find_by_flags (const asection *sec, |
lang_output_section_statement_type **exact, |
lang_match_sec_type_func match_type) |
{ |
lang_output_section_statement_type *first, *look, *found; |
flagword flags; |
/* We know the first statement on this list is *ABS*. May as well |
skip it. */ |
first = &lang_output_section_statement.head->output_section_statement; |
first = first->next; |
/* First try for an exact match. */ |
found = NULL; |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY |
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
if (found != NULL) |
{ |
if (exact != NULL) |
*exact = found; |
return found; |
} |
if ((sec->flags & SEC_CODE) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
{ |
/* Try for a rw code section. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
} |
else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
{ |
/* .rodata can go after .text, .sdata2 after .rodata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_READONLY | SEC_SMALL_DATA)) |
|| (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_READONLY)) |
&& !(look->flags & SEC_SMALL_DATA)) |
|| (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC)) |
&& (look->flags & SEC_THREAD_LOCAL) |
&& (!(flags & SEC_LOAD) |
|| (look->flags & SEC_LOAD)))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_SMALL_DATA) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
{ |
/* .sdata goes after .data, .sbss after .sdata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_THREAD_LOCAL)) |
|| ((look->flags & SEC_SMALL_DATA) |
&& !(sec->flags & SEC_HAS_CONTENTS))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_HAS_CONTENTS) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
{ |
/* .data goes after .rodata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_ALLOC) != 0) |
{ |
/* .bss goes after any other alloc section. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & SEC_ALLOC)) |
found = look; |
} |
} |
else |
{ |
/* non-alloc go last. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
if (look->bfd_section != NULL) |
flags = look->bfd_section->flags; |
flags ^= sec->flags; |
if (!(flags & SEC_DEBUGGING)) |
found = look; |
} |
return found; |
} |
if (found || !match_type) |
return found; |
return lang_output_section_find_by_flags (sec, NULL, NULL); |
} |
/* Find the last output section before given output statement. |
Used by place_orphan. */ |
static asection * |
output_prev_sec_find (lang_output_section_statement_type *os) |
{ |
lang_output_section_statement_type *lookup; |
for (lookup = os->prev; lookup != NULL; lookup = lookup->prev) |
{ |
if (lookup->constraint < 0) |
continue; |
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) |
return lookup->bfd_section; |
} |
return NULL; |
} |
/* Look for a suitable place for a new output section statement. The |
idea is to skip over anything that might be inside a SECTIONS {} |
statement in a script, before we find another output section |
statement. Assignments to "dot" before an output section statement |
are assumed to belong to it, except in two cases; The first |
assignment to dot, and assignments before non-alloc sections. |
Otherwise we might put an orphan before . = . + SIZEOF_HEADERS or |
similar assignments that set the initial address, or we might |
insert non-alloc note sections among assignments setting end of |
image symbols. */ |
static lang_statement_union_type ** |
insert_os_after (lang_output_section_statement_type *after) |
{ |
lang_statement_union_type **where; |
lang_statement_union_type **assign = NULL; |
bfd_boolean ignore_first; |
ignore_first |
= after == &lang_output_section_statement.head->output_section_statement; |
for (where = &after->header.next; |
*where != NULL; |
where = &(*where)->header.next) |
{ |
switch ((*where)->header.type) |
{ |
case lang_assignment_statement_enum: |
if (assign == NULL) |
{ |
lang_assignment_statement_type *ass; |
ass = &(*where)->assignment_statement; |
if (ass->exp->type.node_class != etree_assert |
&& ass->exp->assign.dst[0] == '.' |
&& ass->exp->assign.dst[1] == 0 |
&& !ignore_first) |
assign = where; |
} |
ignore_first = FALSE; |
continue; |
case lang_wild_statement_enum: |
case lang_input_section_enum: |
case lang_object_symbols_statement_enum: |
case lang_fill_statement_enum: |
case lang_data_statement_enum: |
case lang_reloc_statement_enum: |
case lang_padding_statement_enum: |
case lang_constructors_statement_enum: |
assign = NULL; |
continue; |
case lang_output_section_statement_enum: |
if (assign != NULL) |
{ |
asection *s = (*where)->output_section_statement.bfd_section; |
if (s == NULL |
|| s->map_head.s == NULL |
|| (s->flags & SEC_ALLOC) != 0) |
where = assign; |
} |
break; |
case lang_input_statement_enum: |
case lang_address_statement_enum: |
case lang_target_statement_enum: |
case lang_output_statement_enum: |
case lang_group_statement_enum: |
case lang_insert_statement_enum: |
continue; |
} |
break; |
} |
return where; |
} |
lang_output_section_statement_type * |
lang_insert_orphan (asection *s, |
const char *secname, |
int constraint, |
lang_output_section_statement_type *after, |
struct orphan_save *place, |
etree_type *address, |
lang_statement_list_type *add_child) |
{ |
lang_statement_list_type add; |
const char *ps; |
lang_output_section_statement_type *os; |
lang_output_section_statement_type **os_tail; |
/* If we have found an appropriate place for the output section |
statements for this orphan, add them to our own private list, |
inserting them later into the global statement list. */ |
if (after != NULL) |
{ |
lang_list_init (&add); |
push_stat_ptr (&add); |
} |
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
address = exp_intop (0); |
os_tail = ((lang_output_section_statement_type **) |
lang_output_section_statement.tail); |
os = lang_enter_output_section_statement (secname, address, normal_section, |
NULL, NULL, NULL, constraint, 0); |
ps = NULL; |
if (config.build_constructors && *os_tail == os) |
{ |
/* If the name of the section is representable in C, then create |
symbols to mark the start and the end of the section. */ |
for (ps = secname; *ps != '\0'; ps++) |
if (! ISALNUM ((unsigned char) *ps) && *ps != '_') |
break; |
if (*ps == '\0') |
{ |
char *symname; |
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); |
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); |
sprintf (symname + (symname[0] != 0), "__start_%s", secname); |
lang_add_assignment (exp_provide (symname, |
exp_nameop (NAME, "."), |
FALSE)); |
} |
} |
if (add_child == NULL) |
add_child = &os->children; |
lang_add_section (add_child, s, NULL, os); |
if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0) |
{ |
const char *region = (after->region |
? after->region->name_list.name |
: DEFAULT_MEMORY_REGION); |
const char *lma_region = (after->lma_region |
? after->lma_region->name_list.name |
: NULL); |
lang_leave_output_section_statement (NULL, region, after->phdrs, |
lma_region); |
} |
else |
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL, |
NULL); |
if (ps != NULL && *ps == '\0') |
{ |
char *symname; |
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); |
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); |
sprintf (symname + (symname[0] != 0), "__stop_%s", secname); |
lang_add_assignment (exp_provide (symname, |
exp_nameop (NAME, "."), |
FALSE)); |
} |
/* Restore the global list pointer. */ |
if (after != NULL) |
pop_stat_ptr (); |
if (after != NULL && os->bfd_section != NULL) |
{ |
asection *snew, *as; |
snew = os->bfd_section; |
/* Shuffle the bfd section list to make the output file look |
neater. This is really only cosmetic. */ |
if (place->section == NULL |
&& after != (&lang_output_section_statement.head |
->output_section_statement)) |
{ |
asection *bfd_section = after->bfd_section; |
/* If the output statement hasn't been used to place any input |
sections (and thus doesn't have an output bfd_section), |
look for the closest prior output statement having an |
output section. */ |
if (bfd_section == NULL) |
bfd_section = output_prev_sec_find (after); |
if (bfd_section != NULL && bfd_section != snew) |
place->section = &bfd_section->next; |
} |
if (place->section == NULL) |
place->section = &link_info.output_bfd->sections; |
as = *place->section; |
if (!as) |
{ |
/* Put the section at the end of the list. */ |
/* Unlink the section. */ |
bfd_section_list_remove (link_info.output_bfd, snew); |
/* Now tack it back on in the right place. */ |
bfd_section_list_append (link_info.output_bfd, snew); |
} |
else if (as != snew && as->prev != snew) |
{ |
/* Unlink the section. */ |
bfd_section_list_remove (link_info.output_bfd, snew); |
/* Now tack it back on in the right place. */ |
bfd_section_list_insert_before (link_info.output_bfd, as, snew); |
} |
/* Save the end of this list. Further ophans of this type will |
follow the one we've just added. */ |
place->section = &snew->next; |
/* The following is non-cosmetic. We try to put the output |
statements in some sort of reasonable order here, because they |
determine the final load addresses of the orphan sections. |
In addition, placing output statements in the wrong order may |
require extra segments. For instance, given a typical |
situation of all read-only sections placed in one segment and |
following that a segment containing all the read-write |
sections, we wouldn't want to place an orphan read/write |
section before or amongst the read-only ones. */ |
if (add.head != NULL) |
{ |
lang_output_section_statement_type *newly_added_os; |
if (place->stmt == NULL) |
{ |
lang_statement_union_type **where = insert_os_after (after); |
*add.tail = *where; |
*where = add.head; |
place->os_tail = &after->next; |
} |
else |
{ |
/* Put it after the last orphan statement we added. */ |
*add.tail = *place->stmt; |
*place->stmt = add.head; |
} |
/* Fix the global list pointer if we happened to tack our |
new list at the tail. */ |
if (*stat_ptr->tail == add.head) |
stat_ptr->tail = add.tail; |
/* Save the end of this list. */ |
place->stmt = add.tail; |
/* Do the same for the list of output section statements. */ |
newly_added_os = *os_tail; |
*os_tail = NULL; |
newly_added_os->prev = (lang_output_section_statement_type *) |
((char *) place->os_tail |
- offsetof (lang_output_section_statement_type, next)); |
newly_added_os->next = *place->os_tail; |
if (newly_added_os->next != NULL) |
newly_added_os->next->prev = newly_added_os; |
*place->os_tail = newly_added_os; |
place->os_tail = &newly_added_os->next; |
/* Fixing the global list pointer here is a little different. |
We added to the list in lang_enter_output_section_statement, |
trimmed off the new output_section_statment above when |
assigning *os_tail = NULL, but possibly added it back in |
the same place when assigning *place->os_tail. */ |
if (*os_tail == NULL) |
lang_output_section_statement.tail |
= (lang_statement_union_type **) os_tail; |
} |
} |
return os; |
} |
static void |
lang_map_flags (flagword flag) |
{ |
if (flag & SEC_ALLOC) |
minfo ("a"); |
if (flag & SEC_CODE) |
minfo ("x"); |
if (flag & SEC_READONLY) |
minfo ("r"); |
if (flag & SEC_DATA) |
minfo ("w"); |
if (flag & SEC_LOAD) |
minfo ("l"); |
} |
void |
lang_map (void) |
{ |
lang_memory_region_type *m; |
bfd_boolean dis_header_printed = FALSE; |
bfd *p; |
LANG_FOR_EACH_INPUT_STATEMENT (file) |
{ |
asection *s; |
if ((file->the_bfd->flags & (BFD_LINKER_CREATED | DYNAMIC)) != 0 |
|| file->flags.just_syms) |
continue; |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
if ((s->output_section == NULL |
|| s->output_section->owner != link_info.output_bfd) |
&& (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0) |
{ |
if (! dis_header_printed) |
{ |
fprintf (config.map_file, _("\nDiscarded input sections\n\n")); |
dis_header_printed = TRUE; |
} |
print_input_section (s, TRUE); |
} |
} |
minfo (_("\nMemory Configuration\n\n")); |
fprintf (config.map_file, "%-16s %-18s %-18s %s\n", |
_("Name"), _("Origin"), _("Length"), _("Attributes")); |
for (m = lang_memory_region_list; m != NULL; m = m->next) |
{ |
char buf[100]; |
int len; |
fprintf (config.map_file, "%-16s ", m->name_list.name); |
sprintf_vma (buf, m->origin); |
minfo ("0x%s ", buf); |
len = strlen (buf); |
while (len < 16) |
{ |
print_space (); |
++len; |
} |
minfo ("0x%V", m->length); |
if (m->flags || m->not_flags) |
{ |
#ifndef BFD64 |
minfo (" "); |
#endif |
if (m->flags) |
{ |
print_space (); |
lang_map_flags (m->flags); |
} |
if (m->not_flags) |
{ |
minfo (" !"); |
lang_map_flags (m->not_flags); |
} |
} |
print_nl (); |
} |
fprintf (config.map_file, _("\nLinker script and memory map\n\n")); |
if (! link_info.reduce_memory_overheads) |
{ |
obstack_begin (&map_obstack, 1000); |
for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next) |
bfd_map_over_sections (p, init_map_userdata, 0); |
bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0); |
} |
lang_statement_iteration ++; |
print_statements (); |
} |
static void |
init_map_userdata (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec, |
void *data ATTRIBUTE_UNUSED) |
{ |
fat_section_userdata_type *new_data |
= ((fat_section_userdata_type *) (stat_alloc |
(sizeof (fat_section_userdata_type)))); |
ASSERT (get_userdata (sec) == NULL); |
get_userdata (sec) = new_data; |
new_data->map_symbol_def_tail = &new_data->map_symbol_def_head; |
new_data->map_symbol_def_count = 0; |
} |
static bfd_boolean |
sort_def_symbol (struct bfd_link_hash_entry *hash_entry, |
void *info ATTRIBUTE_UNUSED) |
{ |
if (hash_entry->type == bfd_link_hash_defined |
|| hash_entry->type == bfd_link_hash_defweak) |
{ |
struct fat_user_section_struct *ud; |
struct map_symbol_def *def; |
ud = (struct fat_user_section_struct *) |
get_userdata (hash_entry->u.def.section); |
if (! ud) |
{ |
/* ??? What do we have to do to initialize this beforehand? */ |
/* The first time we get here is bfd_abs_section... */ |
init_map_userdata (0, hash_entry->u.def.section, 0); |
ud = (struct fat_user_section_struct *) |
get_userdata (hash_entry->u.def.section); |
} |
else if (!ud->map_symbol_def_tail) |
ud->map_symbol_def_tail = &ud->map_symbol_def_head; |
def = (struct map_symbol_def *) obstack_alloc (&map_obstack, sizeof *def); |
def->entry = hash_entry; |
*(ud->map_symbol_def_tail) = def; |
ud->map_symbol_def_tail = &def->next; |
ud->map_symbol_def_count++; |
} |
return TRUE; |
} |
/* Initialize an output section. */ |
static void |
init_os (lang_output_section_statement_type *s, flagword flags) |
{ |
if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) |
einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME); |
if (s->constraint != SPECIAL) |
s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name); |
if (s->bfd_section == NULL) |
s->bfd_section = bfd_make_section_anyway_with_flags (link_info.output_bfd, |
s->name, flags); |
if (s->bfd_section == NULL) |
{ |
einfo (_("%P%F: output format %s cannot represent section called %s\n"), |
link_info.output_bfd->xvec->name, s->name); |
} |
s->bfd_section->output_section = s->bfd_section; |
s->bfd_section->output_offset = 0; |
if (!link_info.reduce_memory_overheads) |
{ |
fat_section_userdata_type *new_userdata = (fat_section_userdata_type *) |
stat_alloc (sizeof (fat_section_userdata_type)); |
memset (new_userdata, 0, sizeof (fat_section_userdata_type)); |
get_userdata (s->bfd_section) = new_userdata; |
} |
/* If there is a base address, make sure that any sections it might |
mention are initialized. */ |
if (s->addr_tree != NULL) |
exp_init_os (s->addr_tree); |
if (s->load_base != NULL) |
exp_init_os (s->load_base); |
/* If supplied an alignment, set it. */ |
if (s->section_alignment != -1) |
s->bfd_section->alignment_power = s->section_alignment; |
} |
/* Make sure that all output sections mentioned in an expression are |
initialized. */ |
static void |
exp_init_os (etree_type *exp) |
{ |
switch (exp->type.node_class) |
{ |
case etree_assign: |
case etree_provide: |
exp_init_os (exp->assign.src); |
break; |
case etree_binary: |
exp_init_os (exp->binary.lhs); |
exp_init_os (exp->binary.rhs); |
break; |
case etree_trinary: |
exp_init_os (exp->trinary.cond); |
exp_init_os (exp->trinary.lhs); |
exp_init_os (exp->trinary.rhs); |
break; |
case etree_assert: |
exp_init_os (exp->assert_s.child); |
break; |
case etree_unary: |
exp_init_os (exp->unary.child); |
break; |
case etree_name: |
switch (exp->type.node_code) |
{ |
case ADDR: |
case LOADADDR: |
case SIZEOF: |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_find (exp->name.name); |
if (os != NULL && os->bfd_section == NULL) |
init_os (os, 0); |
} |
} |
break; |
default: |
break; |
} |
} |
static void |
section_already_linked (bfd *abfd, asection *sec, void *data) |
{ |
lang_input_statement_type *entry = (lang_input_statement_type *) data; |
/* If we are only reading symbols from this object, then we want to |
discard all sections. */ |
if (entry->flags.just_syms) |
{ |
bfd_link_just_syms (abfd, sec, &link_info); |
return; |
} |
if (!(abfd->flags & DYNAMIC)) |
bfd_section_already_linked (abfd, sec, &link_info); |
} |
/* The wild routines. |
These expand statements like *(.text) and foo.o to a list of |
explicit actions, like foo.o(.text), bar.o(.text) and |
foo.o(.text, .data). */ |
/* Add SECTION to the output section OUTPUT. Do this by creating a |
lang_input_section statement which is placed at PTR. */ |
void |
lang_add_section (lang_statement_list_type *ptr, |
asection *section, |
struct flag_info *sflag_info, |
lang_output_section_statement_type *output) |
{ |
flagword flags = section->flags; |
bfd_boolean discard; |
lang_input_section_type *new_section; |
bfd *abfd = link_info.output_bfd; |
/* Discard sections marked with SEC_EXCLUDE. */ |
discard = (flags & SEC_EXCLUDE) != 0; |
/* Discard input sections which are assigned to a section named |
DISCARD_SECTION_NAME. */ |
if (strcmp (output->name, DISCARD_SECTION_NAME) == 0) |
discard = TRUE; |
/* Discard debugging sections if we are stripping debugging |
information. */ |
if ((link_info.strip == strip_debugger || link_info.strip == strip_all) |
&& (flags & SEC_DEBUGGING) != 0) |
discard = TRUE; |
if (discard) |
{ |
if (section->output_section == NULL) |
{ |
/* This prevents future calls from assigning this section. */ |
section->output_section = bfd_abs_section_ptr; |
} |
return; |
} |
if (sflag_info) |
{ |
bfd_boolean keep; |
keep = bfd_lookup_section_flags (&link_info, sflag_info, section); |
if (!keep) |
return; |
} |
if (section->output_section != NULL) |
return; |
/* We don't copy the SEC_NEVER_LOAD flag from an input section |
to an output section, because we want to be able to include a |
SEC_NEVER_LOAD section in the middle of an otherwise loaded |
section (I don't know why we want to do this, but we do). |
build_link_order in ldwrite.c handles this case by turning |
the embedded SEC_NEVER_LOAD section into a fill. */ |
flags &= ~ SEC_NEVER_LOAD; |
/* If final link, don't copy the SEC_LINK_ONCE flags, they've |
already been processed. One reason to do this is that on pe |
format targets, .text$foo sections go into .text and it's odd |
to see .text with SEC_LINK_ONCE set. */ |
if (!link_info.relocatable) |
flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC); |
switch (output->sectype) |
{ |
case normal_section: |
case overlay_section: |
break; |
case noalloc_section: |
flags &= ~SEC_ALLOC; |
break; |
case noload_section: |
flags &= ~SEC_LOAD; |
flags |= SEC_NEVER_LOAD; |
/* Unfortunately GNU ld has managed to evolve two different |
meanings to NOLOAD in scripts. ELF gets a .bss style noload, |
alloc, no contents section. All others get a noload, noalloc |
section. */ |
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) |
flags &= ~SEC_HAS_CONTENTS; |
else |
flags &= ~SEC_ALLOC; |
break; |
} |
if (output->bfd_section == NULL) |
init_os (output, flags); |
/* If SEC_READONLY is not set in the input section, then clear |
it from the output section. */ |
output->bfd_section->flags &= flags | ~SEC_READONLY; |
if (output->bfd_section->linker_has_input) |
{ |
/* Only set SEC_READONLY flag on the first input section. */ |
flags &= ~ SEC_READONLY; |
/* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */ |
if ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS)) |
!= (flags & (SEC_MERGE | SEC_STRINGS)) |
|| ((flags & SEC_MERGE) != 0 |
&& output->bfd_section->entsize != section->entsize)) |
{ |
output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS); |
flags &= ~ (SEC_MERGE | SEC_STRINGS); |
} |
} |
output->bfd_section->flags |= flags; |
if (!output->bfd_section->linker_has_input) |
{ |
output->bfd_section->linker_has_input = 1; |
/* This must happen after flags have been updated. The output |
section may have been created before we saw its first input |
section, eg. for a data statement. */ |
bfd_init_private_section_data (section->owner, section, |
link_info.output_bfd, |
output->bfd_section, |
&link_info); |
if ((flags & SEC_MERGE) != 0) |
output->bfd_section->entsize = section->entsize; |
} |
if ((flags & SEC_TIC54X_BLOCK) != 0 |
&& bfd_get_arch (section->owner) == bfd_arch_tic54x) |
{ |
/* FIXME: This value should really be obtained from the bfd... */ |
output->block_value = 128; |
} |
if (section->alignment_power > output->bfd_section->alignment_power) |
output->bfd_section->alignment_power = section->alignment_power; |
section->output_section = output->bfd_section; |
if (!link_info.relocatable |
&& !stripped_excluded_sections) |
{ |
asection *s = output->bfd_section->map_tail.s; |
output->bfd_section->map_tail.s = section; |
section->map_head.s = NULL; |
section->map_tail.s = s; |
if (s != NULL) |
s->map_head.s = section; |
else |
output->bfd_section->map_head.s = section; |
} |
/* Add a section reference to the list. */ |
new_section = new_stat (lang_input_section, ptr); |
new_section->section = section; |
} |
/* Handle wildcard sorting. This returns the lang_input_section which |
should follow the one we are going to create for SECTION and FILE, |
based on the sorting requirements of WILD. It returns NULL if the |
new section should just go at the end of the current list. */ |
static lang_statement_union_type * |
wild_sort (lang_wild_statement_type *wild, |
struct wildcard_list *sec, |
lang_input_statement_type *file, |
asection *section) |
{ |
lang_statement_union_type *l; |
if (!wild->filenames_sorted |
&& (sec == NULL || sec->spec.sorted == none)) |
return NULL; |
for (l = wild->children.head; l != NULL; l = l->header.next) |
{ |
lang_input_section_type *ls; |
if (l->header.type != lang_input_section_enum) |
continue; |
ls = &l->input_section; |
/* Sorting by filename takes precedence over sorting by section |
name. */ |
if (wild->filenames_sorted) |
{ |
const char *fn, *ln; |
bfd_boolean fa, la; |
int i; |
/* The PE support for the .idata section as generated by |
dlltool assumes that files will be sorted by the name of |
the archive and then the name of the file within the |
archive. */ |
if (file->the_bfd != NULL |
&& bfd_my_archive (file->the_bfd) != NULL) |
{ |
fn = bfd_get_filename (bfd_my_archive (file->the_bfd)); |
fa = TRUE; |
} |
else |
{ |
fn = file->filename; |
fa = FALSE; |
} |
if (bfd_my_archive (ls->section->owner) != NULL) |
{ |
ln = bfd_get_filename (bfd_my_archive (ls->section->owner)); |
la = TRUE; |
} |
else |
{ |
ln = ls->section->owner->filename; |
la = FALSE; |
} |
i = filename_cmp (fn, ln); |
if (i > 0) |
continue; |
else if (i < 0) |
break; |
if (fa || la) |
{ |
if (fa) |
fn = file->filename; |
if (la) |
ln = ls->section->owner->filename; |
i = filename_cmp (fn, ln); |
if (i > 0) |
continue; |
else if (i < 0) |
break; |
} |
} |
/* Here either the files are not sorted by name, or we are |
looking at the sections for this file. */ |
if (sec != NULL |
&& sec->spec.sorted != none |
&& sec->spec.sorted != by_none) |
if (compare_section (sec->spec.sorted, section, ls->section) < 0) |
break; |
} |
return l; |
} |
/* Expand a wild statement for a particular FILE. SECTION may be |
NULL, in which case it is a wild card. */ |
static void |
output_section_callback (lang_wild_statement_type *ptr, |
struct wildcard_list *sec, |
asection *section, |
struct flag_info *sflag_info, |
lang_input_statement_type *file, |
void *output) |
{ |
lang_statement_union_type *before; |
lang_output_section_statement_type *os; |
os = (lang_output_section_statement_type *) output; |
/* Exclude sections that match UNIQUE_SECTION_LIST. */ |
if (unique_section_p (section, os)) |
return; |
before = wild_sort (ptr, sec, file, section); |
/* Here BEFORE points to the lang_input_section which |
should follow the one we are about to add. If BEFORE |
is NULL, then the section should just go at the end |
of the current list. */ |
if (before == NULL) |
lang_add_section (&ptr->children, section, sflag_info, os); |
else |
{ |
lang_statement_list_type list; |
lang_statement_union_type **pp; |
lang_list_init (&list); |
lang_add_section (&list, section, sflag_info, os); |
/* If we are discarding the section, LIST.HEAD will |
be NULL. */ |
if (list.head != NULL) |
{ |
ASSERT (list.head->header.next == NULL); |
for (pp = &ptr->children.head; |
*pp != before; |
pp = &(*pp)->header.next) |
ASSERT (*pp != NULL); |
list.head->header.next = *pp; |
*pp = list.head; |
} |
} |
} |
/* Check if all sections in a wild statement for a particular FILE |
are readonly. */ |
static void |
check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, |
struct wildcard_list *sec ATTRIBUTE_UNUSED, |
asection *section, |
struct flag_info *sflag_info ATTRIBUTE_UNUSED, |
lang_input_statement_type *file ATTRIBUTE_UNUSED, |
void *output) |
{ |
lang_output_section_statement_type *os; |
os = (lang_output_section_statement_type *) output; |
/* Exclude sections that match UNIQUE_SECTION_LIST. */ |
if (unique_section_p (section, os)) |
return; |
if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0) |
os->all_input_readonly = FALSE; |
} |
/* This is passed a file name which must have been seen already and |
added to the statement tree. We will see if it has been opened |
already and had its symbols read. If not then we'll read it. */ |
static lang_input_statement_type * |
lookup_name (const char *name) |
{ |
lang_input_statement_type *search; |
for (search = (lang_input_statement_type *) input_file_chain.head; |
search != NULL; |
search = (lang_input_statement_type *) search->next_real_file) |
{ |
/* Use the local_sym_name as the name of the file that has |
already been loaded as filename might have been transformed |
via the search directory lookup mechanism. */ |
const char *filename = search->local_sym_name; |
if (filename != NULL |
&& filename_cmp (filename, name) == 0) |
break; |
} |
if (search == NULL) |
search = new_afile (name, lang_input_file_is_search_file_enum, |
default_target, FALSE); |
/* If we have already added this file, or this file is not real |
don't add this file. */ |
if (search->flags.loaded || !search->flags.real) |
return search; |
if (! load_symbols (search, NULL)) |
return NULL; |
return search; |
} |
/* Save LIST as a list of libraries whose symbols should not be exported. */ |
struct excluded_lib |
{ |
char *name; |
struct excluded_lib *next; |
}; |
static struct excluded_lib *excluded_libs; |
void |
add_excluded_libs (const char *list) |
{ |
const char *p = list, *end; |
while (*p != '\0') |
{ |
struct excluded_lib *entry; |
end = strpbrk (p, ",:"); |
if (end == NULL) |
end = p + strlen (p); |
entry = (struct excluded_lib *) xmalloc (sizeof (*entry)); |
entry->next = excluded_libs; |
entry->name = (char *) xmalloc (end - p + 1); |
memcpy (entry->name, p, end - p); |
entry->name[end - p] = '\0'; |
excluded_libs = entry; |
if (*end == '\0') |
break; |
p = end + 1; |
} |
} |
static void |
check_excluded_libs (bfd *abfd) |
{ |
struct excluded_lib *lib = excluded_libs; |
while (lib) |
{ |
int len = strlen (lib->name); |
const char *filename = lbasename (abfd->filename); |
if (strcmp (lib->name, "ALL") == 0) |
{ |
abfd->no_export = TRUE; |
return; |
} |
if (filename_ncmp (lib->name, filename, len) == 0 |
&& (filename[len] == '\0' |
|| (filename[len] == '.' && filename[len + 1] == 'a' |
&& filename[len + 2] == '\0'))) |
{ |
abfd->no_export = TRUE; |
return; |
} |
lib = lib->next; |
} |
} |
/* Get the symbols for an input file. */ |
bfd_boolean |
load_symbols (lang_input_statement_type *entry, |
lang_statement_list_type *place) |
{ |
char **matching; |
if (entry->flags.loaded) |
return TRUE; |
ldfile_open_file (entry); |
/* Do not process further if the file was missing. */ |
if (entry->flags.missing_file) |
return TRUE; |
if (! bfd_check_format (entry->the_bfd, bfd_archive) |
&& ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching)) |
{ |
bfd_error_type err; |
struct lang_input_statement_flags save_flags; |
extern FILE *yyin; |
err = bfd_get_error (); |
/* See if the emulation has some special knowledge. */ |
if (ldemul_unrecognized_file (entry)) |
return TRUE; |
if (err == bfd_error_file_ambiguously_recognized) |
{ |
char **p; |
einfo (_("%B: file not recognized: %E\n"), entry->the_bfd); |
einfo (_("%B: matching formats:"), entry->the_bfd); |
for (p = matching; *p != NULL; p++) |
einfo (" %s", *p); |
einfo ("%F\n"); |
} |
else if (err != bfd_error_file_not_recognized |
|| place == NULL) |
einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd); |
bfd_close (entry->the_bfd); |
entry->the_bfd = NULL; |
/* Try to interpret the file as a linker script. */ |
save_flags = input_flags; |
ldfile_open_command_file (entry->filename); |
push_stat_ptr (place); |
input_flags.add_DT_NEEDED_for_regular |
= entry->flags.add_DT_NEEDED_for_regular; |
input_flags.add_DT_NEEDED_for_dynamic |
= entry->flags.add_DT_NEEDED_for_dynamic; |
input_flags.whole_archive = entry->flags.whole_archive; |
input_flags.dynamic = entry->flags.dynamic; |
ldfile_assumed_script = TRUE; |
parser_input = input_script; |
yyparse (); |
ldfile_assumed_script = FALSE; |
/* missing_file is sticky. sysrooted will already have been |
restored when seeing EOF in yyparse, but no harm to restore |
again. */ |
save_flags.missing_file |= input_flags.missing_file; |
input_flags = save_flags; |
pop_stat_ptr (); |
fclose (yyin); |
yyin = NULL; |
entry->flags.loaded = TRUE; |
return TRUE; |
} |
if (ldemul_recognized_file (entry)) |
return TRUE; |
/* We don't call ldlang_add_file for an archive. Instead, the |
add_symbols entry point will call ldlang_add_file, via the |
add_archive_element callback, for each element of the archive |
which is used. */ |
switch (bfd_get_format (entry->the_bfd)) |
{ |
default: |
break; |
case bfd_object: |
#ifdef ENABLE_PLUGINS |
if (!entry->flags.reload) |
#endif |
ldlang_add_file (entry); |
if (trace_files || verbose) |
info_msg ("%I\n", entry); |
break; |
case bfd_archive: |
check_excluded_libs (entry->the_bfd); |
if (entry->flags.whole_archive) |
{ |
bfd *member = NULL; |
bfd_boolean loaded = TRUE; |
for (;;) |
{ |
bfd *subsbfd; |
member = bfd_openr_next_archived_file (entry->the_bfd, member); |
if (member == NULL) |
break; |
if (! bfd_check_format (member, bfd_object)) |
{ |
einfo (_("%F%B: member %B in archive is not an object\n"), |
entry->the_bfd, member); |
loaded = FALSE; |
} |
subsbfd = member; |
if (!(*link_info.callbacks |
->add_archive_element) (&link_info, member, |
"--whole-archive", &subsbfd)) |
abort (); |
/* Potentially, the add_archive_element hook may have set a |
substitute BFD for us. */ |
if (!bfd_link_add_symbols (subsbfd, &link_info)) |
{ |
einfo (_("%F%B: error adding symbols: %E\n"), member); |
loaded = FALSE; |
} |
} |
entry->flags.loaded = loaded; |
return loaded; |
} |
break; |
} |
if (bfd_link_add_symbols (entry->the_bfd, &link_info)) |
entry->flags.loaded = TRUE; |
else |
einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd); |
return entry->flags.loaded; |
} |
/* Handle a wild statement. S->FILENAME or S->SECTION_LIST or both |
may be NULL, indicating that it is a wildcard. Separate |
lang_input_section statements are created for each part of the |
expansion; they are added after the wild statement S. OUTPUT is |
the output section. */ |
static void |
wild (lang_wild_statement_type *s, |
const char *target ATTRIBUTE_UNUSED, |
lang_output_section_statement_type *output) |
{ |
struct wildcard_list *sec; |
if (s->handler_data[0] |
&& s->handler_data[0]->spec.sorted == by_name |
&& !s->filenames_sorted) |
{ |
lang_section_bst_type *tree; |
walk_wild (s, output_section_callback_fast, output); |
tree = s->tree; |
if (tree) |
{ |
output_section_callback_tree_to_list (s, tree, output); |
s->tree = NULL; |
} |
} |
else |
walk_wild (s, output_section_callback, output); |
if (default_common_section == NULL) |
for (sec = s->section_list; sec != NULL; sec = sec->next) |
if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0) |
{ |
/* Remember the section that common is going to in case we |
later get something which doesn't know where to put it. */ |
default_common_section = output; |
break; |
} |
} |
/* Return TRUE iff target is the sought target. */ |
static int |
get_target (const bfd_target *target, void *data) |
{ |
const char *sought = (const char *) data; |
return strcmp (target->name, sought) == 0; |
} |
/* Like strcpy() but convert to lower case as well. */ |
static void |
stricpy (char *dest, char *src) |
{ |
char c; |
while ((c = *src++) != 0) |
*dest++ = TOLOWER (c); |
*dest = 0; |
} |
/* Remove the first occurrence of needle (if any) in haystack |
from haystack. */ |
static void |
strcut (char *haystack, char *needle) |
{ |
haystack = strstr (haystack, needle); |
if (haystack) |
{ |
char *src; |
for (src = haystack + strlen (needle); *src;) |
*haystack++ = *src++; |
*haystack = 0; |
} |
} |
/* Compare two target format name strings. |
Return a value indicating how "similar" they are. */ |
static int |
name_compare (char *first, char *second) |
{ |
char *copy1; |
char *copy2; |
int result; |
copy1 = (char *) xmalloc (strlen (first) + 1); |
copy2 = (char *) xmalloc (strlen (second) + 1); |
/* Convert the names to lower case. */ |
stricpy (copy1, first); |
stricpy (copy2, second); |
/* Remove size and endian strings from the name. */ |
strcut (copy1, "big"); |
strcut (copy1, "little"); |
strcut (copy2, "big"); |
strcut (copy2, "little"); |
/* Return a value based on how many characters match, |
starting from the beginning. If both strings are |
the same then return 10 * their length. */ |
for (result = 0; copy1[result] == copy2[result]; result++) |
if (copy1[result] == 0) |
{ |
result *= 10; |
break; |
} |
free (copy1); |
free (copy2); |
return result; |
} |
/* Set by closest_target_match() below. */ |
static const bfd_target *winner; |
/* Scan all the valid bfd targets looking for one that has the endianness |
requirement that was specified on the command line, and is the nearest |
match to the original output target. */ |
static int |
closest_target_match (const bfd_target *target, void *data) |
{ |
const bfd_target *original = (const bfd_target *) data; |
if (command_line.endian == ENDIAN_BIG |
&& target->byteorder != BFD_ENDIAN_BIG) |
return 0; |
if (command_line.endian == ENDIAN_LITTLE |
&& target->byteorder != BFD_ENDIAN_LITTLE) |
return 0; |
/* Must be the same flavour. */ |
if (target->flavour != original->flavour) |
return 0; |
/* Ignore generic big and little endian elf vectors. */ |
if (strcmp (target->name, "elf32-big") == 0 |
|| strcmp (target->name, "elf64-big") == 0 |
|| strcmp (target->name, "elf32-little") == 0 |
|| strcmp (target->name, "elf64-little") == 0) |
return 0; |
/* If we have not found a potential winner yet, then record this one. */ |
if (winner == NULL) |
{ |
winner = target; |
return 0; |
} |
/* Oh dear, we now have two potential candidates for a successful match. |
Compare their names and choose the better one. */ |
if (name_compare (target->name, original->name) |
> name_compare (winner->name, original->name)) |
winner = target; |
/* Keep on searching until wqe have checked them all. */ |
return 0; |
} |
/* Return the BFD target format of the first input file. */ |
static char * |
get_first_input_target (void) |
{ |
char *target = NULL; |
LANG_FOR_EACH_INPUT_STATEMENT (s) |
{ |
if (s->header.type == lang_input_statement_enum |
&& s->flags.real) |
{ |
ldfile_open_file (s); |
if (s->the_bfd != NULL |
&& bfd_check_format (s->the_bfd, bfd_object)) |
{ |
target = bfd_get_target (s->the_bfd); |
if (target != NULL) |
break; |
} |
} |
} |
return target; |
} |
const char * |
lang_get_output_target (void) |
{ |
const char *target; |
/* Has the user told us which output format to use? */ |
if (output_target != NULL) |
return output_target; |
/* No - has the current target been set to something other than |
the default? */ |
if (current_target != default_target && current_target != NULL) |
return current_target; |
/* No - can we determine the format of the first input file? */ |
target = get_first_input_target (); |
if (target != NULL) |
return target; |
/* Failed - use the default output target. */ |
return default_target; |
} |
/* Open the output file. */ |
static void |
open_output (const char *name) |
{ |
output_target = lang_get_output_target (); |
/* Has the user requested a particular endianness on the command |
line? */ |
if (command_line.endian != ENDIAN_UNSET) |
{ |
const bfd_target *target; |
enum bfd_endian desired_endian; |
/* Get the chosen target. */ |
target = bfd_search_for_target (get_target, (void *) output_target); |
/* If the target is not supported, we cannot do anything. */ |
if (target != NULL) |
{ |
if (command_line.endian == ENDIAN_BIG) |
desired_endian = BFD_ENDIAN_BIG; |
else |
desired_endian = BFD_ENDIAN_LITTLE; |
/* See if the target has the wrong endianness. This should |
not happen if the linker script has provided big and |
little endian alternatives, but some scrips don't do |
this. */ |
if (target->byteorder != desired_endian) |
{ |
/* If it does, then see if the target provides |
an alternative with the correct endianness. */ |
if (target->alternative_target != NULL |
&& (target->alternative_target->byteorder == desired_endian)) |
output_target = target->alternative_target->name; |
else |
{ |
/* Try to find a target as similar as possible to |
the default target, but which has the desired |
endian characteristic. */ |
bfd_search_for_target (closest_target_match, |
(void *) target); |
/* Oh dear - we could not find any targets that |
satisfy our requirements. */ |
if (winner == NULL) |
einfo (_("%P: warning: could not find any targets" |
" that match endianness requirement\n")); |
else |
output_target = winner->name; |
} |
} |
} |
} |
link_info.output_bfd = bfd_openw (name, output_target); |
if (link_info.output_bfd == NULL) |
{ |
if (bfd_get_error () == bfd_error_invalid_target) |
einfo (_("%P%F: target %s not found\n"), output_target); |
einfo (_("%P%F: cannot open output file %s: %E\n"), name); |
} |
delete_output_file_on_failure = TRUE; |
if (! bfd_set_format (link_info.output_bfd, bfd_object)) |
einfo (_("%P%F:%s: can not make object file: %E\n"), name); |
if (! bfd_set_arch_mach (link_info.output_bfd, |
ldfile_output_architecture, |
ldfile_output_machine)) |
einfo (_("%P%F:%s: can not set architecture: %E\n"), name); |
link_info.hash = bfd_link_hash_table_create (link_info.output_bfd); |
if (link_info.hash == NULL) |
einfo (_("%P%F: can not create hash table: %E\n")); |
bfd_set_gp_size (link_info.output_bfd, g_switch_value); |
} |
static void |
ldlang_open_output (lang_statement_union_type *statement) |
{ |
switch (statement->header.type) |
{ |
case lang_output_statement_enum: |
ASSERT (link_info.output_bfd == NULL); |
open_output (statement->output_statement.name); |
ldemul_set_output_arch (); |
if (config.magic_demand_paged && !link_info.relocatable) |
link_info.output_bfd->flags |= D_PAGED; |
else |
link_info.output_bfd->flags &= ~D_PAGED; |
if (config.text_read_only) |
link_info.output_bfd->flags |= WP_TEXT; |
else |
link_info.output_bfd->flags &= ~WP_TEXT; |
if (link_info.traditional_format) |
link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT; |
else |
link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT; |
break; |
case lang_target_statement_enum: |
current_target = statement->target_statement.target; |
break; |
default: |
break; |
} |
} |
/* Convert between addresses in bytes and sizes in octets. |
For currently supported targets, octets_per_byte is always a power |
of two, so we can use shifts. */ |
#define TO_ADDR(X) ((X) >> opb_shift) |
#define TO_SIZE(X) ((X) << opb_shift) |
/* Support the above. */ |
static unsigned int opb_shift = 0; |
static void |
init_opb (void) |
{ |
unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, |
ldfile_output_machine); |
opb_shift = 0; |
if (x > 1) |
while ((x & 1) == 0) |
{ |
x >>= 1; |
++opb_shift; |
} |
ASSERT (x == 1); |
} |
/* Open all the input files. */ |
enum open_bfd_mode |
{ |
OPEN_BFD_NORMAL = 0, |
OPEN_BFD_FORCE = 1, |
OPEN_BFD_RESCAN = 2 |
}; |
#ifdef ENABLE_PLUGINS |
static lang_input_statement_type *plugin_insert = NULL; |
#endif |
static void |
open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) |
{ |
for (; s != NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
case lang_constructors_statement_enum: |
open_input_bfds (constructor_list.head, mode); |
break; |
case lang_output_section_statement_enum: |
open_input_bfds (s->output_section_statement.children.head, mode); |
break; |
case lang_wild_statement_enum: |
/* Maybe we should load the file's symbols. */ |
if ((mode & OPEN_BFD_RESCAN) == 0 |
&& s->wild_statement.filename |
&& !wildcardp (s->wild_statement.filename) |
&& !archive_path (s->wild_statement.filename)) |
lookup_name (s->wild_statement.filename); |
open_input_bfds (s->wild_statement.children.head, mode); |
break; |
case lang_group_statement_enum: |
{ |
struct bfd_link_hash_entry *undefs; |
/* We must continually search the entries in the group |
until no new symbols are added to the list of undefined |
symbols. */ |
do |
{ |
undefs = link_info.hash->undefs_tail; |
open_input_bfds (s->group_statement.children.head, |
mode | OPEN_BFD_FORCE); |
} |
while (undefs != link_info.hash->undefs_tail); |
} |
break; |
case lang_target_statement_enum: |
current_target = s->target_statement.target; |
break; |
case lang_input_statement_enum: |
if (s->input_statement.flags.real) |
{ |
lang_statement_union_type **os_tail; |
lang_statement_list_type add; |
s->input_statement.target = current_target; |
/* If we are being called from within a group, and this |
is an archive which has already been searched, then |
force it to be researched unless the whole archive |
has been loaded already. Do the same for a rescan. */ |
if (mode != OPEN_BFD_NORMAL |
#ifdef ENABLE_PLUGINS |
&& ((mode & OPEN_BFD_RESCAN) == 0 |
|| plugin_insert == NULL) |
#endif |
&& !s->input_statement.flags.whole_archive |
&& s->input_statement.flags.loaded |
&& s->input_statement.the_bfd != NULL |
&& bfd_check_format (s->input_statement.the_bfd, |
bfd_archive)) |
s->input_statement.flags.loaded = FALSE; |
#ifdef ENABLE_PLUGINS |
/* When rescanning, reload --as-needed shared libs. */ |
else if ((mode & OPEN_BFD_RESCAN) != 0 |
&& plugin_insert == NULL |
&& s->input_statement.flags.loaded |
&& s->input_statement.flags.add_DT_NEEDED_for_regular |
&& s->input_statement.the_bfd != NULL |
&& ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0 |
&& plugin_should_reload (s->input_statement.the_bfd)) |
{ |
s->input_statement.flags.loaded = FALSE; |
s->input_statement.flags.reload = TRUE; |
} |
#endif |
os_tail = lang_output_section_statement.tail; |
lang_list_init (&add); |
if (! load_symbols (&s->input_statement, &add)) |
config.make_executable = FALSE; |
if (add.head != NULL) |
{ |
/* If this was a script with output sections then |
tack any added statements on to the end of the |
list. This avoids having to reorder the output |
section statement list. Very likely the user |
forgot -T, and whatever we do here will not meet |
naive user expectations. */ |
if (os_tail != lang_output_section_statement.tail) |
{ |
einfo (_("%P: warning: %s contains output sections;" |
" did you forget -T?\n"), |
s->input_statement.filename); |
*stat_ptr->tail = add.head; |
stat_ptr->tail = add.tail; |
} |
else |
{ |
*add.tail = s->header.next; |
s->header.next = add.head; |
} |
} |
} |
#ifdef ENABLE_PLUGINS |
/* If we have found the point at which a plugin added new |
files, clear plugin_insert to enable archive rescan. */ |
if (&s->input_statement == plugin_insert) |
plugin_insert = NULL; |
#endif |
break; |
case lang_assignment_statement_enum: |
if (s->assignment_statement.exp->assign.defsym) |
/* This is from a --defsym on the command line. */ |
exp_fold_tree_no_dot (s->assignment_statement.exp); |
break; |
default: |
break; |
} |
} |
/* Exit if any of the files were missing. */ |
if (input_flags.missing_file) |
einfo ("%F"); |
} |
/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */ |
void |
lang_track_definedness (const char *name) |
{ |
if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name); |
} |
/* New-function for the definedness hash table. */ |
static struct bfd_hash_entry * |
lang_definedness_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED) |
{ |
struct lang_definedness_hash_entry *ret |
= (struct lang_definedness_hash_entry *) entry; |
if (ret == NULL) |
ret = (struct lang_definedness_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry)); |
if (ret == NULL) |
einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); |
ret->iteration = -1; |
return &ret->root; |
} |
/* Return the iteration when the definition of NAME was last updated. A |
value of -1 means that the symbol is not defined in the linker script |
or the command line, but may be defined in the linker symbol table. */ |
int |
lang_symbol_definition_iteration (const char *name) |
{ |
struct lang_definedness_hash_entry *defentry |
= (struct lang_definedness_hash_entry *) |
bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); |
/* We've already created this one on the presence of DEFINED in the |
script, so it can't be NULL unless something is borked elsewhere in |
the code. */ |
if (defentry == NULL) |
FAIL (); |
return defentry->iteration; |
} |
/* Update the definedness state of NAME. */ |
void |
lang_update_definedness (const char *name, struct bfd_link_hash_entry *h) |
{ |
struct lang_definedness_hash_entry *defentry |
= (struct lang_definedness_hash_entry *) |
bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); |
/* We don't keep track of symbols not tested with DEFINED. */ |
if (defentry == NULL) |
return; |
/* If the symbol was already defined, and not from an earlier statement |
iteration, don't update the definedness iteration, because that'd |
make the symbol seem defined in the linker script at this point, and |
it wasn't; it was defined in some object. If we do anyway, DEFINED |
would start to yield false before this point and the construct "sym = |
DEFINED (sym) ? sym : X;" would change sym to X despite being defined |
in an object. */ |
if (h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common |
&& h->type != bfd_link_hash_new |
&& defentry->iteration == -1) |
return; |
defentry->iteration = lang_statement_iteration; |
} |
/* Add the supplied name to the symbol table as an undefined reference. |
This is a two step process as the symbol table doesn't even exist at |
the time the ld command line is processed. First we put the name |
on a list, then, once the output file has been opened, transfer the |
name to the symbol table. */ |
typedef struct bfd_sym_chain ldlang_undef_chain_list_type; |
#define ldlang_undef_chain_list_head entry_symbol.next |
void |
ldlang_add_undef (const char *const name, bfd_boolean cmdline) |
{ |
ldlang_undef_chain_list_type *new_undef; |
undef_from_cmdline = undef_from_cmdline || cmdline; |
new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef)); |
new_undef->next = ldlang_undef_chain_list_head; |
ldlang_undef_chain_list_head = new_undef; |
new_undef->name = xstrdup (name); |
if (link_info.output_bfd != NULL) |
insert_undefined (new_undef->name); |
} |
/* Insert NAME as undefined in the symbol table. */ |
static void |
insert_undefined (const char *name) |
{ |
struct bfd_link_hash_entry *h; |
h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE); |
if (h == NULL) |
einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); |
if (h->type == bfd_link_hash_new) |
{ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = NULL; |
bfd_link_add_undef (link_info.hash, h); |
} |
} |
/* Run through the list of undefineds created above and place them |
into the linker hash table as undefined symbols belonging to the |
script file. */ |
static void |
lang_place_undefineds (void) |
{ |
ldlang_undef_chain_list_type *ptr; |
for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next) |
insert_undefined (ptr->name); |
} |
/* Check for all readonly or some readwrite sections. */ |
static void |
check_input_sections |
(lang_statement_union_type *s, |
lang_output_section_statement_type *output_section_statement) |
{ |
for (; s != (lang_statement_union_type *) NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
case lang_wild_statement_enum: |
walk_wild (&s->wild_statement, check_section_callback, |
output_section_statement); |
if (! output_section_statement->all_input_readonly) |
return; |
break; |
case lang_constructors_statement_enum: |
check_input_sections (constructor_list.head, |
output_section_statement); |
if (! output_section_statement->all_input_readonly) |
return; |
break; |
case lang_group_statement_enum: |
check_input_sections (s->group_statement.children.head, |
output_section_statement); |
if (! output_section_statement->all_input_readonly) |
return; |
break; |
default: |
break; |
} |
} |
} |
/* Update wildcard statements if needed. */ |
static void |
update_wild_statements (lang_statement_union_type *s) |
{ |
struct wildcard_list *sec; |
switch (sort_section) |
{ |
default: |
FAIL (); |
case none: |
break; |
case by_name: |
case by_alignment: |
for (; s != NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
default: |
break; |
case lang_wild_statement_enum: |
for (sec = s->wild_statement.section_list; sec != NULL; |
sec = sec->next) |
{ |
switch (sec->spec.sorted) |
{ |
case none: |
sec->spec.sorted = sort_section; |
break; |
case by_name: |
if (sort_section == by_alignment) |
sec->spec.sorted = by_name_alignment; |
break; |
case by_alignment: |
if (sort_section == by_name) |
sec->spec.sorted = by_alignment_name; |
break; |
default: |
break; |
} |
} |
break; |
case lang_constructors_statement_enum: |
update_wild_statements (constructor_list.head); |
break; |
case lang_output_section_statement_enum: |
/* Don't sort .init/.fini sections. */ |
if (strcmp (s->output_section_statement.name, ".init") != 0 |
&& strcmp (s->output_section_statement.name, ".fini") != 0) |
update_wild_statements |
(s->output_section_statement.children.head); |
break; |
case lang_group_statement_enum: |
update_wild_statements (s->group_statement.children.head); |
break; |
} |
} |
break; |
} |
} |
/* Open input files and attach to output sections. */ |
static void |
map_input_to_output_sections |
(lang_statement_union_type *s, const char *target, |
lang_output_section_statement_type *os) |
{ |
for (; s != NULL; s = s->header.next) |
{ |
lang_output_section_statement_type *tos; |
flagword flags; |
switch (s->header.type) |
{ |
case lang_wild_statement_enum: |
wild (&s->wild_statement, target, os); |
break; |
case lang_constructors_statement_enum: |
map_input_to_output_sections (constructor_list.head, |
target, |
os); |
break; |
case lang_output_section_statement_enum: |
tos = &s->output_section_statement; |
if (tos->constraint != 0) |
{ |
if (tos->constraint != ONLY_IF_RW |
&& tos->constraint != ONLY_IF_RO) |
break; |
tos->all_input_readonly = TRUE; |
check_input_sections (tos->children.head, tos); |
if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO)) |
{ |
tos->constraint = -1; |
break; |
} |
} |
map_input_to_output_sections (tos->children.head, |
target, |
tos); |
break; |
case lang_output_statement_enum: |
break; |
case lang_target_statement_enum: |
target = s->target_statement.target; |
break; |
case lang_group_statement_enum: |
map_input_to_output_sections (s->group_statement.children.head, |
target, |
os); |
break; |
case lang_data_statement_enum: |
/* Make sure that any sections mentioned in the expression |
are initialized. */ |
exp_init_os (s->data_statement.exp); |
/* The output section gets CONTENTS, ALLOC and LOAD, but |
these may be overridden by the script. */ |
flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD; |
switch (os->sectype) |
{ |
case normal_section: |
case overlay_section: |
break; |
case noalloc_section: |
flags = SEC_HAS_CONTENTS; |
break; |
case noload_section: |
if (bfd_get_flavour (link_info.output_bfd) |
== bfd_target_elf_flavour) |
flags = SEC_NEVER_LOAD | SEC_ALLOC; |
else |
flags = SEC_NEVER_LOAD | SEC_HAS_CONTENTS; |
break; |
} |
if (os->bfd_section == NULL) |
init_os (os, flags); |
else |
os->bfd_section->flags |= flags; |
break; |
case lang_input_section_enum: |
break; |
case lang_fill_statement_enum: |
case lang_object_symbols_statement_enum: |
case lang_reloc_statement_enum: |
case lang_padding_statement_enum: |
case lang_input_statement_enum: |
if (os != NULL && os->bfd_section == NULL) |
init_os (os, 0); |
break; |
case lang_assignment_statement_enum: |
if (os != NULL && os->bfd_section == NULL) |
init_os (os, 0); |
/* Make sure that any sections mentioned in the assignment |
are initialized. */ |
exp_init_os (s->assignment_statement.exp); |
break; |
case lang_address_statement_enum: |
/* Mark the specified section with the supplied address. |
If this section was actually a segment marker, then the |
directive is ignored if the linker script explicitly |
processed the segment marker. Originally, the linker |
treated segment directives (like -Ttext on the |
command-line) as section directives. We honor the |
section directive semantics for backwards compatibilty; |
linker scripts that do not specifically check for |
SEGMENT_START automatically get the old semantics. */ |
if (!s->address_statement.segment |
|| !s->address_statement.segment->used) |
{ |
const char *name = s->address_statement.section_name; |
/* Create the output section statement here so that |
orphans with a set address will be placed after other |
script sections. If we let the orphan placement code |
place them in amongst other sections then the address |
will affect following script sections, which is |
likely to surprise naive users. */ |
tos = lang_output_section_statement_lookup (name, 0, TRUE); |
tos->addr_tree = s->address_statement.address; |
if (tos->bfd_section == NULL) |
init_os (tos, 0); |
} |
break; |
case lang_insert_statement_enum: |
break; |
} |
} |
} |
/* An insert statement snips out all the linker statements from the |
start of the list and places them after the output section |
statement specified by the insert. This operation is complicated |
by the fact that we keep a doubly linked list of output section |
statements as well as the singly linked list of all statements. */ |
static void |
process_insert_statements (void) |
{ |
lang_statement_union_type **s; |
lang_output_section_statement_type *first_os = NULL; |
lang_output_section_statement_type *last_os = NULL; |
lang_output_section_statement_type *os; |
/* "start of list" is actually the statement immediately after |
the special abs_section output statement, so that it isn't |
reordered. */ |
s = &lang_output_section_statement.head; |
while (*(s = &(*s)->header.next) != NULL) |
{ |
if ((*s)->header.type == lang_output_section_statement_enum) |
{ |
/* Keep pointers to the first and last output section |
statement in the sequence we may be about to move. */ |
os = &(*s)->output_section_statement; |
ASSERT (last_os == NULL || last_os->next == os); |
last_os = os; |
/* Set constraint negative so that lang_output_section_find |
won't match this output section statement. At this |
stage in linking constraint has values in the range |
[-1, ONLY_IN_RW]. */ |
last_os->constraint = -2 - last_os->constraint; |
if (first_os == NULL) |
first_os = last_os; |
} |
else if ((*s)->header.type == lang_insert_statement_enum) |
{ |
lang_insert_statement_type *i = &(*s)->insert_statement; |
lang_output_section_statement_type *where; |
lang_statement_union_type **ptr; |
lang_statement_union_type *first; |
where = lang_output_section_find (i->where); |
if (where != NULL && i->is_before) |
{ |
do |
where = where->prev; |
while (where != NULL && where->constraint < 0); |
} |
if (where == NULL) |
{ |
einfo (_("%F%P: %s not found for insert\n"), i->where); |
return; |
} |
/* Deal with reordering the output section statement list. */ |
if (last_os != NULL) |
{ |
asection *first_sec, *last_sec; |
struct lang_output_section_statement_struct **next; |
/* Snip out the output sections we are moving. */ |
first_os->prev->next = last_os->next; |
if (last_os->next == NULL) |
{ |
next = &first_os->prev->next; |
lang_output_section_statement.tail |
= (lang_statement_union_type **) next; |
} |
else |
last_os->next->prev = first_os->prev; |
/* Add them in at the new position. */ |
last_os->next = where->next; |
if (where->next == NULL) |
{ |
next = &last_os->next; |
lang_output_section_statement.tail |
= (lang_statement_union_type **) next; |
} |
else |
where->next->prev = last_os; |
first_os->prev = where; |
where->next = first_os; |
/* Move the bfd sections in the same way. */ |
first_sec = NULL; |
last_sec = NULL; |
for (os = first_os; os != NULL; os = os->next) |
{ |
os->constraint = -2 - os->constraint; |
if (os->bfd_section != NULL |
&& os->bfd_section->owner != NULL) |
{ |
last_sec = os->bfd_section; |
if (first_sec == NULL) |
first_sec = last_sec; |
} |
if (os == last_os) |
break; |
} |
if (last_sec != NULL) |
{ |
asection *sec = where->bfd_section; |
if (sec == NULL) |
sec = output_prev_sec_find (where); |
/* The place we want to insert must come after the |
sections we are moving. So if we find no |
section or if the section is the same as our |
last section, then no move is needed. */ |
if (sec != NULL && sec != last_sec) |
{ |
/* Trim them off. */ |
if (first_sec->prev != NULL) |
first_sec->prev->next = last_sec->next; |
else |
link_info.output_bfd->sections = last_sec->next; |
if (last_sec->next != NULL) |
last_sec->next->prev = first_sec->prev; |
else |
link_info.output_bfd->section_last = first_sec->prev; |
/* Add back. */ |
last_sec->next = sec->next; |
if (sec->next != NULL) |
sec->next->prev = last_sec; |
else |
link_info.output_bfd->section_last = last_sec; |
first_sec->prev = sec; |
sec->next = first_sec; |
} |
} |
first_os = NULL; |
last_os = NULL; |
} |
ptr = insert_os_after (where); |
/* Snip everything after the abs_section output statement we |
know is at the start of the list, up to and including |
the insert statement we are currently processing. */ |
first = lang_output_section_statement.head->header.next; |
lang_output_section_statement.head->header.next = (*s)->header.next; |
/* Add them back where they belong. */ |
*s = *ptr; |
if (*s == NULL) |
statement_list.tail = s; |
*ptr = first; |
s = &lang_output_section_statement.head; |
} |
} |
/* Undo constraint twiddling. */ |
for (os = first_os; os != NULL; os = os->next) |
{ |
os->constraint = -2 - os->constraint; |
if (os == last_os) |
break; |
} |
} |
/* An output section might have been removed after its statement was |
added. For example, ldemul_before_allocation can remove dynamic |
sections if they turn out to be not needed. Clean them up here. */ |
void |
strip_excluded_output_sections (void) |
{ |
lang_output_section_statement_type *os; |
/* Run lang_size_sections (if not already done). */ |
if (expld.phase != lang_mark_phase_enum) |
{ |
expld.phase = lang_mark_phase_enum; |
expld.dataseg.phase = exp_dataseg_none; |
one_lang_size_sections_pass (NULL, FALSE); |
lang_reset_memory_regions (); |
} |
for (os = &lang_output_section_statement.head->output_section_statement; |
os != NULL; |
os = os->next) |
{ |
asection *output_section; |
bfd_boolean exclude; |
if (os->constraint < 0) |
continue; |
output_section = os->bfd_section; |
if (output_section == NULL) |
continue; |
exclude = (output_section->rawsize == 0 |
&& (output_section->flags & SEC_KEEP) == 0 |
&& !bfd_section_removed_from_list (link_info.output_bfd, |
output_section)); |
/* Some sections have not yet been sized, notably .gnu.version, |
.dynsym, .dynstr and .hash. These all have SEC_LINKER_CREATED |
input sections, so don't drop output sections that have such |
input sections unless they are also marked SEC_EXCLUDE. */ |
if (exclude && output_section->map_head.s != NULL) |
{ |
asection *s; |
for (s = output_section->map_head.s; s != NULL; s = s->map_head.s) |
if ((s->flags & SEC_EXCLUDE) == 0 |
&& ((s->flags & SEC_LINKER_CREATED) != 0 |
|| link_info.emitrelocations)) |
{ |
exclude = FALSE; |
break; |
} |
} |
/* TODO: Don't just junk map_head.s, turn them into link_orders. */ |
output_section->map_head.link_order = NULL; |
output_section->map_tail.link_order = NULL; |
if (exclude) |
{ |
/* We don't set bfd_section to NULL since bfd_section of the |
removed output section statement may still be used. */ |
if (!os->update_dot) |
os->ignored = TRUE; |
output_section->flags |= SEC_EXCLUDE; |
bfd_section_list_remove (link_info.output_bfd, output_section); |
link_info.output_bfd->section_count--; |
} |
} |
/* Stop future calls to lang_add_section from messing with map_head |
and map_tail link_order fields. */ |
stripped_excluded_sections = TRUE; |
} |
static void |
print_output_section_statement |
(lang_output_section_statement_type *output_section_statement) |
{ |
asection *section = output_section_statement->bfd_section; |
int len; |
if (output_section_statement != abs_output_section) |
{ |
minfo ("\n%s", output_section_statement->name); |
if (section != NULL) |
{ |
print_dot = section->vma; |
len = strlen (output_section_statement->name); |
if (len >= SECTION_NAME_MAP_LENGTH - 1) |
{ |
print_nl (); |
len = 0; |
} |
while (len < SECTION_NAME_MAP_LENGTH) |
{ |
print_space (); |
++len; |
} |
minfo ("0x%V %W", section->vma, section->size); |
if (section->vma != section->lma) |
minfo (_(" load address 0x%V"), section->lma); |
if (output_section_statement->update_dot_tree != NULL) |
exp_fold_tree (output_section_statement->update_dot_tree, |
bfd_abs_section_ptr, &print_dot); |
} |
print_nl (); |
} |
print_statement_list (output_section_statement->children.head, |
output_section_statement); |
} |
static void |
print_assignment (lang_assignment_statement_type *assignment, |
lang_output_section_statement_type *output_section) |
{ |
unsigned int i; |
bfd_boolean is_dot; |
etree_type *tree; |
asection *osec; |
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) |
print_space (); |
if (assignment->exp->type.node_class == etree_assert) |
{ |
is_dot = FALSE; |
tree = assignment->exp->assert_s.child; |
} |
else |
{ |
const char *dst = assignment->exp->assign.dst; |
is_dot = (dst[0] == '.' && dst[1] == 0); |
expld.assign_name = dst; |
tree = assignment->exp->assign.src; |
} |
osec = output_section->bfd_section; |
if (osec == NULL) |
osec = bfd_abs_section_ptr; |
exp_fold_tree (tree, osec, &print_dot); |
if (expld.result.valid_p) |
{ |
bfd_vma value; |
if (assignment->exp->type.node_class == etree_assert |
|| is_dot |
|| expld.assign_name != NULL) |
{ |
value = expld.result.value; |
if (expld.result.section != NULL) |
value += expld.result.section->vma; |
minfo ("0x%V", value); |
if (is_dot) |
print_dot = value; |
} |
else |
{ |
struct bfd_link_hash_entry *h; |
h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst, |
FALSE, FALSE, TRUE); |
if (h) |
{ |
value = h->u.def.value; |
value += h->u.def.section->output_section->vma; |
value += h->u.def.section->output_offset; |
minfo ("[0x%V]", value); |
} |
else |
minfo ("[unresolved]"); |
} |
} |
else |
{ |
minfo ("*undef* "); |
#ifdef BFD64 |
minfo (" "); |
#endif |
} |
expld.assign_name = NULL; |
minfo (" "); |
exp_print_tree (assignment->exp); |
print_nl (); |
} |
static void |
print_input_statement (lang_input_statement_type *statm) |
{ |
if (statm->filename != NULL |
&& (statm->the_bfd == NULL |
|| (statm->the_bfd->flags & BFD_LINKER_CREATED) == 0)) |
fprintf (config.map_file, "LOAD %s\n", statm->filename); |
} |
/* Print all symbols defined in a particular section. This is called |
via bfd_link_hash_traverse, or by print_all_symbols. */ |
static bfd_boolean |
print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr) |
{ |
asection *sec = (asection *) ptr; |
if ((hash_entry->type == bfd_link_hash_defined |
|| hash_entry->type == bfd_link_hash_defweak) |
&& sec == hash_entry->u.def.section) |
{ |
int i; |
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) |
print_space (); |
minfo ("0x%V ", |
(hash_entry->u.def.value |
+ hash_entry->u.def.section->output_offset |
+ hash_entry->u.def.section->output_section->vma)); |
minfo (" %T\n", hash_entry->root.string); |
} |
return TRUE; |
} |
static int |
hash_entry_addr_cmp (const void *a, const void *b) |
{ |
const struct bfd_link_hash_entry *l = *(const struct bfd_link_hash_entry **)a; |
const struct bfd_link_hash_entry *r = *(const struct bfd_link_hash_entry **)b; |
if (l->u.def.value < r->u.def.value) |
return -1; |
else if (l->u.def.value > r->u.def.value) |
return 1; |
else |
return 0; |
} |
static void |
print_all_symbols (asection *sec) |
{ |
struct fat_user_section_struct *ud = |
(struct fat_user_section_struct *) get_userdata (sec); |
struct map_symbol_def *def; |
struct bfd_link_hash_entry **entries; |
unsigned int i; |
if (!ud) |
return; |
*ud->map_symbol_def_tail = 0; |
/* Sort the symbols by address. */ |
entries = (struct bfd_link_hash_entry **) |
obstack_alloc (&map_obstack, ud->map_symbol_def_count * sizeof (*entries)); |
for (i = 0, def = ud->map_symbol_def_head; def; def = def->next, i++) |
entries[i] = def->entry; |
qsort (entries, ud->map_symbol_def_count, sizeof (*entries), |
hash_entry_addr_cmp); |
/* Print the symbols. */ |
for (i = 0; i < ud->map_symbol_def_count; i++) |
print_one_symbol (entries[i], sec); |
obstack_free (&map_obstack, entries); |
} |
/* Print information about an input section to the map file. */ |
static void |
print_input_section (asection *i, bfd_boolean is_discarded) |
{ |
bfd_size_type size = i->size; |
int len; |
bfd_vma addr; |
init_opb (); |
print_space (); |
minfo ("%s", i->name); |
len = 1 + strlen (i->name); |
if (len >= SECTION_NAME_MAP_LENGTH - 1) |
{ |
print_nl (); |
len = 0; |
} |
while (len < SECTION_NAME_MAP_LENGTH) |
{ |
print_space (); |
++len; |
} |
if (i->output_section != NULL |
&& i->output_section->owner == link_info.output_bfd) |
addr = i->output_section->vma + i->output_offset; |
else |
{ |
addr = print_dot; |
if (!is_discarded) |
size = 0; |
} |
minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner); |
if (size != i->rawsize && i->rawsize != 0) |
{ |
len = SECTION_NAME_MAP_LENGTH + 3; |
#ifdef BFD64 |
len += 16; |
#else |
len += 8; |
#endif |
while (len > 0) |
{ |
print_space (); |
--len; |
} |
minfo (_("%W (size before relaxing)\n"), i->rawsize); |
} |
if (i->output_section != NULL |
&& i->output_section->owner == link_info.output_bfd) |
{ |
if (link_info.reduce_memory_overheads) |
bfd_link_hash_traverse (link_info.hash, print_one_symbol, i); |
else |
print_all_symbols (i); |
/* Update print_dot, but make sure that we do not move it |
backwards - this could happen if we have overlays and a |
later overlay is shorter than an earier one. */ |
if (addr + TO_ADDR (size) > print_dot) |
print_dot = addr + TO_ADDR (size); |
} |
} |
static void |
print_fill_statement (lang_fill_statement_type *fill) |
{ |
size_t size; |
unsigned char *p; |
fputs (" FILL mask 0x", config.map_file); |
for (p = fill->fill->data, size = fill->fill->size; size != 0; p++, size--) |
fprintf (config.map_file, "%02x", *p); |
fputs ("\n", config.map_file); |
} |
static void |
print_data_statement (lang_data_statement_type *data) |
{ |
int i; |
bfd_vma addr; |
bfd_size_type size; |
const char *name; |
init_opb (); |
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) |
print_space (); |
addr = data->output_offset; |
if (data->output_section != NULL) |
addr += data->output_section->vma; |
switch (data->type) |
{ |
default: |
abort (); |
case BYTE: |
size = BYTE_SIZE; |
name = "BYTE"; |
break; |
case SHORT: |
size = SHORT_SIZE; |
name = "SHORT"; |
break; |
case LONG: |
size = LONG_SIZE; |
name = "LONG"; |
break; |
case QUAD: |
size = QUAD_SIZE; |
name = "QUAD"; |
break; |
case SQUAD: |
size = QUAD_SIZE; |
name = "SQUAD"; |
break; |
} |
minfo ("0x%V %W %s 0x%v", addr, size, name, data->value); |
if (data->exp->type.node_class != etree_value) |
{ |
print_space (); |
exp_print_tree (data->exp); |
} |
print_nl (); |
print_dot = addr + TO_ADDR (size); |
} |
/* Print an address statement. These are generated by options like |
-Ttext. */ |
static void |
print_address_statement (lang_address_statement_type *address) |
{ |
minfo (_("Address of section %s set to "), address->section_name); |
exp_print_tree (address->address); |
print_nl (); |
} |
/* Print a reloc statement. */ |
static void |
print_reloc_statement (lang_reloc_statement_type *reloc) |
{ |
int i; |
bfd_vma addr; |
bfd_size_type size; |
init_opb (); |
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) |
print_space (); |
addr = reloc->output_offset; |
if (reloc->output_section != NULL) |
addr += reloc->output_section->vma; |
size = bfd_get_reloc_size (reloc->howto); |
minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name); |
if (reloc->name != NULL) |
minfo ("%s+", reloc->name); |
else |
minfo ("%s+", reloc->section->name); |
exp_print_tree (reloc->addend_exp); |
print_nl (); |
print_dot = addr + TO_ADDR (size); |
} |
static void |
print_padding_statement (lang_padding_statement_type *s) |
{ |
int len; |
bfd_vma addr; |
init_opb (); |
minfo (" *fill*"); |
len = sizeof " *fill*" - 1; |
while (len < SECTION_NAME_MAP_LENGTH) |
{ |
print_space (); |
++len; |
} |
addr = s->output_offset; |
if (s->output_section != NULL) |
addr += s->output_section->vma; |
minfo ("0x%V %W ", addr, (bfd_vma) s->size); |
if (s->fill->size != 0) |
{ |
size_t size; |
unsigned char *p; |
for (p = s->fill->data, size = s->fill->size; size != 0; p++, size--) |
fprintf (config.map_file, "%02x", *p); |
} |
print_nl (); |
print_dot = addr + TO_ADDR (s->size); |
} |
static void |
print_wild_statement (lang_wild_statement_type *w, |
lang_output_section_statement_type *os) |
{ |
struct wildcard_list *sec; |
print_space (); |
if (w->filenames_sorted) |
minfo ("SORT("); |
if (w->filename != NULL) |
minfo ("%s", w->filename); |
else |
minfo ("*"); |
if (w->filenames_sorted) |
minfo (")"); |
minfo ("("); |
for (sec = w->section_list; sec; sec = sec->next) |
{ |
if (sec->spec.sorted) |
minfo ("SORT("); |
if (sec->spec.exclude_name_list != NULL) |
{ |
name_list *tmp; |
minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name); |
for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next) |
minfo (" %s", tmp->name); |
minfo (") "); |
} |
if (sec->spec.name != NULL) |
minfo ("%s", sec->spec.name); |
else |
minfo ("*"); |
if (sec->spec.sorted) |
minfo (")"); |
if (sec->next) |
minfo (" "); |
} |
minfo (")"); |
print_nl (); |
print_statement_list (w->children.head, os); |
} |
/* Print a group statement. */ |
static void |
print_group (lang_group_statement_type *s, |
lang_output_section_statement_type *os) |
{ |
fprintf (config.map_file, "START GROUP\n"); |
print_statement_list (s->children.head, os); |
fprintf (config.map_file, "END GROUP\n"); |
} |
/* Print the list of statements in S. |
This can be called for any statement type. */ |
static void |
print_statement_list (lang_statement_union_type *s, |
lang_output_section_statement_type *os) |
{ |
while (s != NULL) |
{ |
print_statement (s, os); |
s = s->header.next; |
} |
} |
/* Print the first statement in statement list S. |
This can be called for any statement type. */ |
static void |
print_statement (lang_statement_union_type *s, |
lang_output_section_statement_type *os) |
{ |
switch (s->header.type) |
{ |
default: |
fprintf (config.map_file, _("Fail with %d\n"), s->header.type); |
FAIL (); |
break; |
case lang_constructors_statement_enum: |
if (constructor_list.head != NULL) |
{ |
if (constructors_sorted) |
minfo (" SORT (CONSTRUCTORS)\n"); |
else |
minfo (" CONSTRUCTORS\n"); |
print_statement_list (constructor_list.head, os); |
} |
break; |
case lang_wild_statement_enum: |
print_wild_statement (&s->wild_statement, os); |
break; |
case lang_address_statement_enum: |
print_address_statement (&s->address_statement); |
break; |
case lang_object_symbols_statement_enum: |
minfo (" CREATE_OBJECT_SYMBOLS\n"); |
break; |
case lang_fill_statement_enum: |
print_fill_statement (&s->fill_statement); |
break; |
case lang_data_statement_enum: |
print_data_statement (&s->data_statement); |
break; |
case lang_reloc_statement_enum: |
print_reloc_statement (&s->reloc_statement); |
break; |
case lang_input_section_enum: |
print_input_section (s->input_section.section, FALSE); |
break; |
case lang_padding_statement_enum: |
print_padding_statement (&s->padding_statement); |
break; |
case lang_output_section_statement_enum: |
print_output_section_statement (&s->output_section_statement); |
break; |
case lang_assignment_statement_enum: |
print_assignment (&s->assignment_statement, os); |
break; |
case lang_target_statement_enum: |
fprintf (config.map_file, "TARGET(%s)\n", s->target_statement.target); |
break; |
case lang_output_statement_enum: |
minfo ("OUTPUT(%s", s->output_statement.name); |
if (output_target != NULL) |
minfo (" %s", output_target); |
minfo (")\n"); |
break; |
case lang_input_statement_enum: |
print_input_statement (&s->input_statement); |
break; |
case lang_group_statement_enum: |
print_group (&s->group_statement, os); |
break; |
case lang_insert_statement_enum: |
minfo ("INSERT %s %s\n", |
s->insert_statement.is_before ? "BEFORE" : "AFTER", |
s->insert_statement.where); |
break; |
} |
} |
static void |
print_statements (void) |
{ |
print_statement_list (statement_list.head, abs_output_section); |
} |
/* Print the first N statements in statement list S to STDERR. |
If N == 0, nothing is printed. |
If N < 0, the entire list is printed. |
Intended to be called from GDB. */ |
void |
dprint_statement (lang_statement_union_type *s, int n) |
{ |
FILE *map_save = config.map_file; |
config.map_file = stderr; |
if (n < 0) |
print_statement_list (s, abs_output_section); |
else |
{ |
while (s && --n >= 0) |
{ |
print_statement (s, abs_output_section); |
s = s->header.next; |
} |
} |
config.map_file = map_save; |
} |
static void |
insert_pad (lang_statement_union_type **ptr, |
fill_type *fill, |
bfd_size_type alignment_needed, |
asection *output_section, |
bfd_vma dot) |
{ |
static fill_type zero_fill; |
lang_statement_union_type *pad = NULL; |
if (ptr != &statement_list.head) |
pad = ((lang_statement_union_type *) |
((char *) ptr - offsetof (lang_statement_union_type, header.next))); |
if (pad != NULL |
&& pad->header.type == lang_padding_statement_enum |
&& pad->padding_statement.output_section == output_section) |
{ |
/* Use the existing pad statement. */ |
} |
else if ((pad = *ptr) != NULL |
&& pad->header.type == lang_padding_statement_enum |
&& pad->padding_statement.output_section == output_section) |
{ |
/* Use the existing pad statement. */ |
} |
else |
{ |
/* Make a new padding statement, linked into existing chain. */ |
pad = (lang_statement_union_type *) |
stat_alloc (sizeof (lang_padding_statement_type)); |
pad->header.next = *ptr; |
*ptr = pad; |
pad->header.type = lang_padding_statement_enum; |
pad->padding_statement.output_section = output_section; |
if (fill == NULL) |
fill = &zero_fill; |
pad->padding_statement.fill = fill; |
} |
pad->padding_statement.output_offset = dot - output_section->vma; |
pad->padding_statement.size = alignment_needed; |
output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed) |
- output_section->vma); |
} |
/* Work out how much this section will move the dot point. */ |
static bfd_vma |
size_input_section |
(lang_statement_union_type **this_ptr, |
lang_output_section_statement_type *output_section_statement, |
fill_type *fill, |
bfd_vma dot) |
{ |
lang_input_section_type *is = &((*this_ptr)->input_section); |
asection *i = is->section; |
if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS |
&& (i->flags & SEC_EXCLUDE) == 0) |
{ |
bfd_size_type alignment_needed; |
asection *o; |
/* Align this section first to the input sections requirement, |
then to the output section's requirement. If this alignment |
is greater than any seen before, then record it too. Perform |
the alignment by inserting a magic 'padding' statement. */ |
if (output_section_statement->subsection_alignment != -1) |
i->alignment_power = output_section_statement->subsection_alignment; |
o = output_section_statement->bfd_section; |
if (o->alignment_power < i->alignment_power) |
o->alignment_power = i->alignment_power; |
alignment_needed = align_power (dot, i->alignment_power) - dot; |
if (alignment_needed != 0) |
{ |
insert_pad (this_ptr, fill, TO_SIZE (alignment_needed), o, dot); |
dot += alignment_needed; |
} |
/* Remember where in the output section this input section goes. */ |
i->output_offset = dot - o->vma; |
/* Mark how big the output section must be to contain this now. */ |
dot += TO_ADDR (i->size); |
o->size = TO_SIZE (dot - o->vma); |
} |
else |
{ |
i->output_offset = i->vma - output_section_statement->bfd_section->vma; |
} |
return dot; |
} |
static int |
sort_sections_by_lma (const void *arg1, const void *arg2) |
{ |
const asection *sec1 = *(const asection **) arg1; |
const asection *sec2 = *(const asection **) arg2; |
if (bfd_section_lma (sec1->owner, sec1) |
< bfd_section_lma (sec2->owner, sec2)) |
return -1; |
else if (bfd_section_lma (sec1->owner, sec1) |
> bfd_section_lma (sec2->owner, sec2)) |
return 1; |
else if (sec1->id < sec2->id) |
return -1; |
else if (sec1->id > sec2->id) |
return 1; |
return 0; |
} |
#define IGNORE_SECTION(s) \ |
((s->flags & SEC_ALLOC) == 0 \ |
|| ((s->flags & SEC_THREAD_LOCAL) != 0 \ |
&& (s->flags & SEC_LOAD) == 0)) |
/* Check to see if any allocated sections overlap with other allocated |
sections. This can happen if a linker script specifies the output |
section addresses of the two sections. Also check whether any memory |
region has overflowed. */ |
static void |
lang_check_section_addresses (void) |
{ |
asection *s, *p; |
asection **sections, **spp; |
unsigned int count; |
bfd_vma s_start; |
bfd_vma s_end; |
bfd_vma p_start; |
bfd_vma p_end; |
bfd_size_type amt; |
lang_memory_region_type *m; |
if (bfd_count_sections (link_info.output_bfd) <= 1) |
return; |
amt = bfd_count_sections (link_info.output_bfd) * sizeof (asection *); |
sections = (asection **) xmalloc (amt); |
/* Scan all sections in the output list. */ |
count = 0; |
for (s = link_info.output_bfd->sections; s != NULL; s = s->next) |
{ |
/* Only consider loadable sections with real contents. */ |
if (!(s->flags & SEC_LOAD) |
|| !(s->flags & SEC_ALLOC) |
|| s->size == 0) |
continue; |
sections[count] = s; |
count++; |
} |
if (count <= 1) |
return; |
qsort (sections, (size_t) count, sizeof (asection *), |
sort_sections_by_lma); |
spp = sections; |
s = *spp++; |
s_start = s->lma; |
s_end = s_start + TO_ADDR (s->size) - 1; |
for (count--; count; count--) |
{ |
/* We must check the sections' LMA addresses not their VMA |
addresses because overlay sections can have overlapping VMAs |
but they must have distinct LMAs. */ |
p = s; |
p_start = s_start; |
p_end = s_end; |
s = *spp++; |
s_start = s->lma; |
s_end = s_start + TO_ADDR (s->size) - 1; |
/* Look for an overlap. We have sorted sections by lma, so we |
know that s_start >= p_start. Besides the obvious case of |
overlap when the current section starts before the previous |
one ends, we also must have overlap if the previous section |
wraps around the address space. */ |
if (s_start <= p_end |
|| p_end < p_start) |
einfo (_("%X%P: section %s loaded at [%V,%V] overlaps section %s loaded at [%V,%V]\n"), |
s->name, s_start, s_end, p->name, p_start, p_end); |
} |
free (sections); |
/* If any memory region has overflowed, report by how much. |
We do not issue this diagnostic for regions that had sections |
explicitly placed outside their bounds; os_region_check's |
diagnostics are adequate for that case. |
FIXME: It is conceivable that m->current - (m->origin + m->length) |
might overflow a 32-bit integer. There is, alas, no way to print |
a bfd_vma quantity in decimal. */ |
for (m = lang_memory_region_list; m; m = m->next) |
if (m->had_full_message) |
einfo (_("%X%P: region `%s' overflowed by %ld bytes\n"), |
m->name_list.name, (long)(m->current - (m->origin + m->length))); |
} |
/* Make sure the new address is within the region. We explicitly permit the |
current address to be at the exact end of the region when the address is |
non-zero, in case the region is at the end of addressable memory and the |
calculation wraps around. */ |
static void |
os_region_check (lang_output_section_statement_type *os, |
lang_memory_region_type *region, |
etree_type *tree, |
bfd_vma rbase) |
{ |
if ((region->current < region->origin |
|| (region->current - region->origin > region->length)) |
&& ((region->current != region->origin + region->length) |
|| rbase == 0)) |
{ |
if (tree != NULL) |
{ |
einfo (_("%X%P: address 0x%v of %B section `%s'" |
" is not within region `%s'\n"), |
region->current, |
os->bfd_section->owner, |
os->bfd_section->name, |
region->name_list.name); |
} |
else if (!region->had_full_message) |
{ |
region->had_full_message = TRUE; |
einfo (_("%X%P: %B section `%s' will not fit in region `%s'\n"), |
os->bfd_section->owner, |
os->bfd_section->name, |
region->name_list.name); |
} |
} |
} |
/* Set the sizes for all the output sections. */ |
static bfd_vma |
lang_size_sections_1 |
(lang_statement_union_type **prev, |
lang_output_section_statement_type *output_section_statement, |
fill_type *fill, |
bfd_vma dot, |
bfd_boolean *relax, |
bfd_boolean check_regions) |
{ |
lang_statement_union_type *s; |
/* Size up the sections from their constituent parts. */ |
for (s = *prev; s != NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
case lang_output_section_statement_enum: |
{ |
bfd_vma newdot, after; |
lang_output_section_statement_type *os; |
lang_memory_region_type *r; |
int section_alignment = 0; |
os = &s->output_section_statement; |
if (os->constraint == -1) |
break; |
/* FIXME: We shouldn't need to zero section vmas for ld -r |
here, in lang_insert_orphan, or in the default linker scripts. |
This is covering for coff backend linker bugs. See PR6945. */ |
if (os->addr_tree == NULL |
&& link_info.relocatable |
&& (bfd_get_flavour (link_info.output_bfd) |
== bfd_target_coff_flavour)) |
os->addr_tree = exp_intop (0); |
if (os->addr_tree != NULL) |
{ |
os->processed_vma = FALSE; |
exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot); |
if (expld.result.valid_p) |
{ |
dot = expld.result.value; |
if (expld.result.section != NULL) |
dot += expld.result.section->vma; |
} |
else if (expld.phase != lang_mark_phase_enum) |
einfo (_("%F%S: non constant or forward reference" |
" address expression for section %s\n"), |
os->addr_tree, os->name); |
} |
if (os->bfd_section == NULL) |
/* This section was removed or never actually created. */ |
break; |
/* If this is a COFF shared library section, use the size and |
address from the input section. FIXME: This is COFF |
specific; it would be cleaner if there were some other way |
to do this, but nothing simple comes to mind. */ |
if (((bfd_get_flavour (link_info.output_bfd) |
== bfd_target_ecoff_flavour) |
|| (bfd_get_flavour (link_info.output_bfd) |
== bfd_target_coff_flavour)) |
&& (os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) |
{ |
asection *input; |
if (os->children.head == NULL |
|| os->children.head->header.next != NULL |
|| (os->children.head->header.type |
!= lang_input_section_enum)) |
einfo (_("%P%X: Internal error on COFF shared library" |
" section %s\n"), os->name); |
input = os->children.head->input_section.section; |
bfd_set_section_vma (os->bfd_section->owner, |
os->bfd_section, |
bfd_section_vma (input->owner, input)); |
os->bfd_section->size = input->size; |
break; |
} |
newdot = dot; |
if (bfd_is_abs_section (os->bfd_section)) |
{ |
/* No matter what happens, an abs section starts at zero. */ |
ASSERT (os->bfd_section->vma == 0); |
} |
else |
{ |
if (os->addr_tree == NULL) |
{ |
/* No address specified for this section, get one |
from the region specification. */ |
if (os->region == NULL |
|| ((os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD)) |
&& os->region->name_list.name[0] == '*' |
&& strcmp (os->region->name_list.name, |
DEFAULT_MEMORY_REGION) == 0)) |
{ |
os->region = lang_memory_default (os->bfd_section); |
} |
/* If a loadable section is using the default memory |
region, and some non default memory regions were |
defined, issue an error message. */ |
if (!os->ignored |
&& !IGNORE_SECTION (os->bfd_section) |
&& ! link_info.relocatable |
&& check_regions |
&& strcmp (os->region->name_list.name, |
DEFAULT_MEMORY_REGION) == 0 |
&& lang_memory_region_list != NULL |
&& (strcmp (lang_memory_region_list->name_list.name, |
DEFAULT_MEMORY_REGION) != 0 |
|| lang_memory_region_list->next != NULL) |
&& expld.phase != lang_mark_phase_enum) |
{ |
/* By default this is an error rather than just a |
warning because if we allocate the section to the |
default memory region we can end up creating an |
excessively large binary, or even seg faulting when |
attempting to perform a negative seek. See |
sources.redhat.com/ml/binutils/2003-04/msg00423.html |
for an example of this. This behaviour can be |
overridden by the using the --no-check-sections |
switch. */ |
if (command_line.check_section_addresses) |
einfo (_("%P%F: error: no memory region specified" |
" for loadable section `%s'\n"), |
bfd_get_section_name (link_info.output_bfd, |
os->bfd_section)); |
else |
einfo (_("%P: warning: no memory region specified" |
" for loadable section `%s'\n"), |
bfd_get_section_name (link_info.output_bfd, |
os->bfd_section)); |
} |
newdot = os->region->current; |
section_alignment = os->bfd_section->alignment_power; |
} |
else |
section_alignment = os->section_alignment; |
/* Align to what the section needs. */ |
if (section_alignment > 0) |
{ |
bfd_vma savedot = newdot; |
newdot = align_power (newdot, section_alignment); |
if (newdot != savedot |
&& (config.warn_section_align |
|| os->addr_tree != NULL) |
&& expld.phase != lang_mark_phase_enum) |
einfo (_("%P: warning: changing start of section" |
" %s by %lu bytes\n"), |
os->name, (unsigned long) (newdot - savedot)); |
} |
bfd_set_section_vma (0, os->bfd_section, newdot); |
os->bfd_section->output_offset = 0; |
} |
lang_size_sections_1 (&os->children.head, os, |
os->fill, newdot, relax, check_regions); |
os->processed_vma = TRUE; |
if (bfd_is_abs_section (os->bfd_section) || os->ignored) |
/* Except for some special linker created sections, |
no output section should change from zero size |
after strip_excluded_output_sections. A non-zero |
size on an ignored section indicates that some |
input section was not sized early enough. */ |
ASSERT (os->bfd_section->size == 0); |
else |
{ |
dot = os->bfd_section->vma; |
/* Put the section within the requested block size, or |
align at the block boundary. */ |
after = ((dot |
+ TO_ADDR (os->bfd_section->size) |
+ os->block_value - 1) |
& - (bfd_vma) os->block_value); |
os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma); |
} |
/* Set section lma. */ |
r = os->region; |
if (r == NULL) |
r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); |
if (os->load_base) |
{ |
bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base"); |
os->bfd_section->lma = lma; |
} |
else if (os->lma_region != NULL) |
{ |
bfd_vma lma = os->lma_region->current; |
/* When LMA_REGION is the same as REGION, align the LMA |
as we did for the VMA, possibly including alignment |
from the bfd section. If a different region, then |
only align according to the value in the output |
statement unless specified otherwise. */ |
if (os->lma_region != os->region && !os->align_lma_with_input) |
section_alignment = os->section_alignment; |
if (section_alignment > 0) |
lma = align_power (lma, section_alignment); |
os->bfd_section->lma = lma; |
} |
else if (r->last_os != NULL |
&& (os->bfd_section->flags & SEC_ALLOC) != 0) |
{ |
bfd_vma lma; |
asection *last; |
last = r->last_os->output_section_statement.bfd_section; |
/* A backwards move of dot should be accompanied by |
an explicit assignment to the section LMA (ie. |
os->load_base set) because backwards moves can |
create overlapping LMAs. */ |
if (dot < last->vma |
&& os->bfd_section->size != 0 |
&& dot + os->bfd_section->size <= last->vma) |
{ |
/* If dot moved backwards then leave lma equal to |
vma. This is the old default lma, which might |
just happen to work when the backwards move is |
sufficiently large. Nag if this changes anything, |
so people can fix their linker scripts. */ |
if (last->vma != last->lma) |
einfo (_("%P: warning: dot moved backwards before `%s'\n"), |
os->name); |
} |
else |
{ |
/* If this is an overlay, set the current lma to that |
at the end of the previous section. */ |
if (os->sectype == overlay_section) |
lma = last->lma + last->size; |
/* Otherwise, keep the same lma to vma relationship |
as the previous section. */ |
else |
lma = dot + last->lma - last->vma; |
if (section_alignment > 0) |
lma = align_power (lma, section_alignment); |
os->bfd_section->lma = lma; |
} |
} |
os->processed_lma = TRUE; |
if (bfd_is_abs_section (os->bfd_section) || os->ignored) |
break; |
/* Keep track of normal sections using the default |
lma region. We use this to set the lma for |
following sections. Overlays or other linker |
script assignment to lma might mean that the |
default lma == vma is incorrect. |
To avoid warnings about dot moving backwards when using |
-Ttext, don't start tracking sections until we find one |
of non-zero size or with lma set differently to vma. */ |
if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 |
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0) |
&& (os->bfd_section->flags & SEC_ALLOC) != 0 |
&& (os->bfd_section->size != 0 |
|| (r->last_os == NULL |
&& os->bfd_section->vma != os->bfd_section->lma) |
|| (r->last_os != NULL |
&& dot >= (r->last_os->output_section_statement |
.bfd_section->vma))) |
&& os->lma_region == NULL |
&& !link_info.relocatable) |
r->last_os = s; |
/* .tbss sections effectively have zero size. */ |
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 |
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0 |
|| link_info.relocatable) |
dot += TO_ADDR (os->bfd_section->size); |
if (os->update_dot_tree != 0) |
exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot); |
/* Update dot in the region ? |
We only do this if the section is going to be allocated, |
since unallocated sections do not contribute to the region's |
overall size in memory. */ |
if (os->region != NULL |
&& (os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD))) |
{ |
os->region->current = dot; |
if (check_regions) |
/* Make sure the new address is within the region. */ |
os_region_check (os, os->region, os->addr_tree, |
os->bfd_section->vma); |
if (os->lma_region != NULL && os->lma_region != os->region |
&& (os->bfd_section->flags & SEC_LOAD)) |
{ |
os->lma_region->current |
= os->bfd_section->lma + TO_ADDR (os->bfd_section->size); |
if (check_regions) |
os_region_check (os, os->lma_region, NULL, |
os->bfd_section->lma); |
} |
} |
} |
break; |
case lang_constructors_statement_enum: |
dot = lang_size_sections_1 (&constructor_list.head, |
output_section_statement, |
fill, dot, relax, check_regions); |
break; |
case lang_data_statement_enum: |
{ |
unsigned int size = 0; |
s->data_statement.output_offset = |
dot - output_section_statement->bfd_section->vma; |
s->data_statement.output_section = |
output_section_statement->bfd_section; |
/* We might refer to provided symbols in the expression, and |
need to mark them as needed. */ |
exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot); |
switch (s->data_statement.type) |
{ |
default: |
abort (); |
case QUAD: |
case SQUAD: |
size = QUAD_SIZE; |
break; |
case LONG: |
size = LONG_SIZE; |
break; |
case SHORT: |
size = SHORT_SIZE; |
break; |
case BYTE: |
size = BYTE_SIZE; |
break; |
} |
if (size < TO_SIZE ((unsigned) 1)) |
size = TO_SIZE ((unsigned) 1); |
dot += TO_ADDR (size); |
output_section_statement->bfd_section->size |
= TO_SIZE (dot - output_section_statement->bfd_section->vma); |
} |
break; |
case lang_reloc_statement_enum: |
{ |
int size; |
s->reloc_statement.output_offset = |
dot - output_section_statement->bfd_section->vma; |
s->reloc_statement.output_section = |
output_section_statement->bfd_section; |
size = bfd_get_reloc_size (s->reloc_statement.howto); |
dot += TO_ADDR (size); |
output_section_statement->bfd_section->size |
= TO_SIZE (dot - output_section_statement->bfd_section->vma); |
} |
break; |
case lang_wild_statement_enum: |
dot = lang_size_sections_1 (&s->wild_statement.children.head, |
output_section_statement, |
fill, dot, relax, check_regions); |
break; |
case lang_object_symbols_statement_enum: |
link_info.create_object_symbols_section = |
output_section_statement->bfd_section; |
break; |
case lang_output_statement_enum: |
case lang_target_statement_enum: |
break; |
case lang_input_section_enum: |
{ |
asection *i; |
i = s->input_section.section; |
if (relax) |
{ |
bfd_boolean again; |
if (! bfd_relax_section (i->owner, i, &link_info, &again)) |
einfo (_("%P%F: can't relax section: %E\n")); |
if (again) |
*relax = TRUE; |
} |
dot = size_input_section (prev, output_section_statement, |
output_section_statement->fill, dot); |
} |
break; |
case lang_input_statement_enum: |
break; |
case lang_fill_statement_enum: |
s->fill_statement.output_section = |
output_section_statement->bfd_section; |
fill = s->fill_statement.fill; |
break; |
case lang_assignment_statement_enum: |
{ |
bfd_vma newdot = dot; |
etree_type *tree = s->assignment_statement.exp; |
expld.dataseg.relro = exp_dataseg_relro_none; |
exp_fold_tree (tree, |
output_section_statement->bfd_section, |
&newdot); |
if (expld.dataseg.relro == exp_dataseg_relro_start) |
{ |
if (!expld.dataseg.relro_start_stat) |
expld.dataseg.relro_start_stat = s; |
else |
{ |
ASSERT (expld.dataseg.relro_start_stat == s); |
} |
} |
else if (expld.dataseg.relro == exp_dataseg_relro_end) |
{ |
if (!expld.dataseg.relro_end_stat) |
expld.dataseg.relro_end_stat = s; |
else |
{ |
ASSERT (expld.dataseg.relro_end_stat == s); |
} |
} |
expld.dataseg.relro = exp_dataseg_relro_none; |
/* This symbol may be relative to this section. */ |
if ((tree->type.node_class == etree_provided |
|| tree->type.node_class == etree_assign) |
&& (tree->assign.dst [0] != '.' |
|| tree->assign.dst [1] != '\0')) |
output_section_statement->update_dot = 1; |
if (!output_section_statement->ignored) |
{ |
if (output_section_statement == abs_output_section) |
{ |
/* If we don't have an output section, then just adjust |
the default memory address. */ |
lang_memory_region_lookup (DEFAULT_MEMORY_REGION, |
FALSE)->current = newdot; |
} |
else if (newdot != dot) |
{ |
/* Insert a pad after this statement. We can't |
put the pad before when relaxing, in case the |
assignment references dot. */ |
insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot), |
output_section_statement->bfd_section, dot); |
/* Don't neuter the pad below when relaxing. */ |
s = s->header.next; |
/* If dot is advanced, this implies that the section |
should have space allocated to it, unless the |
user has explicitly stated that the section |
should not be allocated. */ |
if (output_section_statement->sectype != noalloc_section |
&& (output_section_statement->sectype != noload_section |
|| (bfd_get_flavour (link_info.output_bfd) |
== bfd_target_elf_flavour))) |
output_section_statement->bfd_section->flags |= SEC_ALLOC; |
} |
dot = newdot; |
} |
} |
break; |
case lang_padding_statement_enum: |
/* If this is the first time lang_size_sections is called, |
we won't have any padding statements. If this is the |
second or later passes when relaxing, we should allow |
padding to shrink. If padding is needed on this pass, it |
will be added back in. */ |
s->padding_statement.size = 0; |
/* Make sure output_offset is valid. If relaxation shrinks |
the section and this pad isn't needed, it's possible to |
have output_offset larger than the final size of the |
section. bfd_set_section_contents will complain even for |
a pad size of zero. */ |
s->padding_statement.output_offset |
= dot - output_section_statement->bfd_section->vma; |
break; |
case lang_group_statement_enum: |
dot = lang_size_sections_1 (&s->group_statement.children.head, |
output_section_statement, |
fill, dot, relax, check_regions); |
break; |
case lang_insert_statement_enum: |
break; |
/* We can only get here when relaxing is turned on. */ |
case lang_address_statement_enum: |
break; |
default: |
FAIL (); |
break; |
} |
prev = &s->header.next; |
} |
return dot; |
} |
/* Callback routine that is used in _bfd_elf_map_sections_to_segments. |
The BFD library has set NEW_SEGMENT to TRUE iff it thinks that |
CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different |
segments. We are allowed an opportunity to override this decision. */ |
bfd_boolean |
ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED, |
bfd * abfd ATTRIBUTE_UNUSED, |
asection * current_section, |
asection * previous_section, |
bfd_boolean new_segment) |
{ |
lang_output_section_statement_type * cur; |
lang_output_section_statement_type * prev; |
/* The checks below are only necessary when the BFD library has decided |
that the two sections ought to be placed into the same segment. */ |
if (new_segment) |
return TRUE; |
/* Paranoia checks. */ |
if (current_section == NULL || previous_section == NULL) |
return new_segment; |
/* If this flag is set, the target never wants code and non-code |
sections comingled in the same segment. */ |
if (config.separate_code |
&& ((current_section->flags ^ previous_section->flags) & SEC_CODE)) |
return TRUE; |
/* Find the memory regions associated with the two sections. |
We call lang_output_section_find() here rather than scanning the list |
of output sections looking for a matching section pointer because if |
we have a large number of sections then a hash lookup is faster. */ |
cur = lang_output_section_find (current_section->name); |
prev = lang_output_section_find (previous_section->name); |
/* More paranoia. */ |
if (cur == NULL || prev == NULL) |
return new_segment; |
/* If the regions are different then force the sections to live in |
different segments. See the email thread starting at the following |
URL for the reasons why this is necessary: |
http://sourceware.org/ml/binutils/2007-02/msg00216.html */ |
return cur->region != prev->region; |
} |
void |
one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions) |
{ |
lang_statement_iteration++; |
lang_size_sections_1 (&statement_list.head, abs_output_section, |
0, 0, relax, check_regions); |
} |
void |
lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) |
{ |
expld.phase = lang_allocating_phase_enum; |
expld.dataseg.phase = exp_dataseg_none; |
one_lang_size_sections_pass (relax, check_regions); |
if (expld.dataseg.phase == exp_dataseg_end_seen |
&& link_info.relro && expld.dataseg.relro_end) |
{ |
/* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try |
to put expld.dataseg.relro on a (common) page boundary. */ |
bfd_vma min_base, old_base, relro_end, maxpage; |
expld.dataseg.phase = exp_dataseg_relro_adjust; |
maxpage = expld.dataseg.maxpagesize; |
/* MIN_BASE is the absolute minimum address we are allowed to start the |
read-write segment (byte before will be mapped read-only). */ |
min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1); |
/* OLD_BASE is the address for a feasible minimum address which will |
still not cause a data overlap inside MAXPAGE causing file offset skip |
by MAXPAGE. */ |
old_base = expld.dataseg.base; |
expld.dataseg.base += (-expld.dataseg.relro_end |
& (expld.dataseg.pagesize - 1)); |
/* Compute the expected PT_GNU_RELRO segment end. */ |
relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1) |
& ~(expld.dataseg.pagesize - 1)); |
if (min_base + maxpage < expld.dataseg.base) |
{ |
expld.dataseg.base -= maxpage; |
relro_end -= maxpage; |
} |
lang_reset_memory_regions (); |
one_lang_size_sections_pass (relax, check_regions); |
if (expld.dataseg.relro_end > relro_end) |
{ |
/* The alignment of sections between DATA_SEGMENT_ALIGN |
and DATA_SEGMENT_RELRO_END caused huge padding to be |
inserted at DATA_SEGMENT_RELRO_END. Try to start a bit lower so |
that the section alignments will fit in. */ |
asection *sec; |
unsigned int max_alignment_power = 0; |
/* Find maximum alignment power of sections between |
DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */ |
for (sec = link_info.output_bfd->sections; sec; sec = sec->next) |
if (sec->vma >= expld.dataseg.base |
&& sec->vma < expld.dataseg.relro_end |
&& sec->alignment_power > max_alignment_power) |
max_alignment_power = sec->alignment_power; |
if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize) |
{ |
if (expld.dataseg.base - (1 << max_alignment_power) < old_base) |
expld.dataseg.base += expld.dataseg.pagesize; |
expld.dataseg.base -= (1 << max_alignment_power); |
lang_reset_memory_regions (); |
one_lang_size_sections_pass (relax, check_regions); |
} |
} |
link_info.relro_start = expld.dataseg.base; |
link_info.relro_end = expld.dataseg.relro_end; |
} |
else if (expld.dataseg.phase == exp_dataseg_end_seen) |
{ |
/* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether |
a page could be saved in the data segment. */ |
bfd_vma first, last; |
first = -expld.dataseg.base & (expld.dataseg.pagesize - 1); |
last = expld.dataseg.end & (expld.dataseg.pagesize - 1); |
if (first && last |
&& ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1)) |
!= (expld.dataseg.end & ~(expld.dataseg.pagesize - 1))) |
&& first + last <= expld.dataseg.pagesize) |
{ |
expld.dataseg.phase = exp_dataseg_adjust; |
lang_reset_memory_regions (); |
one_lang_size_sections_pass (relax, check_regions); |
} |
else |
expld.dataseg.phase = exp_dataseg_done; |
} |
else |
expld.dataseg.phase = exp_dataseg_done; |
} |
static lang_output_section_statement_type *current_section; |
static lang_assignment_statement_type *current_assign; |
static bfd_boolean prefer_next_section; |
/* Worker function for lang_do_assignments. Recursiveness goes here. */ |
static bfd_vma |
lang_do_assignments_1 (lang_statement_union_type *s, |
lang_output_section_statement_type *current_os, |
fill_type *fill, |
bfd_vma dot, |
bfd_boolean *found_end) |
{ |
for (; s != NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
case lang_constructors_statement_enum: |
dot = lang_do_assignments_1 (constructor_list.head, |
current_os, fill, dot, found_end); |
break; |
case lang_output_section_statement_enum: |
{ |
lang_output_section_statement_type *os; |
os = &(s->output_section_statement); |
os->after_end = *found_end; |
if (os->bfd_section != NULL && !os->ignored) |
{ |
if ((os->bfd_section->flags & SEC_ALLOC) != 0) |
{ |
current_section = os; |
prefer_next_section = FALSE; |
} |
dot = os->bfd_section->vma; |
lang_do_assignments_1 (os->children.head, |
os, os->fill, dot, found_end); |
/* .tbss sections effectively have zero size. */ |
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 |
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0 |
|| link_info.relocatable) |
dot += TO_ADDR (os->bfd_section->size); |
if (os->update_dot_tree != NULL) |
exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot); |
} |
} |
break; |
case lang_wild_statement_enum: |
dot = lang_do_assignments_1 (s->wild_statement.children.head, |
current_os, fill, dot, found_end); |
break; |
case lang_object_symbols_statement_enum: |
case lang_output_statement_enum: |
case lang_target_statement_enum: |
break; |
case lang_data_statement_enum: |
exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot); |
if (expld.result.valid_p) |
{ |
s->data_statement.value = expld.result.value; |
if (expld.result.section != NULL) |
s->data_statement.value += expld.result.section->vma; |
} |
else |
einfo (_("%F%P: invalid data statement\n")); |
{ |
unsigned int size; |
switch (s->data_statement.type) |
{ |
default: |
abort (); |
case QUAD: |
case SQUAD: |
size = QUAD_SIZE; |
break; |
case LONG: |
size = LONG_SIZE; |
break; |
case SHORT: |
size = SHORT_SIZE; |
break; |
case BYTE: |
size = BYTE_SIZE; |
break; |
} |
if (size < TO_SIZE ((unsigned) 1)) |
size = TO_SIZE ((unsigned) 1); |
dot += TO_ADDR (size); |
} |
break; |
case lang_reloc_statement_enum: |
exp_fold_tree (s->reloc_statement.addend_exp, |
bfd_abs_section_ptr, &dot); |
if (expld.result.valid_p) |
s->reloc_statement.addend_value = expld.result.value; |
else |
einfo (_("%F%P: invalid reloc statement\n")); |
dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto)); |
break; |
case lang_input_section_enum: |
{ |
asection *in = s->input_section.section; |
if ((in->flags & SEC_EXCLUDE) == 0) |
dot += TO_ADDR (in->size); |
} |
break; |
case lang_input_statement_enum: |
break; |
case lang_fill_statement_enum: |
fill = s->fill_statement.fill; |
break; |
case lang_assignment_statement_enum: |
current_assign = &s->assignment_statement; |
if (current_assign->exp->type.node_class != etree_assert) |
{ |
const char *p = current_assign->exp->assign.dst; |
if (current_os == abs_output_section && p[0] == '.' && p[1] == 0) |
prefer_next_section = TRUE; |
while (*p == '_') |
++p; |
if (strcmp (p, "end") == 0) |
*found_end = TRUE; |
} |
exp_fold_tree (s->assignment_statement.exp, |
current_os->bfd_section, |
&dot); |
break; |
case lang_padding_statement_enum: |
dot += TO_ADDR (s->padding_statement.size); |
break; |
case lang_group_statement_enum: |
dot = lang_do_assignments_1 (s->group_statement.children.head, |
current_os, fill, dot, found_end); |
break; |
case lang_insert_statement_enum: |
break; |
case lang_address_statement_enum: |
break; |
default: |
FAIL (); |
break; |
} |
} |
return dot; |
} |
void |
lang_do_assignments (lang_phase_type phase) |
{ |
bfd_boolean found_end = FALSE; |
current_section = NULL; |
prefer_next_section = FALSE; |
expld.phase = phase; |
lang_statement_iteration++; |
lang_do_assignments_1 (statement_list.head, |
abs_output_section, NULL, 0, &found_end); |
} |
/* For an assignment statement outside of an output section statement, |
choose the best of neighbouring output sections to use for values |
of "dot". */ |
asection * |
section_for_dot (void) |
{ |
asection *s; |
/* Assignments belong to the previous output section, unless there |
has been an assignment to "dot", in which case following |
assignments belong to the next output section. (The assumption |
is that an assignment to "dot" is setting up the address for the |
next output section.) Except that past the assignment to "_end" |
we always associate with the previous section. This exception is |
for targets like SH that define an alloc .stack or other |
weirdness after non-alloc sections. */ |
if (current_section == NULL || prefer_next_section) |
{ |
lang_statement_union_type *stmt; |
lang_output_section_statement_type *os; |
for (stmt = (lang_statement_union_type *) current_assign; |
stmt != NULL; |
stmt = stmt->header.next) |
if (stmt->header.type == lang_output_section_statement_enum) |
break; |
os = &stmt->output_section_statement; |
while (os != NULL |
&& !os->after_end |
&& (os->bfd_section == NULL |
|| (os->bfd_section->flags & SEC_EXCLUDE) != 0 |
|| bfd_section_removed_from_list (link_info.output_bfd, |
os->bfd_section))) |
os = os->next; |
if (current_section == NULL || os == NULL || !os->after_end) |
{ |
if (os != NULL) |
s = os->bfd_section; |
else |
s = link_info.output_bfd->section_last; |
while (s != NULL |
&& ((s->flags & SEC_ALLOC) == 0 |
|| (s->flags & SEC_THREAD_LOCAL) != 0)) |
s = s->prev; |
if (s != NULL) |
return s; |
return bfd_abs_section_ptr; |
} |
} |
s = current_section->bfd_section; |
/* The section may have been stripped. */ |
while (s != NULL |
&& ((s->flags & SEC_EXCLUDE) != 0 |
|| (s->flags & SEC_ALLOC) == 0 |
|| (s->flags & SEC_THREAD_LOCAL) != 0 |
|| bfd_section_removed_from_list (link_info.output_bfd, s))) |
s = s->prev; |
if (s == NULL) |
s = link_info.output_bfd->sections; |
while (s != NULL |
&& ((s->flags & SEC_ALLOC) == 0 |
|| (s->flags & SEC_THREAD_LOCAL) != 0)) |
s = s->next; |
if (s != NULL) |
return s; |
return bfd_abs_section_ptr; |
} |
/* Fix any .startof. or .sizeof. symbols. When the assemblers see the |
operator .startof. (section_name), it produces an undefined symbol |
.startof.section_name. Similarly, when it sees |
.sizeof. (section_name), it produces an undefined symbol |
.sizeof.section_name. For all the output sections, we look for |
such symbols, and set them to the correct value. */ |
static void |
lang_set_startof (void) |
{ |
asection *s; |
if (link_info.relocatable) |
return; |
for (s = link_info.output_bfd->sections; s != NULL; s = s->next) |
{ |
const char *secname; |
char *buf; |
struct bfd_link_hash_entry *h; |
secname = bfd_get_section_name (link_info.output_bfd, s); |
buf = (char *) xmalloc (10 + strlen (secname)); |
sprintf (buf, ".startof.%s", secname); |
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); |
if (h != NULL && h->type == bfd_link_hash_undefined) |
{ |
h->type = bfd_link_hash_defined; |
h->u.def.value = 0; |
h->u.def.section = s; |
} |
sprintf (buf, ".sizeof.%s", secname); |
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); |
if (h != NULL && h->type == bfd_link_hash_undefined) |
{ |
h->type = bfd_link_hash_defined; |
h->u.def.value = TO_ADDR (s->size); |
h->u.def.section = bfd_abs_section_ptr; |
} |
free (buf); |
} |
} |
static void |
lang_end (void) |
{ |
struct bfd_link_hash_entry *h; |
bfd_boolean warn; |
if ((link_info.relocatable && !link_info.gc_sections) |
|| (link_info.shared && !link_info.executable)) |
warn = entry_from_cmdline; |
else |
warn = TRUE; |
/* Force the user to specify a root when generating a relocatable with |
--gc-sections. */ |
if (link_info.gc_sections && link_info.relocatable |
&& !(entry_from_cmdline || undef_from_cmdline)) |
einfo (_("%P%F: gc-sections requires either an entry or " |
"an undefined symbol\n")); |
if (entry_symbol.name == NULL) |
{ |
/* No entry has been specified. Look for the default entry, but |
don't warn if we don't find it. */ |
entry_symbol.name = entry_symbol_default; |
warn = FALSE; |
} |
h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name, |
FALSE, FALSE, TRUE); |
if (h != NULL |
&& (h->type == bfd_link_hash_defined |
|| h->type == bfd_link_hash_defweak) |
&& h->u.def.section->output_section != NULL) |
{ |
bfd_vma val; |
val = (h->u.def.value |
+ bfd_get_section_vma (link_info.output_bfd, |
h->u.def.section->output_section) |
+ h->u.def.section->output_offset); |
if (! bfd_set_start_address (link_info.output_bfd, val)) |
einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name); |
} |
else |
{ |
bfd_vma val; |
const char *send; |
/* We couldn't find the entry symbol. Try parsing it as a |
number. */ |
val = bfd_scan_vma (entry_symbol.name, &send, 0); |
if (*send == '\0') |
{ |
if (! bfd_set_start_address (link_info.output_bfd, val)) |
einfo (_("%P%F: can't set start address\n")); |
} |
else |
{ |
asection *ts; |
/* Can't find the entry symbol, and it's not a number. Use |
the first address in the text section. */ |
ts = bfd_get_section_by_name (link_info.output_bfd, entry_section); |
if (ts != NULL) |
{ |
if (warn) |
einfo (_("%P: warning: cannot find entry symbol %s;" |
" defaulting to %V\n"), |
entry_symbol.name, |
bfd_get_section_vma (link_info.output_bfd, ts)); |
if (!(bfd_set_start_address |
(link_info.output_bfd, |
bfd_get_section_vma (link_info.output_bfd, ts)))) |
einfo (_("%P%F: can't set start address\n")); |
} |
else |
{ |
if (warn) |
einfo (_("%P: warning: cannot find entry symbol %s;" |
" not setting start address\n"), |
entry_symbol.name); |
} |
} |
} |
} |
/* This is a small function used when we want to ignore errors from |
BFD. */ |
static void |
ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...) |
{ |
/* Don't do anything. */ |
} |
/* Check that the architecture of all the input files is compatible |
with the output file. Also call the backend to let it do any |
other checking that is needed. */ |
static void |
lang_check (void) |
{ |
lang_statement_union_type *file; |
bfd *input_bfd; |
const bfd_arch_info_type *compatible; |
for (file = file_chain.head; file != NULL; file = file->input_statement.next) |
{ |
#ifdef ENABLE_PLUGINS |
/* Don't check format of files claimed by plugin. */ |
if (file->input_statement.flags.claimed) |
continue; |
#endif /* ENABLE_PLUGINS */ |
input_bfd = file->input_statement.the_bfd; |
compatible |
= bfd_arch_get_compatible (input_bfd, link_info.output_bfd, |
command_line.accept_unknown_input_arch); |
/* In general it is not possible to perform a relocatable |
link between differing object formats when the input |
file has relocations, because the relocations in the |
input format may not have equivalent representations in |
the output format (and besides BFD does not translate |
relocs for other link purposes than a final link). */ |
if ((link_info.relocatable || link_info.emitrelocations) |
&& (compatible == NULL |
|| (bfd_get_flavour (input_bfd) |
!= bfd_get_flavour (link_info.output_bfd))) |
&& (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0) |
{ |
einfo (_("%P%F: Relocatable linking with relocations from" |
" format %s (%B) to format %s (%B) is not supported\n"), |
bfd_get_target (input_bfd), input_bfd, |
bfd_get_target (link_info.output_bfd), link_info.output_bfd); |
/* einfo with %F exits. */ |
} |
if (compatible == NULL) |
{ |
if (command_line.warn_mismatch) |
einfo (_("%P%X: %s architecture of input file `%B'" |
" is incompatible with %s output\n"), |
bfd_printable_name (input_bfd), input_bfd, |
bfd_printable_name (link_info.output_bfd)); |
} |
else if (bfd_count_sections (input_bfd)) |
{ |
/* If the input bfd has no contents, it shouldn't set the |
private data of the output bfd. */ |
bfd_error_handler_type pfn = NULL; |
/* If we aren't supposed to warn about mismatched input |
files, temporarily set the BFD error handler to a |
function which will do nothing. We still want to call |
bfd_merge_private_bfd_data, since it may set up |
information which is needed in the output file. */ |
if (! command_line.warn_mismatch) |
pfn = bfd_set_error_handler (ignore_bfd_errors); |
if (! bfd_merge_private_bfd_data (input_bfd, link_info.output_bfd)) |
{ |
if (command_line.warn_mismatch) |
einfo (_("%P%X: failed to merge target specific data" |
" of file %B\n"), input_bfd); |
} |
if (! command_line.warn_mismatch) |
bfd_set_error_handler (pfn); |
} |
} |
} |
/* Look through all the global common symbols and attach them to the |
correct section. The -sort-common command line switch may be used |
to roughly sort the entries by alignment. */ |
static void |
lang_common (void) |
{ |
if (command_line.inhibit_common_definition) |
return; |
if (link_info.relocatable |
&& ! command_line.force_common_definition) |
return; |
if (! config.sort_common) |
bfd_link_hash_traverse (link_info.hash, lang_one_common, NULL); |
else |
{ |
unsigned int power; |
if (config.sort_common == sort_descending) |
{ |
for (power = 4; power > 0; power--) |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
power = 0; |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
} |
else |
{ |
for (power = 0; power <= 4; power++) |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
power = UINT_MAX; |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
} |
} |
} |
/* Place one common symbol in the correct section. */ |
static bfd_boolean |
lang_one_common (struct bfd_link_hash_entry *h, void *info) |
{ |
unsigned int power_of_two; |
bfd_vma size; |
asection *section; |
if (h->type != bfd_link_hash_common) |
return TRUE; |
size = h->u.c.size; |
power_of_two = h->u.c.p->alignment_power; |
if (config.sort_common == sort_descending |
&& power_of_two < *(unsigned int *) info) |
return TRUE; |
else if (config.sort_common == sort_ascending |
&& power_of_two > *(unsigned int *) info) |
return TRUE; |
section = h->u.c.p->section; |
if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h)) |
einfo (_("%P%F: Could not define common symbol `%T': %E\n"), |
h->root.string); |
if (config.map_file != NULL) |
{ |
static bfd_boolean header_printed; |
int len; |
char *name; |
char buf[50]; |
if (! header_printed) |
{ |
minfo (_("\nAllocating common symbols\n")); |
minfo (_("Common symbol size file\n\n")); |
header_printed = TRUE; |
} |
name = bfd_demangle (link_info.output_bfd, h->root.string, |
DMGL_ANSI | DMGL_PARAMS); |
if (name == NULL) |
{ |
minfo ("%s", h->root.string); |
len = strlen (h->root.string); |
} |
else |
{ |
minfo ("%s", name); |
len = strlen (name); |
free (name); |
} |
if (len >= 19) |
{ |
print_nl (); |
len = 0; |
} |
while (len < 20) |
{ |
print_space (); |
++len; |
} |
minfo ("0x"); |
if (size <= 0xffffffff) |
sprintf (buf, "%lx", (unsigned long) size); |
else |
sprintf_vma (buf, size); |
minfo ("%s", buf); |
len = strlen (buf); |
while (len < 16) |
{ |
print_space (); |
++len; |
} |
minfo ("%B\n", section->owner); |
} |
return TRUE; |
} |
/* Run through the input files and ensure that every input section has |
somewhere to go. If one is found without a destination then create |
an input request and place it into the statement tree. */ |
static void |
lang_place_orphans (void) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (file) |
{ |
asection *s; |
for (s = file->the_bfd->sections; s != NULL; s = s->next) |
{ |
if (s->output_section == NULL) |
{ |
/* This section of the file is not attached, root |
around for a sensible place for it to go. */ |
if (file->flags.just_syms) |
bfd_link_just_syms (file->the_bfd, s, &link_info); |
else if ((s->flags & SEC_EXCLUDE) != 0) |
s->output_section = bfd_abs_section_ptr; |
else if (strcmp (s->name, "COMMON") == 0) |
{ |
/* This is a lonely common section which must have |
come from an archive. We attach to the section |
with the wildcard. */ |
if (! link_info.relocatable |
|| command_line.force_common_definition) |
{ |
if (default_common_section == NULL) |
default_common_section |
= lang_output_section_statement_lookup (".bss", 0, |
TRUE); |
lang_add_section (&default_common_section->children, s, |
NULL, default_common_section); |
} |
} |
else |
{ |
const char *name = s->name; |
int constraint = 0; |
if (config.unique_orphan_sections |
|| unique_section_p (s, NULL)) |
constraint = SPECIAL; |
if (!ldemul_place_orphan (s, name, constraint)) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_statement_lookup (name, |
constraint, |
TRUE); |
if (os->addr_tree == NULL |
&& (link_info.relocatable |
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) |
os->addr_tree = exp_intop (0); |
lang_add_section (&os->children, s, NULL, os); |
} |
} |
} |
} |
} |
} |
void |
lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) |
{ |
flagword *ptr_flags; |
ptr_flags = invert ? &ptr->not_flags : &ptr->flags; |
while (*flags) |
{ |
switch (*flags) |
{ |
case 'A': case 'a': |
*ptr_flags |= SEC_ALLOC; |
break; |
case 'R': case 'r': |
*ptr_flags |= SEC_READONLY; |
break; |
case 'W': case 'w': |
*ptr_flags |= SEC_DATA; |
break; |
case 'X': case 'x': |
*ptr_flags |= SEC_CODE; |
break; |
case 'L': case 'l': |
case 'I': case 'i': |
*ptr_flags |= SEC_LOAD; |
break; |
default: |
einfo (_("%P%F: invalid syntax in flags\n")); |
break; |
} |
flags++; |
} |
} |
/* Call a function on each input file. This function will be called |
on an archive, but not on the elements. */ |
void |
lang_for_each_input_file (void (*func) (lang_input_statement_type *)) |
{ |
lang_input_statement_type *f; |
for (f = (lang_input_statement_type *) input_file_chain.head; |
f != NULL; |
f = (lang_input_statement_type *) f->next_real_file) |
func (f); |
} |
/* Call a function on each file. The function will be called on all |
the elements of an archive which are included in the link, but will |
not be called on the archive file itself. */ |
void |
lang_for_each_file (void (*func) (lang_input_statement_type *)) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
func (f); |
} |
} |
void |
ldlang_add_file (lang_input_statement_type *entry) |
{ |
lang_statement_append (&file_chain, |
(lang_statement_union_type *) entry, |
&entry->next); |
/* The BFD linker needs to have a list of all input BFDs involved in |
a link. */ |
ASSERT (entry->the_bfd->link_next == NULL); |
ASSERT (entry->the_bfd != link_info.output_bfd); |
*link_info.input_bfds_tail = entry->the_bfd; |
link_info.input_bfds_tail = &entry->the_bfd->link_next; |
entry->the_bfd->usrdata = entry; |
bfd_set_gp_size (entry->the_bfd, g_switch_value); |
/* Look through the sections and check for any which should not be |
included in the link. We need to do this now, so that we can |
notice when the backend linker tries to report multiple |
definition errors for symbols which are in sections we aren't |
going to link. FIXME: It might be better to entirely ignore |
symbols which are defined in sections which are going to be |
discarded. This would require modifying the backend linker for |
each backend which might set the SEC_LINK_ONCE flag. If we do |
this, we should probably handle SEC_EXCLUDE in the same way. */ |
bfd_map_over_sections (entry->the_bfd, section_already_linked, entry); |
} |
void |
lang_add_output (const char *name, int from_script) |
{ |
/* Make -o on command line override OUTPUT in script. */ |
if (!had_output_filename || !from_script) |
{ |
output_filename = name; |
had_output_filename = TRUE; |
} |
} |
static int |
topower (int x) |
{ |
unsigned int i = 1; |
int l; |
if (x < 0) |
return -1; |
for (l = 0; l < 32; l++) |
{ |
if (i >= (unsigned int) x) |
return l; |
i <<= 1; |
} |
return 0; |
} |
lang_output_section_statement_type * |
lang_enter_output_section_statement (const char *output_section_statement_name, |
etree_type *address_exp, |
enum section_type sectype, |
etree_type *align, |
etree_type *subalign, |
etree_type *ebase, |
int constraint, |
int align_with_input) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_statement_lookup (output_section_statement_name, |
constraint, TRUE); |
current_section = os; |
if (os->addr_tree == NULL) |
{ |
os->addr_tree = address_exp; |
} |
os->sectype = sectype; |
if (sectype != noload_section) |
os->flags = SEC_NO_FLAGS; |
else |
os->flags = SEC_NEVER_LOAD; |
os->block_value = 1; |
/* Make next things chain into subchain of this. */ |
push_stat_ptr (&os->children); |
os->align_lma_with_input = align_with_input == ALIGN_WITH_INPUT; |
if (os->align_lma_with_input && align != NULL) |
einfo (_("%F%P:%S: error: align with input and explicit align specified\n"), NULL); |
os->subsection_alignment = |
topower (exp_get_value_int (subalign, -1, "subsection alignment")); |
os->section_alignment = |
topower (exp_get_value_int (align, -1, "section alignment")); |
os->load_base = ebase; |
return os; |
} |
void |
lang_final (void) |
{ |
lang_output_statement_type *new_stmt; |
new_stmt = new_stat (lang_output_statement, stat_ptr); |
new_stmt->name = output_filename; |
} |
/* Reset the current counters in the regions. */ |
void |
lang_reset_memory_regions (void) |
{ |
lang_memory_region_type *p = lang_memory_region_list; |
asection *o; |
lang_output_section_statement_type *os; |
for (p = lang_memory_region_list; p != NULL; p = p->next) |
{ |
p->current = p->origin; |
p->last_os = NULL; |
} |
for (os = &lang_output_section_statement.head->output_section_statement; |
os != NULL; |
os = os->next) |
{ |
os->processed_vma = FALSE; |
os->processed_lma = FALSE; |
} |
for (o = link_info.output_bfd->sections; o != NULL; o = o->next) |
{ |
/* Save the last size for possible use by bfd_relax_section. */ |
o->rawsize = o->size; |
o->size = 0; |
} |
} |
/* Worker for lang_gc_sections_1. */ |
static void |
gc_section_callback (lang_wild_statement_type *ptr, |
struct wildcard_list *sec ATTRIBUTE_UNUSED, |
asection *section, |
struct flag_info *sflag_info ATTRIBUTE_UNUSED, |
lang_input_statement_type *file ATTRIBUTE_UNUSED, |
void *data ATTRIBUTE_UNUSED) |
{ |
/* If the wild pattern was marked KEEP, the member sections |
should be as well. */ |
if (ptr->keep_sections) |
section->flags |= SEC_KEEP; |
} |
/* Iterate over sections marking them against GC. */ |
static void |
lang_gc_sections_1 (lang_statement_union_type *s) |
{ |
for (; s != NULL; s = s->header.next) |
{ |
switch (s->header.type) |
{ |
case lang_wild_statement_enum: |
walk_wild (&s->wild_statement, gc_section_callback, NULL); |
break; |
case lang_constructors_statement_enum: |
lang_gc_sections_1 (constructor_list.head); |
break; |
case lang_output_section_statement_enum: |
lang_gc_sections_1 (s->output_section_statement.children.head); |
break; |
case lang_group_statement_enum: |
lang_gc_sections_1 (s->group_statement.children.head); |
break; |
default: |
break; |
} |
} |
} |
static void |
lang_gc_sections (void) |
{ |
/* Keep all sections so marked in the link script. */ |
lang_gc_sections_1 (statement_list.head); |
/* SEC_EXCLUDE is ignored when doing a relocatable link, except in |
the special case of debug info. (See bfd/stabs.c) |
Twiddle the flag here, to simplify later linker code. */ |
if (link_info.relocatable) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
asection *sec; |
#ifdef ENABLE_PLUGINS |
if (f->flags.claimed) |
continue; |
#endif |
for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next) |
if ((sec->flags & SEC_DEBUGGING) == 0) |
sec->flags &= ~SEC_EXCLUDE; |
} |
} |
if (link_info.gc_sections) |
bfd_gc_sections (link_info.output_bfd, &link_info); |
} |
/* Worker for lang_find_relro_sections_1. */ |
static void |
find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, |
struct wildcard_list *sec ATTRIBUTE_UNUSED, |
asection *section, |
struct flag_info *sflag_info ATTRIBUTE_UNUSED, |
lang_input_statement_type *file ATTRIBUTE_UNUSED, |
void *data) |
{ |
/* Discarded, excluded and ignored sections effectively have zero |
size. */ |
if (section->output_section != NULL |
&& section->output_section->owner == link_info.output_bfd |
&& (section->output_section->flags & SEC_EXCLUDE) == 0 |
&& !IGNORE_SECTION (section) |
&& section->size != 0) |
{ |
bfd_boolean *has_relro_section = (bfd_boolean *) data; |
*has_relro_section = TRUE; |
} |
} |
/* Iterate over sections for relro sections. */ |
static void |
lang_find_relro_sections_1 (lang_statement_union_type *s, |
bfd_boolean *has_relro_section) |
{ |
if (*has_relro_section) |
return; |
for (; s != NULL; s = s->header.next) |
{ |
if (s == expld.dataseg.relro_end_stat) |
break; |
switch (s->header.type) |
{ |
case lang_wild_statement_enum: |
walk_wild (&s->wild_statement, |
find_relro_section_callback, |
has_relro_section); |
break; |
case lang_constructors_statement_enum: |
lang_find_relro_sections_1 (constructor_list.head, |
has_relro_section); |
break; |
case lang_output_section_statement_enum: |
lang_find_relro_sections_1 (s->output_section_statement.children.head, |
has_relro_section); |
break; |
case lang_group_statement_enum: |
lang_find_relro_sections_1 (s->group_statement.children.head, |
has_relro_section); |
break; |
default: |
break; |
} |
} |
} |
static void |
lang_find_relro_sections (void) |
{ |
bfd_boolean has_relro_section = FALSE; |
/* Check all sections in the link script. */ |
lang_find_relro_sections_1 (expld.dataseg.relro_start_stat, |
&has_relro_section); |
if (!has_relro_section) |
link_info.relro = FALSE; |
} |
/* Relax all sections until bfd_relax_section gives up. */ |
void |
lang_relax_sections (bfd_boolean need_layout) |
{ |
if (RELAXATION_ENABLED) |
{ |
/* We may need more than one relaxation pass. */ |
int i = link_info.relax_pass; |
/* The backend can use it to determine the current pass. */ |
link_info.relax_pass = 0; |
while (i--) |
{ |
/* Keep relaxing until bfd_relax_section gives up. */ |
bfd_boolean relax_again; |
link_info.relax_trip = -1; |
do |
{ |
link_info.relax_trip++; |
/* Note: pe-dll.c does something like this also. If you find |
you need to change this code, you probably need to change |
pe-dll.c also. DJ */ |
/* Do all the assignments with our current guesses as to |
section sizes. */ |
lang_do_assignments (lang_assigning_phase_enum); |
/* We must do this after lang_do_assignments, because it uses |
size. */ |
lang_reset_memory_regions (); |
/* Perform another relax pass - this time we know where the |
globals are, so can make a better guess. */ |
relax_again = FALSE; |
lang_size_sections (&relax_again, FALSE); |
} |
while (relax_again); |
link_info.relax_pass++; |
} |
need_layout = TRUE; |
} |
if (need_layout) |
{ |
/* Final extra sizing to report errors. */ |
lang_do_assignments (lang_assigning_phase_enum); |
lang_reset_memory_regions (); |
lang_size_sections (NULL, TRUE); |
} |
} |
#ifdef ENABLE_PLUGINS |
/* Find the insert point for the plugin's replacement files. We |
place them after the first claimed real object file, or if the |
first claimed object is an archive member, after the last real |
object file immediately preceding the archive. In the event |
no objects have been claimed at all, we return the first dummy |
object file on the list as the insert point; that works, but |
the callee must be careful when relinking the file_chain as it |
is not actually on that chain, only the statement_list and the |
input_file list; in that case, the replacement files must be |
inserted at the head of the file_chain. */ |
static lang_input_statement_type * |
find_replacements_insert_point (void) |
{ |
lang_input_statement_type *claim1, *lastobject; |
lastobject = &input_file_chain.head->input_statement; |
for (claim1 = &file_chain.head->input_statement; |
claim1 != NULL; |
claim1 = &claim1->next->input_statement) |
{ |
if (claim1->flags.claimed) |
return claim1->flags.claim_archive ? lastobject : claim1; |
/* Update lastobject if this is a real object file. */ |
if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL)) |
lastobject = claim1; |
} |
/* No files were claimed by the plugin. Choose the last object |
file found on the list (maybe the first, dummy entry) as the |
insert point. */ |
return lastobject; |
} |
/* Insert SRCLIST into DESTLIST after given element by chaining |
on FIELD as the next-pointer. (Counterintuitively does not need |
a pointer to the actual after-node itself, just its chain field.) */ |
static void |
lang_list_insert_after (lang_statement_list_type *destlist, |
lang_statement_list_type *srclist, |
lang_statement_union_type **field) |
{ |
*(srclist->tail) = *field; |
*field = srclist->head; |
if (destlist->tail == field) |
destlist->tail = srclist->tail; |
} |
/* Detach new nodes added to DESTLIST since the time ORIGLIST |
was taken as a copy of it and leave them in ORIGLIST. */ |
static void |
lang_list_remove_tail (lang_statement_list_type *destlist, |
lang_statement_list_type *origlist) |
{ |
union lang_statement_union **savetail; |
/* Check that ORIGLIST really is an earlier state of DESTLIST. */ |
ASSERT (origlist->head == destlist->head); |
savetail = origlist->tail; |
origlist->head = *(savetail); |
origlist->tail = destlist->tail; |
destlist->tail = savetail; |
*savetail = NULL; |
} |
#endif /* ENABLE_PLUGINS */ |
void |
lang_process (void) |
{ |
/* Finalize dynamic list. */ |
if (link_info.dynamic_list) |
lang_finalize_version_expr_head (&link_info.dynamic_list->head); |
current_target = default_target; |
/* Open the output file. */ |
lang_for_each_statement (ldlang_open_output); |
init_opb (); |
ldemul_create_output_section_statements (); |
/* Add to the hash table all undefineds on the command line. */ |
lang_place_undefineds (); |
if (!bfd_section_already_linked_table_init ()) |
einfo (_("%P%F: Failed to create hash table\n")); |
/* Create a bfd for each input file. */ |
current_target = default_target; |
open_input_bfds (statement_list.head, OPEN_BFD_NORMAL); |
#ifdef ENABLE_PLUGINS |
if (plugin_active_plugins_p ()) |
{ |
lang_statement_list_type added; |
lang_statement_list_type files, inputfiles; |
/* Now all files are read, let the plugin(s) decide if there |
are any more to be added to the link before we call the |
emulation's after_open hook. We create a private list of |
input statements for this purpose, which we will eventually |
insert into the global statment list after the first claimed |
file. */ |
added = *stat_ptr; |
/* We need to manipulate all three chains in synchrony. */ |
files = file_chain; |
inputfiles = input_file_chain; |
if (plugin_call_all_symbols_read ()) |
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"), |
plugin_error_plugin ()); |
/* Open any newly added files, updating the file chains. */ |
link_info.loading_lto_outputs = TRUE; |
open_input_bfds (*added.tail, OPEN_BFD_NORMAL); |
/* Restore the global list pointer now they have all been added. */ |
lang_list_remove_tail (stat_ptr, &added); |
/* And detach the fresh ends of the file lists. */ |
lang_list_remove_tail (&file_chain, &files); |
lang_list_remove_tail (&input_file_chain, &inputfiles); |
/* Were any new files added? */ |
if (added.head != NULL) |
{ |
/* If so, we will insert them into the statement list immediately |
after the first input file that was claimed by the plugin. */ |
plugin_insert = find_replacements_insert_point (); |
/* If a plugin adds input files without having claimed any, we |
don't really have a good idea where to place them. Just putting |
them at the start or end of the list is liable to leave them |
outside the crtbegin...crtend range. */ |
ASSERT (plugin_insert != NULL); |
/* Splice the new statement list into the old one. */ |
lang_list_insert_after (stat_ptr, &added, |
&plugin_insert->header.next); |
/* Likewise for the file chains. */ |
lang_list_insert_after (&input_file_chain, &inputfiles, |
&plugin_insert->next_real_file); |
/* We must be careful when relinking file_chain; we may need to |
insert the new files at the head of the list if the insert |
point chosen is the dummy first input file. */ |
if (plugin_insert->filename) |
lang_list_insert_after (&file_chain, &files, &plugin_insert->next); |
else |
lang_list_insert_after (&file_chain, &files, &file_chain.head); |
/* Rescan archives in case new undefined symbols have appeared. */ |
open_input_bfds (statement_list.head, OPEN_BFD_RESCAN); |
} |
} |
#endif /* ENABLE_PLUGINS */ |
link_info.gc_sym_list = &entry_symbol; |
if (entry_symbol.name == NULL) |
link_info.gc_sym_list = ldlang_undef_chain_list_head; |
ldemul_after_open (); |
bfd_section_already_linked_table_free (); |
/* Make sure that we're not mixing architectures. We call this |
after all the input files have been opened, but before we do any |
other processing, so that any operations merge_private_bfd_data |
does on the output file will be known during the rest of the |
link. */ |
lang_check (); |
/* Handle .exports instead of a version script if we're told to do so. */ |
if (command_line.version_exports_section) |
lang_do_version_exports_section (); |
/* Build all sets based on the information gathered from the input |
files. */ |
ldctor_build_sets (); |
/* PR 13683: We must rerun the assignments prior to running garbage |
collection in order to make sure that all symbol aliases are resolved. */ |
lang_do_assignments (lang_mark_phase_enum); |
expld.phase = lang_first_phase_enum; |
/* Remove unreferenced sections if asked to. */ |
lang_gc_sections (); |
/* Size up the common data. */ |
lang_common (); |
/* Update wild statements. */ |
update_wild_statements (statement_list.head); |
/* Run through the contours of the script and attach input sections |
to the correct output sections. */ |
lang_statement_iteration++; |
map_input_to_output_sections (statement_list.head, NULL, NULL); |
process_insert_statements (); |
/* Find any sections not attached explicitly and handle them. */ |
lang_place_orphans (); |
if (! link_info.relocatable) |
{ |
asection *found; |
/* Merge SEC_MERGE sections. This has to be done after GC of |
sections, so that GCed sections are not merged, but before |
assigning dynamic symbols, since removing whole input sections |
is hard then. */ |
bfd_merge_sections (link_info.output_bfd, &link_info); |
/* Look for a text section and set the readonly attribute in it. */ |
found = bfd_get_section_by_name (link_info.output_bfd, ".text"); |
if (found != NULL) |
{ |
if (config.text_read_only) |
found->flags |= SEC_READONLY; |
else |
found->flags &= ~SEC_READONLY; |
} |
} |
/* Do anything special before sizing sections. This is where ELF |
and other back-ends size dynamic sections. */ |
ldemul_before_allocation (); |
/* We must record the program headers before we try to fix the |
section positions, since they will affect SIZEOF_HEADERS. */ |
lang_record_phdrs (); |
/* Check relro sections. */ |
if (link_info.relro && ! link_info.relocatable) |
lang_find_relro_sections (); |
/* Size up the sections. */ |
lang_size_sections (NULL, ! RELAXATION_ENABLED); |
/* See if anything special should be done now we know how big |
everything is. This is where relaxation is done. */ |
ldemul_after_allocation (); |
/* Fix any .startof. or .sizeof. symbols. */ |
lang_set_startof (); |
/* Do all the assignments, now that we know the final resting places |
of all the symbols. */ |
lang_do_assignments (lang_final_phase_enum); |
ldemul_finish (); |
/* Make sure that the section addresses make sense. */ |
if (command_line.check_section_addresses) |
lang_check_section_addresses (); |
lang_end (); |
} |
/* EXPORTED TO YACC */ |
void |
lang_add_wild (struct wildcard_spec *filespec, |
struct wildcard_list *section_list, |
bfd_boolean keep_sections) |
{ |
struct wildcard_list *curr, *next; |
lang_wild_statement_type *new_stmt; |
/* Reverse the list as the parser puts it back to front. */ |
for (curr = section_list, section_list = NULL; |
curr != NULL; |
section_list = curr, curr = next) |
{ |
if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0) |
placed_commons = TRUE; |
next = curr->next; |
curr->next = section_list; |
} |
if (filespec != NULL && filespec->name != NULL) |
{ |
if (strcmp (filespec->name, "*") == 0) |
filespec->name = NULL; |
else if (! wildcardp (filespec->name)) |
lang_has_input_file = TRUE; |
} |
new_stmt = new_stat (lang_wild_statement, stat_ptr); |
new_stmt->filename = NULL; |
new_stmt->filenames_sorted = FALSE; |
new_stmt->section_flag_list = NULL; |
if (filespec != NULL) |
{ |
new_stmt->filename = filespec->name; |
new_stmt->filenames_sorted = filespec->sorted == by_name; |
new_stmt->section_flag_list = filespec->section_flag_list; |
} |
new_stmt->section_list = section_list; |
new_stmt->keep_sections = keep_sections; |
lang_list_init (&new_stmt->children); |
analyze_walk_wild_section_handler (new_stmt); |
} |
void |
lang_section_start (const char *name, etree_type *address, |
const segment_type *segment) |
{ |
lang_address_statement_type *ad; |
ad = new_stat (lang_address_statement, stat_ptr); |
ad->section_name = name; |
ad->address = address; |
ad->segment = segment; |
} |
/* Set the start symbol to NAME. CMDLINE is nonzero if this is called |
because of a -e argument on the command line, or zero if this is |
called by ENTRY in a linker script. Command line arguments take |
precedence. */ |
void |
lang_add_entry (const char *name, bfd_boolean cmdline) |
{ |
if (entry_symbol.name == NULL |
|| cmdline |
|| ! entry_from_cmdline) |
{ |
entry_symbol.name = name; |
entry_from_cmdline = cmdline; |
} |
} |
/* Set the default start symbol to NAME. .em files should use this, |
not lang_add_entry, to override the use of "start" if neither the |
linker script nor the command line specifies an entry point. NAME |
must be permanently allocated. */ |
void |
lang_default_entry (const char *name) |
{ |
entry_symbol_default = name; |
} |
void |
lang_add_target (const char *name) |
{ |
lang_target_statement_type *new_stmt; |
new_stmt = new_stat (lang_target_statement, stat_ptr); |
new_stmt->target = name; |
} |
void |
lang_add_map (const char *name) |
{ |
while (*name) |
{ |
switch (*name) |
{ |
case 'F': |
map_option_f = TRUE; |
break; |
} |
name++; |
} |
} |
void |
lang_add_fill (fill_type *fill) |
{ |
lang_fill_statement_type *new_stmt; |
new_stmt = new_stat (lang_fill_statement, stat_ptr); |
new_stmt->fill = fill; |
} |
void |
lang_add_data (int type, union etree_union *exp) |
{ |
lang_data_statement_type *new_stmt; |
new_stmt = new_stat (lang_data_statement, stat_ptr); |
new_stmt->exp = exp; |
new_stmt->type = type; |
} |
/* Create a new reloc statement. RELOC is the BFD relocation type to |
generate. HOWTO is the corresponding howto structure (we could |
look this up, but the caller has already done so). SECTION is the |
section to generate a reloc against, or NAME is the name of the |
symbol to generate a reloc against. Exactly one of SECTION and |
NAME must be NULL. ADDEND is an expression for the addend. */ |
void |
lang_add_reloc (bfd_reloc_code_real_type reloc, |
reloc_howto_type *howto, |
asection *section, |
const char *name, |
union etree_union *addend) |
{ |
lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr); |
p->reloc = reloc; |
p->howto = howto; |
p->section = section; |
p->name = name; |
p->addend_exp = addend; |
p->addend_value = 0; |
p->output_section = NULL; |
p->output_offset = 0; |
} |
lang_assignment_statement_type * |
lang_add_assignment (etree_type *exp) |
{ |
lang_assignment_statement_type *new_stmt; |
new_stmt = new_stat (lang_assignment_statement, stat_ptr); |
new_stmt->exp = exp; |
return new_stmt; |
} |
void |
lang_add_attribute (enum statement_enum attribute) |
{ |
new_statement (attribute, sizeof (lang_statement_header_type), stat_ptr); |
} |
void |
lang_startup (const char *name) |
{ |
if (first_file->filename != NULL) |
{ |
einfo (_("%P%F: multiple STARTUP files\n")); |
} |
first_file->filename = name; |
first_file->local_sym_name = name; |
first_file->flags.real = TRUE; |
} |
void |
lang_float (bfd_boolean maybe) |
{ |
lang_float_flag = maybe; |
} |
/* Work out the load- and run-time regions from a script statement, and |
store them in *LMA_REGION and *REGION respectively. |
MEMSPEC is the name of the run-time region, or the value of |
DEFAULT_MEMORY_REGION if the statement didn't specify one. |
LMA_MEMSPEC is the name of the load-time region, or null if the |
statement didn't specify one.HAVE_LMA_P is TRUE if the statement |
had an explicit load address. |
It is an error to specify both a load region and a load address. */ |
static void |
lang_get_regions (lang_memory_region_type **region, |
lang_memory_region_type **lma_region, |
const char *memspec, |
const char *lma_memspec, |
bfd_boolean have_lma, |
bfd_boolean have_vma) |
{ |
*lma_region = lang_memory_region_lookup (lma_memspec, FALSE); |
/* If no runtime region or VMA has been specified, but the load region |
has been specified, then use the load region for the runtime region |
as well. */ |
if (lma_memspec != NULL |
&& ! have_vma |
&& strcmp (memspec, DEFAULT_MEMORY_REGION) == 0) |
*region = *lma_region; |
else |
*region = lang_memory_region_lookup (memspec, FALSE); |
if (have_lma && lma_memspec != 0) |
einfo (_("%X%P:%S: section has both a load address and a load region\n"), |
NULL); |
} |
void |
lang_leave_output_section_statement (fill_type *fill, const char *memspec, |
lang_output_section_phdr_list *phdrs, |
const char *lma_memspec) |
{ |
lang_get_regions (¤t_section->region, |
¤t_section->lma_region, |
memspec, lma_memspec, |
current_section->load_base != NULL, |
current_section->addr_tree != NULL); |
/* If this section has no load region or base, but uses the same |
region as the previous section, then propagate the previous |
section's load region. */ |
if (current_section->lma_region == NULL |
&& current_section->load_base == NULL |
&& current_section->addr_tree == NULL |
&& current_section->region == current_section->prev->region) |
current_section->lma_region = current_section->prev->lma_region; |
current_section->fill = fill; |
current_section->phdrs = phdrs; |
pop_stat_ptr (); |
} |
void |
lang_statement_append (lang_statement_list_type *list, |
lang_statement_union_type *element, |
lang_statement_union_type **field) |
{ |
*(list->tail) = element; |
list->tail = field; |
} |
/* Set the output format type. -oformat overrides scripts. */ |
void |
lang_add_output_format (const char *format, |
const char *big, |
const char *little, |
int from_script) |
{ |
if (output_target == NULL || !from_script) |
{ |
if (command_line.endian == ENDIAN_BIG |
&& big != NULL) |
format = big; |
else if (command_line.endian == ENDIAN_LITTLE |
&& little != NULL) |
format = little; |
output_target = format; |
} |
} |
void |
lang_add_insert (const char *where, int is_before) |
{ |
lang_insert_statement_type *new_stmt; |
new_stmt = new_stat (lang_insert_statement, stat_ptr); |
new_stmt->where = where; |
new_stmt->is_before = is_before; |
saved_script_handle = previous_script_handle; |
} |
/* Enter a group. This creates a new lang_group_statement, and sets |
stat_ptr to build new statements within the group. */ |
void |
lang_enter_group (void) |
{ |
lang_group_statement_type *g; |
g = new_stat (lang_group_statement, stat_ptr); |
lang_list_init (&g->children); |
push_stat_ptr (&g->children); |
} |
/* Leave a group. This just resets stat_ptr to start writing to the |
regular list of statements again. Note that this will not work if |
groups can occur inside anything else which can adjust stat_ptr, |
but currently they can't. */ |
void |
lang_leave_group (void) |
{ |
pop_stat_ptr (); |
} |
/* Add a new program header. This is called for each entry in a PHDRS |
command in a linker script. */ |
void |
lang_new_phdr (const char *name, |
etree_type *type, |
bfd_boolean filehdr, |
bfd_boolean phdrs, |
etree_type *at, |
etree_type *flags) |
{ |
struct lang_phdr *n, **pp; |
bfd_boolean hdrs; |
n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr)); |
n->next = NULL; |
n->name = name; |
n->type = exp_get_value_int (type, 0, "program header type"); |
n->filehdr = filehdr; |
n->phdrs = phdrs; |
n->at = at; |
n->flags = flags; |
hdrs = n->type == 1 && (phdrs || filehdr); |
for (pp = &lang_phdr_list; *pp != NULL; pp = &(*pp)->next) |
if (hdrs |
&& (*pp)->type == 1 |
&& !((*pp)->filehdr || (*pp)->phdrs)) |
{ |
einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported" |
" when prior PT_LOAD headers lack them\n"), NULL); |
hdrs = FALSE; |
} |
*pp = n; |
} |
/* Record the program header information in the output BFD. FIXME: We |
should not be calling an ELF specific function here. */ |
static void |
lang_record_phdrs (void) |
{ |
unsigned int alc; |
asection **secs; |
lang_output_section_phdr_list *last; |
struct lang_phdr *l; |
lang_output_section_statement_type *os; |
alc = 10; |
secs = (asection **) xmalloc (alc * sizeof (asection *)); |
last = NULL; |
for (l = lang_phdr_list; l != NULL; l = l->next) |
{ |
unsigned int c; |
flagword flags; |
bfd_vma at; |
c = 0; |
for (os = &lang_output_section_statement.head->output_section_statement; |
os != NULL; |
os = os->next) |
{ |
lang_output_section_phdr_list *pl; |
if (os->constraint < 0) |
continue; |
pl = os->phdrs; |
if (pl != NULL) |
last = pl; |
else |
{ |
if (os->sectype == noload_section |
|| os->bfd_section == NULL |
|| (os->bfd_section->flags & SEC_ALLOC) == 0) |
continue; |
/* Don't add orphans to PT_INTERP header. */ |
if (l->type == 3) |
continue; |
if (last == NULL) |
{ |
lang_output_section_statement_type * tmp_os; |
/* If we have not run across a section with a program |
header assigned to it yet, then scan forwards to find |
one. This prevents inconsistencies in the linker's |
behaviour when a script has specified just a single |
header and there are sections in that script which are |
not assigned to it, and which occur before the first |
use of that header. See here for more details: |
http://sourceware.org/ml/binutils/2007-02/msg00291.html */ |
for (tmp_os = os; tmp_os; tmp_os = tmp_os->next) |
if (tmp_os->phdrs) |
{ |
last = tmp_os->phdrs; |
break; |
} |
if (last == NULL) |
einfo (_("%F%P: no sections assigned to phdrs\n")); |
} |
pl = last; |
} |
if (os->bfd_section == NULL) |
continue; |
for (; pl != NULL; pl = pl->next) |
{ |
if (strcmp (pl->name, l->name) == 0) |
{ |
if (c >= alc) |
{ |
alc *= 2; |
secs = (asection **) xrealloc (secs, |
alc * sizeof (asection *)); |
} |
secs[c] = os->bfd_section; |
++c; |
pl->used = TRUE; |
} |
} |
} |
if (l->flags == NULL) |
flags = 0; |
else |
flags = exp_get_vma (l->flags, 0, "phdr flags"); |
if (l->at == NULL) |
at = 0; |
else |
at = exp_get_vma (l->at, 0, "phdr load address"); |
if (! bfd_record_phdr (link_info.output_bfd, l->type, |
l->flags != NULL, flags, l->at != NULL, |
at, l->filehdr, l->phdrs, c, secs)) |
einfo (_("%F%P: bfd_record_phdr failed: %E\n")); |
} |
free (secs); |
/* Make sure all the phdr assignments succeeded. */ |
for (os = &lang_output_section_statement.head->output_section_statement; |
os != NULL; |
os = os->next) |
{ |
lang_output_section_phdr_list *pl; |
if (os->constraint < 0 |
|| os->bfd_section == NULL) |
continue; |
for (pl = os->phdrs; |
pl != NULL; |
pl = pl->next) |
if (! pl->used && strcmp (pl->name, "NONE") != 0) |
einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"), |
os->name, pl->name); |
} |
} |
/* Record a list of sections which may not be cross referenced. */ |
void |
lang_add_nocrossref (lang_nocrossref_type *l) |
{ |
struct lang_nocrossrefs *n; |
n = (struct lang_nocrossrefs *) xmalloc (sizeof *n); |
n->next = nocrossref_list; |
n->list = l; |
nocrossref_list = n; |
/* Set notice_all so that we get informed about all symbols. */ |
link_info.notice_all = TRUE; |
} |
/* Overlay handling. We handle overlays with some static variables. */ |
/* The overlay virtual address. */ |
static etree_type *overlay_vma; |
/* And subsection alignment. */ |
static etree_type *overlay_subalign; |
/* An expression for the maximum section size seen so far. */ |
static etree_type *overlay_max; |
/* A list of all the sections in this overlay. */ |
struct overlay_list { |
struct overlay_list *next; |
lang_output_section_statement_type *os; |
}; |
static struct overlay_list *overlay_list; |
/* Start handling an overlay. */ |
void |
lang_enter_overlay (etree_type *vma_expr, etree_type *subalign) |
{ |
/* The grammar should prevent nested overlays from occurring. */ |
ASSERT (overlay_vma == NULL |
&& overlay_subalign == NULL |
&& overlay_max == NULL); |
overlay_vma = vma_expr; |
overlay_subalign = subalign; |
} |
/* Start a section in an overlay. We handle this by calling |
lang_enter_output_section_statement with the correct VMA. |
lang_leave_overlay sets up the LMA and memory regions. */ |
void |
lang_enter_overlay_section (const char *name) |
{ |
struct overlay_list *n; |
etree_type *size; |
lang_enter_output_section_statement (name, overlay_vma, overlay_section, |
0, overlay_subalign, 0, 0, 0); |
/* If this is the first section, then base the VMA of future |
sections on this one. This will work correctly even if `.' is |
used in the addresses. */ |
if (overlay_list == NULL) |
overlay_vma = exp_nameop (ADDR, name); |
/* Remember the section. */ |
n = (struct overlay_list *) xmalloc (sizeof *n); |
n->os = current_section; |
n->next = overlay_list; |
overlay_list = n; |
size = exp_nameop (SIZEOF, name); |
/* Arrange to work out the maximum section end address. */ |
if (overlay_max == NULL) |
overlay_max = size; |
else |
overlay_max = exp_binop (MAX_K, overlay_max, size); |
} |
/* Finish a section in an overlay. There isn't any special to do |
here. */ |
void |
lang_leave_overlay_section (fill_type *fill, |
lang_output_section_phdr_list *phdrs) |
{ |
const char *name; |
char *clean, *s2; |
const char *s1; |
char *buf; |
name = current_section->name; |
/* For now, assume that DEFAULT_MEMORY_REGION is the run-time memory |
region and that no load-time region has been specified. It doesn't |
really matter what we say here, since lang_leave_overlay will |
override it. */ |
lang_leave_output_section_statement (fill, DEFAULT_MEMORY_REGION, phdrs, 0); |
/* Define the magic symbols. */ |
clean = (char *) xmalloc (strlen (name) + 1); |
s2 = clean; |
for (s1 = name; *s1 != '\0'; s1++) |
if (ISALNUM (*s1) || *s1 == '_') |
*s2++ = *s1; |
*s2 = '\0'; |
buf = (char *) xmalloc (strlen (clean) + sizeof "__load_start_"); |
sprintf (buf, "__load_start_%s", clean); |
lang_add_assignment (exp_provide (buf, |
exp_nameop (LOADADDR, name), |
FALSE)); |
buf = (char *) xmalloc (strlen (clean) + sizeof "__load_stop_"); |
sprintf (buf, "__load_stop_%s", clean); |
lang_add_assignment (exp_provide (buf, |
exp_binop ('+', |
exp_nameop (LOADADDR, name), |
exp_nameop (SIZEOF, name)), |
FALSE)); |
free (clean); |
} |
/* Finish an overlay. If there are any overlay wide settings, this |
looks through all the sections in the overlay and sets them. */ |
void |
lang_leave_overlay (etree_type *lma_expr, |
int nocrossrefs, |
fill_type *fill, |
const char *memspec, |
lang_output_section_phdr_list *phdrs, |
const char *lma_memspec) |
{ |
lang_memory_region_type *region; |
lang_memory_region_type *lma_region; |
struct overlay_list *l; |
lang_nocrossref_type *nocrossref; |
lang_get_regions (®ion, &lma_region, |
memspec, lma_memspec, |
lma_expr != NULL, FALSE); |
nocrossref = NULL; |
/* After setting the size of the last section, set '.' to end of the |
overlay region. */ |
if (overlay_list != NULL) |
{ |
overlay_list->os->update_dot = 1; |
overlay_list->os->update_dot_tree |
= exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE); |
} |
l = overlay_list; |
while (l != NULL) |
{ |
struct overlay_list *next; |
if (fill != NULL && l->os->fill == NULL) |
l->os->fill = fill; |
l->os->region = region; |
l->os->lma_region = lma_region; |
/* The first section has the load address specified in the |
OVERLAY statement. The rest are worked out from that. |
The base address is not needed (and should be null) if |
an LMA region was specified. */ |
if (l->next == 0) |
{ |
l->os->load_base = lma_expr; |
l->os->sectype = normal_section; |
} |
if (phdrs != NULL && l->os->phdrs == NULL) |
l->os->phdrs = phdrs; |
if (nocrossrefs) |
{ |
lang_nocrossref_type *nc; |
nc = (lang_nocrossref_type *) xmalloc (sizeof *nc); |
nc->name = l->os->name; |
nc->next = nocrossref; |
nocrossref = nc; |
} |
next = l->next; |
free (l); |
l = next; |
} |
if (nocrossref != NULL) |
lang_add_nocrossref (nocrossref); |
overlay_vma = NULL; |
overlay_list = NULL; |
overlay_max = NULL; |
} |
/* Version handling. This is only useful for ELF. */ |
/* If PREV is NULL, return first version pattern matching particular symbol. |
If PREV is non-NULL, return first version pattern matching particular |
symbol after PREV (previously returned by lang_vers_match). */ |
static struct bfd_elf_version_expr * |
lang_vers_match (struct bfd_elf_version_expr_head *head, |
struct bfd_elf_version_expr *prev, |
const char *sym) |
{ |
const char *c_sym; |
const char *cxx_sym = sym; |
const char *java_sym = sym; |
struct bfd_elf_version_expr *expr = NULL; |
enum demangling_styles curr_style; |
curr_style = CURRENT_DEMANGLING_STYLE; |
cplus_demangle_set_style (no_demangling); |
c_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_NO_OPTS); |
if (!c_sym) |
c_sym = sym; |
cplus_demangle_set_style (curr_style); |
if (head->mask & BFD_ELF_VERSION_CXX_TYPE) |
{ |
cxx_sym = bfd_demangle (link_info.output_bfd, sym, |
DMGL_PARAMS | DMGL_ANSI); |
if (!cxx_sym) |
cxx_sym = sym; |
} |
if (head->mask & BFD_ELF_VERSION_JAVA_TYPE) |
{ |
java_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_JAVA); |
if (!java_sym) |
java_sym = sym; |
} |
if (head->htab && (prev == NULL || prev->literal)) |
{ |
struct bfd_elf_version_expr e; |
switch (prev ? prev->mask : 0) |
{ |
case 0: |
if (head->mask & BFD_ELF_VERSION_C_TYPE) |
{ |
e.pattern = c_sym; |
expr = (struct bfd_elf_version_expr *) |
htab_find ((htab_t) head->htab, &e); |
while (expr && strcmp (expr->pattern, c_sym) == 0) |
if (expr->mask == BFD_ELF_VERSION_C_TYPE) |
goto out_ret; |
else |
expr = expr->next; |
} |
/* Fallthrough */ |
case BFD_ELF_VERSION_C_TYPE: |
if (head->mask & BFD_ELF_VERSION_CXX_TYPE) |
{ |
e.pattern = cxx_sym; |
expr = (struct bfd_elf_version_expr *) |
htab_find ((htab_t) head->htab, &e); |
while (expr && strcmp (expr->pattern, cxx_sym) == 0) |
if (expr->mask == BFD_ELF_VERSION_CXX_TYPE) |
goto out_ret; |
else |
expr = expr->next; |
} |
/* Fallthrough */ |
case BFD_ELF_VERSION_CXX_TYPE: |
if (head->mask & BFD_ELF_VERSION_JAVA_TYPE) |
{ |
e.pattern = java_sym; |
expr = (struct bfd_elf_version_expr *) |
htab_find ((htab_t) head->htab, &e); |
while (expr && strcmp (expr->pattern, java_sym) == 0) |
if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE) |
goto out_ret; |
else |
expr = expr->next; |
} |
/* Fallthrough */ |
default: |
break; |
} |
} |
/* Finally, try the wildcards. */ |
if (prev == NULL || prev->literal) |
expr = head->remaining; |
else |
expr = prev->next; |
for (; expr; expr = expr->next) |
{ |
const char *s; |
if (!expr->pattern) |
continue; |
if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') |
break; |
if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE) |
s = java_sym; |
else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE) |
s = cxx_sym; |
else |
s = c_sym; |
if (fnmatch (expr->pattern, s, 0) == 0) |
break; |
} |
out_ret: |
if (c_sym != sym) |
free ((char *) c_sym); |
if (cxx_sym != sym) |
free ((char *) cxx_sym); |
if (java_sym != sym) |
free ((char *) java_sym); |
return expr; |
} |
/* Return NULL if the PATTERN argument is a glob pattern, otherwise, |
return a pointer to the symbol name with any backslash quotes removed. */ |
static const char * |
realsymbol (const char *pattern) |
{ |
const char *p; |
bfd_boolean changed = FALSE, backslash = FALSE; |
char *s, *symbol = (char *) xmalloc (strlen (pattern) + 1); |
for (p = pattern, s = symbol; *p != '\0'; ++p) |
{ |
/* It is a glob pattern only if there is no preceding |
backslash. */ |
if (backslash) |
{ |
/* Remove the preceding backslash. */ |
*(s - 1) = *p; |
backslash = FALSE; |
changed = TRUE; |
} |
else |
{ |
if (*p == '?' || *p == '*' || *p == '[') |
{ |
free (symbol); |
return NULL; |
} |
*s++ = *p; |
backslash = *p == '\\'; |
} |
} |
if (changed) |
{ |
*s = '\0'; |
return symbol; |
} |
else |
{ |
free (symbol); |
return pattern; |
} |
} |
/* This is called for each variable name or match expression. NEW_NAME is |
the name of the symbol to match, or, if LITERAL_P is FALSE, a glob |
pattern to be matched against symbol names. */ |
struct bfd_elf_version_expr * |
lang_new_vers_pattern (struct bfd_elf_version_expr *orig, |
const char *new_name, |
const char *lang, |
bfd_boolean literal_p) |
{ |
struct bfd_elf_version_expr *ret; |
ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret); |
ret->next = orig; |
ret->symver = 0; |
ret->script = 0; |
ret->literal = TRUE; |
ret->pattern = literal_p ? new_name : realsymbol (new_name); |
if (ret->pattern == NULL) |
{ |
ret->pattern = new_name; |
ret->literal = FALSE; |
} |
if (lang == NULL || strcasecmp (lang, "C") == 0) |
ret->mask = BFD_ELF_VERSION_C_TYPE; |
else if (strcasecmp (lang, "C++") == 0) |
ret->mask = BFD_ELF_VERSION_CXX_TYPE; |
else if (strcasecmp (lang, "Java") == 0) |
ret->mask = BFD_ELF_VERSION_JAVA_TYPE; |
else |
{ |
einfo (_("%X%P: unknown language `%s' in version information\n"), |
lang); |
ret->mask = BFD_ELF_VERSION_C_TYPE; |
} |
return ldemul_new_vers_pattern (ret); |
} |
/* This is called for each set of variable names and match |
expressions. */ |
struct bfd_elf_version_tree * |
lang_new_vers_node (struct bfd_elf_version_expr *globals, |
struct bfd_elf_version_expr *locals) |
{ |
struct bfd_elf_version_tree *ret; |
ret = (struct bfd_elf_version_tree *) xcalloc (1, sizeof *ret); |
ret->globals.list = globals; |
ret->locals.list = locals; |
ret->match = lang_vers_match; |
ret->name_indx = (unsigned int) -1; |
return ret; |
} |
/* This static variable keeps track of version indices. */ |
static int version_index; |
static hashval_t |
version_expr_head_hash (const void *p) |
{ |
const struct bfd_elf_version_expr *e = |
(const struct bfd_elf_version_expr *) p; |
return htab_hash_string (e->pattern); |
} |
static int |
version_expr_head_eq (const void *p1, const void *p2) |
{ |
const struct bfd_elf_version_expr *e1 = |
(const struct bfd_elf_version_expr *) p1; |
const struct bfd_elf_version_expr *e2 = |
(const struct bfd_elf_version_expr *) p2; |
return strcmp (e1->pattern, e2->pattern) == 0; |
} |
static void |
lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head) |
{ |
size_t count = 0; |
struct bfd_elf_version_expr *e, *next; |
struct bfd_elf_version_expr **list_loc, **remaining_loc; |
for (e = head->list; e; e = e->next) |
{ |
if (e->literal) |
count++; |
head->mask |= e->mask; |
} |
if (count) |
{ |
head->htab = htab_create (count * 2, version_expr_head_hash, |
version_expr_head_eq, NULL); |
list_loc = &head->list; |
remaining_loc = &head->remaining; |
for (e = head->list; e; e = next) |
{ |
next = e->next; |
if (!e->literal) |
{ |
*remaining_loc = e; |
remaining_loc = &e->next; |
} |
else |
{ |
void **loc = htab_find_slot ((htab_t) head->htab, e, INSERT); |
if (*loc) |
{ |
struct bfd_elf_version_expr *e1, *last; |
e1 = (struct bfd_elf_version_expr *) *loc; |
last = NULL; |
do |
{ |
if (e1->mask == e->mask) |
{ |
last = NULL; |
break; |
} |
last = e1; |
e1 = e1->next; |
} |
while (e1 && strcmp (e1->pattern, e->pattern) == 0); |
if (last == NULL) |
{ |
/* This is a duplicate. */ |
/* FIXME: Memory leak. Sometimes pattern is not |
xmalloced alone, but in larger chunk of memory. */ |
/* free (e->pattern); */ |
free (e); |
} |
else |
{ |
e->next = last->next; |
last->next = e; |
} |
} |
else |
{ |
*loc = e; |
*list_loc = e; |
list_loc = &e->next; |
} |
} |
} |
*remaining_loc = NULL; |
*list_loc = head->remaining; |
} |
else |
head->remaining = head->list; |
} |
/* This is called when we know the name and dependencies of the |
version. */ |
void |
lang_register_vers_node (const char *name, |
struct bfd_elf_version_tree *version, |
struct bfd_elf_version_deps *deps) |
{ |
struct bfd_elf_version_tree *t, **pp; |
struct bfd_elf_version_expr *e1; |
if (name == NULL) |
name = ""; |
if (link_info.version_info != NULL |
&& (name[0] == '\0' || link_info.version_info->name[0] == '\0')) |
{ |
einfo (_("%X%P: anonymous version tag cannot be combined" |
" with other version tags\n")); |
free (version); |
return; |
} |
/* Make sure this node has a unique name. */ |
for (t = link_info.version_info; t != NULL; t = t->next) |
if (strcmp (t->name, name) == 0) |
einfo (_("%X%P: duplicate version tag `%s'\n"), name); |
lang_finalize_version_expr_head (&version->globals); |
lang_finalize_version_expr_head (&version->locals); |
/* Check the global and local match names, and make sure there |
aren't any duplicates. */ |
for (e1 = version->globals.list; e1 != NULL; e1 = e1->next) |
{ |
for (t = link_info.version_info; t != NULL; t = t->next) |
{ |
struct bfd_elf_version_expr *e2; |
if (t->locals.htab && e1->literal) |
{ |
e2 = (struct bfd_elf_version_expr *) |
htab_find ((htab_t) t->locals.htab, e1); |
while (e2 && strcmp (e1->pattern, e2->pattern) == 0) |
{ |
if (e1->mask == e2->mask) |
einfo (_("%X%P: duplicate expression `%s'" |
" in version information\n"), e1->pattern); |
e2 = e2->next; |
} |
} |
else if (!e1->literal) |
for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next) |
if (strcmp (e1->pattern, e2->pattern) == 0 |
&& e1->mask == e2->mask) |
einfo (_("%X%P: duplicate expression `%s'" |
" in version information\n"), e1->pattern); |
} |
} |
for (e1 = version->locals.list; e1 != NULL; e1 = e1->next) |
{ |
for (t = link_info.version_info; t != NULL; t = t->next) |
{ |
struct bfd_elf_version_expr *e2; |
if (t->globals.htab && e1->literal) |
{ |
e2 = (struct bfd_elf_version_expr *) |
htab_find ((htab_t) t->globals.htab, e1); |
while (e2 && strcmp (e1->pattern, e2->pattern) == 0) |
{ |
if (e1->mask == e2->mask) |
einfo (_("%X%P: duplicate expression `%s'" |
" in version information\n"), |
e1->pattern); |
e2 = e2->next; |
} |
} |
else if (!e1->literal) |
for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next) |
if (strcmp (e1->pattern, e2->pattern) == 0 |
&& e1->mask == e2->mask) |
einfo (_("%X%P: duplicate expression `%s'" |
" in version information\n"), e1->pattern); |
} |
} |
version->deps = deps; |
version->name = name; |
if (name[0] != '\0') |
{ |
++version_index; |
version->vernum = version_index; |
} |
else |
version->vernum = 0; |
for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next) |
; |
*pp = version; |
} |
/* This is called when we see a version dependency. */ |
struct bfd_elf_version_deps * |
lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name) |
{ |
struct bfd_elf_version_deps *ret; |
struct bfd_elf_version_tree *t; |
ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret); |
ret->next = list; |
for (t = link_info.version_info; t != NULL; t = t->next) |
{ |
if (strcmp (t->name, name) == 0) |
{ |
ret->version_needed = t; |
return ret; |
} |
} |
einfo (_("%X%P: unable to find version dependency `%s'\n"), name); |
ret->version_needed = NULL; |
return ret; |
} |
static void |
lang_do_version_exports_section (void) |
{ |
struct bfd_elf_version_expr *greg = NULL, *lreg; |
LANG_FOR_EACH_INPUT_STATEMENT (is) |
{ |
asection *sec = bfd_get_section_by_name (is->the_bfd, ".exports"); |
char *contents, *p; |
bfd_size_type len; |
if (sec == NULL) |
continue; |
len = sec->size; |
contents = (char *) xmalloc (len); |
if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len)) |
einfo (_("%X%P: unable to read .exports section contents\n"), sec); |
p = contents; |
while (p < contents + len) |
{ |
greg = lang_new_vers_pattern (greg, p, NULL, FALSE); |
p = strchr (p, '\0') + 1; |
} |
/* Do not free the contents, as we used them creating the regex. */ |
/* Do not include this section in the link. */ |
sec->flags |= SEC_EXCLUDE | SEC_KEEP; |
} |
lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE); |
lang_register_vers_node (command_line.version_exports_section, |
lang_new_vers_node (greg, lreg), NULL); |
} |
void |
lang_add_unique (const char *name) |
{ |
struct unique_sections *ent; |
for (ent = unique_section_list; ent; ent = ent->next) |
if (strcmp (ent->name, name) == 0) |
return; |
ent = (struct unique_sections *) xmalloc (sizeof *ent); |
ent->name = xstrdup (name); |
ent->next = unique_section_list; |
unique_section_list = ent; |
} |
/* Append the list of dynamic symbols to the existing one. */ |
void |
lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic) |
{ |
if (link_info.dynamic_list) |
{ |
struct bfd_elf_version_expr *tail; |
for (tail = dynamic; tail->next != NULL; tail = tail->next) |
; |
tail->next = link_info.dynamic_list->head.list; |
link_info.dynamic_list->head.list = dynamic; |
} |
else |
{ |
struct bfd_elf_dynamic_list *d; |
d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d); |
d->head.list = dynamic; |
d->match = lang_vers_match; |
link_info.dynamic_list = d; |
} |
} |
/* Append the list of C++ typeinfo dynamic symbols to the existing |
one. */ |
void |
lang_append_dynamic_list_cpp_typeinfo (void) |
{ |
const char * symbols [] = |
{ |
"typeinfo name for*", |
"typeinfo for*" |
}; |
struct bfd_elf_version_expr *dynamic = NULL; |
unsigned int i; |
for (i = 0; i < ARRAY_SIZE (symbols); i++) |
dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++", |
FALSE); |
lang_append_dynamic_list (dynamic); |
} |
/* Append the list of C++ operator new and delete dynamic symbols to the |
existing one. */ |
void |
lang_append_dynamic_list_cpp_new (void) |
{ |
const char * symbols [] = |
{ |
"operator new*", |
"operator delete*" |
}; |
struct bfd_elf_version_expr *dynamic = NULL; |
unsigned int i; |
for (i = 0; i < ARRAY_SIZE (symbols); i++) |
dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++", |
FALSE); |
lang_append_dynamic_list (dynamic); |
} |
/* Scan a space and/or comma separated string of features. */ |
void |
lang_ld_feature (char *str) |
{ |
char *p, *q; |
p = str; |
while (*p) |
{ |
char sep; |
while (*p == ',' || ISSPACE (*p)) |
++p; |
if (!*p) |
break; |
q = p + 1; |
while (*q && *q != ',' && !ISSPACE (*q)) |
++q; |
sep = *q; |
*q = 0; |
if (strcasecmp (p, "SANE_EXPR") == 0) |
config.sane_expr = TRUE; |
else |
einfo (_("%X%P: unknown feature `%s'\n"), p); |
*q = sep; |
p = q; |
} |
} |
/contrib/toolchain/binutils/ld/ldlang.h |
---|
0,0 → 1,663 |
/* ldlang.h - linker command language support |
Copyright 1991-2013 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDLANG_H |
#define LDLANG_H |
#define DEFAULT_MEMORY_REGION "*default*" |
typedef enum |
{ |
lang_input_file_is_l_enum, |
lang_input_file_is_symbols_only_enum, |
lang_input_file_is_marker_enum, |
lang_input_file_is_fake_enum, |
lang_input_file_is_search_file_enum, |
lang_input_file_is_file_enum |
} lang_input_file_enum_type; |
struct _fill_type |
{ |
size_t size; |
unsigned char data[1]; |
}; |
typedef struct statement_list |
{ |
union lang_statement_union * head; |
union lang_statement_union ** tail; |
} lang_statement_list_type; |
typedef struct memory_region_name_struct |
{ |
const char * name; |
struct memory_region_name_struct * next; |
} lang_memory_region_name; |
typedef struct memory_region_struct |
{ |
lang_memory_region_name name_list; |
struct memory_region_struct *next; |
bfd_vma origin; |
bfd_size_type length; |
bfd_vma current; |
union lang_statement_union *last_os; |
flagword flags; |
flagword not_flags; |
bfd_boolean had_full_message; |
} lang_memory_region_type; |
enum statement_enum |
{ |
lang_output_section_statement_enum, |
lang_assignment_statement_enum, |
lang_input_statement_enum, |
lang_address_statement_enum, |
lang_wild_statement_enum, |
lang_input_section_enum, |
lang_object_symbols_statement_enum, |
lang_fill_statement_enum, |
lang_data_statement_enum, |
lang_reloc_statement_enum, |
lang_target_statement_enum, |
lang_output_statement_enum, |
lang_padding_statement_enum, |
lang_group_statement_enum, |
lang_insert_statement_enum, |
lang_constructors_statement_enum |
}; |
typedef struct lang_statement_header_struct |
{ |
union lang_statement_union *next; |
enum statement_enum type; |
} lang_statement_header_type; |
typedef struct |
{ |
lang_statement_header_type header; |
union etree_union *exp; |
} lang_assignment_statement_type; |
typedef struct lang_target_statement_struct |
{ |
lang_statement_header_type header; |
const char *target; |
} lang_target_statement_type; |
typedef struct lang_output_statement_struct |
{ |
lang_statement_header_type header; |
const char *name; |
} lang_output_statement_type; |
/* Section types specified in a linker script. */ |
enum section_type |
{ |
normal_section, |
overlay_section, |
noload_section, |
noalloc_section |
}; |
/* This structure holds a list of program headers describing |
segments in which this section should be placed. */ |
typedef struct lang_output_section_phdr_list |
{ |
struct lang_output_section_phdr_list *next; |
const char *name; |
bfd_boolean used; |
} lang_output_section_phdr_list; |
typedef struct lang_output_section_statement_struct |
{ |
lang_statement_header_type header; |
lang_statement_list_type children; |
struct lang_output_section_statement_struct *next; |
struct lang_output_section_statement_struct *prev; |
const char *name; |
asection *bfd_section; |
lang_memory_region_type *region; |
lang_memory_region_type *lma_region; |
fill_type *fill; |
union etree_union *addr_tree; |
union etree_union *load_base; |
/* If non-null, an expression to evaluate after setting the section's |
size. The expression is evaluated inside REGION (above) with '.' |
set to the end of the section. Used in the last overlay section |
to move '.' past all the overlaid sections. */ |
union etree_union *update_dot_tree; |
lang_output_section_phdr_list *phdrs; |
unsigned int block_value; |
int subsection_alignment; /* Alignment of components. */ |
int section_alignment; /* Alignment of start of section. */ |
int constraint; |
flagword flags; |
enum section_type sectype; |
unsigned int processed_vma : 1; |
unsigned int processed_lma : 1; |
unsigned int all_input_readonly : 1; |
/* If this section should be ignored. */ |
unsigned int ignored : 1; |
/* If this section should update "dot". Prevents section being ignored. */ |
unsigned int update_dot : 1; |
/* If this section is after assignment to _end. */ |
unsigned int after_end : 1; |
/* If this section uses the alignment of its input sections. */ |
unsigned int align_lma_with_input : 1; |
} lang_output_section_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
} lang_common_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
} lang_object_symbols_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
fill_type *fill; |
int size; |
asection *output_section; |
} lang_fill_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
unsigned int type; |
union etree_union *exp; |
bfd_vma value; |
asection *output_section; |
bfd_vma output_offset; |
} lang_data_statement_type; |
/* Generate a reloc in the output file. */ |
typedef struct |
{ |
lang_statement_header_type header; |
/* Reloc to generate. */ |
bfd_reloc_code_real_type reloc; |
/* Reloc howto structure. */ |
reloc_howto_type *howto; |
/* Section to generate reloc against. |
Exactly one of section and name must be NULL. */ |
asection *section; |
/* Name of symbol to generate reloc against. |
Exactly one of section and name must be NULL. */ |
const char *name; |
/* Expression for addend. */ |
union etree_union *addend_exp; |
/* Resolved addend. */ |
bfd_vma addend_value; |
/* Output section where reloc should be performed. */ |
asection *output_section; |
/* Offset within output section. */ |
bfd_vma output_offset; |
} lang_reloc_statement_type; |
struct lang_input_statement_flags |
{ |
/* 1 means this file was specified in a -l option. */ |
unsigned int maybe_archive : 1; |
/* 1 means search a set of directories for this file. */ |
unsigned int search_dirs : 1; |
/* 1 means this was found when processing a script in the sysroot. */ |
unsigned int sysrooted : 1; |
/* 1 means this is base file of incremental load. |
Do not load this file's text or data. |
Also default text_start to after this file's bss. */ |
unsigned int just_syms : 1; |
/* Whether to search for this entry as a dynamic archive. */ |
unsigned int dynamic : 1; |
/* Set if a DT_NEEDED tag should be added not just for the dynamic library |
explicitly given by this entry but also for any dynamic libraries in |
this entry's needed list. */ |
unsigned int add_DT_NEEDED_for_dynamic : 1; |
/* Set if this entry should cause a DT_NEEDED tag only when some |
regular file references its symbols (ie. --as-needed is in effect). */ |
unsigned int add_DT_NEEDED_for_regular : 1; |
/* Whether to include the entire contents of an archive. */ |
unsigned int whole_archive : 1; |
/* Set when bfd opening is successful. */ |
unsigned int loaded : 1; |
unsigned int real : 1; |
/* Set if the file does not exist. */ |
unsigned int missing_file : 1; |
#ifdef ENABLE_PLUGINS |
/* Set if the file was claimed by a plugin. */ |
unsigned int claimed : 1; |
/* Set if the file was claimed from an archive. */ |
unsigned int claim_archive : 1; |
/* Set if reloading an --as-needed lib. */ |
unsigned int reload : 1; |
#endif /* ENABLE_PLUGINS */ |
}; |
typedef struct lang_input_statement_struct |
{ |
lang_statement_header_type header; |
/* Name of this file. */ |
const char *filename; |
/* Name to use for the symbol giving address of text start. |
Usually the same as filename, but for a file spec'd with |
-l this is the -l switch itself rather than the filename. */ |
const char *local_sym_name; |
bfd *the_bfd; |
struct flag_info *section_flag_list; |
/* Point to the next file - whatever it is, wanders up and down |
archives */ |
union lang_statement_union *next; |
/* Point to the next file, but skips archive contents. */ |
union lang_statement_union *next_real_file; |
const char *target; |
struct lang_input_statement_flags flags; |
} lang_input_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
asection *section; |
} lang_input_section_type; |
typedef struct lang_wild_statement_struct lang_wild_statement_type; |
typedef void (*callback_t) (lang_wild_statement_type *, struct wildcard_list *, |
asection *, struct flag_info *, |
lang_input_statement_type *, void *); |
typedef void (*walk_wild_section_handler_t) (lang_wild_statement_type *, |
lang_input_statement_type *, |
callback_t callback, |
void *data); |
typedef bfd_boolean (*lang_match_sec_type_func) (bfd *, const asection *, |
bfd *, const asection *); |
/* Binary search tree structure to efficiently sort sections by |
name. */ |
typedef struct lang_section_bst |
{ |
asection *section; |
struct lang_section_bst *left; |
struct lang_section_bst *right; |
} lang_section_bst_type; |
struct lang_wild_statement_struct |
{ |
lang_statement_header_type header; |
const char *filename; |
bfd_boolean filenames_sorted; |
struct wildcard_list *section_list; |
bfd_boolean keep_sections; |
lang_statement_list_type children; |
walk_wild_section_handler_t walk_wild_section_handler; |
struct wildcard_list *handler_data[4]; |
lang_section_bst_type *tree; |
struct flag_info *section_flag_list; |
}; |
typedef struct lang_address_statement_struct |
{ |
lang_statement_header_type header; |
const char *section_name; |
union etree_union *address; |
const segment_type *segment; |
} lang_address_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
bfd_vma output_offset; |
bfd_size_type size; |
asection *output_section; |
fill_type *fill; |
} lang_padding_statement_type; |
/* A group statement collects a set of libraries together. The |
libraries are searched multiple times, until no new undefined |
symbols are found. The effect is to search a group of libraries as |
though they were a single library. */ |
typedef struct |
{ |
lang_statement_header_type header; |
lang_statement_list_type children; |
} lang_group_statement_type; |
typedef struct |
{ |
lang_statement_header_type header; |
const char *where; |
bfd_boolean is_before; |
} lang_insert_statement_type; |
typedef union lang_statement_union |
{ |
lang_statement_header_type header; |
lang_wild_statement_type wild_statement; |
lang_data_statement_type data_statement; |
lang_reloc_statement_type reloc_statement; |
lang_address_statement_type address_statement; |
lang_output_section_statement_type output_section_statement; |
lang_assignment_statement_type assignment_statement; |
lang_input_statement_type input_statement; |
lang_target_statement_type target_statement; |
lang_output_statement_type output_statement; |
lang_input_section_type input_section; |
lang_common_statement_type common_statement; |
lang_object_symbols_statement_type object_symbols_statement; |
lang_fill_statement_type fill_statement; |
lang_padding_statement_type padding_statement; |
lang_group_statement_type group_statement; |
lang_insert_statement_type insert_statement; |
} lang_statement_union_type; |
/* This structure holds information about a program header, from the |
PHDRS command in the linker script. */ |
struct lang_phdr |
{ |
struct lang_phdr *next; |
const char *name; |
unsigned long type; |
bfd_boolean filehdr; |
bfd_boolean phdrs; |
etree_type *at; |
etree_type *flags; |
}; |
/* This structure is used to hold a list of sections which may not |
cross reference each other. */ |
typedef struct lang_nocrossref |
{ |
struct lang_nocrossref *next; |
const char *name; |
} lang_nocrossref_type; |
/* The list of nocrossref lists. */ |
struct lang_nocrossrefs |
{ |
struct lang_nocrossrefs *next; |
lang_nocrossref_type *list; |
}; |
/* This structure is used to hold a list of input section names which |
will not match an output section in the linker script. */ |
struct unique_sections |
{ |
struct unique_sections *next; |
const char *name; |
}; |
/* This structure records symbols for which we need to keep track of |
definedness for use in the DEFINED () test. */ |
struct lang_definedness_hash_entry |
{ |
struct bfd_hash_entry root; |
int iteration; |
}; |
/* Used by place_orphan to keep track of orphan sections and statements. */ |
struct orphan_save |
{ |
const char *name; |
flagword flags; |
lang_output_section_statement_type *os; |
asection **section; |
lang_statement_union_type **stmt; |
lang_output_section_statement_type **os_tail; |
}; |
extern struct lang_phdr *lang_phdr_list; |
extern struct lang_nocrossrefs *nocrossref_list; |
extern const char *output_target; |
extern lang_output_section_statement_type *abs_output_section; |
extern lang_statement_list_type lang_output_section_statement; |
extern struct lang_input_statement_flags input_flags; |
extern bfd_boolean lang_has_input_file; |
extern etree_type *base; |
extern lang_statement_list_type *stat_ptr; |
extern bfd_boolean delete_output_file_on_failure; |
extern struct bfd_sym_chain entry_symbol; |
extern const char *entry_section; |
extern bfd_boolean entry_from_cmdline; |
extern lang_statement_list_type file_chain; |
extern lang_statement_list_type input_file_chain; |
extern int lang_statement_iteration; |
extern void lang_init |
(void); |
extern void lang_finish |
(void); |
extern lang_memory_region_type * lang_memory_region_lookup |
(const char * const, bfd_boolean); |
extern void lang_memory_region_alias |
(const char *, const char *); |
extern void lang_map |
(void); |
extern void lang_set_flags |
(lang_memory_region_type *, const char *, int); |
extern void lang_add_output |
(const char *, int from_script); |
extern lang_output_section_statement_type *lang_enter_output_section_statement |
(const char *, etree_type *, enum section_type, etree_type *, etree_type *, |
etree_type *, int, int); |
extern void lang_final |
(void); |
extern void lang_relax_sections |
(bfd_boolean); |
extern void lang_process |
(void); |
extern void lang_section_start |
(const char *, union etree_union *, const segment_type *); |
extern void lang_add_entry |
(const char *, bfd_boolean); |
extern void lang_default_entry |
(const char *); |
extern void lang_add_target |
(const char *); |
extern void lang_add_wild |
(struct wildcard_spec *, struct wildcard_list *, bfd_boolean); |
extern void lang_add_map |
(const char *); |
extern void lang_add_fill |
(fill_type *); |
extern lang_assignment_statement_type *lang_add_assignment |
(union etree_union *); |
extern void lang_add_attribute |
(enum statement_enum); |
extern void lang_startup |
(const char *); |
extern void lang_float |
(bfd_boolean); |
extern void lang_leave_output_section_statement |
(fill_type *, const char *, lang_output_section_phdr_list *, |
const char *); |
extern void lang_statement_append |
(lang_statement_list_type *, lang_statement_union_type *, |
lang_statement_union_type **); |
extern void lang_for_each_input_file |
(void (*dothis) (lang_input_statement_type *)); |
extern void lang_for_each_file |
(void (*dothis) (lang_input_statement_type *)); |
extern void lang_reset_memory_regions |
(void); |
extern void lang_do_assignments |
(lang_phase_type); |
extern asection *section_for_dot |
(void); |
#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \ |
lang_input_statement_type *statement; \ |
for (statement = (lang_input_statement_type *) file_chain.head; \ |
statement != (lang_input_statement_type *) NULL; \ |
statement = (lang_input_statement_type *) statement->next) \ |
#define lang_output_section_find(NAME) \ |
lang_output_section_statement_lookup (NAME, 0, FALSE) |
extern void lang_process |
(void); |
extern void ldlang_add_file |
(lang_input_statement_type *); |
extern lang_output_section_statement_type *lang_output_section_find_by_flags |
(const asection *, lang_output_section_statement_type **, |
lang_match_sec_type_func); |
extern lang_output_section_statement_type *lang_insert_orphan |
(asection *, const char *, int, lang_output_section_statement_type *, |
struct orphan_save *, etree_type *, lang_statement_list_type *); |
extern lang_input_statement_type *lang_add_input_file |
(const char *, lang_input_file_enum_type, const char *); |
extern void lang_add_keepsyms_file |
(const char *); |
extern lang_output_section_statement_type *lang_output_section_statement_lookup |
(const char *, int, bfd_boolean); |
extern lang_output_section_statement_type *next_matching_output_section_statement |
(lang_output_section_statement_type *, int); |
extern void ldlang_add_undef |
(const char *const, bfd_boolean); |
extern void lang_add_output_format |
(const char *, const char *, const char *, int); |
extern void lang_list_init |
(lang_statement_list_type *); |
extern void push_stat_ptr |
(lang_statement_list_type *); |
extern void pop_stat_ptr |
(void); |
extern void lang_add_data |
(int type, union etree_union *); |
extern void lang_add_reloc |
(bfd_reloc_code_real_type, reloc_howto_type *, asection *, const char *, |
union etree_union *); |
extern void lang_for_each_statement |
(void (*) (lang_statement_union_type *)); |
extern void lang_for_each_statement_worker |
(void (*) (lang_statement_union_type *), lang_statement_union_type *); |
extern void *stat_alloc |
(size_t); |
extern void strip_excluded_output_sections |
(void); |
extern void dprint_statement |
(lang_statement_union_type *, int); |
extern void lang_size_sections |
(bfd_boolean *, bfd_boolean); |
extern void one_lang_size_sections_pass |
(bfd_boolean *, bfd_boolean); |
extern void lang_add_insert |
(const char *, int); |
extern void lang_enter_group |
(void); |
extern void lang_leave_group |
(void); |
extern void lang_add_section |
(lang_statement_list_type *, asection *, |
struct flag_info *, lang_output_section_statement_type *); |
extern void lang_new_phdr |
(const char *, etree_type *, bfd_boolean, bfd_boolean, etree_type *, |
etree_type *); |
extern void lang_add_nocrossref |
(lang_nocrossref_type *); |
extern void lang_enter_overlay |
(etree_type *, etree_type *); |
extern void lang_enter_overlay_section |
(const char *); |
extern void lang_leave_overlay_section |
(fill_type *, lang_output_section_phdr_list *); |
extern void lang_leave_overlay |
(etree_type *, int, fill_type *, const char *, |
lang_output_section_phdr_list *, const char *); |
extern struct bfd_elf_version_expr *lang_new_vers_pattern |
(struct bfd_elf_version_expr *, const char *, const char *, bfd_boolean); |
extern struct bfd_elf_version_tree *lang_new_vers_node |
(struct bfd_elf_version_expr *, struct bfd_elf_version_expr *); |
extern struct bfd_elf_version_deps *lang_add_vers_depend |
(struct bfd_elf_version_deps *, const char *); |
extern void lang_register_vers_node |
(const char *, struct bfd_elf_version_tree *, struct bfd_elf_version_deps *); |
extern void lang_append_dynamic_list (struct bfd_elf_version_expr *); |
extern void lang_append_dynamic_list_cpp_typeinfo (void); |
extern void lang_append_dynamic_list_cpp_new (void); |
extern void lang_add_unique |
(const char *); |
extern const char *lang_get_output_target |
(void); |
extern void lang_track_definedness (const char *); |
extern int lang_symbol_definition_iteration (const char *); |
extern void lang_update_definedness |
(const char *, struct bfd_link_hash_entry *); |
extern void add_excluded_libs (const char *); |
extern bfd_boolean load_symbols |
(lang_input_statement_type *, lang_statement_list_type *); |
extern bfd_boolean |
ldlang_override_segment_assignment |
(struct bfd_link_info *, bfd *, asection *, asection *, bfd_boolean); |
extern void |
lang_ld_feature (char *); |
#endif |
/contrib/toolchain/binutils/ld/ldlex-wrapper.c |
---|
0,0 → 1,26 |
/* Copyright 2012 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* The flex output (ldlex.c) includes stdio.h before any of the C code |
in ldlex.l. Make sure we include sysdep.h first, so that config.h |
can select the correct value of things like _FILE_OFFSET_BITS and |
_LARGE_FILES. */ |
#include "sysdep.h" |
#include "ldlex.c" |
/contrib/toolchain/binutils/ld/ldlex.c |
---|
0,0 → 1,4348 |
#line 3 "ldlex.c" |
#define YY_INT_ALIGNED short int |
/* A lexical scanner generated by flex */ |
#define FLEX_SCANNER |
#define YY_FLEX_MAJOR_VERSION 2 |
#define YY_FLEX_MINOR_VERSION 5 |
#define YY_FLEX_SUBMINOR_VERSION 35 |
#if YY_FLEX_SUBMINOR_VERSION > 0 |
#define FLEX_BETA |
#endif |
/* First, we deal with platform-specific or compiler-specific issues. */ |
/* begin standard C headers. */ |
#include <stdio.h> |
#include <string.h> |
#include <errno.h> |
#include <stdlib.h> |
/* end standard C headers. */ |
/* flex integer type definitions */ |
#ifndef FLEXINT_H |
#define FLEXINT_H |
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ |
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L |
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, |
* if you want the limit (max/min) macros for int types. |
*/ |
#ifndef __STDC_LIMIT_MACROS |
#define __STDC_LIMIT_MACROS 1 |
#endif |
#include <inttypes.h> |
typedef int8_t flex_int8_t; |
typedef uint8_t flex_uint8_t; |
typedef int16_t flex_int16_t; |
typedef uint16_t flex_uint16_t; |
typedef int32_t flex_int32_t; |
typedef uint32_t flex_uint32_t; |
typedef uint64_t flex_uint64_t; |
#else |
typedef signed char flex_int8_t; |
typedef short int flex_int16_t; |
typedef int flex_int32_t; |
typedef unsigned char flex_uint8_t; |
typedef unsigned short int flex_uint16_t; |
typedef unsigned int flex_uint32_t; |
#endif /* ! C99 */ |
/* Limits of integral types. */ |
#ifndef INT8_MIN |
#define INT8_MIN (-128) |
#endif |
#ifndef INT16_MIN |
#define INT16_MIN (-32767-1) |
#endif |
#ifndef INT32_MIN |
#define INT32_MIN (-2147483647-1) |
#endif |
#ifndef INT8_MAX |
#define INT8_MAX (127) |
#endif |
#ifndef INT16_MAX |
#define INT16_MAX (32767) |
#endif |
#ifndef INT32_MAX |
#define INT32_MAX (2147483647) |
#endif |
#ifndef UINT8_MAX |
#define UINT8_MAX (255U) |
#endif |
#ifndef UINT16_MAX |
#define UINT16_MAX (65535U) |
#endif |
#ifndef UINT32_MAX |
#define UINT32_MAX (4294967295U) |
#endif |
#endif /* ! FLEXINT_H */ |
#ifdef __cplusplus |
/* The "const" storage-class-modifier is valid. */ |
#define YY_USE_CONST |
#else /* ! __cplusplus */ |
/* C99 requires __STDC__ to be defined as 1. */ |
#if defined (__STDC__) |
#define YY_USE_CONST |
#endif /* defined (__STDC__) */ |
#endif /* ! __cplusplus */ |
#ifdef YY_USE_CONST |
#define yyconst const |
#else |
#define yyconst |
#endif |
/* Returned upon end-of-file. */ |
#define YY_NULL 0 |
/* Promotes a possibly negative, possibly signed char to an unsigned |
* integer for use as an array index. If the signed char is negative, |
* we want to instead treat it as an 8-bit unsigned char, hence the |
* double cast. |
*/ |
#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) |
/* Enter a start condition. This macro really ought to take a parameter, |
* but we do it the disgusting crufty way forced on us by the ()-less |
* definition of BEGIN. |
*/ |
#define BEGIN (yy_start) = 1 + 2 * |
/* Translate the current start state into a value that can be later handed |
* to BEGIN to return to the state. The YYSTATE alias is for lex |
* compatibility. |
*/ |
#define YY_START (((yy_start) - 1) / 2) |
#define YYSTATE YY_START |
/* Action number for EOF rule of a given start state. */ |
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) |
/* Special action meaning "start processing a new file". */ |
#define YY_NEW_FILE yyrestart(yyin ) |
#define YY_END_OF_BUFFER_CHAR 0 |
/* Size of default input buffer. */ |
#ifndef YY_BUF_SIZE |
#define YY_BUF_SIZE 16384 |
#endif |
/* The state buf must be large enough to hold one state per character in the main buffer. |
*/ |
#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) |
#ifndef YY_TYPEDEF_YY_BUFFER_STATE |
#define YY_TYPEDEF_YY_BUFFER_STATE |
typedef struct yy_buffer_state *YY_BUFFER_STATE; |
#endif |
#ifndef YY_TYPEDEF_YY_SIZE_T |
#define YY_TYPEDEF_YY_SIZE_T |
typedef size_t yy_size_t; |
#endif |
extern yy_size_t yyleng; |
extern FILE *yyin, *yyout; |
#define EOB_ACT_CONTINUE_SCAN 0 |
#define EOB_ACT_END_OF_FILE 1 |
#define EOB_ACT_LAST_MATCH 2 |
#define YY_LESS_LINENO(n) |
/* Return all but the first "n" matched characters back to the input stream. */ |
#define yyless(n) \ |
do \ |
{ \ |
/* Undo effects of setting up yytext. */ \ |
int yyless_macro_arg = (n); \ |
YY_LESS_LINENO(yyless_macro_arg);\ |
*yy_cp = (yy_hold_char); \ |
YY_RESTORE_YY_MORE_OFFSET \ |
(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ |
YY_DO_BEFORE_ACTION; /* set up yytext again */ \ |
} \ |
while ( 0 ) |
#define unput(c) yyunput( c, (yytext_ptr) ) |
#ifndef YY_STRUCT_YY_BUFFER_STATE |
#define YY_STRUCT_YY_BUFFER_STATE |
struct yy_buffer_state |
{ |
FILE *yy_input_file; |
char *yy_ch_buf; /* input buffer */ |
char *yy_buf_pos; /* current position in input buffer */ |
/* Size of input buffer in bytes, not including room for EOB |
* characters. |
*/ |
yy_size_t yy_buf_size; |
/* Number of characters read into yy_ch_buf, not including EOB |
* characters. |
*/ |
yy_size_t yy_n_chars; |
/* Whether we "own" the buffer - i.e., we know we created it, |
* and can realloc() it to grow it, and should free() it to |
* delete it. |
*/ |
int yy_is_our_buffer; |
/* Whether this is an "interactive" input source; if so, and |
* if we're using stdio for input, then we want to use getc() |
* instead of fread(), to make sure we stop fetching input after |
* each newline. |
*/ |
int yy_is_interactive; |
/* Whether we're considered to be at the beginning of a line. |
* If so, '^' rules will be active on the next match, otherwise |
* not. |
*/ |
int yy_at_bol; |
int yy_bs_lineno; /**< The line count. */ |
int yy_bs_column; /**< The column count. */ |
/* Whether to try to fill the input buffer when we reach the |
* end of it. |
*/ |
int yy_fill_buffer; |
int yy_buffer_status; |
#define YY_BUFFER_NEW 0 |
#define YY_BUFFER_NORMAL 1 |
/* When an EOF's been seen but there's still some text to process |
* then we mark the buffer as YY_EOF_PENDING, to indicate that we |
* shouldn't try reading from the input source any more. We might |
* still have a bunch of tokens to match, though, because of |
* possible backing-up. |
* |
* When we actually see the EOF, we change the status to "new" |
* (via yyrestart()), so that the user can continue scanning by |
* just pointing yyin at a new input file. |
*/ |
#define YY_BUFFER_EOF_PENDING 2 |
}; |
#endif /* !YY_STRUCT_YY_BUFFER_STATE */ |
/* Stack of input buffers. */ |
static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ |
static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ |
static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ |
/* We provide macros for accessing buffer states in case in the |
* future we want to put the buffer states in a more general |
* "scanner state". |
* |
* Returns the top of the stack, or NULL. |
*/ |
#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ |
? (yy_buffer_stack)[(yy_buffer_stack_top)] \ |
: NULL) |
/* Same as previous macro, but useful when we know that the buffer stack is not |
* NULL or when we need an lvalue. For internal use only. |
*/ |
#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] |
/* yy_hold_char holds the character lost when yytext is formed. */ |
static char yy_hold_char; |
static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ |
yy_size_t yyleng; |
/* Points to current character in buffer. */ |
static char *yy_c_buf_p = (char *) 0; |
static int yy_init = 0; /* whether we need to initialize */ |
static int yy_start = 0; /* start state number */ |
/* Flag which is used to allow yywrap()'s to do buffer switches |
* instead of setting up a fresh yyin. A bit of a hack ... |
*/ |
static int yy_did_buffer_switch_on_eof; |
void yyrestart (FILE *input_file ); |
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); |
YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); |
void yy_delete_buffer (YY_BUFFER_STATE b ); |
void yy_flush_buffer (YY_BUFFER_STATE b ); |
void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); |
void yypop_buffer_state (void ); |
static void yyensure_buffer_stack (void ); |
static void yy_load_buffer_state (void ); |
static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); |
#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) |
YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); |
YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); |
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); |
void *yyalloc (yy_size_t ); |
void *yyrealloc (void *,yy_size_t ); |
void yyfree (void * ); |
#define yy_new_buffer yy_create_buffer |
#define yy_set_interactive(is_interactive) \ |
{ \ |
if ( ! YY_CURRENT_BUFFER ){ \ |
yyensure_buffer_stack (); \ |
YY_CURRENT_BUFFER_LVALUE = \ |
yy_create_buffer(yyin,YY_BUF_SIZE ); \ |
} \ |
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ |
} |
#define yy_set_bol(at_bol) \ |
{ \ |
if ( ! YY_CURRENT_BUFFER ){\ |
yyensure_buffer_stack (); \ |
YY_CURRENT_BUFFER_LVALUE = \ |
yy_create_buffer(yyin,YY_BUF_SIZE ); \ |
} \ |
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ |
} |
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) |
/* Begin user sect3 */ |
typedef unsigned char YY_CHAR; |
FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; |
typedef int yy_state_type; |
extern int yylineno; |
int yylineno = 1; |
extern char *yytext; |
#define yytext_ptr yytext |
static yy_state_type yy_get_previous_state (void ); |
static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); |
static int yy_get_next_buffer (void ); |
static void yy_fatal_error (yyconst char msg[] ); |
/* Done after the current pattern has been matched and before the |
* corresponding action - sets up yytext. |
*/ |
#define YY_DO_BEFORE_ACTION \ |
(yytext_ptr) = yy_bp; \ |
yyleng = (yy_size_t) (yy_cp - yy_bp); \ |
(yy_hold_char) = *yy_cp; \ |
*yy_cp = '\0'; \ |
(yy_c_buf_p) = yy_cp; |
#define YY_NUM_RULES 197 |
#define YY_END_OF_BUFFER 198 |
/* This struct is not used in this scanner, |
but its presence is necessary. */ |
struct yy_trans_info |
{ |
flex_int32_t yy_verify; |
flex_int32_t yy_nxt; |
}; |
static yyconst flex_int16_t yy_accept[1751] = |
{ 0, |
0, 0, 177, 177, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 198, 197, |
195, 180, 179, 32, 195, 177, 38, 29, 44, 43, |
34, 35, 28, 36, 177, 37, 8, 8, 45, 46, |
39, 40, 27, 33, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 10, 9, 177, 119, 117, 177, |
42, 30, 41, 31, 196, 180, 32, 196, 175, 38, |
29, 44, 43, 34, 35, 28, 36, 175, 37, 8, |
8, 45, 46, 39, 40, 27, 33, 175, 175, 175, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
175, 175, 175, 10, 9, 175, 175, 42, 30, 41, |
31, 173, 36, 173, 37, 8, 8, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 119, 117, |
173, 31, 4, 3, 2, 4, 5, 134, 32, 133, |
172, 34, 35, 28, 36, 172, 37, 8, 8, 45, |
46, 40, 33, 172, 172, 172, 172, 172, 172, 172, |
172, 172, 172, 172, 172, 10, 9, 172, 172, 172, |
172, 172, 172, 172, 172, 172, 172, 172, 31, 194, |
192, 193, 195, 187, 186, 181, 188, 189, 185, 185, |
185, 185, 190, 191, 180, 177, 15, 0, 178, 8, |
26, 24, 22, 20, 21, 1, 23, 8, 8, 177, |
18, 17, 14, 16, 19, 177, 177, 177, 177, 177, |
124, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
25, 13, 15, 175, 6, 22, 20, 21, 0, 1, |
23, 8, 0, 7, 7, 8, 7, 14, 175, 7, |
7, 7, 175, 175, 124, 7, 175, 175, 7, 175, |
175, 175, 7, 175, 175, 175, 175, 175, 175, 175, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
175, 7, 175, 173, 8, 0, 23, 8, 0, 173, |
173, 173, 173, 173, 124, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 4, 4, 133, 133, 172, |
6, 135, 22, 136, 172, 7, 7, 7, 172, 172, |
172, 7, 172, 7, 7, 172, 172, 172, 172, 172, |
172, 172, 172, 7, 172, 172, 172, 7, 172, 7, |
7, 172, 172, 172, 172, 172, 172, 172, 172, 194, |
193, 186, 185, 0, 185, 185, 185, 11, 12, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 93, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 72, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 120, 118, 177, 8, 176, 8, 175, 7, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
62, 63, 175, 175, 175, 175, 175, 175, 175, 175, |
175, 175, 175, 175, 175, 8, 174, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 93, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 72, 62, 173, 63, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 120, 118, 173, 4, 8, 172, 172, |
172, 172, 172, 137, 172, 172, 172, 172, 172, 172, |
172, 172, 172, 172, 172, 172, 172, 172, 172, 154, |
172, 172, 172, 172, 172, 172, 172, 172, 172, 172, |
185, 185, 185, 177, 59, 177, 177, 177, 177, 177, |
53, 177, 100, 177, 111, 177, 177, 177, 177, 177, |
177, 177, 89, 177, 177, 177, 177, 177, 112, 177, |
177, 177, 130, 177, 177, 177, 98, 177, 68, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 96, 177, |
177, 177, 177, 177, 177, 106, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 175, 59, 175, 175, 175, |
53, 175, 175, 111, 175, 175, 175, 175, 175, 175, |
175, 112, 175, 130, 175, 175, 175, 68, 175, 175, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
173, 59, 173, 173, 173, 173, 173, 53, 173, 100, |
173, 111, 173, 173, 173, 173, 173, 173, 173, 89, |
173, 173, 173, 173, 173, 112, 173, 173, 173, 130, |
173, 173, 173, 173, 98, 173, 68, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 96, 173, 173, 173, |
173, 173, 173, 106, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 172, 172, 172, 141, 149, 140, 172, |
172, 151, 144, 147, 172, 172, 152, 172, 172, 172, |
172, 172, 158, 166, 157, 172, 172, 169, 161, 164, |
172, 172, 170, 172, 172, 185, 185, 185, 177, 87, |
55, 177, 177, 177, 52, 177, 177, 177, 177, 110, |
66, 177, 177, 95, 177, 78, 177, 177, 177, 77, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 123, 177, 177, 177, 177, 177, 99, 177, |
177, 177, 97, 177, 177, 177, 177, 177, 177, 177, |
175, 55, 175, 175, 52, 175, 175, 175, 110, 175, |
78, 175, 175, 175, 175, 175, 175, 175, 175, 175, |
175, 175, 175, 175, 175, 175, 175, 175, 175, 173, |
87, 55, 173, 173, 173, 52, 173, 173, 173, 173, |
110, 66, 173, 173, 95, 173, 78, 173, 173, 173, |
77, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 123, 173, 173, 173, 173, 173, |
99, 173, 173, 173, 97, 173, 173, 173, 173, 173, |
173, 173, 172, 142, 139, 172, 172, 151, 151, 146, |
172, 150, 172, 172, 159, 156, 172, 172, 169, 169, |
163, 172, 168, 172, 185, 185, 183, 177, 177, 177, |
65, 177, 88, 177, 177, 177, 177, 177, 177, 67, |
177, 127, 177, 177, 177, 86, 177, 54, 177, 47, |
177, 177, 109, 177, 50, 76, 177, 177, 177, 177, |
177, 177, 73, 177, 177, 177, 177, 177, 94, 74, |
177, 177, 177, 175, 175, 175, 65, 175, 175, 175, |
175, 175, 127, 175, 175, 54, 175, 175, 175, 109, |
175, 50, 175, 175, 175, 73, 175, 175, 175, 175, |
173, 173, 173, 65, 173, 88, 173, 173, 173, 173, |
173, 173, 67, 173, 127, 173, 173, 173, 86, 173, |
54, 173, 173, 47, 173, 173, 109, 173, 50, 76, |
173, 173, 173, 173, 173, 173, 73, 173, 173, 173, |
173, 173, 94, 74, 173, 173, 173, 172, 172, 67, |
148, 145, 172, 172, 172, 167, 165, 162, 172, 184, |
182, 177, 61, 177, 177, 177, 177, 177, 177, 80, |
177, 177, 122, 177, 177, 177, 177, 177, 101, 177, |
177, 103, 128, 177, 177, 177, 177, 177, 177, 177, |
116, 90, 177, 51, 177, 177, 175, 61, 175, 175, |
175, 175, 80, 175, 122, 175, 175, 175, 175, 175, |
113, 128, 175, 175, 116, 175, 175, 175, 173, 61, |
173, 173, 173, 173, 173, 173, 80, 173, 173, 122, |
173, 173, 173, 173, 173, 173, 101, 173, 173, 103, |
128, 173, 173, 173, 173, 173, 173, 173, 116, 90, |
173, 51, 173, 173, 172, 172, 172, 172, 172, 172, |
153, 177, 177, 132, 177, 177, 177, 177, 177, 177, |
177, 177, 60, 177, 177, 177, 177, 177, 177, 177, |
85, 177, 177, 177, 177, 126, 171, 177, 153, 175, |
175, 132, 175, 175, 175, 60, 64, 175, 175, 175, |
175, 175, 126, 171, 175, 153, 173, 173, 132, 173, |
173, 173, 173, 173, 173, 173, 173, 60, 64, 173, |
173, 173, 173, 173, 173, 173, 85, 173, 173, 173, |
173, 126, 171, 173, 153, 138, 143, 171, 155, 160, |
177, 79, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 108, 177, 175, 79, 175, 175, 175, 175, |
175, 175, 175, 175, 175, 173, 79, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 108, 173, 177, |
177, 177, 177, 177, 177, 177, 177, 49, 177, 114, |
115, 177, 177, 177, 177, 75, 177, 177, 177, 177, |
177, 177, 175, 175, 175, 175, 175, 114, 115, 175, |
175, 175, 175, 173, 173, 173, 173, 173, 173, 173, |
173, 49, 173, 114, 115, 173, 173, 173, 173, 75, |
173, 173, 173, 173, 173, 173, 177, 177, 177, 177, |
177, 177, 177, 177, 102, 92, 177, 177, 177, 177, |
177, 177, 177, 177, 177, 175, 175, 175, 175, 102, |
175, 175, 175, 175, 173, 173, 173, 173, 173, 173, |
173, 173, 102, 92, 173, 173, 173, 173, 173, 173, |
173, 173, 173, 177, 82, 177, 177, 131, 177, 177, |
177, 177, 177, 48, 177, 177, 177, 177, 104, 177, |
175, 175, 131, 175, 175, 175, 175, 175, 173, 82, |
173, 173, 131, 173, 173, 173, 173, 173, 48, 173, |
173, 173, 173, 104, 173, 177, 177, 177, 177, 177, |
177, 91, 177, 71, 177, 177, 177, 177, 175, 175, |
175, 175, 71, 175, 175, 173, 173, 173, 173, 173, |
173, 91, 173, 71, 173, 173, 173, 173, 177, 177, |
177, 177, 177, 177, 177, 177, 129, 70, 177, 177, |
69, 175, 175, 175, 175, 175, 129, 70, 69, 173, |
173, 173, 173, 173, 173, 173, 173, 129, 70, 173, |
173, 69, 177, 177, 177, 177, 177, 177, 177, 177, |
177, 177, 175, 175, 175, 175, 175, 173, 173, 173, |
173, 173, 173, 173, 173, 173, 173, 125, 177, 177, |
58, 177, 177, 177, 177, 177, 177, 125, 175, 58, |
175, 175, 125, 173, 173, 58, 173, 173, 173, 173, |
173, 173, 177, 177, 177, 177, 177, 177, 105, 177, |
175, 175, 175, 173, 173, 173, 173, 173, 173, 105, |
173, 177, 56, 177, 177, 177, 177, 177, 56, 175, |
175, 173, 56, 173, 173, 173, 173, 173, 177, 177, |
177, 177, 121, 177, 175, 121, 173, 173, 173, 173, |
121, 173, 177, 177, 177, 177, 177, 175, 173, 173, |
173, 173, 173, 81, 177, 177, 177, 107, 175, 81, |
173, 173, 173, 107, 57, 177, 177, 57, 57, 173, |
173, 83, 177, 83, 173, 177, 173, 84, 84, 0 |
} ; |
static yyconst flex_int32_t yy_ec[256] = |
{ 0, |
1, 1, 1, 1, 1, 1, 1, 1, 2, 3, |
1, 1, 2, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 2, 4, 5, 6, 7, 8, 9, 1, 10, |
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, |
19, 19, 19, 19, 19, 19, 19, 21, 22, 23, |
24, 25, 26, 1, 27, 28, 29, 30, 31, 32, |
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, |
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, |
53, 54, 55, 56, 57, 1, 58, 59, 60, 61, |
62, 63, 64, 65, 66, 16, 67, 68, 69, 70, |
71, 72, 16, 73, 74, 75, 76, 16, 16, 77, |
16, 78, 79, 80, 81, 82, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1 |
} ; |
static yyconst flex_int32_t yy_meta[83] = |
{ 0, |
1, 1, 2, 3, 1, 1, 4, 1, 1, 1, |
1, 3, 5, 6, 7, 8, 9, 10, 10, 10, |
7, 1, 1, 6, 1, 3, 10, 10, 10, 10, |
10, 10, 8, 8, 8, 8, 8, 8, 8, 8, |
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
8, 8, 7, 4, 7, 3, 8, 10, 10, 10, |
10, 10, 10, 8, 8, 8, 8, 8, 8, 8, |
8, 8, 8, 8, 8, 8, 8, 8, 1, 1, |
1, 9 |
} ; |
static yyconst flex_int16_t yy_base[1775] = |
{ 0, |
0, 0, 0, 0, 82, 0, 164, 0, 246, 327, |
408, 0, 275, 277, 490, 572, 654, 736, 2703, 2704, |
2704, 2700, 2704, 2677, 2695, 801, 2704, 264, 2704, 2704, |
2675, 2674, 0, 2673, 0, 250, 581, 499, 0, 2704, |
252, 2672, 260, 0, 259, 255, 254, 269, 263, 274, |
2651, 272, 2654, 2662, 327, 289, 277, 315, 277, 2645, |
2660, 330, 2663, 2658, 0, 0, 2629, 2625, 2613, 2619, |
2704, 239, 2704, 0, 2704, 2682, 2659, 2677, 847, 2704, |
351, 2704, 2704, 2657, 2656, 2704, 298, 0, 355, 893, |
267, 2704, 2704, 300, 2655, 345, 2704, 953, 356, 359, |
494, 503, 576, 2634, 2642, 2636, 2644, 347, 358, 489, |
355, 2630, 516, 2704, 2704, 652, 2607, 2704, 482, 2704, |
0, 1013, 499, 0, 530, 745, 757, 655, 572, 485, |
534, 487, 567, 2628, 517, 2631, 2639, 599, 529, 578, |
594, 599, 2622, 2637, 661, 2640, 2635, 2606, 2602, 2590, |
2596, 0, 1059, 2704, 2704, 0, 2704, 2704, 2637, 2657, |
1105, 2635, 2634, 2704, 2633, 0, 2632, 0, 538, 2704, |
0, 2631, 2704, 1151, 608, 686, 609, 677, 653, 355, |
2627, 2609, 2605, 504, 2607, 2704, 2704, 724, 611, 661, |
702, 740, 545, 2592, 2576, 2572, 570, 2574, 0, 2644, |
2704, 0, 2633, 2704, 0, 2704, 2704, 2704, 2623, 536, |
663, 700, 2704, 2704, 2641, 0, 0, 2637, 2704, 730, |
2704, 2704, 0, 0, 0, 0, 0, 768, 0, 0, |
2617, 2704, 0, 2704, 2616, 2594, 2608, 2591, 2601, 567, |
0, 2603, 2594, 2592, 2586, 646, 2600, 2584, 2597, 2597, |
2581, 615, 2588, 2584, 2580, 2582, 2592, 2583, 807, 2589, |
2562, 2578, 683, 2575, 2577, 2565, 813, 2576, 2578, 2566, |
2580, 2580, 2568, 2581, 2574, 811, 2565, 2553, 2560, 2572, |
2555, 2574, 2572, 2554, 2554, 2553, 2522, 2525, 2530, 2515, |
2704, 2704, 2704, 0, 1211, 2704, 2704, 2704, 0, 2704, |
2704, 693, 864, 0, 2704, 2704, 0, 2704, 763, 842, |
929, 0, 2557, 728, 0, 962, 2551, 2549, 783, 989, |
1018, 2558, 2559, 2546, 2556, 814, 2554, 2544, 365, 2533, |
2542, 2531, 751, 2542, 2544, 2547, 2536, 2543, 2523, 2543, |
2545, 1009, 2494, 0, 1263, 0, 0, 878, 0, 2526, |
2540, 2523, 2533, 745, 0, 2535, 2526, 2524, 2518, 808, |
2532, 2516, 2529, 2529, 2513, 781, 2520, 2516, 2512, 2514, |
2524, 2515, 857, 2521, 2494, 2510, 902, 724, 2510, 2508, |
2497, 908, 2508, 2510, 2498, 2512, 2512, 2500, 2513, 2506, |
936, 2497, 2485, 2492, 2504, 2487, 2506, 2504, 2486, 2486, |
2485, 2454, 2457, 2462, 2447, 0, 1315, 2521, 2704, 0, |
1367, 0, 0, 0, 775, 948, 819, 0, 2488, 950, |
951, 2487, 2491, 2474, 2475, 2473, 2490, 2477, 2485, 2486, |
2484, 2485, 2464, 830, 2444, 862, 1021, 2443, 2447, 2432, |
2433, 2431, 2446, 2434, 2441, 2442, 2440, 2441, 2422, 2495, |
0, 0, 2475, 2474, 864, 848, 649, 2704, 2704, 2453, |
2449, 2461, 2458, 2459, 2449, 2447, 2457, 2457, 2454, 2439, |
2432, 2455, 2454, 2445, 2450, 2434, 2439, 2445, 2437, 2447, |
2444, 2425, 2441, 0, 2432, 2428, 2433, 2420, 2435, 2423, |
2432, 2430, 2432, 2428, 0, 2419, 2413, 2414, 2419, 2415, |
2404, 2421, 2411, 2408, 2407, 2402, 2419, 2413, 2403, 2400, |
2406, 2400, 2412, 2396, 2412, 2413, 2395, 2411, 2399, 2403, |
2390, 2363, 0, 0, 2371, 0, 0, 984, 2391, 1054, |
2398, 2399, 2389, 2398, 2398, 2381, 2374, 2397, 1066, 2394, |
2384, 2374, 2390, 2381, 2377, 2370, 2374, 2382, 2384, 2393, |
0, 0, 2366, 2367, 2369, 2358, 2375, 2363, 2358, 2366, |
2373, 2374, 2375, 2330, 2338, 0, 0, 2358, 2354, 2366, |
2363, 2364, 2354, 2352, 2362, 2362, 2359, 2344, 2337, 2360, |
2359, 2350, 2355, 2339, 2344, 2350, 2342, 2352, 2349, 2330, |
2346, 0, 2337, 2333, 2338, 2325, 2340, 2328, 2337, 2335, |
2337, 2346, 2332, 0, 0, 2323, 0, 2317, 2318, 2323, |
2319, 2308, 2325, 2315, 2312, 2311, 2306, 2323, 2317, 2307, |
2304, 2310, 2304, 2316, 2300, 2316, 2317, 2299, 2315, 2303, |
2307, 2294, 2267, 0, 0, 2275, 0, 0, 2295, 501, |
2304, 2303, 2291, 0, 2301, 2292, 2284, 2299, 2297, 2296, |
2288, 2279, 2280, 2283, 2251, 880, 2259, 2258, 2247, 0, |
2256, 2248, 2241, 2254, 2252, 2251, 2244, 2236, 2237, 2239, |
832, 833, 813, 2270, 0, 2263, 2266, 2261, 2273, 2259, |
0, 2265, 0, 2255, 0, 2254, 2242, 2258, 2251, 2245, |
2248, 2250, 0, 2247, 2261, 2249, 2259, 2242, 0, 2260, |
2241, 2242, 0, 2254, 2238, 2256, 0, 2238, 0, 2240, |
2239, 2252, 2221, 2242, 2229, 2237, 2229, 2238, 0, 2231, |
2242, 2235, 2238, 2222, 2226, 2209, 2230, 2234, 2217, 2224, |
2226, 2229, 2224, 2190, 2186, 2218, 0, 2215, 2210, 2222, |
0, 2215, 2205, 0, 2193, 2209, 2202, 2200, 2204, 2214, |
2197, 0, 2197, 0, 2196, 2214, 2211, 0, 2198, 2211, |
2180, 2201, 2197, 2199, 2202, 2191, 2196, 2192, 2161, 2157, |
2189, 0, 2182, 2185, 2180, 2192, 2178, 0, 2184, 0, |
2166, 0, 2156, 2135, 2142, 2123, 2114, 2115, 2117, 0, |
2111, 2116, 2095, 2096, 2074, 0, 2077, 2058, 2059, 0, |
251, 297, 347, 468, 0, 515, 0, 576, 625, 679, |
668, 693, 682, 694, 703, 716, 0, 740, 777, 820, |
842, 835, 852, 838, 881, 888, 880, 890, 913, 918, |
915, 893, 895, 930, 932, 957, 0, 0, 0, 957, |
975, 1436, 0, 0, 960, 970, 0, 960, 980, 942, |
946, 952, 0, 0, 0, 952, 968, 1517, 0, 0, |
955, 963, 0, 961, 978, 1036, 1039, 1037, 1005, 0, |
1024, 1015, 1031, 1035, 0, 1041, 1036, 1024, 1039, 0, |
0, 1050, 1053, 0, 1045, 0, 1063, 1076, 1072, 1051, |
1064, 1086, 1080, 1085, 1065, 1081, 1100, 1098, 1094, 1090, |
1085, 1111, 0, 1109, 1100, 1107, 1101, 1103, 0, 1112, |
1117, 1119, 0, 1100, 1113, 1121, 1104, 1110, 1076, 1090, |
1107, 1115, 1109, 1127, 0, 1132, 1115, 1130, 0, 1132, |
0, 1133, 1144, 1118, 1142, 1147, 1153, 1141, 1157, 1153, |
1150, 1164, 1163, 1154, 1163, 1169, 1162, 1122, 1136, 1153, |
0, 1161, 1157, 1173, 1174, 0, 1179, 1176, 1163, 1184, |
0, 0, 1187, 1179, 0, 1163, 0, 1181, 1194, 1190, |
1169, 1181, 1205, 1199, 1204, 1204, 1185, 1192, 1217, 1215, |
1211, 1207, 1203, 1224, 0, 1222, 1213, 1220, 1214, 1216, |
0, 1225, 1235, 1231, 0, 1212, 1225, 1233, 1216, 1223, |
1189, 1203, 1220, 0, 1229, 1236, 1231, 0, 1598, 0, |
1250, 0, 1257, 1209, 0, 1217, 1217, 1213, 0, 1679, |
0, 1229, 0, 1238, 1278, 1282, 1276, 1252, 1269, 1255, |
0, 1275, 0, 1266, 1260, 1251, 1278, 1280, 1280, 0, |
1283, 0, 1282, 1268, 1270, 0, 1270, 0, 1287, 0, |
1273, 1273, 0, 1288, 0, 1270, 1277, 1298, 1274, 1279, |
1297, 1292, 1282, 1289, 1300, 1311, 1309, 1320, 0, 0, |
1315, 1281, 1300, 1312, 1327, 1311, 0, 1331, 1322, 1332, |
1334, 1334, 0, 1335, 1322, 0, 1338, 1334, 1325, 0, |
1339, 0, 1321, 1348, 1334, 1324, 1345, 1355, 1314, 1333, |
1345, 1360, 1344, 0, 1370, 0, 1361, 1355, 1346, 1374, |
1377, 1377, 0, 1380, 0, 1379, 1365, 1367, 0, 1367, |
0, 1384, 1380, 0, 1371, 1371, 0, 1386, 0, 1362, |
1369, 1390, 1365, 1366, 1384, 1385, 1375, 1382, 1394, 1401, |
1401, 1416, 0, 0, 1411, 1377, 1396, 1408, 1414, 0, |
0, 0, 1410, 1382, 1392, 0, 0, 0, 1389, 1444, |
1445, 1436, 0, 1433, 1438, 1424, 1442, 1431, 1440, 0, |
1417, 1434, 0, 1419, 1446, 1431, 1435, 1436, 0, 1424, |
1455, 0, 1426, 1457, 1455, 1441, 1431, 1455, 1433, 1451, |
0, 0, 1453, 0, 1432, 1430, 1465, 0, 1462, 1467, |
1453, 1467, 0, 1444, 0, 1471, 1459, 1466, 1461, 1449, |
0, 1450, 1451, 1475, 0, 1470, 1449, 1447, 1482, 0, |
1479, 1489, 1478, 1501, 1491, 1500, 0, 1477, 1494, 0, |
1479, 1506, 1491, 1500, 1507, 1502, 0, 1490, 1521, 0, |
1492, 1523, 1521, 1507, 1497, 1521, 1499, 1517, 0, 0, |
1518, 0, 1497, 1495, 1530, 1532, 1532, 1502, 1504, 1504, |
0, 1521, 1538, 0, 1523, 1542, 1532, 1540, 1535, 1546, |
1547, 1533, 0, 1547, 1535, 1536, 1540, 1548, 1545, 1549, |
0, 1540, 1555, 1578, 1556, 0, 0, 1526, 0, 1543, |
1560, 0, 1552, 1560, 1564, 0, 0, 1563, 1551, 1567, |
1566, 1583, 0, 0, 1553, 0, 1570, 1587, 0, 1573, |
1597, 1587, 1595, 1589, 1600, 1601, 1587, 0, 0, 1601, |
1589, 1590, 1594, 1602, 1599, 1603, 0, 1594, 1609, 1615, |
1610, 0, 0, 1581, 0, 0, 0, 0, 0, 0, |
1610, 0, 1604, 1610, 1616, 1613, 1610, 1610, 1606, 1622, |
1624, 1616, 1629, 1615, 1625, 1626, 1618, 1617, 1637, 1628, |
1627, 1641, 0, 1611, 1636, 0, 1640, 1637, 1627, 1642, |
1645, 1640, 1630, 1655, 1634, 1661, 0, 1655, 1661, 1667, |
1664, 1661, 1665, 1661, 1677, 1677, 1669, 1682, 1668, 1678, |
1679, 1671, 1670, 1690, 1681, 1680, 1694, 0, 1664, 1666, |
1680, 1694, 1686, 1689, 1687, 1690, 1695, 0, 1686, 0, |
0, 1698, 1694, 1704, 1709, 0, 1710, 1708, 1704, 1705, |
1702, 1681, 1686, 1704, 1707, 1711, 1702, 0, 0, 1718, |
1722, 1720, 1690, 1695, 1709, 1723, 1715, 1718, 1716, 1722, |
1727, 0, 1718, 0, 0, 1730, 1726, 1736, 1740, 0, |
1741, 1739, 1735, 1736, 1733, 1712, 1739, 1730, 1747, 1731, |
1747, 1739, 1741, 1740, 0, 0, 1755, 1753, 1739, 1741, |
1755, 1754, 1742, 1758, 1728, 1756, 1746, 1762, 1753, 0, |
1765, 1752, 1766, 1736, 1764, 1755, 1772, 1756, 1772, 1764, |
1766, 1765, 0, 0, 1780, 1778, 1764, 1766, 1780, 1779, |
1767, 1783, 1753, 1776, 0, 1771, 1761, 0, 1762, 1779, |
1781, 1776, 1792, 0, 1778, 1781, 1786, 1770, 0, 1755, |
1789, 1773, 0, 1791, 1801, 1787, 1790, 1762, 1796, 0, |
1791, 1781, 0, 1782, 1799, 1801, 1796, 1812, 0, 1798, |
1801, 1806, 1790, 0, 1775, 1807, 1793, 1824, 1825, 1813, |
1797, 0, 1816, 0, 1812, 1819, 1817, 1786, 1819, 1835, |
1806, 1824, 0, 1820, 1793, 1827, 1813, 1844, 1845, 1833, |
1817, 0, 1836, 0, 1832, 1839, 1838, 1807, 1835, 1838, |
1846, 1845, 1855, 1849, 1832, 1858, 0, 0, 1860, 1848, |
0, 1846, 1856, 1855, 1865, 1865, 0, 0, 0, 1851, |
1854, 1862, 1861, 1871, 1865, 1847, 1873, 0, 0, 1875, |
1863, 0, 1862, 1858, 1875, 1881, 1874, 1875, 1887, 1877, |
1876, 1882, 1872, 1884, 1890, 1883, 1884, 1877, 1873, 1890, |
1896, 1889, 1890, 1902, 1892, 1891, 1897, 0, 1894, 1901, |
0, 1891, 1895, 1899, 1911, 1893, 1899, 0, 1908, 0, |
1898, 1916, 0, 1905, 1912, 0, 1902, 1906, 1910, 1922, |
1904, 1910, 1924, 1913, 1913, 1926, 1918, 1924, 0, 1914, |
1919, 1919, 1928, 1934, 1923, 1923, 1936, 1928, 1934, 0, |
1924, 1928, 0, 1913, 1944, 1931, 1928, 1939, 0, 1918, |
1931, 1936, 0, 1921, 1952, 1939, 1936, 1947, 1945, 1953, |
1939, 1957, 0, 1941, 1957, 0, 1951, 1959, 1945, 1963, |
0, 1947, 1949, 1955, 1961, 1970, 1947, 1959, 1955, 1961, |
1967, 1976, 1953, 0, 1975, 1965, 1961, 0, 1978, 0, |
1979, 1969, 1965, 0, 0, 1972, 1978, 0, 0, 1974, |
1980, 0, 1975, 0, 1976, 1978, 1979, 0, 0, 2704, |
2019, 2029, 2039, 2049, 2059, 2067, 2077, 2084, 2091, 2098, |
2108, 2115, 2125, 2135, 2145, 2148, 2156, 2163, 2080, 2170, |
2180, 2190, 2200, 2210 |
} ; |
static yyconst flex_int16_t yy_def[1775] = |
{ 0, |
1751, 1751, 1750, 3, 1750, 5, 1750, 7, 1752, 1752, |
1750, 11, 1753, 1753, 1754, 1754, 1755, 1755, 1750, 1750, |
1750, 1750, 1750, 1756, 1757, 1756, 1750, 1750, 1750, 1750, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1750, |
1750, 1756, 1750, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1750, 1750, 1750, 1756, 1750, 1750, 1750, 1757, 1758, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1758, 1758, 1750, |
90, 1750, 1750, 1750, 1750, 1750, 1750, 1758, 98, 98, |
98, 98, 98, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1750, 1750, 98, 1758, 1750, 1750, 1750, |
1758, 1759, 1750, 1759, 1759, 1750, 1750, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1760, 1750, 1750, 1760, 1750, 1750, 1750, 1761, |
1762, 1763, 1750, 1750, 1750, 1762, 1762, 90, 90, 1750, |
1764, 1750, 1750, 1762, 174, 174, 174, 174, 174, 1762, |
1762, 1762, 1762, 1762, 1762, 1750, 1750, 174, 174, 174, |
174, 174, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1750, |
1750, 1765, 1750, 1750, 1766, 1750, 1750, 1750, 1767, 1767, |
1767, 1767, 1750, 1750, 1750, 1756, 1756, 1757, 1750, 26, |
1750, 1750, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 26, |
1750, 1750, 1756, 1750, 1750, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1750, 1750, 1750, 1758, 1758, 1750, 1750, 1750, 1768, 1750, |
1750, 90, 90, 303, 1750, 1750, 1769, 1750, 98, 98, |
98, 1758, 1758, 1758, 1758, 98, 1758, 1758, 1758, 98, |
98, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 98, 1758, 1759, 1759, 1770, 1759, 1750, 1769, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1760, 1760, 1761, 1750, 1762, |
1762, 1763, 1763, 1764, 174, 174, 174, 1762, 1762, 174, |
174, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1762, 1762, 1762, 174, 1762, 174, 174, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1750, |
1765, 1766, 1767, 1750, 1767, 1767, 1767, 1750, 1750, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1758, 1768, 1769, 1758, 98, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 98, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1759, 1770, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1760, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1767, 1767, 1767, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1762, 1771, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1772, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1767, 1767, 1767, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1762, 1762, 1762, 1762, 1762, 1773, 1771, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1774, 1772, |
1762, 1762, 1762, 1762, 1767, 1767, 1767, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1762, 1762, 1762, |
1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1762, 1767, |
1767, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1762, 1762, 1762, 1762, 1762, 1762, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1762, 1762, 1762, 1762, 1762, 1762, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1758, 1758, 1758, 1758, 1758, |
1758, 1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, |
1758, 1758, 1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1758, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1756, 1756, 1758, 1758, 1758, 1758, 1758, 1759, 1759, 1759, |
1759, 1759, 1759, 1759, 1759, 1759, 1759, 1756, 1756, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, 1758, |
1758, 1758, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1759, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, |
1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, |
1758, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1756, 1756, |
1756, 1756, 1756, 1756, 1758, 1758, 1759, 1759, 1759, 1759, |
1759, 1759, 1756, 1756, 1756, 1756, 1756, 1758, 1759, 1759, |
1759, 1759, 1759, 1756, 1756, 1756, 1756, 1756, 1758, 1759, |
1759, 1759, 1759, 1759, 1756, 1756, 1756, 1758, 1759, 1759, |
1759, 1756, 1756, 1759, 1759, 1756, 1759, 1756, 1759, 0, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750 |
} ; |
static yyconst flex_int16_t yy_nxt[2787] = |
{ 0, |
21, 22, 23, 24, 25, 21, 26, 27, 28, 29, |
30, 31, 32, 33, 34, 35, 36, 37, 38, 38, |
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
49, 50, 51, 52, 53, 35, 54, 55, 56, 57, |
58, 59, 60, 61, 62, 63, 35, 64, 35, 35, |
35, 35, 65, 35, 66, 35, 35, 67, 35, 35, |
35, 35, 35, 35, 35, 35, 35, 68, 35, 35, |
69, 35, 35, 70, 35, 35, 35, 35, 71, 72, |
73, 74, 75, 76, 23, 77, 78, 75, 79, 80, |
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, |
91, 91, 92, 93, 94, 95, 96, 97, 98, 99, |
100, 101, 102, 103, 104, 105, 106, 88, 107, 108, |
109, 110, 111, 112, 88, 88, 113, 88, 88, 88, |
88, 88, 88, 88, 114, 88, 115, 75, 88, 116, |
103, 103, 103, 103, 103, 88, 88, 88, 88, 88, |
88, 88, 88, 88, 88, 117, 88, 88, 88, 88, |
118, 119, 120, 121, 75, 76, 23, 77, 78, 75, |
122, 80, 81, 82, 83, 84, 85, 86, 123, 124, |
125, 126, 127, 127, 92, 93, 94, 95, 96, 97, |
128, 129, 130, 131, 132, 133, 134, 135, 136, 124, |
137, 138, 139, 140, 141, 142, 143, 144, 145, 146, |
124, 147, 124, 124, 124, 124, 114, 124, 115, 75, |
124, 148, 124, 124, 124, 124, 124, 124, 124, 124, |
124, 149, 124, 124, 150, 124, 124, 151, 124, 124, |
124, 124, 118, 119, 120, 152, 75, 75, 20, 75, |
75, 75, 153, 75, 75, 75, 75, 75, 154, 75, |
155, 226, 291, 126, 127, 127, 75, 75, 75, 157, |
75, 75, 221, 227, 231, 232, 200, 201, 200, 201, |
202, 973, 202, 234, 235, 242, 236, 222, 237, 243, |
238, 203, 244, 203, 246, 248, 239, 247, 75, 249, |
75, 75, 251, 240, 241, 245, 257, 266, 253, 258, |
272, 254, 252, 250, 255, 264, 305, 267, 292, 265, |
273, 298, 231, 232, 75, 75, 75, 75, 75, 20, |
75, 75, 75, 153, 75, 75, 75, 75, 75, 154, |
75, 155, 974, 305, 126, 127, 127, 75, 75, 75, |
157, 75, 75, 204, 268, 204, 261, 262, 269, 221, |
276, 270, 271, 277, 278, 299, 300, 263, 234, 235, |
279, 280, 281, 975, 222, 282, 283, 328, 301, 75, |
284, 75, 75, 316, 330, 316, 316, 329, 316, 426, |
317, 549, 331, 318, 334, 427, 294, 550, 335, 319, |
294, 294, 336, 294, 294, 75, 75, 75, 21, 22, |
158, 159, 21, 160, 161, 27, 28, 29, 30, 162, |
163, 164, 165, 166, 167, 168, 169, 169, 170, 171, |
41, 172, 43, 173, 174, 175, 176, 177, 178, 179, |
166, 166, 166, 166, 166, 180, 166, 181, 182, 183, |
166, 166, 184, 185, 166, 166, 166, 166, 166, 166, |
186, 166, 187, 21, 166, 188, 189, 190, 177, 191, |
192, 166, 166, 166, 166, 193, 166, 194, 195, 196, |
166, 197, 198, 166, 166, 166, 71, 72, 73, 199, |
21, 200, 201, 21, 21, 202, 976, 21, 21, 21, |
21, 21, 21, 206, 21, 291, 203, 21, 21, 21, |
206, 206, 21, 21, 21, 21, 228, 228, 228, 332, |
320, 316, 298, 316, 321, 360, 365, 835, 361, 333, |
316, 294, 316, 836, 431, 229, 366, 229, 322, 294, |
294, 300, 21, 21, 21, 21, 338, 294, 294, 432, |
339, 371, 323, 347, 372, 378, 454, 340, 977, 379, |
362, 292, 341, 380, 363, 229, 346, 229, 207, 21, |
208, 21, 21, 200, 201, 21, 21, 202, 364, 21, |
21, 21, 21, 21, 21, 206, 21, 305, 203, 21, |
21, 21, 206, 206, 21, 21, 21, 21, 228, 228, |
228, 367, 356, 316, 368, 316, 357, 369, 381, 358, |
442, 464, 455, 294, 305, 443, 978, 229, 382, 229, |
294, 294, 359, 465, 21, 21, 21, 21, 375, 376, |
230, 447, 387, 383, 420, 417, 417, 384, 417, 377, |
385, 386, 388, 477, 448, 410, 410, 229, 410, 229, |
207, 21, 208, 21, 21, 200, 201, 230, 25, 202, |
478, 21, 21, 21, 21, 979, 21, 206, 436, 454, |
203, 21, 21, 21, 206, 206, 21, 21, 21, 316, |
417, 316, 350, 454, 351, 470, 352, 471, 417, 294, |
410, 391, 353, 425, 392, 393, 294, 294, 410, 354, |
355, 394, 395, 396, 417, 980, 397, 398, 673, 493, |
342, 399, 421, 417, 410, 210, 423, 211, 437, 422, |
454, 212, 494, 410, 981, 438, 424, 982, 983, 417, |
456, 984, 213, 21, 214, 21, 21, 200, 201, 410, |
25, 202, 305, 21, 21, 21, 21, 985, 21, 206, |
986, 417, 203, 21, 21, 21, 206, 206, 21, 21, |
21, 410, 348, 348, 348, 604, 229, 417, 229, 305, |
457, 439, 532, 605, 348, 348, 348, 410, 440, 554, |
987, 306, 434, 306, 533, 228, 228, 228, 555, 572, |
316, 435, 316, 306, 349, 306, 229, 210, 229, 211, |
294, 573, 417, 212, 229, 988, 229, 294, 294, 585, |
441, 306, 410, 306, 213, 21, 214, 21, 220, 220, |
220, 349, 536, 306, 537, 306, 586, 220, 220, 220, |
220, 220, 220, 454, 229, 485, 229, 509, 486, 510, |
487, 498, 544, 511, 499, 545, 417, 578, 488, 579, |
500, 489, 454, 454, 989, 546, 410, 417, 220, 220, |
220, 220, 220, 220, 295, 295, 295, 410, 454, 316, |
868, 316, 990, 295, 295, 295, 295, 295, 295, 294, |
991, 303, 303, 303, 454, 593, 529, 294, 594, 417, |
595, 867, 992, 866, 993, 348, 348, 348, 596, 410, |
1750, 597, 1750, 655, 295, 295, 295, 295, 295, 295, |
302, 302, 302, 305, 306, 994, 306, 995, 672, 303, |
304, 303, 304, 303, 303, 996, 305, 997, 601, 306, |
1750, 306, 1750, 305, 602, 657, 609, 851, 671, 610, |
305, 603, 307, 852, 306, 611, 306, 998, 999, 1000, |
303, 304, 303, 304, 303, 303, 316, 305, 530, 306, |
1001, 306, 620, 305, 621, 1002, 294, 1003, 622, 307, |
309, 309, 309, 294, 294, 417, 1004, 417, 417, 309, |
310, 309, 311, 309, 309, 410, 312, 410, 410, 316, |
313, 316, 639, 312, 641, 642, 1005, 314, 315, 294, |
1006, 1007, 312, 1010, 1011, 1012, 294, 294, 1013, 1014, |
309, 316, 309, 316, 309, 309, 316, 312, 316, 1015, |
306, 1016, 306, 312, 1017, 1018, 294, 1021, 1022, 312, |
345, 345, 345, 294, 538, 1023, 316, 1024, 316, 345, |
345, 345, 345, 345, 345, 316, 294, 316, 417, 539, |
306, 1028, 306, 294, 294, 294, 454, 454, 410, 454, |
1031, 1032, 294, 294, 1029, 1033, 1036, 1034, 1037, 1038, |
345, 345, 345, 345, 345, 345, 407, 407, 407, 1039, |
1030, 316, 564, 316, 1035, 407, 407, 407, 407, 407, |
407, 294, 1040, 316, 658, 316, 1026, 737, 294, 294, |
746, 1041, 1042, 294, 1027, 1043, 1044, 1045, 1025, 1046, |
294, 294, 1047, 1048, 1049, 1050, 407, 407, 407, 407, |
407, 407, 411, 411, 411, 1051, 1052, 1053, 1054, 1055, |
1056, 411, 411, 411, 411, 411, 411, 1057, 1058, 1059, |
1060, 1061, 1062, 1063, 1064, 1066, 1067, 1068, 1069, 1070, |
1071, 1072, 1073, 1074, 1077, 1075, 1065, 1078, 1079, 1080, |
1081, 1082, 411, 411, 411, 411, 411, 411, 415, 415, |
415, 1076, 1083, 1084, 1085, 1086, 1087, 415, 416, 415, |
417, 415, 415, 1088, 418, 1089, 1090, 1091, 419, 1092, |
1093, 418, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, |
418, 1102, 1104, 1105, 1106, 1107, 1109, 1110, 415, 417, |
415, 417, 415, 415, 1111, 418, 1112, 1103, 1113, 1114, |
1115, 418, 1108, 1116, 1117, 1118, 1119, 418, 295, 295, |
295, 1120, 1121, 1122, 1123, 1124, 1125, 295, 295, 295, |
295, 295, 295, 1126, 1127, 1128, 1129, 526, 1130, 526, |
1131, 1132, 1133, 1134, 1135, 1136, 1137, 1140, 1141, 1142, |
1143, 1144, 1138, 1145, 1146, 1147, 1148, 1149, 295, 295, |
295, 295, 295, 295, 1139, 1150, 1151, 526, 1152, 526, |
345, 345, 345, 1153, 1154, 1155, 1156, 1157, 1158, 345, |
345, 345, 345, 345, 345, 1159, 454, 1162, 454, 566, |
1163, 566, 454, 1164, 1165, 1166, 1167, 1168, 1169, 1170, |
1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, |
345, 345, 345, 345, 345, 345, 1181, 1182, 1183, 566, |
1184, 566, 407, 407, 407, 1185, 1186, 1187, 1188, 1189, |
1190, 407, 407, 407, 407, 407, 407, 1160, 1191, 1161, |
1192, 637, 1193, 637, 1194, 1195, 1196, 1197, 1198, 1199, |
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, |
1210, 1211, 407, 407, 407, 407, 407, 407, 1212, 1213, |
1214, 637, 1215, 637, 411, 411, 411, 1216, 1217, 1218, |
1219, 1220, 1221, 411, 411, 411, 411, 411, 411, 1222, |
1223, 1224, 1225, 638, 1226, 638, 1227, 1228, 1229, 1230, |
1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, |
1241, 1242, 1243, 1244, 411, 411, 411, 411, 411, 411, |
1245, 1246, 1247, 638, 1248, 638, 1008, 1008, 1249, 1008, |
1008, 1008, 1250, 1008, 1008, 1008, 1008, 1008, 1251, 1008, |
1252, 1253, 1254, 1255, 1256, 1257, 1258, 1008, 1008, 1008, |
1008, 1008, 1259, 1260, 454, 454, 1261, 1262, 1263, 1264, |
1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, |
1275, 1276, 1278, 1279, 1280, 1281, 1277, 1282, 1283, 1284, |
1285, 1008, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, |
1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, |
1304, 1305, 1306, 1307, 1008, 1008, 1008, 1019, 1019, 1308, |
1019, 1019, 1019, 1309, 1019, 1019, 1019, 1019, 1019, 1310, |
1019, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1019, 1019, |
1019, 1019, 1019, 1318, 1319, 1320, 1321, 1322, 1324, 1325, |
1326, 1327, 1323, 1328, 1329, 1330, 1331, 1332, 1333, 1334, |
1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, |
1345, 1346, 1019, 1347, 1348, 1349, 1350, 1351, 1352, 1353, |
1354, 1355, 1356, 1357, 1358, 1359, 1363, 1364, 1365, 1366, |
1367, 1368, 1369, 1370, 1371, 1019, 1019, 1019, 1008, 1008, |
1372, 1008, 1008, 1008, 1360, 1008, 1008, 1008, 1008, 1008, |
1373, 1008, 1361, 1374, 1375, 1376, 1377, 1362, 1378, 1008, |
1008, 1008, 1008, 1008, 1379, 1380, 1381, 1382, 1383, 1384, |
1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, |
1398, 1395, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1396, |
1406, 1407, 1408, 1008, 1397, 1409, 1410, 1412, 1413, 1414, |
1415, 1416, 1417, 1418, 1411, 1419, 1420, 1421, 1422, 1423, |
1424, 1425, 1426, 1427, 1430, 1431, 1008, 1008, 1008, 1019, |
1019, 1432, 1019, 1019, 1019, 1428, 1019, 1019, 1019, 1019, |
1019, 1433, 1019, 1429, 1434, 1435, 1436, 1437, 1438, 1439, |
1019, 1019, 1019, 1019, 1019, 1440, 1441, 1442, 1443, 1444, |
1446, 1447, 1448, 1449, 1450, 1451, 1452, 1445, 1453, 1454, |
1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, |
1465, 1466, 1467, 1468, 1019, 1469, 1470, 1471, 1472, 1473, |
1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, |
1484, 1485, 1486, 1487, 1488, 1489, 1490, 1019, 1019, 1019, |
1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, |
1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, |
1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, |
1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, |
1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, |
1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, 1550, |
1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, |
1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, |
1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, |
1581, 1584, 1585, 1586, 1582, 1587, 1588, 1589, 1590, 1591, |
1592, 1593, 1596, 1597, 1598, 1594, 1599, 1583, 1600, 1601, |
1602, 1605, 1606, 1607, 1603, 1608, 1609, 1610, 1595, 1611, |
1612, 1613, 1614, 1615, 1616, 1617, 1618, 1604, 1619, 1620, |
1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, |
1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, |
1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, |
1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, |
1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, |
1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, |
1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, |
1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, |
1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, |
1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, |
1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, |
1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, |
1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 20, |
20, 20, 20, 20, 20, 20, 20, 20, 20, 156, |
156, 156, 156, 156, 156, 156, 156, 156, 156, 21, |
21, 21, 21, 21, 21, 21, 21, 21, 21, 205, |
205, 205, 205, 205, 205, 205, 205, 205, 205, 209, |
209, 209, 209, 209, 209, 209, 209, 209, 209, 216, |
216, 216, 216, 216, 216, 216, 216, 218, 218, 218, |
218, 218, 218, 218, 218, 218, 218, 294, 294, 528, |
294, 294, 294, 294, 344, 344, 344, 344, 344, 344, |
344, 406, 972, 971, 970, 406, 406, 406, 408, 408, |
408, 408, 408, 408, 408, 408, 408, 408, 410, 410, |
969, 410, 410, 410, 410, 412, 968, 412, 412, 412, |
412, 412, 412, 412, 412, 414, 967, 414, 414, 414, |
414, 414, 414, 414, 414, 451, 966, 451, 451, 451, |
451, 451, 451, 451, 451, 452, 965, 452, 453, 453, |
964, 963, 453, 453, 962, 453, 527, 527, 961, 527, |
527, 527, 527, 567, 567, 567, 567, 567, 567, 567, |
1009, 960, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, |
1020, 959, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, |
1008, 958, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, |
1019, 957, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, |
956, 955, 954, 953, 952, 951, 950, 949, 948, 947, |
946, 945, 944, 943, 942, 941, 940, 939, 938, 937, |
936, 935, 934, 933, 932, 931, 930, 929, 928, 927, |
926, 925, 924, 923, 922, 921, 920, 919, 918, 917, |
916, 915, 914, 913, 912, 911, 910, 909, 908, 907, |
906, 905, 904, 903, 902, 901, 900, 899, 898, 897, |
896, 895, 894, 893, 892, 891, 890, 889, 888, 887, |
886, 885, 884, 883, 882, 881, 880, 879, 878, 877, |
876, 875, 874, 873, 872, 871, 870, 869, 865, 864, |
863, 862, 861, 860, 859, 858, 857, 856, 855, 854, |
853, 850, 849, 848, 847, 846, 845, 844, 843, 842, |
841, 840, 839, 838, 837, 834, 833, 832, 831, 830, |
829, 828, 827, 826, 825, 824, 823, 822, 821, 820, |
819, 818, 817, 816, 815, 814, 813, 812, 811, 810, |
809, 808, 807, 806, 805, 804, 803, 802, 801, 800, |
799, 798, 797, 796, 795, 794, 793, 792, 791, 790, |
789, 788, 787, 786, 785, 784, 783, 782, 781, 780, |
779, 778, 777, 776, 775, 774, 773, 772, 771, 770, |
769, 768, 767, 766, 765, 764, 763, 762, 761, 760, |
759, 758, 757, 756, 755, 754, 753, 752, 751, 750, |
749, 748, 747, 745, 744, 743, 742, 741, 740, 739, |
738, 736, 735, 734, 733, 732, 731, 730, 729, 728, |
727, 726, 725, 724, 723, 722, 721, 720, 719, 718, |
717, 716, 715, 714, 713, 712, 711, 710, 709, 708, |
707, 706, 705, 704, 703, 702, 701, 700, 699, 698, |
697, 696, 695, 694, 693, 692, 691, 690, 689, 688, |
687, 686, 685, 684, 683, 682, 681, 680, 679, 678, |
677, 676, 675, 674, 453, 454, 450, 670, 669, 668, |
667, 666, 665, 664, 663, 662, 661, 660, 659, 656, |
654, 653, 652, 651, 650, 649, 648, 647, 646, 645, |
644, 643, 640, 409, 636, 635, 634, 633, 632, 631, |
630, 629, 628, 627, 626, 625, 624, 623, 619, 618, |
617, 616, 615, 614, 613, 612, 608, 607, 606, 600, |
599, 598, 592, 591, 590, 589, 588, 587, 584, 583, |
582, 581, 580, 577, 576, 575, 574, 571, 570, 569, |
568, 565, 563, 562, 561, 560, 559, 558, 557, 556, |
553, 552, 551, 548, 547, 543, 542, 541, 540, 535, |
534, 531, 525, 524, 523, 522, 521, 520, 519, 518, |
517, 516, 515, 514, 513, 512, 508, 507, 506, 505, |
504, 503, 502, 501, 497, 496, 495, 492, 491, 490, |
484, 483, 482, 481, 480, 479, 476, 475, 474, 473, |
472, 469, 468, 467, 466, 463, 462, 461, 460, 459, |
458, 219, 215, 454, 300, 450, 449, 446, 445, 444, |
433, 430, 429, 428, 308, 301, 298, 297, 413, 409, |
293, 405, 404, 403, 402, 401, 400, 390, 389, 374, |
373, 370, 343, 337, 327, 326, 325, 324, 308, 297, |
296, 219, 293, 215, 290, 289, 288, 287, 286, 285, |
275, 274, 260, 259, 256, 233, 225, 224, 223, 219, |
217, 215, 1750, 19, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750 |
} ; |
static yyconst flex_int16_t yy_chk[2787] = |
{ 0, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
3, 3, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
5, 5, 5, 5, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
7, 7, 7, 7, 7, 7, 9, 9, 9, 9, |
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, |
9, 36, 72, 9, 9, 9, 9, 9, 9, 9, |
9, 9, 28, 36, 41, 41, 13, 13, 14, 14, |
13, 801, 14, 43, 43, 46, 45, 28, 45, 46, |
45, 13, 46, 14, 47, 48, 45, 47, 9, 48, |
9, 9, 49, 45, 45, 46, 52, 57, 50, 52, |
59, 50, 49, 48, 50, 56, 91, 57, 72, 56, |
59, 87, 94, 94, 9, 9, 9, 10, 10, 10, |
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, |
10, 10, 802, 91, 10, 10, 10, 10, 10, 10, |
10, 10, 10, 13, 58, 14, 55, 55, 58, 81, |
62, 58, 58, 62, 62, 87, 89, 55, 96, 96, |
62, 62, 62, 803, 81, 62, 62, 108, 89, 10, |
62, 10, 10, 99, 109, 99, 100, 108, 100, 180, |
99, 329, 109, 99, 111, 180, 100, 329, 111, 100, |
99, 99, 111, 100, 100, 10, 10, 10, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, |
15, 15, 15, 15, 15, 15, 804, 15, 15, 15, |
15, 15, 15, 15, 15, 119, 15, 15, 15, 15, |
15, 15, 15, 15, 15, 15, 38, 38, 38, 110, |
101, 101, 123, 101, 101, 130, 132, 640, 130, 110, |
102, 101, 102, 640, 184, 38, 132, 38, 101, 101, |
102, 125, 15, 15, 15, 15, 113, 102, 102, 184, |
113, 135, 102, 125, 135, 139, 210, 113, 806, 139, |
131, 119, 113, 139, 131, 38, 123, 38, 15, 15, |
15, 15, 16, 16, 16, 16, 16, 16, 131, 16, |
16, 16, 16, 16, 16, 16, 16, 169, 16, 16, |
16, 16, 16, 16, 16, 16, 16, 16, 37, 37, |
37, 133, 129, 103, 133, 103, 129, 133, 140, 129, |
193, 240, 210, 103, 169, 193, 808, 37, 140, 37, |
103, 103, 129, 240, 16, 16, 16, 16, 138, 138, |
37, 197, 142, 141, 175, 175, 177, 141, 189, 138, |
141, 141, 142, 252, 197, 175, 177, 37, 189, 37, |
16, 16, 16, 16, 17, 17, 17, 37, 17, 17, |
252, 17, 17, 17, 17, 809, 17, 17, 189, 457, |
17, 17, 17, 17, 17, 17, 17, 17, 17, 116, |
179, 116, 128, 211, 128, 246, 128, 246, 190, 116, |
179, 145, 128, 179, 145, 145, 116, 116, 190, 128, |
128, 145, 145, 145, 178, 810, 145, 145, 457, 263, |
116, 145, 176, 176, 178, 17, 178, 17, 190, 176, |
212, 17, 263, 176, 811, 190, 178, 812, 813, 191, |
211, 814, 17, 17, 17, 17, 18, 18, 18, 191, |
18, 18, 302, 18, 18, 18, 18, 815, 18, 18, |
816, 188, 18, 18, 18, 18, 18, 18, 18, 18, |
18, 188, 126, 126, 126, 378, 220, 192, 220, 302, |
212, 191, 314, 378, 127, 127, 127, 192, 191, 333, |
818, 126, 188, 126, 314, 228, 228, 228, 333, 354, |
309, 188, 309, 127, 126, 127, 220, 18, 220, 18, |
309, 354, 415, 18, 228, 819, 228, 309, 309, 366, |
192, 126, 415, 126, 18, 18, 18, 18, 26, 26, |
26, 126, 319, 127, 319, 127, 366, 26, 26, 26, |
26, 26, 26, 673, 228, 259, 228, 276, 259, 276, |
259, 267, 326, 276, 267, 326, 417, 360, 259, 360, |
267, 259, 671, 672, 820, 326, 417, 434, 26, 26, |
26, 26, 26, 26, 79, 79, 79, 434, 456, 310, |
673, 310, 821, 79, 79, 79, 79, 79, 79, 310, |
822, 303, 303, 303, 455, 373, 310, 310, 373, 436, |
373, 672, 823, 671, 824, 348, 348, 348, 373, 436, |
303, 373, 303, 434, 79, 79, 79, 79, 79, 79, |
90, 90, 90, 303, 348, 825, 348, 826, 456, 90, |
90, 90, 90, 90, 90, 827, 90, 828, 377, 90, |
303, 90, 303, 90, 377, 436, 382, 656, 455, 382, |
303, 377, 90, 656, 348, 382, 348, 829, 830, 831, |
90, 90, 90, 90, 90, 90, 311, 90, 311, 90, |
832, 90, 391, 90, 391, 833, 311, 834, 391, 90, |
98, 98, 98, 311, 311, 416, 835, 420, 421, 98, |
98, 98, 98, 98, 98, 416, 98, 420, 421, 316, |
98, 316, 416, 98, 420, 421, 836, 98, 98, 316, |
840, 841, 98, 845, 846, 848, 316, 316, 849, 850, |
98, 98, 98, 98, 98, 98, 320, 98, 320, 851, |
528, 852, 528, 98, 856, 857, 320, 861, 862, 98, |
122, 122, 122, 320, 320, 864, 342, 865, 342, 122, |
122, 122, 122, 122, 122, 321, 342, 321, 437, 321, |
528, 869, 528, 342, 342, 321, 866, 868, 437, 867, |
872, 873, 321, 321, 871, 874, 877, 876, 878, 879, |
122, 122, 122, 122, 122, 122, 153, 153, 153, 882, |
871, 530, 342, 530, 876, 153, 153, 153, 153, 153, |
153, 530, 883, 539, 437, 539, 867, 530, 530, 530, |
539, 885, 887, 539, 868, 888, 889, 890, 866, 891, |
539, 539, 892, 893, 894, 895, 153, 153, 153, 153, |
153, 153, 161, 161, 161, 896, 897, 898, 899, 900, |
901, 161, 161, 161, 161, 161, 161, 902, 904, 905, |
906, 907, 908, 910, 911, 912, 914, 915, 916, 917, |
918, 919, 920, 921, 923, 922, 911, 924, 926, 927, |
928, 930, 161, 161, 161, 161, 161, 161, 174, 174, |
174, 922, 932, 933, 934, 935, 936, 174, 174, 174, |
174, 174, 174, 937, 174, 938, 939, 940, 174, 941, |
942, 174, 943, 944, 945, 946, 947, 948, 949, 950, |
174, 952, 953, 954, 955, 957, 958, 959, 174, 174, |
174, 174, 174, 174, 960, 174, 963, 952, 964, 966, |
968, 174, 957, 969, 970, 971, 972, 174, 295, 295, |
295, 973, 974, 975, 976, 977, 978, 295, 295, 295, |
295, 295, 295, 979, 980, 981, 982, 295, 983, 295, |
984, 986, 987, 988, 989, 990, 992, 994, 996, 997, |
998, 999, 993, 1000, 1001, 1002, 1003, 1005, 295, 295, |
295, 295, 295, 295, 993, 1006, 1007, 295, 1011, 295, |
345, 345, 345, 1013, 1014, 1016, 1017, 1018, 1022, 345, |
345, 345, 345, 345, 345, 1024, 1027, 1028, 1025, 345, |
1029, 345, 1026, 1030, 1032, 1034, 1035, 1036, 1037, 1038, |
1039, 1041, 1043, 1044, 1045, 1047, 1049, 1051, 1052, 1054, |
345, 345, 345, 345, 345, 345, 1056, 1057, 1058, 345, |
1059, 345, 407, 407, 407, 1060, 1061, 1062, 1063, 1064, |
1065, 407, 407, 407, 407, 407, 407, 1025, 1066, 1026, |
1067, 407, 1068, 407, 1071, 1072, 1073, 1074, 1075, 1076, |
1078, 1079, 1080, 1081, 1082, 1084, 1085, 1087, 1088, 1089, |
1091, 1093, 407, 407, 407, 407, 407, 407, 1094, 1095, |
1096, 407, 1097, 407, 411, 411, 411, 1098, 1099, 1100, |
1101, 1102, 1103, 411, 411, 411, 411, 411, 411, 1105, |
1107, 1108, 1109, 411, 1110, 411, 1111, 1112, 1114, 1116, |
1117, 1118, 1120, 1122, 1123, 1125, 1126, 1128, 1130, 1131, |
1132, 1133, 1134, 1135, 411, 411, 411, 411, 411, 411, |
1136, 1137, 1138, 411, 1139, 411, 842, 842, 1140, 842, |
842, 842, 1141, 842, 842, 842, 842, 842, 1142, 842, |
1145, 1146, 1147, 1148, 1149, 1153, 1154, 842, 842, 842, |
842, 842, 1155, 1159, 1160, 1161, 1162, 1164, 1165, 1166, |
1167, 1168, 1169, 1171, 1172, 1174, 1175, 1176, 1177, 1178, |
1180, 1181, 1183, 1184, 1185, 1186, 1181, 1187, 1188, 1189, |
1190, 842, 1193, 1195, 1196, 1197, 1199, 1200, 1201, 1202, |
1204, 1206, 1207, 1208, 1209, 1210, 1212, 1213, 1214, 1216, |
1217, 1218, 1219, 1221, 842, 842, 842, 858, 858, 1222, |
858, 858, 858, 1223, 858, 858, 858, 858, 858, 1224, |
858, 1225, 1226, 1228, 1229, 1231, 1232, 1233, 858, 858, |
858, 858, 858, 1234, 1235, 1236, 1238, 1239, 1241, 1242, |
1243, 1244, 1239, 1245, 1246, 1247, 1248, 1251, 1253, 1254, |
1255, 1256, 1257, 1258, 1259, 1260, 1262, 1263, 1265, 1266, |
1267, 1268, 858, 1269, 1270, 1271, 1272, 1274, 1275, 1276, |
1277, 1278, 1279, 1280, 1282, 1283, 1285, 1288, 1290, 1291, |
1293, 1294, 1295, 1298, 1299, 858, 858, 858, 1009, 1009, |
1300, 1009, 1009, 1009, 1284, 1009, 1009, 1009, 1009, 1009, |
1301, 1009, 1284, 1302, 1305, 1307, 1308, 1284, 1310, 1009, |
1009, 1009, 1009, 1009, 1311, 1312, 1313, 1314, 1315, 1316, |
1317, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1328, 1329, |
1331, 1330, 1334, 1341, 1343, 1344, 1345, 1346, 1347, 1330, |
1348, 1349, 1350, 1009, 1330, 1351, 1352, 1353, 1354, 1355, |
1356, 1357, 1358, 1359, 1352, 1360, 1361, 1362, 1364, 1365, |
1367, 1368, 1369, 1370, 1372, 1373, 1009, 1009, 1009, 1020, |
1020, 1374, 1020, 1020, 1020, 1371, 1020, 1020, 1020, 1020, |
1020, 1375, 1020, 1371, 1376, 1378, 1379, 1380, 1381, 1382, |
1020, 1020, 1020, 1020, 1020, 1383, 1384, 1385, 1386, 1387, |
1388, 1389, 1390, 1391, 1392, 1393, 1394, 1387, 1395, 1396, |
1397, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, |
1409, 1412, 1413, 1414, 1020, 1415, 1417, 1418, 1419, 1420, |
1421, 1422, 1423, 1424, 1425, 1426, 1427, 1430, 1431, 1432, |
1433, 1434, 1435, 1436, 1437, 1438, 1439, 1020, 1020, 1020, |
1440, 1441, 1443, 1446, 1447, 1448, 1449, 1451, 1452, 1453, |
1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, |
1464, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, |
1476, 1477, 1478, 1479, 1481, 1482, 1483, 1484, 1485, 1486, |
1487, 1488, 1489, 1490, 1491, 1492, 1495, 1496, 1497, 1498, |
1499, 1500, 1501, 1502, 1503, 1504, 1506, 1507, 1509, 1510, |
1511, 1512, 1513, 1515, 1516, 1517, 1518, 1520, 1521, 1522, |
1524, 1525, 1526, 1527, 1528, 1529, 1531, 1532, 1534, 1535, |
1536, 1537, 1538, 1540, 1541, 1542, 1543, 1545, 1546, 1547, |
1548, 1549, 1550, 1551, 1548, 1553, 1555, 1556, 1557, 1558, |
1559, 1560, 1561, 1562, 1564, 1560, 1565, 1548, 1566, 1567, |
1568, 1569, 1570, 1571, 1568, 1573, 1575, 1576, 1560, 1577, |
1578, 1579, 1580, 1581, 1582, 1583, 1584, 1568, 1585, 1586, |
1589, 1590, 1592, 1593, 1594, 1595, 1596, 1600, 1601, 1602, |
1603, 1604, 1605, 1606, 1607, 1610, 1611, 1613, 1614, 1615, |
1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, |
1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, |
1636, 1637, 1639, 1640, 1642, 1643, 1644, 1645, 1646, 1647, |
1649, 1651, 1652, 1654, 1655, 1657, 1658, 1659, 1660, 1661, |
1662, 1663, 1664, 1665, 1666, 1667, 1668, 1670, 1671, 1672, |
1673, 1674, 1675, 1676, 1677, 1678, 1679, 1681, 1682, 1684, |
1685, 1686, 1687, 1688, 1690, 1691, 1692, 1694, 1695, 1696, |
1697, 1698, 1699, 1700, 1701, 1702, 1704, 1705, 1707, 1708, |
1709, 1710, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, |
1720, 1721, 1722, 1723, 1725, 1726, 1727, 1729, 1731, 1732, |
1733, 1736, 1737, 1740, 1741, 1743, 1745, 1746, 1747, 1751, |
1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1752, |
1752, 1752, 1752, 1752, 1752, 1752, 1752, 1752, 1752, 1753, |
1753, 1753, 1753, 1753, 1753, 1753, 1753, 1753, 1753, 1754, |
1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1755, |
1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1756, |
1756, 1756, 1756, 1756, 1756, 1756, 1756, 1757, 1757, 1757, |
1757, 1757, 1757, 1757, 1757, 1757, 1757, 1758, 1758, 1769, |
1758, 1758, 1758, 1758, 1759, 1759, 1759, 1759, 1759, 1759, |
1759, 1760, 799, 798, 797, 1760, 1760, 1760, 1761, 1761, |
1761, 1761, 1761, 1761, 1761, 1761, 1761, 1761, 1762, 1762, |
795, 1762, 1762, 1762, 1762, 1763, 794, 1763, 1763, 1763, |
1763, 1763, 1763, 1763, 1763, 1764, 793, 1764, 1764, 1764, |
1764, 1764, 1764, 1764, 1764, 1765, 792, 1765, 1765, 1765, |
1765, 1765, 1765, 1765, 1765, 1766, 791, 1766, 1767, 1767, |
789, 788, 1767, 1767, 787, 1767, 1768, 1768, 786, 1768, |
1768, 1768, 1768, 1770, 1770, 1770, 1770, 1770, 1770, 1770, |
1771, 785, 1771, 1771, 1771, 1771, 1771, 1771, 1771, 1771, |
1772, 784, 1772, 1772, 1772, 1772, 1772, 1772, 1772, 1772, |
1773, 783, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, |
1774, 781, 1774, 1774, 1774, 1774, 1774, 1774, 1774, 1774, |
779, 777, 776, 775, 774, 773, 771, 770, 769, 768, |
767, 766, 765, 764, 763, 762, 761, 760, 759, 757, |
756, 755, 753, 751, 750, 749, 748, 747, 746, 745, |
743, 742, 740, 739, 738, 736, 735, 734, 733, 732, |
731, 730, 729, 728, 727, 726, 725, 724, 723, 722, |
721, 720, 718, 717, 716, 715, 714, 713, 712, 711, |
710, 708, 706, 705, 704, 702, 701, 700, 698, 697, |
696, 695, 694, 692, 691, 690, 689, 688, 687, 686, |
684, 682, 680, 679, 678, 677, 676, 674, 670, 669, |
668, 667, 666, 665, 664, 663, 662, 661, 659, 658, |
657, 655, 654, 653, 652, 651, 650, 649, 648, 647, |
646, 645, 643, 642, 641, 639, 636, 633, 632, 631, |
630, 629, 628, 627, 626, 625, 624, 623, 622, 621, |
620, 619, 618, 617, 616, 615, 614, 613, 612, 611, |
610, 609, 608, 606, 603, 602, 601, 600, 599, 598, |
597, 596, 595, 594, 593, 591, 590, 589, 588, 587, |
586, 585, 584, 583, 582, 581, 580, 579, 578, 577, |
576, 575, 574, 573, 572, 571, 570, 569, 568, 565, |
564, 563, 562, 561, 560, 559, 558, 557, 556, 555, |
554, 553, 550, 549, 548, 547, 546, 545, 544, 543, |
542, 541, 540, 538, 537, 536, 535, 534, 533, 532, |
531, 529, 525, 522, 521, 520, 519, 518, 517, 516, |
515, 514, 513, 512, 511, 510, 509, 508, 507, 506, |
505, 504, 503, 502, 501, 500, 499, 498, 497, 496, |
494, 493, 492, 491, 490, 489, 488, 487, 486, 485, |
483, 482, 481, 480, 479, 478, 477, 476, 475, 474, |
473, 472, 471, 470, 469, 468, 467, 466, 465, 464, |
463, 462, 461, 460, 454, 453, 450, 449, 448, 447, |
446, 445, 444, 443, 442, 441, 440, 439, 438, 435, |
433, 432, 431, 430, 429, 428, 427, 426, 425, 424, |
423, 422, 419, 408, 405, 404, 403, 402, 401, 400, |
399, 398, 397, 396, 395, 394, 393, 392, 390, 389, |
388, 387, 386, 385, 384, 383, 381, 380, 379, 376, |
375, 374, 372, 371, 370, 369, 368, 367, 365, 364, |
363, 362, 361, 359, 358, 357, 356, 353, 352, 351, |
350, 343, 341, 340, 339, 338, 337, 336, 335, 334, |
332, 331, 330, 328, 327, 325, 324, 323, 322, 318, |
317, 313, 290, 289, 288, 287, 286, 285, 284, 283, |
282, 281, 280, 279, 278, 277, 275, 274, 273, 272, |
271, 270, 269, 268, 266, 265, 264, 262, 261, 260, |
258, 257, 256, 255, 254, 253, 251, 250, 249, 248, |
247, 245, 244, 243, 242, 239, 238, 237, 236, 235, |
231, 218, 215, 209, 203, 200, 198, 196, 195, 194, |
185, 183, 182, 181, 172, 167, 165, 163, 162, 160, |
159, 151, 150, 149, 148, 147, 146, 144, 143, 137, |
136, 134, 117, 112, 107, 106, 105, 104, 95, 85, |
84, 78, 77, 76, 70, 69, 68, 67, 64, 63, |
61, 60, 54, 53, 51, 42, 34, 32, 31, 25, |
24, 22, 19, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, |
1750, 1750, 1750, 1750, 1750, 1750 |
} ; |
static yy_state_type yy_last_accepting_state; |
static char *yy_last_accepting_cpos; |
extern int yy_flex_debug; |
int yy_flex_debug = 0; |
/* The intent behind this definition is that it'll catch |
* any uses of REJECT which flex missed. |
*/ |
#define REJECT reject_used_but_not_detected |
#define yymore() yymore_used_but_not_detected |
#define YY_MORE_ADJ 0 |
#define YY_RESTORE_YY_MORE_OFFSET |
char *yytext; |
#line 1 "ldlex.l" |
#line 4 "ldlex.l" |
/* Copyright 1991-2013 Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "bfd.h" |
#include "safe-ctype.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include <ldgram.h> |
#include "ldfile.h" |
#include "ldlex.h" |
#include "ldmain.h" |
#include "libiberty.h" |
/* The type of top-level parser input. |
yylex and yyparse (indirectly) both check this. */ |
input_type parser_input; |
/* Line number in the current input file. |
(FIXME Actually, it doesn't appear to get reset for each file?) */ |
unsigned int lineno = 1; |
/* The string we are currently lexing, or NULL if we are reading a |
file. */ |
const char *lex_string = NULL; |
/* Support for flex reading from more than one input file (stream). |
`include_stack' is flex's input state for each open file; |
`file_name_stack' is the file names. `lineno_stack' is the current |
line numbers. |
If `include_stack_ptr' is 0, we haven't started reading anything yet. |
Otherwise, stack elements 0 through `include_stack_ptr - 1' are valid. */ |
#undef YY_INPUT |
#define YY_INPUT(buf,result,max_size) result = yy_input (buf, max_size) |
#ifndef YY_NO_UNPUT |
#define YY_NO_UNPUT |
#endif |
#define MAX_INCLUDE_DEPTH 10 |
static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; |
static const char *file_name_stack[MAX_INCLUDE_DEPTH]; |
static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; |
static unsigned int sysrooted_stack[MAX_INCLUDE_DEPTH]; |
static unsigned int include_stack_ptr = 0; |
static int vers_node_nesting = 0; |
static int yy_input (char *, int); |
static void comment (void); |
static void lex_warn_invalid (char *where, char *what); |
/* STATES |
EXPRESSION definitely in an expression |
SCRIPT definitely in a script |
BOTH either EXPRESSION or SCRIPT |
DEFSYMEXP in an argument to -defsym |
MRI in an MRI script |
VERS_START starting a Sun style mapfile |
VERS_SCRIPT a Sun style mapfile |
VERS_NODE a node within a Sun style mapfile |
*/ |
#define RTOKEN(x) { yylval.token = x; return x; } |
/* Some versions of flex want this. */ |
#ifndef yywrap |
int yywrap (void) { return 1; } |
#endif |
#line 1745 "ldlex.c" |
#define INITIAL 0 |
#define SCRIPT 1 |
#define EXPRESSION 2 |
#define BOTH 3 |
#define DEFSYMEXP 4 |
#define MRI 5 |
#define VERS_START 6 |
#define VERS_SCRIPT 7 |
#define VERS_NODE 8 |
#ifndef YY_NO_UNISTD_H |
/* Special case for "unistd.h", since it is non-ANSI. We include it way |
* down here because we want the user's section 1 to have been scanned first. |
* The user has a chance to override it with an option. |
*/ |
#include <unistd.h> |
#endif |
#ifndef YY_EXTRA_TYPE |
#define YY_EXTRA_TYPE void * |
#endif |
static int yy_init_globals (void ); |
/* Accessor methods to globals. |
These are made visible to non-reentrant scanners for convenience. */ |
int yylex_destroy (void ); |
int yyget_debug (void ); |
void yyset_debug (int debug_flag ); |
YY_EXTRA_TYPE yyget_extra (void ); |
void yyset_extra (YY_EXTRA_TYPE user_defined ); |
FILE *yyget_in (void ); |
void yyset_in (FILE * in_str ); |
FILE *yyget_out (void ); |
void yyset_out (FILE * out_str ); |
yy_size_t yyget_leng (void ); |
char *yyget_text (void ); |
int yyget_lineno (void ); |
void yyset_lineno (int line_number ); |
/* Macros after this point can all be overridden by user definitions in |
* section 1. |
*/ |
#ifndef YY_SKIP_YYWRAP |
#ifdef __cplusplus |
extern "C" int yywrap (void ); |
#else |
extern int yywrap (void ); |
#endif |
#endif |
#ifndef yytext_ptr |
static void yy_flex_strncpy (char *,yyconst char *,int ); |
#endif |
#ifdef YY_NEED_STRLEN |
static int yy_flex_strlen (yyconst char * ); |
#endif |
#ifndef YY_NO_INPUT |
#ifdef __cplusplus |
static int yyinput (void ); |
#else |
static int input (void ); |
#endif |
#endif |
/* Amount of stuff to slurp up with each read. */ |
#ifndef YY_READ_BUF_SIZE |
#define YY_READ_BUF_SIZE 8192 |
#endif |
/* Copy whatever the last rule matched to the standard output. */ |
#ifndef ECHO |
/* This used to be an fputs(), but since the string might contain NUL's, |
* we now use fwrite(). |
*/ |
#define ECHO fwrite( yytext, yyleng, 1, yyout ) |
#endif |
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, |
* is returned in "result". |
*/ |
#ifndef YY_INPUT |
#define YY_INPUT(buf,result,max_size) \ |
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ |
{ \ |
int c = '*'; \ |
yy_size_t n; \ |
for ( n = 0; n < max_size && \ |
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \ |
buf[n] = (char) c; \ |
if ( c == '\n' ) \ |
buf[n++] = (char) c; \ |
if ( c == EOF && ferror( yyin ) ) \ |
YY_FATAL_ERROR( "input in flex scanner failed" ); \ |
result = n; \ |
} \ |
else \ |
{ \ |
errno=0; \ |
while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ |
{ \ |
if( errno != EINTR) \ |
{ \ |
YY_FATAL_ERROR( "input in flex scanner failed" ); \ |
break; \ |
} \ |
errno=0; \ |
clearerr(yyin); \ |
} \ |
}\ |
\ |
#endif |
/* No semi-colon after return; correct usage is to write "yyterminate();" - |
* we don't want an extra ';' after the "return" because that will cause |
* some compilers to complain about unreachable statements. |
*/ |
#ifndef yyterminate |
#define yyterminate() return YY_NULL |
#endif |
/* Number of entries by which start-condition stack grows. */ |
#ifndef YY_START_STACK_INCR |
#define YY_START_STACK_INCR 25 |
#endif |
/* Report a fatal error. */ |
#ifndef YY_FATAL_ERROR |
#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) |
#endif |
/* end tables serialization structures and prototypes */ |
/* Default declaration of generated scanner - a define so the user can |
* easily add parameters. |
*/ |
#ifndef YY_DECL |
#define YY_DECL_IS_OURS 1 |
extern int yylex (void); |
#define YY_DECL int yylex (void) |
#endif /* !YY_DECL */ |
/* Code executed at the beginning of each rule, after yytext and yyleng |
* have been set up. |
*/ |
#ifndef YY_USER_ACTION |
#define YY_USER_ACTION |
#endif |
/* Code executed at the end of each rule. */ |
#ifndef YY_BREAK |
#define YY_BREAK break; |
#endif |
#define YY_RULE_SETUP \ |
YY_USER_ACTION |
/** The main scanner function which does all the work. |
*/ |
YY_DECL |
{ |
register yy_state_type yy_current_state; |
register char *yy_cp, *yy_bp; |
register int yy_act; |
#line 119 "ldlex.l" |
if (parser_input != input_selected) |
{ |
/* The first token of the input determines the initial parser state. */ |
input_type t = parser_input; |
parser_input = input_selected; |
switch (t) |
{ |
case input_script: return INPUT_SCRIPT; break; |
case input_mri_script: return INPUT_MRI_SCRIPT; break; |
case input_version_script: return INPUT_VERSION_SCRIPT; break; |
case input_dynamic_list: return INPUT_DYNAMIC_LIST; break; |
case input_defsym: return INPUT_DEFSYM; break; |
default: abort (); |
} |
} |
#line 1952 "ldlex.c" |
if ( !(yy_init) ) |
{ |
(yy_init) = 1; |
#ifdef YY_USER_INIT |
YY_USER_INIT; |
#endif |
if ( ! (yy_start) ) |
(yy_start) = 1; /* first start state */ |
if ( ! yyin ) |
yyin = stdin; |
if ( ! yyout ) |
yyout = stdout; |
if ( ! YY_CURRENT_BUFFER ) { |
yyensure_buffer_stack (); |
YY_CURRENT_BUFFER_LVALUE = |
yy_create_buffer(yyin,YY_BUF_SIZE ); |
} |
yy_load_buffer_state( ); |
} |
while ( 1 ) /* loops until end-of-file is reached */ |
{ |
yy_cp = (yy_c_buf_p); |
/* Support of yytext. */ |
*yy_cp = (yy_hold_char); |
/* yy_bp points to the position in yy_ch_buf of the start of |
* the current run. |
*/ |
yy_bp = yy_cp; |
yy_current_state = (yy_start); |
yy_match: |
do |
{ |
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; |
if ( yy_accept[yy_current_state] ) |
{ |
(yy_last_accepting_state) = yy_current_state; |
(yy_last_accepting_cpos) = yy_cp; |
} |
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) |
{ |
yy_current_state = (int) yy_def[yy_current_state]; |
if ( yy_current_state >= 1751 ) |
yy_c = yy_meta[(unsigned int) yy_c]; |
} |
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; |
++yy_cp; |
} |
while ( yy_base[yy_current_state] != 2704 ); |
yy_find_action: |
yy_act = yy_accept[yy_current_state]; |
if ( yy_act == 0 ) |
{ /* have to back up */ |
yy_cp = (yy_last_accepting_cpos); |
yy_current_state = (yy_last_accepting_state); |
yy_act = yy_accept[yy_current_state]; |
} |
YY_DO_BEFORE_ACTION; |
do_action: /* This label is used only to access EOF actions. */ |
switch ( yy_act ) |
{ /* beginning of action switch */ |
case 0: /* must back up */ |
/* undo the effects of YY_DO_BEFORE_ACTION */ |
*yy_cp = (yy_hold_char); |
yy_cp = (yy_last_accepting_cpos); |
yy_current_state = (yy_last_accepting_state); |
goto yy_find_action; |
case 1: |
YY_RULE_SETUP |
#line 137 "ldlex.l" |
{ comment (); } |
YY_BREAK |
case 2: |
YY_RULE_SETUP |
#line 140 "ldlex.l" |
{ RTOKEN('-');} |
YY_BREAK |
case 3: |
YY_RULE_SETUP |
#line 141 "ldlex.l" |
{ RTOKEN('+');} |
YY_BREAK |
case 4: |
YY_RULE_SETUP |
#line 142 "ldlex.l" |
{ yylval.name = xstrdup (yytext); return NAME; } |
YY_BREAK |
case 5: |
YY_RULE_SETUP |
#line 143 "ldlex.l" |
{ RTOKEN('='); } |
YY_BREAK |
case 6: |
YY_RULE_SETUP |
#line 145 "ldlex.l" |
{ |
yylval.integer = bfd_scan_vma (yytext + 1, 0, 16); |
yylval.bigint.str = NULL; |
return INT; |
} |
YY_BREAK |
case 7: |
YY_RULE_SETUP |
#line 151 "ldlex.l" |
{ |
int ibase ; |
switch (yytext[yyleng - 1]) { |
case 'X': |
case 'x': |
case 'H': |
case 'h': |
ibase = 16; |
break; |
case 'O': |
case 'o': |
ibase = 8; |
break; |
case 'B': |
case 'b': |
ibase = 2; |
break; |
default: |
ibase = 10; |
} |
yylval.integer = bfd_scan_vma (yytext, 0, |
ibase); |
yylval.bigint.str = NULL; |
return INT; |
} |
YY_BREAK |
case 8: |
YY_RULE_SETUP |
#line 176 "ldlex.l" |
{ |
char *s = yytext; |
int ibase = 0; |
if (*s == '$') |
{ |
++s; |
ibase = 16; |
} |
yylval.integer = bfd_scan_vma (s, 0, ibase); |
yylval.bigint.str = NULL; |
if (yytext[yyleng - 1] == 'M' |
|| yytext[yyleng - 1] == 'm') |
{ |
yylval.integer *= 1024 * 1024; |
} |
else if (yytext[yyleng - 1] == 'K' |
|| yytext[yyleng - 1]=='k') |
{ |
yylval.integer *= 1024; |
} |
else if (yytext[0] == '0' |
&& (yytext[1] == 'x' |
|| yytext[1] == 'X')) |
{ |
yylval.bigint.str = xstrdup (yytext + 2); |
} |
return INT; |
} |
YY_BREAK |
case 9: |
YY_RULE_SETUP |
#line 205 "ldlex.l" |
{ RTOKEN(']');} |
YY_BREAK |
case 10: |
YY_RULE_SETUP |
#line 206 "ldlex.l" |
{ RTOKEN('[');} |
YY_BREAK |
case 11: |
YY_RULE_SETUP |
#line 207 "ldlex.l" |
{ RTOKEN(LSHIFTEQ);} |
YY_BREAK |
case 12: |
YY_RULE_SETUP |
#line 208 "ldlex.l" |
{ RTOKEN(RSHIFTEQ);} |
YY_BREAK |
case 13: |
YY_RULE_SETUP |
#line 209 "ldlex.l" |
{ RTOKEN(OROR);} |
YY_BREAK |
case 14: |
YY_RULE_SETUP |
#line 210 "ldlex.l" |
{ RTOKEN(EQ);} |
YY_BREAK |
case 15: |
YY_RULE_SETUP |
#line 211 "ldlex.l" |
{ RTOKEN(NE);} |
YY_BREAK |
case 16: |
YY_RULE_SETUP |
#line 212 "ldlex.l" |
{ RTOKEN(GE);} |
YY_BREAK |
case 17: |
YY_RULE_SETUP |
#line 213 "ldlex.l" |
{ RTOKEN(LE);} |
YY_BREAK |
case 18: |
YY_RULE_SETUP |
#line 214 "ldlex.l" |
{ RTOKEN(LSHIFT);} |
YY_BREAK |
case 19: |
YY_RULE_SETUP |
#line 215 "ldlex.l" |
{ RTOKEN(RSHIFT);} |
YY_BREAK |
case 20: |
YY_RULE_SETUP |
#line 216 "ldlex.l" |
{ RTOKEN(PLUSEQ);} |
YY_BREAK |
case 21: |
YY_RULE_SETUP |
#line 217 "ldlex.l" |
{ RTOKEN(MINUSEQ);} |
YY_BREAK |
case 22: |
YY_RULE_SETUP |
#line 218 "ldlex.l" |
{ RTOKEN(MULTEQ);} |
YY_BREAK |
case 23: |
YY_RULE_SETUP |
#line 219 "ldlex.l" |
{ RTOKEN(DIVEQ);} |
YY_BREAK |
case 24: |
YY_RULE_SETUP |
#line 220 "ldlex.l" |
{ RTOKEN(ANDEQ);} |
YY_BREAK |
case 25: |
YY_RULE_SETUP |
#line 221 "ldlex.l" |
{ RTOKEN(OREQ);} |
YY_BREAK |
case 26: |
YY_RULE_SETUP |
#line 222 "ldlex.l" |
{ RTOKEN(ANDAND);} |
YY_BREAK |
case 27: |
YY_RULE_SETUP |
#line 223 "ldlex.l" |
{ RTOKEN('>');} |
YY_BREAK |
case 28: |
YY_RULE_SETUP |
#line 224 "ldlex.l" |
{ RTOKEN(',');} |
YY_BREAK |
case 29: |
YY_RULE_SETUP |
#line 225 "ldlex.l" |
{ RTOKEN('&');} |
YY_BREAK |
case 30: |
YY_RULE_SETUP |
#line 226 "ldlex.l" |
{ RTOKEN('|');} |
YY_BREAK |
case 31: |
YY_RULE_SETUP |
#line 227 "ldlex.l" |
{ RTOKEN('~');} |
YY_BREAK |
case 32: |
YY_RULE_SETUP |
#line 228 "ldlex.l" |
{ RTOKEN('!');} |
YY_BREAK |
case 33: |
YY_RULE_SETUP |
#line 229 "ldlex.l" |
{ RTOKEN('?');} |
YY_BREAK |
case 34: |
YY_RULE_SETUP |
#line 230 "ldlex.l" |
{ RTOKEN('*');} |
YY_BREAK |
case 35: |
YY_RULE_SETUP |
#line 231 "ldlex.l" |
{ RTOKEN('+');} |
YY_BREAK |
case 36: |
YY_RULE_SETUP |
#line 232 "ldlex.l" |
{ RTOKEN('-');} |
YY_BREAK |
case 37: |
YY_RULE_SETUP |
#line 233 "ldlex.l" |
{ RTOKEN('/');} |
YY_BREAK |
case 38: |
YY_RULE_SETUP |
#line 234 "ldlex.l" |
{ RTOKEN('%');} |
YY_BREAK |
case 39: |
YY_RULE_SETUP |
#line 235 "ldlex.l" |
{ RTOKEN('<');} |
YY_BREAK |
case 40: |
YY_RULE_SETUP |
#line 236 "ldlex.l" |
{ RTOKEN('=');} |
YY_BREAK |
case 41: |
YY_RULE_SETUP |
#line 237 "ldlex.l" |
{ RTOKEN('}') ; } |
YY_BREAK |
case 42: |
YY_RULE_SETUP |
#line 238 "ldlex.l" |
{ RTOKEN('{'); } |
YY_BREAK |
case 43: |
YY_RULE_SETUP |
#line 239 "ldlex.l" |
{ RTOKEN(')');} |
YY_BREAK |
case 44: |
YY_RULE_SETUP |
#line 240 "ldlex.l" |
{ RTOKEN('(');} |
YY_BREAK |
case 45: |
YY_RULE_SETUP |
#line 241 "ldlex.l" |
{ RTOKEN(':'); } |
YY_BREAK |
case 46: |
YY_RULE_SETUP |
#line 242 "ldlex.l" |
{ RTOKEN(';');} |
YY_BREAK |
case 47: |
YY_RULE_SETUP |
#line 243 "ldlex.l" |
{ RTOKEN(MEMORY);} |
YY_BREAK |
case 48: |
YY_RULE_SETUP |
#line 244 "ldlex.l" |
{ RTOKEN(REGION_ALIAS);} |
YY_BREAK |
case 49: |
YY_RULE_SETUP |
#line 245 "ldlex.l" |
{ RTOKEN(LD_FEATURE);} |
YY_BREAK |
case 50: |
YY_RULE_SETUP |
#line 246 "ldlex.l" |
{ RTOKEN(ORIGIN);} |
YY_BREAK |
case 51: |
YY_RULE_SETUP |
#line 247 "ldlex.l" |
{ RTOKEN(VERSIONK);} |
YY_BREAK |
case 52: |
YY_RULE_SETUP |
#line 248 "ldlex.l" |
{ RTOKEN(BLOCK);} |
YY_BREAK |
case 53: |
YY_RULE_SETUP |
#line 249 "ldlex.l" |
{ RTOKEN(BIND);} |
YY_BREAK |
case 54: |
YY_RULE_SETUP |
#line 250 "ldlex.l" |
{ RTOKEN(LENGTH);} |
YY_BREAK |
case 55: |
YY_RULE_SETUP |
#line 251 "ldlex.l" |
{ RTOKEN(ALIGN_K);} |
YY_BREAK |
case 56: |
YY_RULE_SETUP |
#line 252 "ldlex.l" |
{ RTOKEN(DATA_SEGMENT_ALIGN);} |
YY_BREAK |
case 57: |
YY_RULE_SETUP |
#line 253 "ldlex.l" |
{ RTOKEN(DATA_SEGMENT_RELRO_END);} |
YY_BREAK |
case 58: |
YY_RULE_SETUP |
#line 254 "ldlex.l" |
{ RTOKEN(DATA_SEGMENT_END);} |
YY_BREAK |
case 59: |
YY_RULE_SETUP |
#line 255 "ldlex.l" |
{ RTOKEN(ADDR);} |
YY_BREAK |
case 60: |
YY_RULE_SETUP |
#line 256 "ldlex.l" |
{ RTOKEN(LOADADDR);} |
YY_BREAK |
case 61: |
YY_RULE_SETUP |
#line 257 "ldlex.l" |
{ RTOKEN(ALIGNOF); } |
YY_BREAK |
case 62: |
YY_RULE_SETUP |
#line 258 "ldlex.l" |
{ RTOKEN(MAX_K); } |
YY_BREAK |
case 63: |
YY_RULE_SETUP |
#line 259 "ldlex.l" |
{ RTOKEN(MIN_K); } |
YY_BREAK |
case 64: |
YY_RULE_SETUP |
#line 260 "ldlex.l" |
{ RTOKEN(LOG2CEIL); } |
YY_BREAK |
case 65: |
YY_RULE_SETUP |
#line 261 "ldlex.l" |
{ RTOKEN(ASSERT_K); } |
YY_BREAK |
case 66: |
YY_RULE_SETUP |
#line 262 "ldlex.l" |
{ RTOKEN(ENTRY);} |
YY_BREAK |
case 67: |
YY_RULE_SETUP |
#line 263 "ldlex.l" |
{ RTOKEN(EXTERN);} |
YY_BREAK |
case 68: |
YY_RULE_SETUP |
#line 264 "ldlex.l" |
{ RTOKEN(NEXT);} |
YY_BREAK |
case 69: |
YY_RULE_SETUP |
#line 265 "ldlex.l" |
{ RTOKEN(SIZEOF_HEADERS);} |
YY_BREAK |
case 70: |
YY_RULE_SETUP |
#line 266 "ldlex.l" |
{ RTOKEN(SIZEOF_HEADERS);} |
YY_BREAK |
case 71: |
YY_RULE_SETUP |
#line 267 "ldlex.l" |
{ RTOKEN(SEGMENT_START);} |
YY_BREAK |
case 72: |
YY_RULE_SETUP |
#line 268 "ldlex.l" |
{ RTOKEN(MAP);} |
YY_BREAK |
case 73: |
YY_RULE_SETUP |
#line 269 "ldlex.l" |
{ RTOKEN(SIZEOF);} |
YY_BREAK |
case 74: |
YY_RULE_SETUP |
#line 270 "ldlex.l" |
{ RTOKEN(TARGET_K);} |
YY_BREAK |
case 75: |
YY_RULE_SETUP |
#line 271 "ldlex.l" |
{ RTOKEN(SEARCH_DIR);} |
YY_BREAK |
case 76: |
YY_RULE_SETUP |
#line 272 "ldlex.l" |
{ RTOKEN(OUTPUT);} |
YY_BREAK |
case 77: |
YY_RULE_SETUP |
#line 273 "ldlex.l" |
{ RTOKEN(INPUT);} |
YY_BREAK |
case 78: |
YY_RULE_SETUP |
#line 274 "ldlex.l" |
{ RTOKEN(GROUP);} |
YY_BREAK |
case 79: |
YY_RULE_SETUP |
#line 275 "ldlex.l" |
{ RTOKEN(AS_NEEDED);} |
YY_BREAK |
case 80: |
YY_RULE_SETUP |
#line 276 "ldlex.l" |
{ RTOKEN(DEFINED);} |
YY_BREAK |
case 81: |
YY_RULE_SETUP |
#line 277 "ldlex.l" |
{ RTOKEN(CREATE_OBJECT_SYMBOLS);} |
YY_BREAK |
case 82: |
YY_RULE_SETUP |
#line 278 "ldlex.l" |
{ RTOKEN( CONSTRUCTORS);} |
YY_BREAK |
case 83: |
YY_RULE_SETUP |
#line 279 "ldlex.l" |
{ RTOKEN(FORCE_COMMON_ALLOCATION);} |
YY_BREAK |
case 84: |
YY_RULE_SETUP |
#line 280 "ldlex.l" |
{ RTOKEN(INHIBIT_COMMON_ALLOCATION);} |
YY_BREAK |
case 85: |
YY_RULE_SETUP |
#line 281 "ldlex.l" |
{ RTOKEN(SECTIONS);} |
YY_BREAK |
case 86: |
YY_RULE_SETUP |
#line 282 "ldlex.l" |
{ RTOKEN(INSERT_K);} |
YY_BREAK |
case 87: |
YY_RULE_SETUP |
#line 283 "ldlex.l" |
{ RTOKEN(AFTER);} |
YY_BREAK |
case 88: |
YY_RULE_SETUP |
#line 284 "ldlex.l" |
{ RTOKEN(BEFORE);} |
YY_BREAK |
case 89: |
YY_RULE_SETUP |
#line 285 "ldlex.l" |
{ RTOKEN(FILL);} |
YY_BREAK |
case 90: |
YY_RULE_SETUP |
#line 286 "ldlex.l" |
{ RTOKEN(STARTUP);} |
YY_BREAK |
case 91: |
YY_RULE_SETUP |
#line 287 "ldlex.l" |
{ RTOKEN(OUTPUT_FORMAT);} |
YY_BREAK |
case 92: |
YY_RULE_SETUP |
#line 288 "ldlex.l" |
{ RTOKEN( OUTPUT_ARCH);} |
YY_BREAK |
case 93: |
YY_RULE_SETUP |
#line 289 "ldlex.l" |
{ RTOKEN(HLL);} |
YY_BREAK |
case 94: |
YY_RULE_SETUP |
#line 290 "ldlex.l" |
{ RTOKEN(SYSLIB);} |
YY_BREAK |
case 95: |
YY_RULE_SETUP |
#line 291 "ldlex.l" |
{ RTOKEN(FLOAT);} |
YY_BREAK |
case 96: |
YY_RULE_SETUP |
#line 292 "ldlex.l" |
{ RTOKEN( QUAD);} |
YY_BREAK |
case 97: |
YY_RULE_SETUP |
#line 293 "ldlex.l" |
{ RTOKEN( SQUAD);} |
YY_BREAK |
case 98: |
YY_RULE_SETUP |
#line 294 "ldlex.l" |
{ RTOKEN( LONG);} |
YY_BREAK |
case 99: |
YY_RULE_SETUP |
#line 295 "ldlex.l" |
{ RTOKEN( SHORT);} |
YY_BREAK |
case 100: |
YY_RULE_SETUP |
#line 296 "ldlex.l" |
{ RTOKEN( BYTE);} |
YY_BREAK |
case 101: |
YY_RULE_SETUP |
#line 297 "ldlex.l" |
{ RTOKEN(NOFLOAT);} |
YY_BREAK |
case 102: |
YY_RULE_SETUP |
#line 298 "ldlex.l" |
{ RTOKEN(NOCROSSREFS);} |
YY_BREAK |
case 103: |
YY_RULE_SETUP |
#line 299 "ldlex.l" |
{ RTOKEN(OVERLAY); } |
YY_BREAK |
case 104: |
YY_RULE_SETUP |
#line 300 "ldlex.l" |
{ RTOKEN(SORT_BY_NAME); } |
YY_BREAK |
case 105: |
YY_RULE_SETUP |
#line 301 "ldlex.l" |
{ RTOKEN(SORT_BY_ALIGNMENT); } |
YY_BREAK |
case 106: |
YY_RULE_SETUP |
#line 302 "ldlex.l" |
{ RTOKEN(SORT_BY_NAME); } |
YY_BREAK |
case 107: |
YY_RULE_SETUP |
#line 303 "ldlex.l" |
{ RTOKEN(SORT_BY_INIT_PRIORITY); } |
YY_BREAK |
case 108: |
YY_RULE_SETUP |
#line 304 "ldlex.l" |
{ RTOKEN(SORT_NONE); } |
YY_BREAK |
case 109: |
YY_RULE_SETUP |
#line 305 "ldlex.l" |
{ RTOKEN(NOLOAD);} |
YY_BREAK |
case 110: |
YY_RULE_SETUP |
#line 306 "ldlex.l" |
{ RTOKEN(DSECT);} |
YY_BREAK |
case 111: |
YY_RULE_SETUP |
#line 307 "ldlex.l" |
{ RTOKEN(COPY);} |
YY_BREAK |
case 112: |
YY_RULE_SETUP |
#line 308 "ldlex.l" |
{ RTOKEN(INFO);} |
YY_BREAK |
case 113: |
YY_RULE_SETUP |
#line 309 "ldlex.l" |
{ RTOKEN(OVERLAY);} |
YY_BREAK |
case 114: |
YY_RULE_SETUP |
#line 310 "ldlex.l" |
{ RTOKEN(ONLY_IF_RO); } |
YY_BREAK |
case 115: |
YY_RULE_SETUP |
#line 311 "ldlex.l" |
{ RTOKEN(ONLY_IF_RW); } |
YY_BREAK |
case 116: |
YY_RULE_SETUP |
#line 312 "ldlex.l" |
{ RTOKEN(SPECIAL); } |
YY_BREAK |
case 117: |
YY_RULE_SETUP |
#line 313 "ldlex.l" |
{ RTOKEN(ORIGIN);} |
YY_BREAK |
case 118: |
YY_RULE_SETUP |
#line 314 "ldlex.l" |
{ RTOKEN(ORIGIN);} |
YY_BREAK |
case 119: |
YY_RULE_SETUP |
#line 315 "ldlex.l" |
{ RTOKEN( LENGTH);} |
YY_BREAK |
case 120: |
YY_RULE_SETUP |
#line 316 "ldlex.l" |
{ RTOKEN( LENGTH);} |
YY_BREAK |
case 121: |
YY_RULE_SETUP |
#line 317 "ldlex.l" |
{ RTOKEN(INPUT_SECTION_FLAGS); } |
YY_BREAK |
case 122: |
YY_RULE_SETUP |
#line 318 "ldlex.l" |
{ RTOKEN(INCLUDE);} |
YY_BREAK |
case 123: |
YY_RULE_SETUP |
#line 319 "ldlex.l" |
{ RTOKEN (PHDRS); } |
YY_BREAK |
case 124: |
YY_RULE_SETUP |
#line 320 "ldlex.l" |
{ RTOKEN(AT);} |
YY_BREAK |
case 125: |
YY_RULE_SETUP |
#line 321 "ldlex.l" |
{ RTOKEN(ALIGN_WITH_INPUT);} |
YY_BREAK |
case 126: |
YY_RULE_SETUP |
#line 322 "ldlex.l" |
{ RTOKEN(SUBALIGN);} |
YY_BREAK |
case 127: |
YY_RULE_SETUP |
#line 323 "ldlex.l" |
{ RTOKEN(HIDDEN); } |
YY_BREAK |
case 128: |
YY_RULE_SETUP |
#line 324 "ldlex.l" |
{ RTOKEN(PROVIDE); } |
YY_BREAK |
case 129: |
YY_RULE_SETUP |
#line 325 "ldlex.l" |
{ RTOKEN(PROVIDE_HIDDEN); } |
YY_BREAK |
case 130: |
YY_RULE_SETUP |
#line 326 "ldlex.l" |
{ RTOKEN(KEEP); } |
YY_BREAK |
case 131: |
YY_RULE_SETUP |
#line 327 "ldlex.l" |
{ RTOKEN(EXCLUDE_FILE); } |
YY_BREAK |
case 132: |
YY_RULE_SETUP |
#line 328 "ldlex.l" |
{ RTOKEN(CONSTANT);} |
YY_BREAK |
case 133: |
/* rule 133 can match eol */ |
YY_RULE_SETUP |
#line 329 "ldlex.l" |
{ ++ lineno; } |
YY_BREAK |
case 134: |
/* rule 134 can match eol */ |
YY_RULE_SETUP |
#line 330 "ldlex.l" |
{ ++ lineno; RTOKEN(NEWLINE); } |
YY_BREAK |
case 135: |
YY_RULE_SETUP |
#line 331 "ldlex.l" |
{ /* Mri comment line */ } |
YY_BREAK |
case 136: |
YY_RULE_SETUP |
#line 332 "ldlex.l" |
{ /* Mri comment line */ } |
YY_BREAK |
case 137: |
YY_RULE_SETUP |
#line 333 "ldlex.l" |
{ RTOKEN(ENDWORD); } |
YY_BREAK |
case 138: |
YY_RULE_SETUP |
#line 334 "ldlex.l" |
{ RTOKEN(ALIGNMOD);} |
YY_BREAK |
case 139: |
YY_RULE_SETUP |
#line 335 "ldlex.l" |
{ RTOKEN(ALIGN_K);} |
YY_BREAK |
case 140: |
YY_RULE_SETUP |
#line 336 "ldlex.l" |
{ RTOKEN(CHIP); } |
YY_BREAK |
case 141: |
YY_RULE_SETUP |
#line 337 "ldlex.l" |
{ RTOKEN(BASE); } |
YY_BREAK |
case 142: |
YY_RULE_SETUP |
#line 338 "ldlex.l" |
{ RTOKEN(ALIAS); } |
YY_BREAK |
case 143: |
YY_RULE_SETUP |
#line 339 "ldlex.l" |
{ RTOKEN(TRUNCATE); } |
YY_BREAK |
case 144: |
YY_RULE_SETUP |
#line 340 "ldlex.l" |
{ RTOKEN(LOAD); } |
YY_BREAK |
case 145: |
YY_RULE_SETUP |
#line 341 "ldlex.l" |
{ RTOKEN(PUBLIC); } |
YY_BREAK |
case 146: |
YY_RULE_SETUP |
#line 342 "ldlex.l" |
{ RTOKEN(ORDER); } |
YY_BREAK |
case 147: |
YY_RULE_SETUP |
#line 343 "ldlex.l" |
{ RTOKEN(NAMEWORD); } |
YY_BREAK |
case 148: |
YY_RULE_SETUP |
#line 344 "ldlex.l" |
{ RTOKEN(FORMAT); } |
YY_BREAK |
case 149: |
YY_RULE_SETUP |
#line 345 "ldlex.l" |
{ RTOKEN(CASE); } |
YY_BREAK |
case 150: |
YY_RULE_SETUP |
#line 346 "ldlex.l" |
{ RTOKEN(START); } |
YY_BREAK |
case 151: |
YY_RULE_SETUP |
#line 347 "ldlex.l" |
{ RTOKEN(LIST); /* LIST and ignore to end of line */ } |
YY_BREAK |
case 152: |
YY_RULE_SETUP |
#line 348 "ldlex.l" |
{ RTOKEN(SECT); } |
YY_BREAK |
case 153: |
YY_RULE_SETUP |
#line 349 "ldlex.l" |
{ RTOKEN(ABSOLUTE); } |
YY_BREAK |
case 154: |
YY_RULE_SETUP |
#line 350 "ldlex.l" |
{ RTOKEN(ENDWORD); } |
YY_BREAK |
case 155: |
YY_RULE_SETUP |
#line 351 "ldlex.l" |
{ RTOKEN(ALIGNMOD);} |
YY_BREAK |
case 156: |
YY_RULE_SETUP |
#line 352 "ldlex.l" |
{ RTOKEN(ALIGN_K);} |
YY_BREAK |
case 157: |
YY_RULE_SETUP |
#line 353 "ldlex.l" |
{ RTOKEN(CHIP); } |
YY_BREAK |
case 158: |
YY_RULE_SETUP |
#line 354 "ldlex.l" |
{ RTOKEN(BASE); } |
YY_BREAK |
case 159: |
YY_RULE_SETUP |
#line 355 "ldlex.l" |
{ RTOKEN(ALIAS); } |
YY_BREAK |
case 160: |
YY_RULE_SETUP |
#line 356 "ldlex.l" |
{ RTOKEN(TRUNCATE); } |
YY_BREAK |
case 161: |
YY_RULE_SETUP |
#line 357 "ldlex.l" |
{ RTOKEN(LOAD); } |
YY_BREAK |
case 162: |
YY_RULE_SETUP |
#line 358 "ldlex.l" |
{ RTOKEN(PUBLIC); } |
YY_BREAK |
case 163: |
YY_RULE_SETUP |
#line 359 "ldlex.l" |
{ RTOKEN(ORDER); } |
YY_BREAK |
case 164: |
YY_RULE_SETUP |
#line 360 "ldlex.l" |
{ RTOKEN(NAMEWORD); } |
YY_BREAK |
case 165: |
YY_RULE_SETUP |
#line 361 "ldlex.l" |
{ RTOKEN(FORMAT); } |
YY_BREAK |
case 166: |
YY_RULE_SETUP |
#line 362 "ldlex.l" |
{ RTOKEN(CASE); } |
YY_BREAK |
case 167: |
YY_RULE_SETUP |
#line 363 "ldlex.l" |
{ RTOKEN(EXTERN); } |
YY_BREAK |
case 168: |
YY_RULE_SETUP |
#line 364 "ldlex.l" |
{ RTOKEN(START); } |
YY_BREAK |
case 169: |
YY_RULE_SETUP |
#line 365 "ldlex.l" |
{ RTOKEN(LIST); /* LIST and ignore to end of line */ } |
YY_BREAK |
case 170: |
YY_RULE_SETUP |
#line 366 "ldlex.l" |
{ RTOKEN(SECT); } |
YY_BREAK |
case 171: |
YY_RULE_SETUP |
#line 367 "ldlex.l" |
{ RTOKEN(ABSOLUTE); } |
YY_BREAK |
case 172: |
YY_RULE_SETUP |
#line 369 "ldlex.l" |
{ |
/* Filename without commas, needed to parse mri stuff */ |
yylval.name = xstrdup (yytext); |
return NAME; |
} |
YY_BREAK |
case 173: |
YY_RULE_SETUP |
#line 376 "ldlex.l" |
{ |
yylval.name = xstrdup (yytext); |
return NAME; |
} |
YY_BREAK |
case 174: |
YY_RULE_SETUP |
#line 380 "ldlex.l" |
{ |
yylval.name = xstrdup (yytext + 2); |
return LNAME; |
} |
YY_BREAK |
case 175: |
YY_RULE_SETUP |
#line 384 "ldlex.l" |
{ |
yylval.name = xstrdup (yytext); |
return NAME; |
} |
YY_BREAK |
case 176: |
YY_RULE_SETUP |
#line 388 "ldlex.l" |
{ |
yylval.name = xstrdup (yytext + 2); |
return LNAME; |
} |
YY_BREAK |
case 177: |
YY_RULE_SETUP |
#line 392 "ldlex.l" |
{ |
/* Annoyingly, this pattern can match comments, and we have |
longest match issues to consider. So if the first two |
characters are a comment opening, put the input back and |
try again. */ |
if (yytext[0] == '/' && yytext[1] == '*') |
{ |
yyless (2); |
comment (); |
} |
else |
{ |
yylval.name = xstrdup (yytext); |
return NAME; |
} |
} |
YY_BREAK |
case 178: |
/* rule 178 can match eol */ |
YY_RULE_SETUP |
#line 409 "ldlex.l" |
{ |
/* No matter the state, quotes |
give what's inside */ |
yylval.name = xstrdup (yytext + 1); |
yylval.name[yyleng - 2] = 0; |
return NAME; |
} |
YY_BREAK |
case 179: |
/* rule 179 can match eol */ |
YY_RULE_SETUP |
#line 416 "ldlex.l" |
{ lineno++;} |
YY_BREAK |
case 180: |
YY_RULE_SETUP |
#line 417 "ldlex.l" |
{ } |
YY_BREAK |
case 181: |
YY_RULE_SETUP |
#line 419 "ldlex.l" |
{ return *yytext; } |
YY_BREAK |
case 182: |
YY_RULE_SETUP |
#line 421 "ldlex.l" |
{ RTOKEN(GLOBAL); } |
YY_BREAK |
case 183: |
YY_RULE_SETUP |
#line 423 "ldlex.l" |
{ RTOKEN(LOCAL); } |
YY_BREAK |
case 184: |
YY_RULE_SETUP |
#line 425 "ldlex.l" |
{ RTOKEN(EXTERN); } |
YY_BREAK |
case 185: |
YY_RULE_SETUP |
#line 427 "ldlex.l" |
{ yylval.name = xstrdup (yytext); |
return VERS_IDENTIFIER; } |
YY_BREAK |
case 186: |
YY_RULE_SETUP |
#line 430 "ldlex.l" |
{ yylval.name = xstrdup (yytext); |
return VERS_TAG; } |
YY_BREAK |
case 187: |
YY_RULE_SETUP |
#line 433 "ldlex.l" |
{ BEGIN(VERS_SCRIPT); return *yytext; } |
YY_BREAK |
case 188: |
YY_RULE_SETUP |
#line 435 "ldlex.l" |
{ BEGIN(VERS_NODE); |
vers_node_nesting = 0; |
return *yytext; |
} |
YY_BREAK |
case 189: |
YY_RULE_SETUP |
#line 439 "ldlex.l" |
{ return *yytext; } |
YY_BREAK |
case 190: |
YY_RULE_SETUP |
#line 440 "ldlex.l" |
{ vers_node_nesting++; return *yytext; } |
YY_BREAK |
case 191: |
YY_RULE_SETUP |
#line 441 "ldlex.l" |
{ if (--vers_node_nesting < 0) |
BEGIN(VERS_SCRIPT); |
return *yytext; |
} |
YY_BREAK |
case 192: |
/* rule 192 can match eol */ |
YY_RULE_SETUP |
#line 446 "ldlex.l" |
{ lineno++; } |
YY_BREAK |
case 193: |
YY_RULE_SETUP |
#line 448 "ldlex.l" |
{ /* Eat up comments */ } |
YY_BREAK |
case 194: |
YY_RULE_SETUP |
#line 450 "ldlex.l" |
{ /* Eat up whitespace */ } |
YY_BREAK |
case YY_STATE_EOF(INITIAL): |
case YY_STATE_EOF(SCRIPT): |
case YY_STATE_EOF(EXPRESSION): |
case YY_STATE_EOF(BOTH): |
case YY_STATE_EOF(DEFSYMEXP): |
case YY_STATE_EOF(MRI): |
case YY_STATE_EOF(VERS_START): |
case YY_STATE_EOF(VERS_SCRIPT): |
case YY_STATE_EOF(VERS_NODE): |
#line 452 "ldlex.l" |
{ |
include_stack_ptr--; |
if (include_stack_ptr == 0) |
yyterminate (); |
else |
yy_switch_to_buffer (include_stack[include_stack_ptr]); |
lineno = lineno_stack[include_stack_ptr]; |
input_flags.sysrooted = sysrooted_stack[include_stack_ptr]; |
return END; |
} |
YY_BREAK |
case 195: |
YY_RULE_SETUP |
#line 465 "ldlex.l" |
lex_warn_invalid (" in script", yytext); |
YY_BREAK |
case 196: |
YY_RULE_SETUP |
#line 466 "ldlex.l" |
lex_warn_invalid (" in expression", yytext); |
YY_BREAK |
case 197: |
YY_RULE_SETUP |
#line 468 "ldlex.l" |
ECHO; |
YY_BREAK |
#line 3149 "ldlex.c" |
case YY_END_OF_BUFFER: |
{ |
/* Amount of text matched not including the EOB char. */ |
int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; |
/* Undo the effects of YY_DO_BEFORE_ACTION. */ |
*yy_cp = (yy_hold_char); |
YY_RESTORE_YY_MORE_OFFSET |
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) |
{ |
/* We're scanning a new file or input source. It's |
* possible that this happened because the user |
* just pointed yyin at a new source and called |
* yylex(). If so, then we have to assure |
* consistency between YY_CURRENT_BUFFER and our |
* globals. Here is the right place to do so, because |
* this is the first action (other than possibly a |
* back-up) that will match for the new input source. |
*/ |
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; |
YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; |
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; |
} |
/* Note that here we test for yy_c_buf_p "<=" to the position |
* of the first EOB in the buffer, since yy_c_buf_p will |
* already have been incremented past the NUL character |
* (since all states make transitions on EOB to the |
* end-of-buffer state). Contrast this with the test |
* in input(). |
*/ |
if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) |
{ /* This was really a NUL. */ |
yy_state_type yy_next_state; |
(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; |
yy_current_state = yy_get_previous_state( ); |
/* Okay, we're now positioned to make the NUL |
* transition. We couldn't have |
* yy_get_previous_state() go ahead and do it |
* for us because it doesn't know how to deal |
* with the possibility of jamming (and we don't |
* want to build jamming into it because then it |
* will run more slowly). |
*/ |
yy_next_state = yy_try_NUL_trans( yy_current_state ); |
yy_bp = (yytext_ptr) + YY_MORE_ADJ; |
if ( yy_next_state ) |
{ |
/* Consume the NUL. */ |
yy_cp = ++(yy_c_buf_p); |
yy_current_state = yy_next_state; |
goto yy_match; |
} |
else |
{ |
yy_cp = (yy_c_buf_p); |
goto yy_find_action; |
} |
} |
else switch ( yy_get_next_buffer( ) ) |
{ |
case EOB_ACT_END_OF_FILE: |
{ |
(yy_did_buffer_switch_on_eof) = 0; |
if ( yywrap( ) ) |
{ |
/* Note: because we've taken care in |
* yy_get_next_buffer() to have set up |
* yytext, we can now set up |
* yy_c_buf_p so that if some total |
* hoser (like flex itself) wants to |
* call the scanner after we return the |
* YY_NULL, it'll still work - another |
* YY_NULL will get returned. |
*/ |
(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; |
yy_act = YY_STATE_EOF(YY_START); |
goto do_action; |
} |
else |
{ |
if ( ! (yy_did_buffer_switch_on_eof) ) |
YY_NEW_FILE; |
} |
break; |
} |
case EOB_ACT_CONTINUE_SCAN: |
(yy_c_buf_p) = |
(yytext_ptr) + yy_amount_of_matched_text; |
yy_current_state = yy_get_previous_state( ); |
yy_cp = (yy_c_buf_p); |
yy_bp = (yytext_ptr) + YY_MORE_ADJ; |
goto yy_match; |
case EOB_ACT_LAST_MATCH: |
(yy_c_buf_p) = |
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; |
yy_current_state = yy_get_previous_state( ); |
yy_cp = (yy_c_buf_p); |
yy_bp = (yytext_ptr) + YY_MORE_ADJ; |
goto yy_find_action; |
} |
break; |
} |
default: |
YY_FATAL_ERROR( |
"fatal flex scanner internal error--no action found" ); |
} /* end of action switch */ |
} /* end of scanning one token */ |
} /* end of yylex */ |
/* yy_get_next_buffer - try to read in a new buffer |
* |
* Returns a code representing an action: |
* EOB_ACT_LAST_MATCH - |
* EOB_ACT_CONTINUE_SCAN - continue scanning from current position |
* EOB_ACT_END_OF_FILE - end of file |
*/ |
static int yy_get_next_buffer (void) |
{ |
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; |
register char *source = (yytext_ptr); |
register int number_to_move, i; |
int ret_val; |
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) |
YY_FATAL_ERROR( |
"fatal flex scanner internal error--end of buffer missed" ); |
if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) |
{ /* Don't try to fill the buffer, so this is an EOF. */ |
if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) |
{ |
/* We matched a single character, the EOB, so |
* treat this as a final EOF. |
*/ |
return EOB_ACT_END_OF_FILE; |
} |
else |
{ |
/* We matched some text prior to the EOB, first |
* process it. |
*/ |
return EOB_ACT_LAST_MATCH; |
} |
} |
/* Try to read more data. */ |
/* First move last chars to start of buffer. */ |
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; |
for ( i = 0; i < number_to_move; ++i ) |
*(dest++) = *(source++); |
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) |
/* don't do the read, it's not guaranteed to return an EOF, |
* just force an EOF |
*/ |
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; |
else |
{ |
yy_size_t num_to_read = |
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; |
while ( num_to_read <= 0 ) |
{ /* Not enough room in the buffer - grow it. */ |
/* just a shorter name for the current buffer */ |
YY_BUFFER_STATE b = YY_CURRENT_BUFFER; |
int yy_c_buf_p_offset = |
(int) ((yy_c_buf_p) - b->yy_ch_buf); |
if ( b->yy_is_our_buffer ) |
{ |
yy_size_t new_size = b->yy_buf_size * 2; |
if ( new_size <= 0 ) |
b->yy_buf_size += b->yy_buf_size / 8; |
else |
b->yy_buf_size *= 2; |
b->yy_ch_buf = (char *) |
/* Include room in for 2 EOB chars. */ |
yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); |
} |
else |
/* Can't grow it, we don't own it. */ |
b->yy_ch_buf = 0; |
if ( ! b->yy_ch_buf ) |
YY_FATAL_ERROR( |
"fatal error - scanner input buffer overflow" ); |
(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; |
num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - |
number_to_move - 1; |
} |
if ( num_to_read > YY_READ_BUF_SIZE ) |
num_to_read = YY_READ_BUF_SIZE; |
/* Read in more data. */ |
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), |
(yy_n_chars), num_to_read ); |
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); |
} |
if ( (yy_n_chars) == 0 ) |
{ |
if ( number_to_move == YY_MORE_ADJ ) |
{ |
ret_val = EOB_ACT_END_OF_FILE; |
yyrestart(yyin ); |
} |
else |
{ |
ret_val = EOB_ACT_LAST_MATCH; |
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = |
YY_BUFFER_EOF_PENDING; |
} |
} |
else |
ret_val = EOB_ACT_CONTINUE_SCAN; |
if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { |
/* Extend the array by 50%, plus the number we really need. */ |
yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); |
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); |
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) |
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); |
} |
(yy_n_chars) += number_to_move; |
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; |
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; |
(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; |
return ret_val; |
} |
/* yy_get_previous_state - get the state just before the EOB char was reached */ |
static yy_state_type yy_get_previous_state (void) |
{ |
register yy_state_type yy_current_state; |
register char *yy_cp; |
yy_current_state = (yy_start); |
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) |
{ |
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); |
if ( yy_accept[yy_current_state] ) |
{ |
(yy_last_accepting_state) = yy_current_state; |
(yy_last_accepting_cpos) = yy_cp; |
} |
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) |
{ |
yy_current_state = (int) yy_def[yy_current_state]; |
if ( yy_current_state >= 1751 ) |
yy_c = yy_meta[(unsigned int) yy_c]; |
} |
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; |
} |
return yy_current_state; |
} |
/* yy_try_NUL_trans - try to make a transition on the NUL character |
* |
* synopsis |
* next_state = yy_try_NUL_trans( current_state ); |
*/ |
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) |
{ |
register int yy_is_jam; |
register char *yy_cp = (yy_c_buf_p); |
register YY_CHAR yy_c = 1; |
if ( yy_accept[yy_current_state] ) |
{ |
(yy_last_accepting_state) = yy_current_state; |
(yy_last_accepting_cpos) = yy_cp; |
} |
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) |
{ |
yy_current_state = (int) yy_def[yy_current_state]; |
if ( yy_current_state >= 1751 ) |
yy_c = yy_meta[(unsigned int) yy_c]; |
} |
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; |
yy_is_jam = (yy_current_state == 1750); |
return yy_is_jam ? 0 : yy_current_state; |
} |
#ifndef YY_NO_INPUT |
#ifdef __cplusplus |
static int yyinput (void) |
#else |
static int input (void) |
#endif |
{ |
int c; |
*(yy_c_buf_p) = (yy_hold_char); |
if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) |
{ |
/* yy_c_buf_p now points to the character we want to return. |
* If this occurs *before* the EOB characters, then it's a |
* valid NUL; if not, then we've hit the end of the buffer. |
*/ |
if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) |
/* This was really a NUL. */ |
*(yy_c_buf_p) = '\0'; |
else |
{ /* need more input */ |
yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); |
++(yy_c_buf_p); |
switch ( yy_get_next_buffer( ) ) |
{ |
case EOB_ACT_LAST_MATCH: |
/* This happens because yy_g_n_b() |
* sees that we've accumulated a |
* token and flags that we need to |
* try matching the token before |
* proceeding. But for input(), |
* there's no matching to consider. |
* So convert the EOB_ACT_LAST_MATCH |
* to EOB_ACT_END_OF_FILE. |
*/ |
/* Reset buffer status. */ |
yyrestart(yyin ); |
/*FALLTHROUGH*/ |
case EOB_ACT_END_OF_FILE: |
{ |
if ( yywrap( ) ) |
return 0; |
if ( ! (yy_did_buffer_switch_on_eof) ) |
YY_NEW_FILE; |
#ifdef __cplusplus |
return yyinput(); |
#else |
return input(); |
#endif |
} |
case EOB_ACT_CONTINUE_SCAN: |
(yy_c_buf_p) = (yytext_ptr) + offset; |
break; |
} |
} |
} |
c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ |
*(yy_c_buf_p) = '\0'; /* preserve yytext */ |
(yy_hold_char) = *++(yy_c_buf_p); |
return c; |
} |
#endif /* ifndef YY_NO_INPUT */ |
/** Immediately switch to a different input stream. |
* @param input_file A readable stream. |
* |
* @note This function does not reset the start condition to @c INITIAL . |
*/ |
void yyrestart (FILE * input_file ) |
{ |
if ( ! YY_CURRENT_BUFFER ){ |
yyensure_buffer_stack (); |
YY_CURRENT_BUFFER_LVALUE = |
yy_create_buffer(yyin,YY_BUF_SIZE ); |
} |
yy_init_buffer(YY_CURRENT_BUFFER,input_file ); |
yy_load_buffer_state( ); |
} |
/** Switch to a different input buffer. |
* @param new_buffer The new input buffer. |
* |
*/ |
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) |
{ |
/* TODO. We should be able to replace this entire function body |
* with |
* yypop_buffer_state(); |
* yypush_buffer_state(new_buffer); |
*/ |
yyensure_buffer_stack (); |
if ( YY_CURRENT_BUFFER == new_buffer ) |
return; |
if ( YY_CURRENT_BUFFER ) |
{ |
/* Flush out information for old buffer. */ |
*(yy_c_buf_p) = (yy_hold_char); |
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); |
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); |
} |
YY_CURRENT_BUFFER_LVALUE = new_buffer; |
yy_load_buffer_state( ); |
/* We don't actually know whether we did this switch during |
* EOF (yywrap()) processing, but the only time this flag |
* is looked at is after yywrap() is called, so it's safe |
* to go ahead and always set it. |
*/ |
(yy_did_buffer_switch_on_eof) = 1; |
} |
static void yy_load_buffer_state (void) |
{ |
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; |
(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; |
yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; |
(yy_hold_char) = *(yy_c_buf_p); |
} |
/** Allocate and initialize an input buffer state. |
* @param file A readable stream. |
* @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. |
* |
* @return the allocated buffer state. |
*/ |
YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) |
{ |
YY_BUFFER_STATE b; |
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); |
if ( ! b ) |
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); |
b->yy_buf_size = size; |
/* yy_ch_buf has to be 2 characters longer than the size given because |
* we need to put in 2 end-of-buffer characters. |
*/ |
b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); |
if ( ! b->yy_ch_buf ) |
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); |
b->yy_is_our_buffer = 1; |
yy_init_buffer(b,file ); |
return b; |
} |
/** Destroy the buffer. |
* @param b a buffer created with yy_create_buffer() |
* |
*/ |
void yy_delete_buffer (YY_BUFFER_STATE b ) |
{ |
if ( ! b ) |
return; |
if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ |
YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; |
if ( b->yy_is_our_buffer ) |
yyfree((void *) b->yy_ch_buf ); |
yyfree((void *) b ); |
} |
#ifndef __cplusplus |
extern int isatty (int ); |
#endif /* __cplusplus */ |
/* Initializes or reinitializes a buffer. |
* This function is sometimes called more than once on the same buffer, |
* such as during a yyrestart() or at EOF. |
*/ |
static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) |
{ |
int oerrno = errno; |
yy_flush_buffer(b ); |
b->yy_input_file = file; |
b->yy_fill_buffer = 1; |
/* If b is the current buffer, then yy_init_buffer was _probably_ |
* called from yyrestart() or through yy_get_next_buffer. |
* In that case, we don't want to reset the lineno or column. |
*/ |
if (b != YY_CURRENT_BUFFER){ |
b->yy_bs_lineno = 1; |
b->yy_bs_column = 0; |
} |
b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; |
errno = oerrno; |
} |
/** Discard all buffered characters. On the next scan, YY_INPUT will be called. |
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. |
* |
*/ |
void yy_flush_buffer (YY_BUFFER_STATE b ) |
{ |
if ( ! b ) |
return; |
b->yy_n_chars = 0; |
/* We always need two end-of-buffer characters. The first causes |
* a transition to the end-of-buffer state. The second causes |
* a jam in that state. |
*/ |
b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; |
b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; |
b->yy_buf_pos = &b->yy_ch_buf[0]; |
b->yy_at_bol = 1; |
b->yy_buffer_status = YY_BUFFER_NEW; |
if ( b == YY_CURRENT_BUFFER ) |
yy_load_buffer_state( ); |
} |
/** Pushes the new state onto the stack. The new state becomes |
* the current state. This function will allocate the stack |
* if necessary. |
* @param new_buffer The new state. |
* |
*/ |
void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) |
{ |
if (new_buffer == NULL) |
return; |
yyensure_buffer_stack(); |
/* This block is copied from yy_switch_to_buffer. */ |
if ( YY_CURRENT_BUFFER ) |
{ |
/* Flush out information for old buffer. */ |
*(yy_c_buf_p) = (yy_hold_char); |
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); |
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); |
} |
/* Only push if top exists. Otherwise, replace top. */ |
if (YY_CURRENT_BUFFER) |
(yy_buffer_stack_top)++; |
YY_CURRENT_BUFFER_LVALUE = new_buffer; |
/* copied from yy_switch_to_buffer. */ |
yy_load_buffer_state( ); |
(yy_did_buffer_switch_on_eof) = 1; |
} |
/** Removes and deletes the top of the stack, if present. |
* The next element becomes the new top. |
* |
*/ |
void yypop_buffer_state (void) |
{ |
if (!YY_CURRENT_BUFFER) |
return; |
yy_delete_buffer(YY_CURRENT_BUFFER ); |
YY_CURRENT_BUFFER_LVALUE = NULL; |
if ((yy_buffer_stack_top) > 0) |
--(yy_buffer_stack_top); |
if (YY_CURRENT_BUFFER) { |
yy_load_buffer_state( ); |
(yy_did_buffer_switch_on_eof) = 1; |
} |
} |
/* Allocates the stack if it does not exist. |
* Guarantees space for at least one push. |
*/ |
static void yyensure_buffer_stack (void) |
{ |
yy_size_t num_to_alloc; |
if (!(yy_buffer_stack)) { |
/* First allocation is just for 2 elements, since we don't know if this |
* scanner will even need a stack. We use 2 instead of 1 to avoid an |
* immediate realloc on the next call. |
*/ |
num_to_alloc = 1; |
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc |
(num_to_alloc * sizeof(struct yy_buffer_state*) |
); |
if ( ! (yy_buffer_stack) ) |
YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); |
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); |
(yy_buffer_stack_max) = num_to_alloc; |
(yy_buffer_stack_top) = 0; |
return; |
} |
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ |
/* Increase the buffer to prepare for a possible push. */ |
int grow_size = 8 /* arbitrary grow size */; |
num_to_alloc = (yy_buffer_stack_max) + grow_size; |
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc |
((yy_buffer_stack), |
num_to_alloc * sizeof(struct yy_buffer_state*) |
); |
if ( ! (yy_buffer_stack) ) |
YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); |
/* zero only the new slots.*/ |
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); |
(yy_buffer_stack_max) = num_to_alloc; |
} |
} |
/** Setup the input buffer state to scan directly from a user-specified character buffer. |
* @param base the character buffer |
* @param size the size in bytes of the character buffer |
* |
* @return the newly allocated buffer state object. |
*/ |
YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) |
{ |
YY_BUFFER_STATE b; |
if ( size < 2 || |
base[size-2] != YY_END_OF_BUFFER_CHAR || |
base[size-1] != YY_END_OF_BUFFER_CHAR ) |
/* They forgot to leave room for the EOB's. */ |
return 0; |
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); |
if ( ! b ) |
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); |
b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ |
b->yy_buf_pos = b->yy_ch_buf = base; |
b->yy_is_our_buffer = 0; |
b->yy_input_file = 0; |
b->yy_n_chars = b->yy_buf_size; |
b->yy_is_interactive = 0; |
b->yy_at_bol = 1; |
b->yy_fill_buffer = 0; |
b->yy_buffer_status = YY_BUFFER_NEW; |
yy_switch_to_buffer(b ); |
return b; |
} |
/** Setup the input buffer state to scan a string. The next call to yylex() will |
* scan from a @e copy of @a str. |
* @param yystr a NUL-terminated string to scan |
* |
* @return the newly allocated buffer state object. |
* @note If you want to scan bytes that may contain NUL values, then use |
* yy_scan_bytes() instead. |
*/ |
YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) |
{ |
return yy_scan_bytes(yystr,strlen(yystr) ); |
} |
/** Setup the input buffer state to scan the given bytes. The next call to yylex() will |
* scan from a @e copy of @a bytes. |
* @param bytes the byte buffer to scan |
* @param len the number of bytes in the buffer pointed to by @a bytes. |
* |
* @return the newly allocated buffer state object. |
*/ |
YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) |
{ |
YY_BUFFER_STATE b; |
char *buf; |
yy_size_t n, i; |
/* Get memory for full buffer, including space for trailing EOB's. */ |
n = _yybytes_len + 2; |
buf = (char *) yyalloc(n ); |
if ( ! buf ) |
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); |
for ( i = 0; i < _yybytes_len; ++i ) |
buf[i] = yybytes[i]; |
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; |
b = yy_scan_buffer(buf,n ); |
if ( ! b ) |
YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); |
/* It's okay to grow etc. this buffer, and we should throw it |
* away when we're done. |
*/ |
b->yy_is_our_buffer = 1; |
return b; |
} |
#ifndef YY_EXIT_FAILURE |
#define YY_EXIT_FAILURE 2 |
#endif |
static void yy_fatal_error (yyconst char* msg ) |
{ |
(void) fprintf( stderr, "%s\n", msg ); |
exit( YY_EXIT_FAILURE ); |
} |
/* Redefine yyless() so it works in section 3 code. */ |
#undef yyless |
#define yyless(n) \ |
do \ |
{ \ |
/* Undo effects of setting up yytext. */ \ |
int yyless_macro_arg = (n); \ |
YY_LESS_LINENO(yyless_macro_arg);\ |
yytext[yyleng] = (yy_hold_char); \ |
(yy_c_buf_p) = yytext + yyless_macro_arg; \ |
(yy_hold_char) = *(yy_c_buf_p); \ |
*(yy_c_buf_p) = '\0'; \ |
yyleng = yyless_macro_arg; \ |
} \ |
while ( 0 ) |
/* Accessor methods (get/set functions) to struct members. */ |
/** Get the current line number. |
* |
*/ |
int yyget_lineno (void) |
{ |
return yylineno; |
} |
/** Get the input stream. |
* |
*/ |
FILE *yyget_in (void) |
{ |
return yyin; |
} |
/** Get the output stream. |
* |
*/ |
FILE *yyget_out (void) |
{ |
return yyout; |
} |
/** Get the length of the current token. |
* |
*/ |
yy_size_t yyget_leng (void) |
{ |
return yyleng; |
} |
/** Get the current token. |
* |
*/ |
char *yyget_text (void) |
{ |
return yytext; |
} |
/** Set the current line number. |
* @param line_number |
* |
*/ |
void yyset_lineno (int line_number ) |
{ |
yylineno = line_number; |
} |
/** Set the input stream. This does not discard the current |
* input buffer. |
* @param in_str A readable stream. |
* |
* @see yy_switch_to_buffer |
*/ |
void yyset_in (FILE * in_str ) |
{ |
yyin = in_str ; |
} |
void yyset_out (FILE * out_str ) |
{ |
yyout = out_str ; |
} |
int yyget_debug (void) |
{ |
return yy_flex_debug; |
} |
void yyset_debug (int bdebug ) |
{ |
yy_flex_debug = bdebug ; |
} |
static int yy_init_globals (void) |
{ |
/* Initialization is the same as for the non-reentrant scanner. |
* This function is called from yylex_destroy(), so don't allocate here. |
*/ |
(yy_buffer_stack) = 0; |
(yy_buffer_stack_top) = 0; |
(yy_buffer_stack_max) = 0; |
(yy_c_buf_p) = (char *) 0; |
(yy_init) = 0; |
(yy_start) = 0; |
/* Defined in main.c */ |
#ifdef YY_STDINIT |
yyin = stdin; |
yyout = stdout; |
#else |
yyin = (FILE *) 0; |
yyout = (FILE *) 0; |
#endif |
/* For future reference: Set errno on error, since we are called by |
* yylex_init() |
*/ |
return 0; |
} |
/* yylex_destroy is for both reentrant and non-reentrant scanners. */ |
int yylex_destroy (void) |
{ |
/* Pop the buffer stack, destroying each element. */ |
while(YY_CURRENT_BUFFER){ |
yy_delete_buffer(YY_CURRENT_BUFFER ); |
YY_CURRENT_BUFFER_LVALUE = NULL; |
yypop_buffer_state(); |
} |
/* Destroy the stack itself. */ |
yyfree((yy_buffer_stack) ); |
(yy_buffer_stack) = NULL; |
/* Reset the globals. This is important in a non-reentrant scanner so the next time |
* yylex() is called, initialization will occur. */ |
yy_init_globals( ); |
return 0; |
} |
/* |
* Internal utility routines. |
*/ |
#ifndef yytext_ptr |
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) |
{ |
register int i; |
for ( i = 0; i < n; ++i ) |
s1[i] = s2[i]; |
} |
#endif |
#ifdef YY_NEED_STRLEN |
static int yy_flex_strlen (yyconst char * s ) |
{ |
register int n; |
for ( n = 0; s[n]; ++n ) |
; |
return n; |
} |
#endif |
void *yyalloc (yy_size_t size ) |
{ |
return (void *) malloc( size ); |
} |
void *yyrealloc (void * ptr, yy_size_t size ) |
{ |
/* The cast to (char *) in the following accommodates both |
* implementations that use char* generic pointers, and those |
* that use void* generic pointers. It works with the latter |
* because both ANSI C and C++ allow castless assignment from |
* any pointer type to void*, and deal with argument conversions |
* as though doing an assignment. |
*/ |
return (void *) realloc( (char *) ptr, size ); |
} |
void yyfree (void * ptr ) |
{ |
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ |
} |
#define YYTABLES_NAME "yytables" |
#line 468 "ldlex.l" |
/* Switch flex to reading script file NAME, open on FILE, |
saving the current input info on the include stack. */ |
void |
lex_push_file (FILE *file, const char *name, unsigned int sysrooted) |
{ |
if (include_stack_ptr >= MAX_INCLUDE_DEPTH) |
{ |
einfo ("%F:includes nested too deeply\n"); |
} |
file_name_stack[include_stack_ptr] = name; |
lineno_stack[include_stack_ptr] = lineno; |
sysrooted_stack[include_stack_ptr] = input_flags.sysrooted; |
include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; |
include_stack_ptr++; |
lineno = 1; |
input_flags.sysrooted = sysrooted; |
yyin = file; |
yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE)); |
} |
/* Return a newly created flex input buffer containing STRING, |
which is SIZE bytes long. */ |
static YY_BUFFER_STATE |
yy_create_string_buffer (const char *string, size_t size) |
{ |
YY_BUFFER_STATE b; |
/* Calls to m-alloc get turned by sed into xm-alloc. */ |
b = malloc (sizeof (struct yy_buffer_state)); |
b->yy_input_file = 0; |
b->yy_buf_size = size; |
/* yy_ch_buf has to be 2 characters longer than the size given because |
we need to put in 2 end-of-buffer characters. */ |
b->yy_ch_buf = malloc ((unsigned) (b->yy_buf_size + 3)); |
b->yy_ch_buf[0] = '\n'; |
strcpy (b->yy_ch_buf+1, string); |
b->yy_ch_buf[size+1] = YY_END_OF_BUFFER_CHAR; |
b->yy_ch_buf[size+2] = YY_END_OF_BUFFER_CHAR; |
b->yy_n_chars = size+1; |
b->yy_buf_pos = &b->yy_ch_buf[1]; |
b->yy_is_our_buffer = 1; |
b->yy_is_interactive = 0; |
b->yy_at_bol = 1; |
b->yy_fill_buffer = 0; |
/* flex 2.4.7 changed the interface. FIXME: We should not be using |
a flex internal interface in the first place! */ |
#ifdef YY_BUFFER_NEW |
b->yy_buffer_status = YY_BUFFER_NEW; |
#else |
b->yy_eof_status = EOF_NOT_SEEN; |
#endif |
return b; |
} |
/* Switch flex to reading from STRING, saving the current input info |
on the include stack. */ |
void |
lex_redirect (const char *string, const char *fake_filename, unsigned int count) |
{ |
YY_BUFFER_STATE tmp; |
yy_init = 0; |
if (include_stack_ptr >= MAX_INCLUDE_DEPTH) |
{ |
einfo("%F: macros nested too deeply\n"); |
} |
file_name_stack[include_stack_ptr] = fake_filename; |
lineno_stack[include_stack_ptr] = lineno; |
include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; |
include_stack_ptr++; |
lineno = count; |
tmp = yy_create_string_buffer (string, strlen (string)); |
yy_switch_to_buffer (tmp); |
} |
/* Functions to switch to a different flex start condition, |
saving the current start condition on `state_stack'. */ |
static int state_stack[MAX_INCLUDE_DEPTH * 2]; |
static int *state_stack_p = state_stack; |
void |
ldlex_script (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (SCRIPT); |
} |
void |
ldlex_mri_script (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (MRI); |
} |
void |
ldlex_version_script (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (VERS_START); |
} |
void |
ldlex_version_file (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (VERS_SCRIPT); |
} |
void |
ldlex_defsym (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (DEFSYMEXP); |
} |
void |
ldlex_expression (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (EXPRESSION); |
} |
void |
ldlex_both (void) |
{ |
*(state_stack_p)++ = yy_start; |
BEGIN (BOTH); |
} |
void |
ldlex_popstate (void) |
{ |
yy_start = *(--state_stack_p); |
} |
/* Return the current file name, or the previous file if no file is |
current. */ |
const char* |
ldlex_filename (void) |
{ |
return file_name_stack[include_stack_ptr - (include_stack_ptr != 0)]; |
} |
/* Place up to MAX_SIZE characters in BUF and return |
either the number of characters read, or 0 to indicate EOF. */ |
static int |
yy_input (char *buf, int max_size) |
{ |
int result = 0; |
if (YY_CURRENT_BUFFER->yy_input_file) |
{ |
if (yyin) |
{ |
result = fread (buf, 1, max_size, yyin); |
// if (result < max_size && ferror (yyin)) |
// einfo ("%F%P: read in flex scanner failed\n"); |
} |
} |
return result; |
} |
/* Eat the rest of a C-style comment. */ |
static void |
comment (void) |
{ |
int c; |
while (1) |
{ |
c = input(); |
while (c != '*' && c != EOF) |
{ |
if (c == '\n') |
lineno++; |
c = input(); |
} |
if (c == '*') |
{ |
c = input(); |
while (c == '*') |
c = input(); |
if (c == '/') |
break; /* found the end */ |
} |
if (c == '\n') |
lineno++; |
if (c == EOF) |
{ |
einfo( "%F%P: EOF in comment\n"); |
break; |
} |
} |
} |
/* Warn the user about a garbage character WHAT in the input |
in context WHERE. */ |
static void |
lex_warn_invalid (char *where, char *what) |
{ |
char buf[5]; |
/* If we have found an input file whose format we do not recognize, |
and we are therefore treating it as a linker script, and we find |
an invalid character, then most likely this is a real object file |
of some different format. Treat it as such. */ |
if (ldfile_assumed_script) |
{ |
bfd_set_error (bfd_error_file_not_recognized); |
einfo ("%F%s: file not recognized: %E\n", ldlex_filename ()); |
} |
if (! ISPRINT (*what)) |
{ |
sprintf (buf, "\\%03o", *(unsigned char *) what); |
what = buf; |
} |
einfo ("%P:%S: ignoring invalid character `%s'%s\n", NULL, what, where); |
} |
/contrib/toolchain/binutils/ld/ldlex.h |
---|
0,0 → 1,181 |
/* ldlex.h - |
Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2000, 2003, 2005, 2006, |
2007, 2012 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDLEX_H |
#define LDLEX_H |
#include <stdio.h> |
/* Codes used for the long options with no short synonyms. 150 isn't |
special; it's just an arbitrary non-ASCII char value. */ |
enum option_values |
{ |
OPTION_ASSERT = 150, |
OPTION_CALL_SHARED, |
OPTION_CREF, |
OPTION_DEFSYM, |
OPTION_DEMANGLE, |
OPTION_DYNAMIC_LINKER, |
OPTION_SYSROOT, |
OPTION_EB, |
OPTION_EL, |
OPTION_EMBEDDED_RELOCS, |
OPTION_EXPORT_DYNAMIC, |
OPTION_NO_EXPORT_DYNAMIC, |
OPTION_HELP, |
OPTION_IGNORE, |
OPTION_MAP, |
OPTION_NO_DEMANGLE, |
OPTION_NO_KEEP_MEMORY, |
OPTION_NO_WARN_MISMATCH, |
OPTION_NO_WARN_SEARCH_MISMATCH, |
OPTION_NOINHIBIT_EXEC, |
OPTION_NON_SHARED, |
OPTION_NO_WHOLE_ARCHIVE, |
OPTION_OFORMAT, |
OPTION_RELAX, |
OPTION_NO_RELAX, |
OPTION_RETAIN_SYMBOLS_FILE, |
OPTION_RPATH, |
OPTION_RPATH_LINK, |
OPTION_SHARED, |
OPTION_SONAME, |
OPTION_SORT_COMMON, |
OPTION_SORT_SECTION, |
OPTION_STATS, |
OPTION_SYMBOLIC, |
OPTION_SYMBOLIC_FUNCTIONS, |
OPTION_TASK_LINK, |
OPTION_TBSS, |
OPTION_TDATA, |
OPTION_TTEXT, |
OPTION_TTEXT_SEGMENT, |
OPTION_TRODATA_SEGMENT, |
OPTION_TLDATA_SEGMENT, |
OPTION_TRADITIONAL_FORMAT, |
OPTION_UR, |
OPTION_VERBOSE, |
OPTION_VERSION, |
OPTION_VERSION_SCRIPT, |
OPTION_VERSION_EXPORTS_SECTION, |
OPTION_DYNAMIC_LIST, |
OPTION_DYNAMIC_LIST_CPP_NEW, |
OPTION_DYNAMIC_LIST_CPP_TYPEINFO, |
OPTION_DYNAMIC_LIST_DATA, |
OPTION_WARN_COMMON, |
OPTION_WARN_CONSTRUCTORS, |
OPTION_WARN_FATAL, |
OPTION_NO_WARN_FATAL, |
OPTION_WARN_MULTIPLE_GP, |
OPTION_WARN_ONCE, |
OPTION_WARN_SECTION_ALIGN, |
OPTION_SPLIT_BY_RELOC, |
OPTION_SPLIT_BY_FILE , |
OPTION_WHOLE_ARCHIVE, |
OPTION_ADD_DT_NEEDED_FOR_DYNAMIC, |
OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC, |
OPTION_ADD_DT_NEEDED_FOR_REGULAR, |
OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR, |
OPTION_WRAP, |
OPTION_FORCE_EXE_SUFFIX, |
OPTION_GC_SECTIONS, |
OPTION_NO_GC_SECTIONS, |
OPTION_PRINT_GC_SECTIONS, |
OPTION_NO_PRINT_GC_SECTIONS, |
OPTION_HASH_SIZE, |
OPTION_CHECK_SECTIONS, |
OPTION_NO_CHECK_SECTIONS, |
OPTION_NO_UNDEFINED, |
OPTION_INIT, |
OPTION_FINI, |
OPTION_SECTION_START, |
OPTION_UNIQUE, |
OPTION_TARGET_HELP, |
OPTION_ALLOW_SHLIB_UNDEFINED, |
OPTION_NO_ALLOW_SHLIB_UNDEFINED, |
OPTION_ALLOW_MULTIPLE_DEFINITION, |
OPTION_NO_UNDEFINED_VERSION, |
OPTION_DEFAULT_SYMVER, |
OPTION_DEFAULT_IMPORTED_SYMVER, |
OPTION_DISCARD_NONE, |
OPTION_SPARE_DYNAMIC_TAGS, |
OPTION_NO_DEFINE_COMMON, |
OPTION_NOSTDLIB, |
OPTION_NO_OMAGIC, |
OPTION_STRIP_DISCARDED, |
OPTION_NO_STRIP_DISCARDED, |
OPTION_ACCEPT_UNKNOWN_INPUT_ARCH, |
OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH, |
OPTION_PIE, |
OPTION_UNRESOLVED_SYMBOLS, |
OPTION_WARN_UNRESOLVED_SYMBOLS, |
OPTION_ERROR_UNRESOLVED_SYMBOLS, |
OPTION_WARN_SHARED_TEXTREL, |
OPTION_WARN_ALTERNATE_EM, |
OPTION_REDUCE_MEMORY_OVERHEADS, |
#ifdef ENABLE_PLUGINS |
OPTION_PLUGIN, |
OPTION_PLUGIN_OPT, |
#endif /* ENABLE_PLUGINS */ |
OPTION_DEFAULT_SCRIPT, |
OPTION_PRINT_OUTPUT_FORMAT, |
OPTION_IGNORE_UNRESOLVED_SYMBOL, |
}; |
/* The initial parser states. */ |
typedef enum input_enum { |
input_selected, /* We've set the initial state. */ |
input_script, |
input_mri_script, |
input_version_script, |
input_dynamic_list, |
input_defsym |
} input_type; |
extern input_type parser_input; |
extern unsigned int lineno; |
extern const char *lex_string; |
/* In ldlex.l. */ |
extern int yylex (void); |
extern void lex_push_file (FILE *, const char *, unsigned int); |
extern void lex_redirect (const char *, const char *, unsigned int); |
extern void ldlex_script (void); |
extern void ldlex_mri_script (void); |
extern void ldlex_version_script (void); |
extern void ldlex_version_file (void); |
extern void ldlex_defsym (void); |
extern void ldlex_expression (void); |
extern void ldlex_both (void); |
extern void ldlex_command (void); |
extern void ldlex_popstate (void); |
extern const char* ldlex_filename (void); |
/* In lexsup.c. */ |
extern int lex_input (void); |
extern void lex_unput (int); |
#ifndef yywrap |
extern int yywrap (void); |
#endif |
extern void parse_args (unsigned, char **); |
#endif |
/contrib/toolchain/binutils/ld/ldmain.c |
---|
0,0 → 1,1480 |
/* Main program of GNU linker. |
Copyright 1991-2013 Free Software Foundation, Inc. |
Written by Steve Chamberlain steve@cygnus.com |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "safe-ctype.h" |
#include "libiberty.h" |
#include "progress.h" |
#include "bfdlink.h" |
#include "filenames.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldmisc.h" |
#include "ldwrite.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "ldctor.h" |
#ifdef ENABLE_PLUGINS |
#include "plugin.h" |
#include "plugin-api.h" |
#include "libbfd.h" |
#endif /* ENABLE_PLUGINS */ |
/* Somewhere above, sys/stat.h got included. */ |
#if !defined(S_ISDIR) && defined(S_IFDIR) |
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
#endif |
#include <string.h> |
#ifdef HAVE_SBRK |
#if !HAVE_DECL_SBRK |
extern void *sbrk (); |
#endif |
#endif |
#ifndef TARGET_SYSTEM_ROOT |
#define TARGET_SYSTEM_ROOT "" |
#endif |
/* EXPORTS */ |
FILE *saved_script_handle = NULL; |
FILE *previous_script_handle = NULL; |
bfd_boolean force_make_executable = FALSE; |
char *default_target; |
const char *output_filename = "a.out"; |
/* Name this program was invoked by. */ |
char *program_name; |
/* The prefix for system library directories. */ |
const char *ld_sysroot; |
/* The canonical representation of ld_sysroot. */ |
char * ld_canon_sysroot; |
int ld_canon_sysroot_len; |
/* Set by -G argument, for targets like MIPS ELF. */ |
int g_switch_value = 8; |
/* Nonzero means print names of input files as processed. */ |
bfd_boolean trace_files; |
/* Nonzero means report actions taken by the linker, and describe the linker script in use. */ |
bfd_boolean verbose; |
/* Nonzero means version number was printed, so exit successfully |
instead of complaining if no input files are given. */ |
bfd_boolean version_printed; |
/* TRUE if we should demangle symbol names. */ |
bfd_boolean demangling; |
args_type command_line; |
ld_config_type config; |
sort_type sort_section; |
static const char *get_sysroot |
(int, char **); |
static char *get_emulation |
(int, char **); |
static bfd_boolean add_archive_element |
(struct bfd_link_info *, bfd *, const char *, bfd **); |
static bfd_boolean multiple_definition |
(struct bfd_link_info *, struct bfd_link_hash_entry *, |
bfd *, asection *, bfd_vma); |
static bfd_boolean multiple_common |
(struct bfd_link_info *, struct bfd_link_hash_entry *, |
bfd *, enum bfd_link_hash_type, bfd_vma); |
static bfd_boolean add_to_set |
(struct bfd_link_info *, struct bfd_link_hash_entry *, |
bfd_reloc_code_real_type, bfd *, asection *, bfd_vma); |
static bfd_boolean constructor_callback |
(struct bfd_link_info *, bfd_boolean, const char *, bfd *, |
asection *, bfd_vma); |
static bfd_boolean warning_callback |
(struct bfd_link_info *, const char *, const char *, bfd *, |
asection *, bfd_vma); |
static void warning_find_reloc |
(bfd *, asection *, void *); |
static bfd_boolean undefined_symbol |
(struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma, |
bfd_boolean); |
static bfd_boolean reloc_overflow |
(struct bfd_link_info *, struct bfd_link_hash_entry *, const char *, |
const char *, bfd_vma, bfd *, asection *, bfd_vma); |
static bfd_boolean reloc_dangerous |
(struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma); |
static bfd_boolean unattached_reloc |
(struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma); |
static bfd_boolean notice |
(struct bfd_link_info *, struct bfd_link_hash_entry *, |
bfd *, asection *, bfd_vma, flagword, const char *); |
static struct bfd_link_callbacks link_callbacks = |
{ |
add_archive_element, |
multiple_definition, |
multiple_common, |
add_to_set, |
constructor_callback, |
warning_callback, |
undefined_symbol, |
reloc_overflow, |
reloc_dangerous, |
unattached_reloc, |
notice, |
einfo, |
info_msg, |
minfo, |
ldlang_override_segment_assignment |
}; |
static bfd_assert_handler_type default_bfd_assert_handler; |
struct bfd_link_info link_info; |
static void |
ld_cleanup (void) |
{ |
bfd_cache_close_all (); |
#ifdef ENABLE_PLUGINS |
plugin_call_cleanup (); |
#endif |
if (output_filename && delete_output_file_on_failure) |
unlink_if_ordinary (output_filename); |
} |
/* If there's a BFD assertion, we'll notice and exit with an error |
unless otherwise instructed. */ |
static void |
ld_bfd_assert_handler (const char *fmt, const char *bfdver, |
const char *file, int line) |
{ |
(*default_bfd_assert_handler) (fmt, bfdver, file, line); |
config.make_executable = FALSE; |
} |
static inline void set_cwd(const char* cwd) |
{ |
__asm__ __volatile__( |
"int $0x40" |
::"a"(30),"b"(1),"c"(cwd)); |
}; |
int |
main (int argc, char **argv) |
{ |
char *emulation; |
long start_time = get_run_time (); |
set_cwd("/kolibrios/contrib/toolchain/binutils/ld"); |
#ifdef HAVE_SBRK |
char *start_sbrk = (char *) sbrk (0); |
#endif |
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) |
setlocale (LC_MESSAGES, ""); |
#endif |
#if defined (HAVE_SETLOCALE) |
setlocale (LC_CTYPE, ""); |
#endif |
bindtextdomain (PACKAGE, LOCALEDIR); |
textdomain (PACKAGE); |
program_name = argv[0]; |
xmalloc_set_program_name (program_name); |
START_PROGRESS (program_name, 0); |
expandargv (&argc, &argv); |
bfd_init (); |
bfd_set_error_program_name (program_name); |
/* We want to notice and fail on those nasty BFD assertions which are |
likely to signal incorrect output being generated but otherwise may |
leave no trace. */ |
default_bfd_assert_handler = bfd_set_assert_handler (ld_bfd_assert_handler); |
xatexit (ld_cleanup); |
/* Set up the sysroot directory. */ |
ld_sysroot = get_sysroot (argc, argv); |
if (*ld_sysroot) |
{ |
if (*TARGET_SYSTEM_ROOT == 0) |
{ |
einfo ("%P%F: this linker was not configured to use sysroots\n"); |
ld_sysroot = ""; |
} |
else |
ld_canon_sysroot = lrealpath (ld_sysroot); |
} |
if (ld_canon_sysroot) |
ld_canon_sysroot_len = strlen (ld_canon_sysroot); |
else |
ld_canon_sysroot_len = -1; |
/* Set the default BFD target based on the configured target. Doing |
this permits the linker to be configured for a particular target, |
and linked against a shared BFD library which was configured for |
a different target. The macro TARGET is defined by Makefile. */ |
if (! bfd_set_default_target (TARGET)) |
{ |
einfo (_("%X%P: can't set BFD default target to `%s': %E\n"), TARGET); |
xexit (1); |
} |
#if YYDEBUG |
{ |
extern int yydebug; |
yydebug = 1; |
} |
#endif |
config.build_constructors = TRUE; |
config.rpath_separator = ':'; |
config.split_by_reloc = (unsigned) -1; |
config.split_by_file = (bfd_size_type) -1; |
config.make_executable = TRUE; |
config.magic_demand_paged = TRUE; |
config.text_read_only = TRUE; |
link_info.disable_target_specific_optimizations = -1; |
command_line.warn_mismatch = TRUE; |
command_line.warn_search_mismatch = TRUE; |
command_line.check_section_addresses = -1; |
/* We initialize DEMANGLING based on the environment variable |
COLLECT_NO_DEMANGLE. The gcc collect2 program will demangle the |
output of the linker, unless COLLECT_NO_DEMANGLE is set in the |
environment. Acting the same way here lets us provide the same |
interface by default. */ |
demangling = getenv ("COLLECT_NO_DEMANGLE") == NULL; |
link_info.allow_undefined_version = TRUE; |
link_info.keep_memory = TRUE; |
link_info.combreloc = TRUE; |
link_info.strip_discarded = TRUE; |
link_info.emit_hash = TRUE; |
link_info.callbacks = &link_callbacks; |
link_info.input_bfds_tail = &link_info.input_bfds; |
/* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init |
and _fini symbols. We are compatible. */ |
link_info.init_function = "_init"; |
link_info.fini_function = "_fini"; |
link_info.relax_pass = 1; |
link_info.pei386_auto_import = -1; |
link_info.spare_dynamic_tags = 5; |
link_info.path_separator = ':'; |
ldfile_add_arch (""); |
emulation = get_emulation (argc, argv); |
ldemul_choose_mode (emulation); |
default_target = ldemul_choose_target (argc, argv); |
config.maxpagesize = bfd_emul_get_maxpagesize (default_target); |
config.commonpagesize = bfd_emul_get_commonpagesize (default_target); |
lang_init (); |
ldemul_before_parse (); |
lang_has_input_file = FALSE; |
parse_args (argc, argv); |
if (config.hash_table_size != 0) |
bfd_hash_set_default_size (config.hash_table_size); |
#ifdef ENABLE_PLUGINS |
/* Now all the plugin arguments have been gathered, we can load them. */ |
plugin_load_plugins (); |
#endif /* ENABLE_PLUGINS */ |
ldemul_set_symbols (); |
/* If we have not already opened and parsed a linker script, |
try the default script from command line first. */ |
if (saved_script_handle == NULL |
&& command_line.default_script != NULL) |
{ |
ldfile_open_command_file (command_line.default_script); |
parser_input = input_script; |
yyparse (); |
} |
/* If we have not already opened and parsed a linker script |
read the emulation's appropriate default script. */ |
if (saved_script_handle == NULL) |
{ |
int isfile; |
char *s = ldemul_get_script (&isfile); |
if (isfile) |
ldfile_open_default_command_file (s); |
else |
{ |
lex_string = s; |
lex_redirect (s, _("built in linker script"), 1); |
} |
parser_input = input_script; |
yyparse (); |
lex_string = NULL; |
} |
if (verbose) |
{ |
if (saved_script_handle) |
info_msg (_("using external linker script:")); |
else |
info_msg (_("using internal linker script:")); |
info_msg ("\n==================================================\n"); |
if (saved_script_handle) |
{ |
static const int ld_bufsz = 8193; |
size_t n; |
char *buf = (char *) xmalloc (ld_bufsz); |
rewind (saved_script_handle); |
while ((n = fread (buf, 1, ld_bufsz - 1, saved_script_handle)) > 0) |
{ |
buf[n] = 0; |
info_msg (buf); |
} |
rewind (saved_script_handle); |
free (buf); |
} |
else |
{ |
int isfile; |
info_msg (ldemul_get_script (&isfile)); |
} |
info_msg ("\n==================================================\n"); |
} |
if (command_line.print_output_format) |
info_msg ("%s\n", lang_get_output_target ()); |
lang_final (); |
if (!lang_has_input_file) |
{ |
if (version_printed || command_line.print_output_format) |
xexit (0); |
einfo (_("%P%F: no input files\n")); |
} |
if (trace_files) |
info_msg (_("%P: mode %s\n"), emulation); |
ldemul_after_parse (); |
if (config.map_filename) |
{ |
if (strcmp (config.map_filename, "-") == 0) |
{ |
config.map_file = stdout; |
} |
else |
{ |
config.map_file = fopen (config.map_filename, FOPEN_WT); |
if (config.map_file == (FILE *) NULL) |
{ |
bfd_set_error (bfd_error_system_call); |
einfo (_("%P%F: cannot open map file %s: %E\n"), |
config.map_filename); |
} |
} |
} |
lang_process (); |
/* Print error messages for any missing symbols, for any warning |
symbols, and possibly multiple definitions. */ |
if (link_info.relocatable) |
link_info.output_bfd->flags &= ~EXEC_P; |
else |
link_info.output_bfd->flags |= EXEC_P; |
ldwrite (); |
if (config.map_file != NULL) |
lang_map (); |
if (command_line.cref) |
output_cref (config.map_file != NULL ? config.map_file : stdout); |
if (nocrossref_list != NULL) |
check_nocrossrefs (); |
lang_finish (); |
/* Even if we're producing relocatable output, some non-fatal errors should |
be reported in the exit status. (What non-fatal errors, if any, do we |
want to ignore for relocatable output?) */ |
if (!config.make_executable && !force_make_executable) |
{ |
if (trace_files) |
einfo (_("%P: link errors found, deleting executable `%s'\n"), |
output_filename); |
/* The file will be removed by ld_cleanup. */ |
xexit (1); |
} |
else |
{ |
if (! bfd_close (link_info.output_bfd)) |
einfo (_("%F%B: final close failed: %E\n"), link_info.output_bfd); |
/* If the --force-exe-suffix is enabled, and we're making an |
executable file and it doesn't end in .exe, copy it to one |
which does. */ |
if (! link_info.relocatable && command_line.force_exe_suffix) |
{ |
int len = strlen (output_filename); |
if (len < 4 |
|| (strcasecmp (output_filename + len - 4, ".exe") != 0 |
&& strcasecmp (output_filename + len - 4, ".dll") != 0)) |
{ |
FILE *src; |
FILE *dst; |
const int bsize = 4096; |
char *buf = (char *) xmalloc (bsize); |
int l; |
char *dst_name = (char *) xmalloc (len + 5); |
strcpy (dst_name, output_filename); |
strcat (dst_name, ".exe"); |
src = fopen (output_filename, FOPEN_RB); |
dst = fopen (dst_name, FOPEN_WB); |
if (!src) |
einfo (_("%X%P: unable to open for source of copy `%s'\n"), |
output_filename); |
if (!dst) |
einfo (_("%X%P: unable to open for destination of copy `%s'\n"), |
dst_name); |
while ((l = fread (buf, 1, bsize, src)) > 0) |
{ |
int done = fwrite (buf, 1, l, dst); |
if (done != l) |
einfo (_("%P: Error writing file `%s'\n"), dst_name); |
} |
fclose (src); |
if (fclose (dst) == EOF) |
einfo (_("%P: Error closing file `%s'\n"), dst_name); |
free (dst_name); |
free (buf); |
} |
} |
} |
END_PROGRESS (program_name); |
if (config.stats) |
{ |
#ifdef HAVE_SBRK |
char *lim = (char *) sbrk (0); |
#endif |
long run_time = get_run_time () - start_time; |
fflush (stdout); |
fprintf (stderr, _("%s: total time in link: %ld.%06ld\n"), |
program_name, run_time / 1000000, run_time % 1000000); |
#ifdef HAVE_SBRK |
fprintf (stderr, _("%s: data size %ld\n"), program_name, |
(long) (lim - start_sbrk)); |
#endif |
fflush (stderr); |
} |
/* Prevent ld_cleanup from doing anything, after a successful link. */ |
output_filename = NULL; |
xexit (0); |
return 0; |
} |
/* If the configured sysroot is relocatable, try relocating it based on |
default prefix FROM. Return the relocated directory if it exists, |
otherwise return null. */ |
static char * |
get_relative_sysroot (const char *from ATTRIBUTE_UNUSED) |
{ |
#ifdef TARGET_SYSTEM_ROOT_RELOCATABLE |
char *path; |
struct stat s; |
path = make_relative_prefix (program_name, from, TARGET_SYSTEM_ROOT); |
if (path) |
{ |
if (stat (path, &s) == 0 && S_ISDIR (s.st_mode)) |
return path; |
free (path); |
} |
#endif |
return 0; |
} |
/* Return the sysroot directory. Return "" if no sysroot is being used. */ |
static const char * |
get_sysroot (int argc, char **argv) |
{ |
int i; |
const char *path; |
for (i = 1; i < argc; i++) |
if (CONST_STRNEQ (argv[i], "--sysroot=")) |
return argv[i] + strlen ("--sysroot="); |
path = get_relative_sysroot (BINDIR); |
if (path) |
return path; |
path = get_relative_sysroot (TOOLBINDIR); |
if (path) |
return path; |
return TARGET_SYSTEM_ROOT; |
} |
/* We need to find any explicitly given emulation in order to initialize the |
state that's needed by the lex&yacc argument parser (parse_args). */ |
static char * |
get_emulation (int argc, char **argv) |
{ |
char *emulation; |
int i; |
emulation = getenv (EMULATION_ENVIRON); |
if (emulation == NULL) |
emulation = DEFAULT_EMULATION; |
for (i = 1; i < argc; i++) |
{ |
if (CONST_STRNEQ (argv[i], "-m")) |
{ |
if (argv[i][2] == '\0') |
{ |
/* -m EMUL */ |
if (i < argc - 1) |
{ |
emulation = argv[i + 1]; |
i++; |
} |
else |
einfo (_("%P%F: missing argument to -m\n")); |
} |
else if (strcmp (argv[i], "-mips1") == 0 |
|| strcmp (argv[i], "-mips2") == 0 |
|| strcmp (argv[i], "-mips3") == 0 |
|| strcmp (argv[i], "-mips4") == 0 |
|| strcmp (argv[i], "-mips5") == 0 |
|| strcmp (argv[i], "-mips32") == 0 |
|| strcmp (argv[i], "-mips32r2") == 0 |
|| strcmp (argv[i], "-mips64") == 0 |
|| strcmp (argv[i], "-mips64r2") == 0) |
{ |
/* FIXME: The arguments -mips1, -mips2, -mips3, etc. are |
passed to the linker by some MIPS compilers. They |
generally tell the linker to use a slightly different |
library path. Perhaps someday these should be |
implemented as emulations; until then, we just ignore |
the arguments and hope that nobody ever creates |
emulations named ips1, ips2 or ips3. */ |
} |
else if (strcmp (argv[i], "-m486") == 0) |
{ |
/* FIXME: The argument -m486 is passed to the linker on |
some Linux systems. Hope that nobody creates an |
emulation named 486. */ |
} |
else |
{ |
/* -mEMUL */ |
emulation = &argv[i][2]; |
} |
} |
} |
return emulation; |
} |
void |
add_ysym (const char *name) |
{ |
if (link_info.notice_hash == NULL) |
{ |
link_info.notice_hash = |
(struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table)); |
if (!bfd_hash_table_init_n (link_info.notice_hash, |
bfd_hash_newfunc, |
sizeof (struct bfd_hash_entry), |
61)) |
einfo (_("%P%F: bfd_hash_table_init failed: %E\n")); |
} |
if (bfd_hash_lookup (link_info.notice_hash, name, TRUE, TRUE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup failed: %E\n")); |
} |
void |
add_ignoresym (struct bfd_link_info *info, const char *name) |
{ |
if (info->ignore_hash == NULL) |
{ |
info->ignore_hash = xmalloc (sizeof (struct bfd_hash_table)); |
if (! bfd_hash_table_init_n (info->ignore_hash, |
bfd_hash_newfunc, |
sizeof (struct bfd_hash_entry), |
61)) |
einfo (_("%P%F: bfd_hash_table_init failed: %E\n")); |
} |
if (bfd_hash_lookup (info->ignore_hash, name, TRUE, TRUE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup failed: %E\n")); |
} |
/* Record a symbol to be wrapped, from the --wrap option. */ |
void |
add_wrap (const char *name) |
{ |
if (link_info.wrap_hash == NULL) |
{ |
link_info.wrap_hash = |
(struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table)); |
if (!bfd_hash_table_init_n (link_info.wrap_hash, |
bfd_hash_newfunc, |
sizeof (struct bfd_hash_entry), |
61)) |
einfo (_("%P%F: bfd_hash_table_init failed: %E\n")); |
} |
if (bfd_hash_lookup (link_info.wrap_hash, name, TRUE, TRUE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup failed: %E\n")); |
} |
/* Handle the -retain-symbols-file option. */ |
void |
add_keepsyms_file (const char *filename) |
{ |
FILE *file; |
char *buf; |
size_t bufsize; |
int c; |
if (link_info.strip == strip_some) |
einfo (_("%X%P: error: duplicate retain-symbols-file\n")); |
file = fopen (filename, "r"); |
if (file == NULL) |
{ |
bfd_set_error (bfd_error_system_call); |
einfo ("%X%P: %s: %E\n", filename); |
return; |
} |
link_info.keep_hash = (struct bfd_hash_table *) |
xmalloc (sizeof (struct bfd_hash_table)); |
if (!bfd_hash_table_init (link_info.keep_hash, bfd_hash_newfunc, |
sizeof (struct bfd_hash_entry))) |
einfo (_("%P%F: bfd_hash_table_init failed: %E\n")); |
bufsize = 100; |
buf = (char *) xmalloc (bufsize); |
c = getc (file); |
while (c != EOF) |
{ |
while (ISSPACE (c)) |
c = getc (file); |
if (c != EOF) |
{ |
size_t len = 0; |
while (! ISSPACE (c) && c != EOF) |
{ |
buf[len] = c; |
++len; |
if (len >= bufsize) |
{ |
bufsize *= 2; |
buf = (char *) xrealloc (buf, bufsize); |
} |
c = getc (file); |
} |
buf[len] = '\0'; |
if (bfd_hash_lookup (link_info.keep_hash, buf, TRUE, TRUE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup for insertion failed: %E\n")); |
} |
} |
if (link_info.strip != strip_none) |
einfo (_("%P: `-retain-symbols-file' overrides `-s' and `-S'\n")); |
free (buf); |
link_info.strip = strip_some; |
} |
/* Callbacks from the BFD linker routines. */ |
/* This is called when BFD has decided to include an archive member in |
a link. */ |
static bfd_boolean |
add_archive_element (struct bfd_link_info *info, |
bfd *abfd, |
const char *name, |
bfd **subsbfd ATTRIBUTE_UNUSED) |
{ |
lang_input_statement_type *input; |
lang_input_statement_type orig_input; |
input = (lang_input_statement_type *) |
xcalloc (1, sizeof (lang_input_statement_type)); |
input->filename = abfd->filename; |
input->local_sym_name = abfd->filename; |
input->the_bfd = abfd; |
/* Save the original data for trace files/tries below, as plugins |
(if enabled) may possibly alter it to point to a replacement |
BFD, but we still want to output the original BFD filename. */ |
orig_input = *input; |
#ifdef ENABLE_PLUGINS |
if (plugin_active_plugins_p () && !no_more_claiming) |
{ |
/* We must offer this archive member to the plugins to claim. */ |
const char *filename = (bfd_my_archive (abfd) != NULL |
? bfd_my_archive (abfd)->filename : abfd->filename); |
int fd = open (filename, O_RDONLY | O_BINARY); |
if (fd >= 0) |
{ |
struct ld_plugin_input_file file; |
/* Offset and filesize must refer to the individual archive |
member, not the whole file, and must exclude the header. |
Fortunately for us, that is how the data is stored in the |
origin field of the bfd and in the arelt_data. */ |
file.name = filename; |
file.offset = abfd->origin; |
file.filesize = arelt_size (abfd); |
file.fd = fd; |
plugin_maybe_claim (&file, input); |
if (input->flags.claimed) |
{ |
input->flags.claim_archive = TRUE; |
*subsbfd = input->the_bfd; |
} |
} |
} |
#endif /* ENABLE_PLUGINS */ |
ldlang_add_file (input); |
if (config.map_file != NULL) |
{ |
static bfd_boolean header_printed; |
struct bfd_link_hash_entry *h; |
bfd *from; |
int len; |
h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); |
if (h == NULL) |
from = NULL; |
else |
{ |
switch (h->type) |
{ |
default: |
from = NULL; |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
from = h->u.def.section->owner; |
break; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
from = h->u.undef.abfd; |
break; |
case bfd_link_hash_common: |
from = h->u.c.p->section->owner; |
break; |
} |
} |
if (! header_printed) |
{ |
char buf[100]; |
sprintf (buf, _("Archive member included because of file (symbol)\n\n")); |
minfo ("%s", buf); |
header_printed = TRUE; |
} |
if (bfd_my_archive (abfd) == NULL) |
{ |
minfo ("%s", bfd_get_filename (abfd)); |
len = strlen (bfd_get_filename (abfd)); |
} |
else |
{ |
minfo ("%s(%s)", bfd_get_filename (bfd_my_archive (abfd)), |
bfd_get_filename (abfd)); |
len = (strlen (bfd_get_filename (bfd_my_archive (abfd))) |
+ strlen (bfd_get_filename (abfd)) |
+ 2); |
} |
if (len >= 29) |
{ |
print_nl (); |
len = 0; |
} |
while (len < 30) |
{ |
print_space (); |
++len; |
} |
if (from != NULL) |
minfo ("%B ", from); |
if (h != NULL) |
minfo ("(%T)\n", h->root.string); |
else |
minfo ("(%s)\n", name); |
} |
if (trace_files || verbose) |
info_msg ("%I\n", &orig_input); |
return TRUE; |
} |
/* This is called when BFD has discovered a symbol which is defined |
multiple times. */ |
static bfd_boolean |
multiple_definition (struct bfd_link_info *info, |
struct bfd_link_hash_entry *h, |
bfd *nbfd, |
asection *nsec, |
bfd_vma nval) |
{ |
const char *name; |
bfd *obfd; |
asection *osec; |
bfd_vma oval; |
if (info->allow_multiple_definition) |
return TRUE; |
switch (h->type) |
{ |
case bfd_link_hash_defined: |
osec = h->u.def.section; |
oval = h->u.def.value; |
obfd = h->u.def.section->owner; |
break; |
case bfd_link_hash_indirect: |
osec = bfd_ind_section_ptr; |
oval = 0; |
obfd = NULL; |
break; |
default: |
abort (); |
} |
/* Ignore a redefinition of an absolute symbol to the |
same value; it's harmless. */ |
if (h->type == bfd_link_hash_defined |
&& bfd_is_abs_section (osec) |
&& bfd_is_abs_section (nsec) |
&& nval == oval) |
return TRUE; |
/* If either section has the output_section field set to |
bfd_abs_section_ptr, it means that the section is being |
discarded, and this is not really a multiple definition at all. |
FIXME: It would be cleaner to somehow ignore symbols defined in |
sections which are being discarded. */ |
if ((osec->output_section != NULL |
&& ! bfd_is_abs_section (osec) |
&& bfd_is_abs_section (osec->output_section)) |
|| (nsec->output_section != NULL |
&& ! bfd_is_abs_section (nsec) |
&& bfd_is_abs_section (nsec->output_section))) |
return TRUE; |
name = h->root.string; |
if (nbfd == NULL) |
{ |
nbfd = obfd; |
nsec = osec; |
nval = oval; |
obfd = NULL; |
} |
einfo (_("%X%C: multiple definition of `%T'\n"), |
nbfd, nsec, nval, name); |
if (obfd != NULL) |
einfo (_("%D: first defined here\n"), obfd, osec, oval); |
if (RELAXATION_ENABLED_BY_USER) |
{ |
einfo (_("%P: Disabling relaxation: it will not work with multiple definitions\n")); |
DISABLE_RELAXATION; |
} |
return TRUE; |
} |
/* This is called when there is a definition of a common symbol, or |
when a common symbol is found for a symbol that is already defined, |
or when two common symbols are found. We only do something if |
-warn-common was used. */ |
static bfd_boolean |
multiple_common (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry *h, |
bfd *nbfd, |
enum bfd_link_hash_type ntype, |
bfd_vma nsize) |
{ |
const char *name; |
bfd *obfd; |
enum bfd_link_hash_type otype; |
bfd_vma osize; |
if (!config.warn_common) |
return TRUE; |
name = h->root.string; |
otype = h->type; |
if (otype == bfd_link_hash_common) |
{ |
obfd = h->u.c.p->section->owner; |
osize = h->u.c.size; |
} |
else if (otype == bfd_link_hash_defined |
|| otype == bfd_link_hash_defweak) |
{ |
obfd = h->u.def.section->owner; |
osize = 0; |
} |
else |
{ |
/* FIXME: It would nice if we could report the BFD which defined |
an indirect symbol, but we don't have anywhere to store the |
information. */ |
obfd = NULL; |
osize = 0; |
} |
if (ntype == bfd_link_hash_defined |
|| ntype == bfd_link_hash_defweak |
|| ntype == bfd_link_hash_indirect) |
{ |
ASSERT (otype == bfd_link_hash_common); |
einfo (_("%B: warning: definition of `%T' overriding common\n"), |
nbfd, name); |
if (obfd != NULL) |
einfo (_("%B: warning: common is here\n"), obfd); |
} |
else if (otype == bfd_link_hash_defined |
|| otype == bfd_link_hash_defweak |
|| otype == bfd_link_hash_indirect) |
{ |
ASSERT (ntype == bfd_link_hash_common); |
einfo (_("%B: warning: common of `%T' overridden by definition\n"), |
nbfd, name); |
if (obfd != NULL) |
einfo (_("%B: warning: defined here\n"), obfd); |
} |
else |
{ |
ASSERT (otype == bfd_link_hash_common && ntype == bfd_link_hash_common); |
if (osize > nsize) |
{ |
einfo (_("%B: warning: common of `%T' overridden by larger common\n"), |
nbfd, name); |
if (obfd != NULL) |
einfo (_("%B: warning: larger common is here\n"), obfd); |
} |
else if (nsize > osize) |
{ |
einfo (_("%B: warning: common of `%T' overriding smaller common\n"), |
nbfd, name); |
if (obfd != NULL) |
einfo (_("%B: warning: smaller common is here\n"), obfd); |
} |
else |
{ |
einfo (_("%B: warning: multiple common of `%T'\n"), nbfd, name); |
if (obfd != NULL) |
einfo (_("%B: warning: previous common is here\n"), obfd); |
} |
} |
return TRUE; |
} |
/* This is called when BFD has discovered a set element. H is the |
entry in the linker hash table for the set. SECTION and VALUE |
represent a value which should be added to the set. */ |
static bfd_boolean |
add_to_set (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry *h, |
bfd_reloc_code_real_type reloc, |
bfd *abfd, |
asection *section, |
bfd_vma value) |
{ |
if (config.warn_constructors) |
einfo (_("%P: warning: global constructor %s used\n"), |
h->root.string); |
if (! config.build_constructors) |
return TRUE; |
ldctor_add_set_entry (h, reloc, NULL, section, value); |
if (h->type == bfd_link_hash_new) |
{ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = abfd; |
/* We don't call bfd_link_add_undef to add this to the list of |
undefined symbols because we are going to define it |
ourselves. */ |
} |
return TRUE; |
} |
/* This is called when BFD has discovered a constructor. This is only |
called for some object file formats--those which do not handle |
constructors in some more clever fashion. This is similar to |
adding an element to a set, but less general. */ |
static bfd_boolean |
constructor_callback (struct bfd_link_info *info, |
bfd_boolean constructor, |
const char *name, |
bfd *abfd, |
asection *section, |
bfd_vma value) |
{ |
char *s; |
struct bfd_link_hash_entry *h; |
char set_name[1 + sizeof "__CTOR_LIST__"]; |
if (config.warn_constructors) |
einfo (_("%P: warning: global constructor %s used\n"), name); |
if (! config.build_constructors) |
return TRUE; |
/* Ensure that BFD_RELOC_CTOR exists now, so that we can give a |
useful error message. */ |
if (bfd_reloc_type_lookup (info->output_bfd, BFD_RELOC_CTOR) == NULL |
&& (info->relocatable |
|| bfd_reloc_type_lookup (abfd, BFD_RELOC_CTOR) == NULL)) |
einfo (_("%P%F: BFD backend error: BFD_RELOC_CTOR unsupported\n")); |
s = set_name; |
if (bfd_get_symbol_leading_char (abfd) != '\0') |
*s++ = bfd_get_symbol_leading_char (abfd); |
if (constructor) |
strcpy (s, "__CTOR_LIST__"); |
else |
strcpy (s, "__DTOR_LIST__"); |
h = bfd_link_hash_lookup (info->hash, set_name, TRUE, TRUE, TRUE); |
if (h == (struct bfd_link_hash_entry *) NULL) |
einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); |
if (h->type == bfd_link_hash_new) |
{ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = abfd; |
/* We don't call bfd_link_add_undef to add this to the list of |
undefined symbols because we are going to define it |
ourselves. */ |
} |
ldctor_add_set_entry (h, BFD_RELOC_CTOR, name, section, value); |
return TRUE; |
} |
/* A structure used by warning_callback to pass information through |
bfd_map_over_sections. */ |
struct warning_callback_info |
{ |
bfd_boolean found; |
const char *warning; |
const char *symbol; |
asymbol **asymbols; |
}; |
/* This is called when there is a reference to a warning symbol. */ |
static bfd_boolean |
warning_callback (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
const char *warning, |
const char *symbol, |
bfd *abfd, |
asection *section, |
bfd_vma address) |
{ |
/* This is a hack to support warn_multiple_gp. FIXME: This should |
have a cleaner interface, but what? */ |
if (! config.warn_multiple_gp |
&& strcmp (warning, "using multiple gp values") == 0) |
return TRUE; |
if (section != NULL) |
einfo ("%C: %s%s\n", abfd, section, address, _("warning: "), warning); |
else if (abfd == NULL) |
einfo ("%P: %s%s\n", _("warning: "), warning); |
else if (symbol == NULL) |
einfo ("%B: %s%s\n", abfd, _("warning: "), warning); |
else |
{ |
struct warning_callback_info cinfo; |
/* Look through the relocs to see if we can find a plausible |
address. */ |
if (!bfd_generic_link_read_symbols (abfd)) |
einfo (_("%B%F: could not read symbols: %E\n"), abfd); |
cinfo.found = FALSE; |
cinfo.warning = warning; |
cinfo.symbol = symbol; |
cinfo.asymbols = bfd_get_outsymbols (abfd); |
bfd_map_over_sections (abfd, warning_find_reloc, &cinfo); |
if (! cinfo.found) |
einfo ("%B: %s%s\n", abfd, _("warning: "), warning); |
} |
return TRUE; |
} |
/* This is called by warning_callback for each section. It checks the |
relocs of the section to see if it can find a reference to the |
symbol which triggered the warning. If it can, it uses the reloc |
to give an error message with a file and line number. */ |
static void |
warning_find_reloc (bfd *abfd, asection *sec, void *iarg) |
{ |
struct warning_callback_info *info = (struct warning_callback_info *) iarg; |
long relsize; |
arelent **relpp; |
long relcount; |
arelent **p, **pend; |
if (info->found) |
return; |
relsize = bfd_get_reloc_upper_bound (abfd, sec); |
if (relsize < 0) |
einfo (_("%B%F: could not read relocs: %E\n"), abfd); |
if (relsize == 0) |
return; |
relpp = (arelent **) xmalloc (relsize); |
relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols); |
if (relcount < 0) |
einfo (_("%B%F: could not read relocs: %E\n"), abfd); |
p = relpp; |
pend = p + relcount; |
for (; p < pend && *p != NULL; p++) |
{ |
arelent *q = *p; |
if (q->sym_ptr_ptr != NULL |
&& *q->sym_ptr_ptr != NULL |
&& strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), info->symbol) == 0) |
{ |
/* We found a reloc for the symbol we are looking for. */ |
einfo ("%C: %s%s\n", abfd, sec, q->address, _("warning: "), |
info->warning); |
info->found = TRUE; |
break; |
} |
} |
free (relpp); |
} |
/* This is called when an undefined symbol is found. */ |
static bfd_boolean |
undefined_symbol (struct bfd_link_info *info, |
const char *name, |
bfd *abfd, |
asection *section, |
bfd_vma address, |
bfd_boolean error) |
{ |
static char *error_name; |
static unsigned int error_count; |
#define MAX_ERRORS_IN_A_ROW 5 |
if (info->ignore_hash != NULL |
&& bfd_hash_lookup (info->ignore_hash, name, FALSE, FALSE) != NULL) |
return TRUE; |
if (config.warn_once) |
{ |
/* Only warn once about a particular undefined symbol. */ |
add_ignoresym (info, name); |
} |
/* We never print more than a reasonable number of errors in a row |
for a single symbol. */ |
if (error_name != NULL |
&& strcmp (name, error_name) == 0) |
++error_count; |
else |
{ |
error_count = 0; |
if (error_name != NULL) |
free (error_name); |
error_name = xstrdup (name); |
} |
if (section != NULL) |
{ |
if (error_count < MAX_ERRORS_IN_A_ROW) |
{ |
if (error) |
einfo (_("%X%C: undefined reference to `%T'\n"), |
abfd, section, address, name); |
else |
einfo (_("%C: warning: undefined reference to `%T'\n"), |
abfd, section, address, name); |
} |
else if (error_count == MAX_ERRORS_IN_A_ROW) |
{ |
if (error) |
einfo (_("%X%D: more undefined references to `%T' follow\n"), |
abfd, section, address, name); |
else |
einfo (_("%D: warning: more undefined references to `%T' follow\n"), |
abfd, section, address, name); |
} |
else if (error) |
einfo ("%X"); |
} |
else |
{ |
if (error_count < MAX_ERRORS_IN_A_ROW) |
{ |
if (error) |
einfo (_("%X%B: undefined reference to `%T'\n"), |
abfd, name); |
else |
einfo (_("%B: warning: undefined reference to `%T'\n"), |
abfd, name); |
} |
else if (error_count == MAX_ERRORS_IN_A_ROW) |
{ |
if (error) |
einfo (_("%X%B: more undefined references to `%T' follow\n"), |
abfd, name); |
else |
einfo (_("%B: warning: more undefined references to `%T' follow\n"), |
abfd, name); |
} |
else if (error) |
einfo ("%X"); |
} |
return TRUE; |
} |
/* Counter to limit the number of relocation overflow error messages |
to print. Errors are printed as it is decremented. When it's |
called and the counter is zero, a final message is printed |
indicating more relocations were omitted. When it gets to -1, no |
such errors are printed. If it's initially set to a value less |
than -1, all such errors will be printed (--verbose does this). */ |
int overflow_cutoff_limit = 10; |
/* This is called when a reloc overflows. */ |
static bfd_boolean |
reloc_overflow (struct bfd_link_info *info, |
struct bfd_link_hash_entry *entry, |
const char *name, |
const char *reloc_name, |
bfd_vma addend, |
bfd *abfd, |
asection *section, |
bfd_vma address) |
{ |
if (overflow_cutoff_limit == -1) |
return TRUE; |
einfo ("%X%H:", abfd, section, address); |
if (overflow_cutoff_limit >= 0 |
&& overflow_cutoff_limit-- == 0) |
{ |
einfo (_(" additional relocation overflows omitted from the output\n")); |
return TRUE; |
} |
if (entry) |
{ |
while (entry->type == bfd_link_hash_indirect |
|| entry->type == bfd_link_hash_warning) |
entry = entry->u.i.link; |
switch (entry->type) |
{ |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
einfo (_(" relocation truncated to fit: %s against undefined symbol `%T'"), |
reloc_name, entry->root.string); |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
einfo (_(" relocation truncated to fit: %s against symbol `%T' defined in %A section in %B"), |
reloc_name, entry->root.string, |
entry->u.def.section, |
entry->u.def.section == bfd_abs_section_ptr |
? info->output_bfd : entry->u.def.section->owner); |
break; |
default: |
abort (); |
break; |
} |
} |
else |
einfo (_(" relocation truncated to fit: %s against `%T'"), |
reloc_name, name); |
if (addend != 0) |
einfo ("+%v", addend); |
einfo ("\n"); |
return TRUE; |
} |
/* This is called when a dangerous relocation is made. */ |
static bfd_boolean |
reloc_dangerous (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
const char *message, |
bfd *abfd, |
asection *section, |
bfd_vma address) |
{ |
einfo (_("%X%H: dangerous relocation: %s\n"), |
abfd, section, address, message); |
return TRUE; |
} |
/* This is called when a reloc is being generated attached to a symbol |
that is not being output. */ |
static bfd_boolean |
unattached_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
const char *name, |
bfd *abfd, |
asection *section, |
bfd_vma address) |
{ |
einfo (_("%X%H: reloc refers to symbol `%T' which is not being output\n"), |
abfd, section, address, name); |
return TRUE; |
} |
/* This is called if link_info.notice_all is set, or when a symbol in |
link_info.notice_hash is found. Symbols are put in notice_hash |
using the -y option, while notice_all is set if the --cref option |
has been supplied, or if there are any NOCROSSREFS sections in the |
linker script; and if plugins are active, since they need to monitor |
all references from non-IR files. */ |
static bfd_boolean |
notice (struct bfd_link_info *info, |
struct bfd_link_hash_entry *h, |
bfd *abfd, |
asection *section, |
bfd_vma value, |
flagword flags ATTRIBUTE_UNUSED, |
const char *string ATTRIBUTE_UNUSED) |
{ |
const char *name; |
if (h == NULL) |
{ |
if (command_line.cref || nocrossref_list != NULL) |
return handle_asneeded_cref (abfd, (enum notice_asneeded_action) value); |
return TRUE; |
} |
name = h->root.string; |
if (info->notice_hash != NULL |
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL) |
{ |
if (bfd_is_und_section (section)) |
einfo ("%B: reference to %s\n", abfd, name); |
else |
einfo ("%B: definition of %s\n", abfd, name); |
} |
if (command_line.cref || nocrossref_list != NULL) |
add_cref (name, abfd, section, value); |
return TRUE; |
} |
/contrib/toolchain/binutils/ld/ldmain.h |
---|
0,0 → 1,62 |
/* ldmain.h - |
Copyright 1991-2013 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDMAIN_H |
#define LDMAIN_H |
extern char *program_name; |
extern const char *ld_sysroot; |
extern char *ld_canon_sysroot; |
extern int ld_canon_sysroot_len; |
extern FILE *saved_script_handle; |
extern FILE *previous_script_handle; |
extern bfd_boolean force_make_executable; |
extern char *default_target; |
extern bfd_boolean trace_files; |
extern bfd_boolean verbose; |
extern bfd_boolean version_printed; |
extern bfd_boolean demangling; |
extern int g_switch_value; |
extern const char *output_filename; |
extern struct bfd_link_info link_info; |
extern int overflow_cutoff_limit; |
#define RELAXATION_DISABLED_BY_DEFAULT \ |
(link_info.disable_target_specific_optimizations < 0) |
#define RELAXATION_DISABLED_BY_USER \ |
(link_info.disable_target_specific_optimizations > 1) |
#define RELAXATION_ENABLED \ |
(link_info.disable_target_specific_optimizations == 0 \ |
|| link_info.disable_target_specific_optimizations == 1) |
#define RELAXATION_ENABLED_BY_USER \ |
(link_info.disable_target_specific_optimizations == 0) |
#define TARGET_ENABLE_RELAXATION \ |
do { link_info.disable_target_specific_optimizations = 1; } while (0) |
#define DISABLE_RELAXATION \ |
do { link_info.disable_target_specific_optimizations = 2; } while (0) |
#define ENABLE_RELAXATION \ |
do { link_info.disable_target_specific_optimizations = 0; } while (0) |
extern void add_ysym (const char *); |
extern void add_wrap (const char *); |
extern void add_ignoresym (struct bfd_link_info *, const char *); |
extern void add_keepsyms_file (const char *); |
#endif |
/contrib/toolchain/binutils/ld/ldmisc.c |
---|
0,0 → 1,530 |
/* ldmisc.c |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012, 2013 |
Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libiberty.h" |
#include "filenames.h" |
#include "demangle.h" |
#include <stdarg.h> |
#include "ld.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldmain.h" |
#include "ldfile.h" |
#include "elf-bfd.h" |
/* |
%% literal % |
%A section name from a section |
%B filename from a bfd |
%C clever filename:linenumber with function |
%D like %C, but no function name |
%E current bfd error or errno |
%F error is fatal |
%G like %D, but only function name |
%H like %C but in addition emit section+offset |
%I filename from a lang_input_statement_type |
%P print program name |
%R info about a relent |
%S print script file and linenumber from etree_type. |
%T symbol name |
%V hex bfd_vma |
%W hex bfd_vma with 0x with no leading zeros taking up 8 spaces |
%X no object output, fail return |
%d integer, like printf |
%ld long, like printf |
%lu unsigned long, like printf |
%p native (host) void* pointer, like printf |
%s arbitrary string, like printf |
%u integer, like printf |
%v hex bfd_vma, no leading zeros |
*/ |
void |
vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) |
{ |
bfd_boolean fatal = FALSE; |
while (*fmt != '\0') |
{ |
const char *str = fmt; |
while (*fmt != '%' && *fmt != '\0') |
fmt++; |
if (fmt != str) |
if (fwrite (str, 1, fmt - str, fp)) |
{ |
/* Ignore. */ |
} |
if (*fmt == '%') |
{ |
fmt++; |
switch (*fmt++) |
{ |
case '%': |
/* literal % */ |
putc ('%', fp); |
break; |
case 'X': |
/* no object output, fail return */ |
config.make_executable = FALSE; |
break; |
case 'V': |
/* hex bfd_vma */ |
{ |
bfd_vma value = va_arg (arg, bfd_vma); |
fprintf_vma (fp, value); |
} |
break; |
case 'v': |
/* hex bfd_vma, no leading zeros */ |
{ |
char buf[100]; |
char *p = buf; |
bfd_vma value = va_arg (arg, bfd_vma); |
sprintf_vma (p, value); |
while (*p == '0') |
p++; |
if (!*p) |
p--; |
fputs (p, fp); |
} |
break; |
case 'W': |
/* hex bfd_vma with 0x with no leading zeroes taking up |
8 spaces. */ |
{ |
char buf[100]; |
bfd_vma value; |
char *p; |
int len; |
value = va_arg (arg, bfd_vma); |
sprintf_vma (buf, value); |
for (p = buf; *p == '0'; ++p) |
; |
if (*p == '\0') |
--p; |
len = strlen (p); |
while (len < 8) |
{ |
putc (' ', fp); |
++len; |
} |
fprintf (fp, "0x%s", p); |
} |
break; |
case 'T': |
/* Symbol name. */ |
{ |
const char *name = va_arg (arg, const char *); |
if (name == NULL || *name == 0) |
{ |
fprintf (fp, _("no symbol")); |
break; |
} |
else if (demangling) |
{ |
char *demangled; |
demangled = bfd_demangle (link_info.output_bfd, name, |
DMGL_ANSI | DMGL_PARAMS); |
if (demangled != NULL) |
{ |
fprintf (fp, "%s", demangled); |
free (demangled); |
break; |
} |
} |
fprintf (fp, "%s", name); |
} |
break; |
case 'A': |
/* section name from a section */ |
{ |
asection *sec = va_arg (arg, asection *); |
bfd *abfd = sec->owner; |
const char *group = NULL; |
struct coff_comdat_info *ci; |
fprintf (fp, "%s", sec->name); |
if (abfd != NULL |
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& elf_next_in_group (sec) != NULL |
&& (sec->flags & SEC_GROUP) == 0) |
group = elf_group_name (sec); |
else if (abfd != NULL |
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour |
&& (ci = bfd_coff_get_comdat_section (sec->owner, |
sec)) != NULL) |
group = ci->name; |
if (group != NULL) |
fprintf (fp, "[%s]", group); |
} |
break; |
case 'B': |
/* filename from a bfd */ |
{ |
bfd *abfd = va_arg (arg, bfd *); |
if (abfd == NULL) |
fprintf (fp, "%s generated", program_name); |
else if (abfd->my_archive) |
fprintf (fp, "%s(%s)", abfd->my_archive->filename, |
abfd->filename); |
else |
fprintf (fp, "%s", abfd->filename); |
} |
break; |
case 'F': |
/* Error is fatal. */ |
fatal = TRUE; |
break; |
case 'P': |
/* Print program name. */ |
fprintf (fp, "%s", program_name); |
break; |
case 'E': |
/* current bfd error or errno */ |
fprintf (fp, "%s", bfd_errmsg (bfd_get_error ())); |
break; |
case 'I': |
/* filename from a lang_input_statement_type */ |
{ |
lang_input_statement_type *i; |
i = va_arg (arg, lang_input_statement_type *); |
if (bfd_my_archive (i->the_bfd) != NULL) |
fprintf (fp, "(%s)", |
bfd_get_filename (bfd_my_archive (i->the_bfd))); |
fprintf (fp, "%s", i->local_sym_name); |
if (bfd_my_archive (i->the_bfd) == NULL |
&& filename_cmp (i->local_sym_name, i->filename) != 0) |
fprintf (fp, " (%s)", i->filename); |
} |
break; |
case 'S': |
/* Print script file and linenumber. */ |
{ |
etree_type node; |
etree_type *tp = va_arg (arg, etree_type *); |
if (tp == NULL) |
{ |
tp = &node; |
tp->type.filename = ldlex_filename (); |
tp->type.lineno = lineno; |
} |
if (tp->type.filename != NULL) |
fprintf (fp, "%s:%u", tp->type.filename, tp->type.lineno); |
} |
break; |
case 'R': |
/* Print all that's interesting about a relent. */ |
{ |
arelent *relent = va_arg (arg, arelent *); |
lfinfo (fp, "%s+0x%v (type %s)", |
(*(relent->sym_ptr_ptr))->name, |
relent->addend, |
relent->howto->name); |
} |
break; |
case 'C': |
case 'D': |
case 'G': |
case 'H': |
/* Clever filename:linenumber with function name if possible. |
The arguments are a BFD, a section, and an offset. */ |
{ |
static bfd *last_bfd; |
static char *last_file = NULL; |
static char *last_function = NULL; |
bfd *abfd; |
asection *section; |
bfd_vma offset; |
asymbol **asymbols = NULL; |
const char *filename; |
const char *functionname; |
unsigned int linenumber; |
bfd_boolean discard_last; |
bfd_boolean done; |
abfd = va_arg (arg, bfd *); |
section = va_arg (arg, asection *); |
offset = va_arg (arg, bfd_vma); |
if (abfd != NULL) |
{ |
if (!bfd_generic_link_read_symbols (abfd)) |
einfo (_("%B%F: could not read symbols: %E\n"), abfd); |
asymbols = bfd_get_outsymbols (abfd); |
} |
/* The GNU Coding Standard requires that error messages |
be of the form: |
source-file-name:lineno: message |
We do not always have a line number available so if |
we cannot find them we print out the section name and |
offset instead. */ |
discard_last = TRUE; |
if (abfd != NULL |
&& bfd_find_nearest_line (abfd, section, asymbols, offset, |
&filename, &functionname, |
&linenumber)) |
{ |
if (functionname != NULL |
&& (fmt[-1] == 'C' || fmt[-1] == 'H')) |
{ |
/* Detect the case where we are printing out a |
message for the same function as the last |
call to vinfo ("%C"). In this situation do |
not print out the ABFD filename or the |
function name again. Note - we do still |
print out the source filename, as this will |
allow programs that parse the linker's output |
(eg emacs) to correctly locate multiple |
errors in the same source file. */ |
if (last_bfd == NULL |
|| last_file == NULL |
|| last_function == NULL |
|| last_bfd != abfd |
|| (filename != NULL |
&& filename_cmp (last_file, filename) != 0) |
|| strcmp (last_function, functionname) != 0) |
{ |
lfinfo (fp, _("%B: In function `%T':\n"), |
abfd, functionname); |
last_bfd = abfd; |
if (last_file != NULL) |
free (last_file); |
last_file = NULL; |
if (filename) |
last_file = xstrdup (filename); |
if (last_function != NULL) |
free (last_function); |
last_function = xstrdup (functionname); |
} |
discard_last = FALSE; |
} |
else |
lfinfo (fp, "%B:", abfd); |
if (filename != NULL) |
fprintf (fp, "%s:", filename); |
done = fmt[-1] != 'H'; |
if (functionname != NULL && fmt[-1] == 'G') |
lfinfo (fp, "%T", functionname); |
else if (filename != NULL && linenumber != 0) |
fprintf (fp, "%u%s", linenumber, done ? "" : ":"); |
else |
done = FALSE; |
} |
else |
{ |
lfinfo (fp, "%B:", abfd); |
done = FALSE; |
} |
if (!done) |
lfinfo (fp, "(%A+0x%v)", section, offset); |
if (discard_last) |
{ |
last_bfd = NULL; |
if (last_file != NULL) |
{ |
free (last_file); |
last_file = NULL; |
} |
if (last_function != NULL) |
{ |
free (last_function); |
last_function = NULL; |
} |
} |
} |
break; |
case 'p': |
/* native (host) void* pointer, like printf */ |
fprintf (fp, "%p", va_arg (arg, void *)); |
break; |
case 's': |
/* arbitrary string, like printf */ |
fprintf (fp, "%s", va_arg (arg, char *)); |
break; |
case 'd': |
/* integer, like printf */ |
fprintf (fp, "%d", va_arg (arg, int)); |
break; |
case 'u': |
/* unsigned integer, like printf */ |
fprintf (fp, "%u", va_arg (arg, unsigned int)); |
break; |
case 'l': |
if (*fmt == 'd') |
{ |
fprintf (fp, "%ld", va_arg (arg, long)); |
++fmt; |
break; |
} |
else if (*fmt == 'u') |
{ |
fprintf (fp, "%lu", va_arg (arg, unsigned long)); |
++fmt; |
break; |
} |
/* Fall thru */ |
default: |
fprintf (fp, "%%%c", fmt[-1]); |
break; |
} |
} |
} |
if (is_warning && config.fatal_warnings) |
config.make_executable = FALSE; |
if (fatal) |
xexit (1); |
} |
/* Format info message and print on stdout. */ |
/* (You would think this should be called just "info", but then you |
would be hosed by LynxOS, which defines that name in its libc.) */ |
void |
info_msg (const char *fmt, ...) |
{ |
va_list arg; |
va_start (arg, fmt); |
vfinfo (stdout, fmt, arg, FALSE); |
va_end (arg); |
} |
/* ('e' for error.) Format info message and print on stderr. */ |
void |
einfo (const char *fmt, ...) |
{ |
va_list arg; |
fflush (stdout); |
va_start (arg, fmt); |
vfinfo (stderr, fmt, arg, TRUE); |
va_end (arg); |
fflush (stderr); |
} |
void |
info_assert (const char *file, unsigned int line) |
{ |
einfo (_("%F%P: internal error %s %d\n"), file, line); |
} |
/* ('m' for map) Format info message and print on map. */ |
void |
minfo (const char *fmt, ...) |
{ |
if (config.map_file != NULL) |
{ |
va_list arg; |
va_start (arg, fmt); |
vfinfo (config.map_file, fmt, arg, FALSE); |
va_end (arg); |
} |
} |
void |
lfinfo (FILE *file, const char *fmt, ...) |
{ |
va_list arg; |
va_start (arg, fmt); |
vfinfo (file, fmt, arg, FALSE); |
va_end (arg); |
} |
/* Functions to print the link map. */ |
void |
print_space (void) |
{ |
fprintf (config.map_file, " "); |
} |
void |
print_nl (void) |
{ |
fprintf (config.map_file, "\n"); |
} |
/* A more or less friendly abort message. In ld.h abort is defined to |
call this function. */ |
void |
ld_abort (const char *file, int line, const char *fn) |
{ |
if (fn != NULL) |
einfo (_("%P: internal error: aborting at %s line %d in %s\n"), |
file, line, fn); |
else |
einfo (_("%P: internal error: aborting at %s line %d\n"), |
file, line); |
einfo (_("%P%F: please report this bug\n")); |
xexit (1); |
} |
/contrib/toolchain/binutils/ld/ldmisc.h |
---|
0,0 → 1,45 |
/* ldmisc.h - |
Copyright 1991, 1992, 1993, 1994, 1996, 1997, 2001, 2003, 2004, 2005, 2007 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LDMISC_H |
#define LDMISC_H |
extern void vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning); |
extern void einfo (const char *, ...); |
extern void minfo (const char *, ...); |
extern void info_msg (const char *, ...); |
extern void lfinfo (FILE *, const char *, ...); |
extern void info_assert (const char *, unsigned int); |
extern void yyerror (const char *); |
extern void *xmalloc (size_t); |
extern void *xrealloc (void *, size_t); |
extern void xexit (int); |
#define ASSERT(x) \ |
do { if (!(x)) info_assert(__FILE__,__LINE__); } while (0) |
#define FAIL() \ |
do { info_assert(__FILE__,__LINE__); } while (0) |
extern void print_space (void); |
extern void print_nl (void); |
#endif |
/contrib/toolchain/binutils/ld/ldver.c |
---|
0,0 → 1,61 |
/* ldver.c -- Print linker version. |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, |
2003, 2005, 2007, 2008, 2009, 2010, 2011, 2012, 2013 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdver.h" |
#include "ld.h" |
#include "ldver.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "ldmain.h" |
void |
ldversion (int noisy) |
{ |
/* Output for noisy == 2 is intended to follow the GNU standards. */ |
fprintf (stdout, _("GNU ld %s\n"), BFD_VERSION_STRING); |
if (noisy & 2) |
{ |
printf (_("Copyright 2013 Free Software Foundation, Inc.\n")); |
printf (_("\ |
This program is free software; you may redistribute it under the terms of\n\ |
the GNU General Public License version 3 or (at your option) a later version.\n\ |
This program has absolutely no warranty.\n")); |
} |
if (noisy & 1) |
{ |
ld_emulation_xfer_type **ptr = ld_emulations; |
printf (_(" Supported emulations:\n")); |
while (*ptr) |
{ |
printf (" %s\n", (*ptr)->emulation_name); |
ptr++; |
} |
} |
} |
/contrib/toolchain/binutils/ld/ldver.h |
---|
0,0 → 1,22 |
/* ldver.h -- Header file for ldver.c. |
Copyright 1991, 1992, 1993, 1996, 2001, 2003, 2005, 2007 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
void ldversion (int); |
/contrib/toolchain/binutils/ld/ldwrite.c |
---|
0,0 → 1,593 |
/* ldwrite.c -- write out the linked file |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002, |
2003, 2004, 2005, 2006, 2007, 2008, 2010, 2012 |
Free Software Foundation, Inc. |
Written by Steve Chamberlain sac@cygnus.com |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
#include "ld.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldwrite.h" |
#include "ldmisc.h" |
#include <ldgram.h> |
#include "ldmain.h" |
/* Build link_order structures for the BFD linker. */ |
static void |
build_link_order (lang_statement_union_type *statement) |
{ |
switch (statement->header.type) |
{ |
case lang_data_statement_enum: |
{ |
asection *output_section; |
struct bfd_link_order *link_order; |
bfd_vma value; |
bfd_boolean big_endian = FALSE; |
output_section = statement->data_statement.output_section; |
ASSERT (output_section->owner == link_info.output_bfd); |
if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 |
|| ((output_section->flags & SEC_LOAD) != 0 |
&& (output_section->flags & SEC_THREAD_LOCAL)))) |
break; |
link_order = bfd_new_link_order (link_info.output_bfd, output_section); |
if (link_order == NULL) |
einfo (_("%P%F: bfd_new_link_order failed\n")); |
link_order->type = bfd_data_link_order; |
link_order->offset = statement->data_statement.output_offset; |
link_order->u.data.contents = (bfd_byte *) xmalloc (QUAD_SIZE); |
value = statement->data_statement.value; |
/* If the endianness of the output BFD is not known, then we |
base the endianness of the data on the first input file. |
By convention, the bfd_put routines for an unknown |
endianness are big endian, so we must swap here if the |
input file is little endian. */ |
if (bfd_big_endian (link_info.output_bfd)) |
big_endian = TRUE; |
else if (bfd_little_endian (link_info.output_bfd)) |
big_endian = FALSE; |
else |
{ |
bfd_boolean swap; |
swap = FALSE; |
if (command_line.endian == ENDIAN_BIG) |
big_endian = TRUE; |
else if (command_line.endian == ENDIAN_LITTLE) |
{ |
big_endian = FALSE; |
swap = TRUE; |
} |
else if (command_line.endian == ENDIAN_UNSET) |
{ |
big_endian = TRUE; |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (s) |
{ |
if (s->the_bfd != NULL) |
{ |
if (bfd_little_endian (s->the_bfd)) |
{ |
big_endian = FALSE; |
swap = TRUE; |
} |
break; |
} |
} |
} |
} |
if (swap) |
{ |
bfd_byte buffer[8]; |
switch (statement->data_statement.type) |
{ |
case QUAD: |
case SQUAD: |
if (sizeof (bfd_vma) >= QUAD_SIZE) |
{ |
bfd_putl64 (value, buffer); |
value = bfd_getb64 (buffer); |
break; |
} |
/* Fall through. */ |
case LONG: |
bfd_putl32 (value, buffer); |
value = bfd_getb32 (buffer); |
break; |
case SHORT: |
bfd_putl16 (value, buffer); |
value = bfd_getb16 (buffer); |
break; |
case BYTE: |
break; |
default: |
abort (); |
} |
} |
} |
ASSERT (output_section->owner == link_info.output_bfd); |
switch (statement->data_statement.type) |
{ |
case QUAD: |
case SQUAD: |
if (sizeof (bfd_vma) >= QUAD_SIZE) |
bfd_put_64 (link_info.output_bfd, value, |
link_order->u.data.contents); |
else |
{ |
bfd_vma high; |
if (statement->data_statement.type == QUAD) |
high = 0; |
else if ((value & 0x80000000) == 0) |
high = 0; |
else |
high = (bfd_vma) -1; |
bfd_put_32 (link_info.output_bfd, high, |
(link_order->u.data.contents |
+ (big_endian ? 0 : 4))); |
bfd_put_32 (link_info.output_bfd, value, |
(link_order->u.data.contents |
+ (big_endian ? 4 : 0))); |
} |
link_order->size = QUAD_SIZE; |
break; |
case LONG: |
bfd_put_32 (link_info.output_bfd, value, |
link_order->u.data.contents); |
link_order->size = LONG_SIZE; |
break; |
case SHORT: |
bfd_put_16 (link_info.output_bfd, value, |
link_order->u.data.contents); |
link_order->size = SHORT_SIZE; |
break; |
case BYTE: |
bfd_put_8 (link_info.output_bfd, value, |
link_order->u.data.contents); |
link_order->size = BYTE_SIZE; |
break; |
default: |
abort (); |
} |
link_order->u.data.size = link_order->size; |
} |
break; |
case lang_reloc_statement_enum: |
{ |
lang_reloc_statement_type *rs; |
asection *output_section; |
struct bfd_link_order *link_order; |
rs = &statement->reloc_statement; |
output_section = rs->output_section; |
ASSERT (output_section->owner == link_info.output_bfd); |
if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 |
|| ((output_section->flags & SEC_LOAD) != 0 |
&& (output_section->flags & SEC_THREAD_LOCAL)))) |
break; |
link_order = bfd_new_link_order (link_info.output_bfd, output_section); |
if (link_order == NULL) |
einfo (_("%P%F: bfd_new_link_order failed\n")); |
link_order->offset = rs->output_offset; |
link_order->size = bfd_get_reloc_size (rs->howto); |
link_order->u.reloc.p = (struct bfd_link_order_reloc *) |
xmalloc (sizeof (struct bfd_link_order_reloc)); |
link_order->u.reloc.p->reloc = rs->reloc; |
link_order->u.reloc.p->addend = rs->addend_value; |
if (rs->name == NULL) |
{ |
link_order->type = bfd_section_reloc_link_order; |
if (rs->section->owner == link_info.output_bfd) |
link_order->u.reloc.p->u.section = rs->section; |
else |
{ |
link_order->u.reloc.p->u.section = rs->section->output_section; |
link_order->u.reloc.p->addend += rs->section->output_offset; |
} |
} |
else |
{ |
link_order->type = bfd_symbol_reloc_link_order; |
link_order->u.reloc.p->u.name = rs->name; |
} |
} |
break; |
case lang_input_section_enum: |
{ |
/* Create a new link_order in the output section with this |
attached */ |
asection *i = statement->input_section.section; |
if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS |
&& (i->flags & SEC_EXCLUDE) == 0) |
{ |
asection *output_section = i->output_section; |
struct bfd_link_order *link_order; |
ASSERT (output_section->owner == link_info.output_bfd); |
if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 |
|| ((output_section->flags & SEC_LOAD) != 0 |
&& (output_section->flags & SEC_THREAD_LOCAL)))) |
break; |
link_order = bfd_new_link_order (link_info.output_bfd, |
output_section); |
if ((i->flags & SEC_NEVER_LOAD) != 0 |
&& (i->flags & SEC_DEBUGGING) == 0) |
{ |
/* We've got a never load section inside one which is |
going to be output, we'll change it into a fill. */ |
link_order->type = bfd_data_link_order; |
link_order->u.data.contents = (unsigned char *) ""; |
link_order->u.data.size = 1; |
} |
else |
{ |
link_order->type = bfd_indirect_link_order; |
link_order->u.indirect.section = i; |
ASSERT (i->output_section == output_section); |
} |
link_order->size = i->size; |
link_order->offset = i->output_offset; |
} |
} |
break; |
case lang_padding_statement_enum: |
/* Make a new link_order with the right filler */ |
{ |
asection *output_section; |
struct bfd_link_order *link_order; |
output_section = statement->padding_statement.output_section; |
ASSERT (statement->padding_statement.output_section->owner |
== link_info.output_bfd); |
if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 |
|| ((output_section->flags & SEC_LOAD) != 0 |
&& (output_section->flags & SEC_THREAD_LOCAL)))) |
break; |
link_order = bfd_new_link_order (link_info.output_bfd, |
output_section); |
link_order->type = bfd_data_link_order; |
link_order->size = statement->padding_statement.size; |
link_order->offset = statement->padding_statement.output_offset; |
link_order->u.data.contents = statement->padding_statement.fill->data; |
link_order->u.data.size = statement->padding_statement.fill->size; |
} |
break; |
default: |
/* All the other ones fall through */ |
break; |
} |
} |
/* Return true if NAME is the name of an unsplittable section. These |
are the stabs strings, dwarf strings. */ |
static bfd_boolean |
unsplittable_name (const char *name) |
{ |
if (CONST_STRNEQ (name, ".stab")) |
{ |
/* There are several stab like string sections. We pattern match on |
".stab...str" */ |
unsigned len = strlen (name); |
if (strcmp (&name[len-3], "str") == 0) |
return TRUE; |
} |
else if (strcmp (name, "$GDB_STRINGS$") == 0) |
return TRUE; |
return FALSE; |
} |
/* Wander around the input sections, make sure that |
we'll never try and create an output section with more relocs |
than will fit.. Do this by always assuming the worst case, and |
creating new output sections with all the right bits. */ |
#define TESTIT 1 |
static asection * |
clone_section (bfd *abfd, asection *s, const char *name, int *count) |
{ |
char *tname; |
char *sname; |
unsigned int len; |
asection *n; |
struct bfd_link_hash_entry *h; |
/* Invent a section name from the section name and a dotted numeric |
suffix. */ |
len = strlen (name); |
tname = (char *) xmalloc (len + 1); |
memcpy (tname, name, len + 1); |
/* Remove a dotted number suffix, from a previous split link. */ |
while (len && ISDIGIT (tname[len-1])) |
len--; |
if (len > 1 && tname[len-1] == '.') |
/* It was a dotted number. */ |
tname[len-1] = 0; |
/* We want to use the whole of the original section name for the |
split name, but coff can be restricted to 8 character names. */ |
if (bfd_family_coff (abfd) && strlen (tname) > 5) |
{ |
/* Some section names cannot be truncated, as the name is |
used to locate some other section. */ |
if (CONST_STRNEQ (name, ".stab") |
|| strcmp (name, "$GDB_SYMBOLS$") == 0) |
{ |
einfo (_ ("%F%P: cannot create split section name for %s\n"), name); |
/* Silence gcc warnings. einfo exits, so we never reach here. */ |
return NULL; |
} |
tname[5] = 0; |
} |
if ((sname = bfd_get_unique_section_name (abfd, tname, count)) == NULL |
|| (n = bfd_make_section_anyway (abfd, sname)) == NULL |
|| (h = bfd_link_hash_lookup (link_info.hash, |
sname, TRUE, TRUE, FALSE)) == NULL) |
{ |
einfo (_("%F%P: clone section failed: %E\n")); |
/* Silence gcc warnings. einfo exits, so we never reach here. */ |
return NULL; |
} |
free (tname); |
/* Set up section symbol. */ |
h->type = bfd_link_hash_defined; |
h->u.def.value = 0; |
h->u.def.section = n; |
n->flags = s->flags; |
n->vma = s->vma; |
n->user_set_vma = s->user_set_vma; |
n->lma = s->lma; |
n->size = 0; |
n->output_offset = s->output_offset; |
n->output_section = n; |
n->orelocation = 0; |
n->reloc_count = 0; |
n->alignment_power = s->alignment_power; |
bfd_copy_private_section_data (abfd, s, abfd, n); |
return n; |
} |
#if TESTING |
static void |
ds (asection *s) |
{ |
struct bfd_link_order *l = s->map_head.link_order; |
printf ("vma %x size %x\n", s->vma, s->size); |
while (l) |
{ |
if (l->type == bfd_indirect_link_order) |
{ |
printf ("%8x %s\n", l->offset, l->u.indirect.section->owner->filename); |
} |
else |
{ |
printf (_("%8x something else\n"), l->offset); |
} |
l = l->next; |
} |
printf ("\n"); |
} |
dump (char *s, asection *a1, asection *a2) |
{ |
printf ("%s\n", s); |
ds (a1); |
ds (a2); |
} |
static void |
sanity_check (bfd *abfd) |
{ |
asection *s; |
for (s = abfd->sections; s; s = s->next) |
{ |
struct bfd_link_order *p; |
bfd_vma prev = 0; |
for (p = s->map_head.link_order; p; p = p->next) |
{ |
if (p->offset > 100000) |
abort (); |
if (p->offset < prev) |
abort (); |
prev = p->offset; |
} |
} |
} |
#else |
#define sanity_check(a) |
#define dump(a, b, c) |
#endif |
static void |
split_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
asection *original_sec; |
int nsecs = abfd->section_count; |
sanity_check (abfd); |
/* Look through all the original sections. */ |
for (original_sec = abfd->sections; |
original_sec && nsecs; |
original_sec = original_sec->next, nsecs--) |
{ |
int count = 0; |
unsigned int lines = 0; |
unsigned int relocs = 0; |
bfd_size_type sec_size = 0; |
struct bfd_link_order *l; |
struct bfd_link_order *p; |
bfd_vma vma = original_sec->vma; |
asection *cursor = original_sec; |
/* Count up the relocations and line entries to see if anything |
would be too big to fit. Accumulate section size too. */ |
for (l = NULL, p = cursor->map_head.link_order; p != NULL; p = l->next) |
{ |
unsigned int thislines = 0; |
unsigned int thisrelocs = 0; |
bfd_size_type thissize = 0; |
if (p->type == bfd_indirect_link_order) |
{ |
asection *sec; |
sec = p->u.indirect.section; |
if (info->strip == strip_none |
|| info->strip == strip_some) |
thislines = sec->lineno_count; |
if (info->relocatable) |
thisrelocs = sec->reloc_count; |
thissize = sec->size; |
} |
else if (info->relocatable |
&& (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order)) |
thisrelocs++; |
if (l != NULL |
&& (thisrelocs + relocs >= config.split_by_reloc |
|| thislines + lines >= config.split_by_reloc |
|| (thissize + sec_size >= config.split_by_file)) |
&& !unsplittable_name (cursor->name)) |
{ |
/* Create a new section and put this link order and the |
following link orders into it. */ |
bfd_vma shift_offset; |
asection *n; |
n = clone_section (abfd, cursor, original_sec->name, &count); |
/* Attach the link orders to the new section and snip |
them off from the old section. */ |
n->map_head.link_order = p; |
n->map_tail.link_order = cursor->map_tail.link_order; |
cursor->map_tail.link_order = l; |
l->next = NULL; |
l = p; |
/* Change the size of the original section and |
update the vma of the new one. */ |
dump ("before snip", cursor, n); |
shift_offset = p->offset; |
n->size = cursor->size - shift_offset; |
cursor->size = shift_offset; |
vma += shift_offset; |
n->lma = n->vma = vma; |
/* Run down the chain and change the output section to |
the right one, update the offsets too. */ |
do |
{ |
p->offset -= shift_offset; |
if (p->type == bfd_indirect_link_order) |
{ |
p->u.indirect.section->output_section = n; |
p->u.indirect.section->output_offset = p->offset; |
} |
p = p->next; |
} |
while (p); |
dump ("after snip", cursor, n); |
cursor = n; |
relocs = thisrelocs; |
lines = thislines; |
sec_size = thissize; |
} |
else |
{ |
l = p; |
relocs += thisrelocs; |
lines += thislines; |
sec_size += thissize; |
} |
} |
} |
sanity_check (abfd); |
} |
/* Call BFD to write out the linked file. */ |
void |
ldwrite (void) |
{ |
/* Reset error indicator, which can typically something like invalid |
format from opening up the .o files. */ |
bfd_set_error (bfd_error_no_error); |
lang_for_each_statement (build_link_order); |
if (config.split_by_reloc != (unsigned) -1 |
|| config.split_by_file != (bfd_size_type) -1) |
split_sections (link_info.output_bfd, &link_info); |
if (!bfd_final_link (link_info.output_bfd, &link_info)) |
{ |
/* If there was an error recorded, print it out. Otherwise assume |
an appropriate error message like unknown symbol was printed |
out. */ |
if (bfd_get_error () != bfd_error_no_error) |
einfo (_("%F%P: final link failed: %E\n")); |
else |
xexit (1); |
} |
} |
/contrib/toolchain/binutils/ld/ldwrite.h |
---|
0,0 → 1,21 |
/* ldwrite.h - |
Copyright 1991, 1992, 1993, 2003, 2005, 2007 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
extern void ldwrite (void); |
/contrib/toolchain/binutils/ld/lexsup.c |
---|
0,0 → 1,1718 |
/* Parse options for the GNU linker. |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdver.h" |
#include "libiberty.h" |
#include <stdio.h> |
#include <string.h> |
#include "safe-ctype.h" |
#include "getopt.h" |
#include "bfdlink.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include <ldgram.h> |
#include "ldlex.h" |
#include "ldfile.h" |
#include "ldver.h" |
#include "ldemul.h" |
#include "demangle.h" |
#ifdef ENABLE_PLUGINS |
#include "plugin.h" |
#endif /* ENABLE_PLUGINS */ |
#ifndef PATH_SEPARATOR |
#if defined (__MSDOS__) || (defined (_WIN32) && ! defined (__CYGWIN32__)) |
#define PATH_SEPARATOR ';' |
#else |
#define PATH_SEPARATOR ':' |
#endif |
#endif |
/* Somewhere above, sys/stat.h got included . . . . */ |
#if !defined(S_ISDIR) && defined(S_IFDIR) |
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
#endif |
static void set_default_dirlist (char *); |
static void set_section_start (char *, char *); |
static void set_segment_start (const char *, char *); |
static void help (void); |
/* The long options. This structure is used for both the option |
parsing and the help text. */ |
enum control_enum { |
/* Use one dash before long option name. */ |
ONE_DASH, |
/* Use two dashes before long option name. */ |
TWO_DASHES, |
/* Only accept two dashes before the long option name. |
This is an overloading of the use of this enum, since originally it |
was only intended to tell the --help display function how to display |
the long option name. This feature was added in order to resolve |
the confusion about the -omagic command line switch. Is it setting |
the output file name to "magic" or is it setting the NMAGIC flag on |
the output ? It has been decided that it is setting the output file |
name, and that if you want to set the NMAGIC flag you should use -N |
or --omagic. */ |
EXACTLY_TWO_DASHES, |
/* Don't mention this option in --help output. */ |
NO_HELP |
}; |
struct ld_option |
{ |
/* The long option information. */ |
struct option opt; |
/* The short option with the same meaning ('\0' if none). */ |
char shortopt; |
/* The name of the argument (NULL if none). */ |
const char *arg; |
/* The documentation string. If this is NULL, this is a synonym for |
the previous option. */ |
const char *doc; |
enum control_enum control; |
}; |
static const struct ld_option ld_options[] = |
{ |
{ {NULL, required_argument, NULL, '\0'}, |
'a', N_("KEYWORD"), N_("Shared library control for HP/UX compatibility"), |
ONE_DASH }, |
{ {"architecture", required_argument, NULL, 'A'}, |
'A', N_("ARCH"), N_("Set architecture") , TWO_DASHES }, |
{ {"format", required_argument, NULL, 'b'}, |
'b', N_("TARGET"), N_("Specify target for following input files"), |
TWO_DASHES }, |
{ {"mri-script", required_argument, NULL, 'c'}, |
'c', N_("FILE"), N_("Read MRI format linker script"), TWO_DASHES }, |
{ {"dc", no_argument, NULL, 'd'}, |
'd', NULL, N_("Force common symbols to be defined"), ONE_DASH }, |
{ {"dp", no_argument, NULL, 'd'}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"entry", required_argument, NULL, 'e'}, |
'e', N_("ADDRESS"), N_("Set start address"), TWO_DASHES }, |
{ {"export-dynamic", no_argument, NULL, OPTION_EXPORT_DYNAMIC}, |
'E', NULL, N_("Export all dynamic symbols"), TWO_DASHES }, |
{ {"no-export-dynamic", no_argument, NULL, OPTION_NO_EXPORT_DYNAMIC}, |
'\0', NULL, N_("Undo the effect of --export-dynamic"), TWO_DASHES }, |
{ {"EB", no_argument, NULL, OPTION_EB}, |
'\0', NULL, N_("Link big-endian objects"), ONE_DASH }, |
{ {"EL", no_argument, NULL, OPTION_EL}, |
'\0', NULL, N_("Link little-endian objects"), ONE_DASH }, |
{ {"auxiliary", required_argument, NULL, 'f'}, |
'f', N_("SHLIB"), N_("Auxiliary filter for shared object symbol table"), |
TWO_DASHES }, |
{ {"filter", required_argument, NULL, 'F'}, |
'F', N_("SHLIB"), N_("Filter for shared object symbol table"), |
TWO_DASHES }, |
{ {NULL, no_argument, NULL, '\0'}, |
'g', NULL, N_("Ignored"), ONE_DASH }, |
{ {"gpsize", required_argument, NULL, 'G'}, |
'G', N_("SIZE"), N_("Small data size (if no size, same as --shared)"), |
TWO_DASHES }, |
{ {"soname", required_argument, NULL, OPTION_SONAME}, |
'h', N_("FILENAME"), N_("Set internal name of shared library"), ONE_DASH }, |
{ {"dynamic-linker", required_argument, NULL, OPTION_DYNAMIC_LINKER}, |
'I', N_("PROGRAM"), N_("Set PROGRAM as the dynamic linker to use"), |
TWO_DASHES }, |
{ {"library", required_argument, NULL, 'l'}, |
'l', N_("LIBNAME"), N_("Search for library LIBNAME"), TWO_DASHES }, |
{ {"library-path", required_argument, NULL, 'L'}, |
'L', N_("DIRECTORY"), N_("Add DIRECTORY to library search path"), |
TWO_DASHES }, |
{ {"sysroot=<DIRECTORY>", required_argument, NULL, OPTION_SYSROOT}, |
'\0', NULL, N_("Override the default sysroot location"), TWO_DASHES }, |
{ {NULL, required_argument, NULL, '\0'}, |
'm', N_("EMULATION"), N_("Set emulation"), ONE_DASH }, |
{ {"print-map", no_argument, NULL, 'M'}, |
'M', NULL, N_("Print map file on standard output"), TWO_DASHES }, |
{ {"nmagic", no_argument, NULL, 'n'}, |
'n', NULL, N_("Do not page align data"), TWO_DASHES }, |
{ {"omagic", no_argument, NULL, 'N'}, |
'N', NULL, N_("Do not page align data, do not make text readonly"), |
EXACTLY_TWO_DASHES }, |
{ {"no-omagic", no_argument, NULL, OPTION_NO_OMAGIC}, |
'\0', NULL, N_("Page align data, make text readonly"), |
EXACTLY_TWO_DASHES }, |
{ {"output", required_argument, NULL, 'o'}, |
'o', N_("FILE"), N_("Set output file name"), EXACTLY_TWO_DASHES }, |
{ {NULL, required_argument, NULL, '\0'}, |
'O', NULL, N_("Optimize output file"), ONE_DASH }, |
#ifdef ENABLE_PLUGINS |
{ {"plugin", required_argument, NULL, OPTION_PLUGIN}, |
'\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH }, |
{ {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT}, |
'\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH }, |
{ {"flto", optional_argument, NULL, OPTION_IGNORE}, |
'\0', NULL, N_("Ignored for GCC LTO option compatibility"), |
ONE_DASH }, |
{ {"flto-partition=", required_argument, NULL, OPTION_IGNORE}, |
'\0', NULL, N_("Ignored for GCC LTO option compatibility"), |
ONE_DASH }, |
#endif /* ENABLE_PLUGINS */ |
{ {"fuse-ld=", required_argument, NULL, OPTION_IGNORE}, |
'\0', NULL, N_("Ignored for GCC linker option compatibility"), |
ONE_DASH }, |
{ {"Qy", no_argument, NULL, OPTION_IGNORE}, |
'\0', NULL, N_("Ignored for SVR4 compatibility"), ONE_DASH }, |
{ {"emit-relocs", no_argument, NULL, 'q'}, |
'q', NULL, "Generate relocations in final output", TWO_DASHES }, |
{ {"relocatable", no_argument, NULL, 'r'}, |
'r', NULL, N_("Generate relocatable output"), TWO_DASHES }, |
{ {NULL, no_argument, NULL, '\0'}, |
'i', NULL, NULL, ONE_DASH }, |
{ {"just-symbols", required_argument, NULL, 'R'}, |
'R', N_("FILE"), N_("Just link symbols (if directory, same as --rpath)"), |
TWO_DASHES }, |
{ {"strip-all", no_argument, NULL, 's'}, |
's', NULL, N_("Strip all symbols"), TWO_DASHES }, |
{ {"strip-debug", no_argument, NULL, 'S'}, |
'S', NULL, N_("Strip debugging symbols"), TWO_DASHES }, |
{ {"strip-discarded", no_argument, NULL, OPTION_STRIP_DISCARDED}, |
'\0', NULL, N_("Strip symbols in discarded sections"), TWO_DASHES }, |
{ {"no-strip-discarded", no_argument, NULL, OPTION_NO_STRIP_DISCARDED}, |
'\0', NULL, N_("Do not strip symbols in discarded sections"), TWO_DASHES }, |
{ {"trace", no_argument, NULL, 't'}, |
't', NULL, N_("Trace file opens"), TWO_DASHES }, |
{ {"script", required_argument, NULL, 'T'}, |
'T', N_("FILE"), N_("Read linker script"), TWO_DASHES }, |
{ {"default-script", required_argument, NULL, OPTION_DEFAULT_SCRIPT}, |
'\0', N_("FILE"), N_("Read default linker script"), TWO_DASHES }, |
{ {"dT", required_argument, NULL, OPTION_DEFAULT_SCRIPT}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"undefined", required_argument, NULL, 'u'}, |
'u', N_("SYMBOL"), N_("Start with undefined reference to SYMBOL"), |
TWO_DASHES }, |
{ {"unique", optional_argument, NULL, OPTION_UNIQUE}, |
'\0', N_("[=SECTION]"), |
N_("Don't merge input [SECTION | orphan] sections"), TWO_DASHES }, |
{ {"Ur", no_argument, NULL, OPTION_UR}, |
'\0', NULL, N_("Build global constructor/destructor tables"), ONE_DASH }, |
{ {"version", no_argument, NULL, OPTION_VERSION}, |
'v', NULL, N_("Print version information"), TWO_DASHES }, |
{ {NULL, no_argument, NULL, '\0'}, |
'V', NULL, N_("Print version and emulation information"), ONE_DASH }, |
{ {"discard-all", no_argument, NULL, 'x'}, |
'x', NULL, N_("Discard all local symbols"), TWO_DASHES }, |
{ {"discard-locals", no_argument, NULL, 'X'}, |
'X', NULL, N_("Discard temporary local symbols (default)"), TWO_DASHES }, |
{ {"discard-none", no_argument, NULL, OPTION_DISCARD_NONE}, |
'\0', NULL, N_("Don't discard any local symbols"), TWO_DASHES }, |
{ {"trace-symbol", required_argument, NULL, 'y'}, |
'y', N_("SYMBOL"), N_("Trace mentions of SYMBOL"), TWO_DASHES }, |
{ {NULL, required_argument, NULL, '\0'}, |
'Y', N_("PATH"), N_("Default search path for Solaris compatibility"), |
ONE_DASH }, |
{ {"start-group", no_argument, NULL, '('}, |
'(', NULL, N_("Start a group"), TWO_DASHES }, |
{ {"end-group", no_argument, NULL, ')'}, |
')', NULL, N_("End a group"), TWO_DASHES }, |
{ {"accept-unknown-input-arch", no_argument, NULL, |
OPTION_ACCEPT_UNKNOWN_INPUT_ARCH}, |
'\0', NULL, |
N_("Accept input files whose architecture cannot be determined"), |
TWO_DASHES }, |
{ {"no-accept-unknown-input-arch", no_argument, NULL, |
OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH}, |
'\0', NULL, N_("Reject input files whose architecture is unknown"), |
TWO_DASHES }, |
/* The next two options are deprecated because of their similarity to |
--as-needed and --no-as-needed. They have been replaced by |
--copy-dt-needed-entries and --no-copy-dt-needed-entries. */ |
{ {"add-needed", no_argument, NULL, OPTION_ADD_DT_NEEDED_FOR_DYNAMIC}, |
'\0', NULL, NULL, NO_HELP }, |
{ {"no-add-needed", no_argument, NULL, OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC}, |
'\0', NULL, NULL, NO_HELP }, |
{ {"as-needed", no_argument, NULL, OPTION_ADD_DT_NEEDED_FOR_REGULAR}, |
'\0', NULL, N_("Only set DT_NEEDED for following dynamic libs if used"), |
TWO_DASHES }, |
{ {"no-as-needed", no_argument, NULL, OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR}, |
'\0', NULL, N_("Always set DT_NEEDED for dynamic libraries mentioned on\n" |
" the command line"), |
TWO_DASHES }, |
{ {"assert", required_argument, NULL, OPTION_ASSERT}, |
'\0', N_("KEYWORD"), N_("Ignored for SunOS compatibility"), ONE_DASH }, |
{ {"Bdynamic", no_argument, NULL, OPTION_CALL_SHARED}, |
'\0', NULL, N_("Link against shared libraries"), ONE_DASH }, |
{ {"dy", no_argument, NULL, OPTION_CALL_SHARED}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"call_shared", no_argument, NULL, OPTION_CALL_SHARED}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"Bstatic", no_argument, NULL, OPTION_NON_SHARED}, |
'\0', NULL, N_("Do not link against shared libraries"), ONE_DASH }, |
{ {"dn", no_argument, NULL, OPTION_NON_SHARED}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"non_shared", no_argument, NULL, OPTION_NON_SHARED}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"static", no_argument, NULL, OPTION_NON_SHARED}, |
'\0', NULL, NULL, ONE_DASH }, |
{ {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC}, |
'\0', NULL, N_("Bind global references locally"), ONE_DASH }, |
{ {"Bsymbolic-functions", no_argument, NULL, OPTION_SYMBOLIC_FUNCTIONS}, |
'\0', NULL, N_("Bind global function references locally"), ONE_DASH }, |
{ {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS}, |
'\0', NULL, N_("Check section addresses for overlaps (default)"), |
TWO_DASHES }, |
{ {"no-check-sections", no_argument, NULL, OPTION_NO_CHECK_SECTIONS}, |
'\0', NULL, N_("Do not check section addresses for overlaps"), |
TWO_DASHES }, |
{ {"copy-dt-needed-entries", no_argument, NULL, |
OPTION_ADD_DT_NEEDED_FOR_DYNAMIC}, |
'\0', NULL, N_("Copy DT_NEEDED links mentioned inside DSOs that follow"), |
TWO_DASHES }, |
{ {"no-copy-dt-needed-entries", no_argument, NULL, |
OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC}, |
'\0', NULL, N_("Do not copy DT_NEEDED links mentioned inside DSOs that follow"), |
TWO_DASHES }, |
{ {"cref", no_argument, NULL, OPTION_CREF}, |
'\0', NULL, N_("Output cross reference table"), TWO_DASHES }, |
{ {"defsym", required_argument, NULL, OPTION_DEFSYM}, |
'\0', N_("SYMBOL=EXPRESSION"), N_("Define a symbol"), TWO_DASHES }, |
{ {"demangle", optional_argument, NULL, OPTION_DEMANGLE}, |
'\0', N_("[=STYLE]"), N_("Demangle symbol names [using STYLE]"), |
TWO_DASHES }, |
{ {"embedded-relocs", no_argument, NULL, OPTION_EMBEDDED_RELOCS}, |
'\0', NULL, N_("Generate embedded relocs"), TWO_DASHES}, |
{ {"fatal-warnings", no_argument, NULL, OPTION_WARN_FATAL}, |
'\0', NULL, N_("Treat warnings as errors"), |
TWO_DASHES }, |
{ {"no-fatal-warnings", no_argument, NULL, OPTION_NO_WARN_FATAL}, |
'\0', NULL, N_("Do not treat warnings as errors (default)"), |
TWO_DASHES }, |
{ {"fini", required_argument, NULL, OPTION_FINI}, |
'\0', N_("SYMBOL"), N_("Call SYMBOL at unload-time"), ONE_DASH }, |
{ {"force-exe-suffix", no_argument, NULL, OPTION_FORCE_EXE_SUFFIX}, |
'\0', NULL, N_("Force generation of file with .exe suffix"), TWO_DASHES}, |
{ {"gc-sections", no_argument, NULL, OPTION_GC_SECTIONS}, |
'\0', NULL, N_("Remove unused sections (on some targets)"), |
TWO_DASHES }, |
{ {"no-gc-sections", no_argument, NULL, OPTION_NO_GC_SECTIONS}, |
'\0', NULL, N_("Don't remove unused sections (default)"), |
TWO_DASHES }, |
{ {"print-gc-sections", no_argument, NULL, OPTION_PRINT_GC_SECTIONS}, |
'\0', NULL, N_("List removed unused sections on stderr"), |
TWO_DASHES }, |
{ {"no-print-gc-sections", no_argument, NULL, OPTION_NO_PRINT_GC_SECTIONS}, |
'\0', NULL, N_("Do not list removed unused sections"), |
TWO_DASHES }, |
{ {"hash-size=<NUMBER>", required_argument, NULL, OPTION_HASH_SIZE}, |
'\0', NULL, N_("Set default hash table size close to <NUMBER>"), |
TWO_DASHES }, |
{ {"help", no_argument, NULL, OPTION_HELP}, |
'\0', NULL, N_("Print option help"), TWO_DASHES }, |
{ {"init", required_argument, NULL, OPTION_INIT}, |
'\0', N_("SYMBOL"), N_("Call SYMBOL at load-time"), ONE_DASH }, |
{ {"Map", required_argument, NULL, OPTION_MAP}, |
'\0', N_("FILE"), N_("Write a map file"), ONE_DASH }, |
{ {"no-define-common", no_argument, NULL, OPTION_NO_DEFINE_COMMON}, |
'\0', NULL, N_("Do not define Common storage"), TWO_DASHES }, |
{ {"no-demangle", no_argument, NULL, OPTION_NO_DEMANGLE }, |
'\0', NULL, N_("Do not demangle symbol names"), TWO_DASHES }, |
{ {"no-keep-memory", no_argument, NULL, OPTION_NO_KEEP_MEMORY}, |
'\0', NULL, N_("Use less memory and more disk I/O"), TWO_DASHES }, |
{ {"no-undefined", no_argument, NULL, OPTION_NO_UNDEFINED}, |
'\0', NULL, N_("Do not allow unresolved references in object files"), |
TWO_DASHES }, |
{ {"allow-shlib-undefined", no_argument, NULL, OPTION_ALLOW_SHLIB_UNDEFINED}, |
'\0', NULL, N_("Allow unresolved references in shared libraries"), |
TWO_DASHES }, |
{ {"no-allow-shlib-undefined", no_argument, NULL, |
OPTION_NO_ALLOW_SHLIB_UNDEFINED}, |
'\0', NULL, N_("Do not allow unresolved references in shared libs"), |
TWO_DASHES }, |
{ {"allow-multiple-definition", no_argument, NULL, |
OPTION_ALLOW_MULTIPLE_DEFINITION}, |
'\0', NULL, N_("Allow multiple definitions"), TWO_DASHES }, |
{ {"no-undefined-version", no_argument, NULL, OPTION_NO_UNDEFINED_VERSION}, |
'\0', NULL, N_("Disallow undefined version"), TWO_DASHES }, |
{ {"default-symver", no_argument, NULL, OPTION_DEFAULT_SYMVER}, |
'\0', NULL, N_("Create default symbol version"), TWO_DASHES }, |
{ {"default-imported-symver", no_argument, NULL, |
OPTION_DEFAULT_IMPORTED_SYMVER}, |
'\0', NULL, N_("Create default symbol version for imported symbols"), |
TWO_DASHES }, |
{ {"no-warn-mismatch", no_argument, NULL, OPTION_NO_WARN_MISMATCH}, |
'\0', NULL, N_("Don't warn about mismatched input files"), TWO_DASHES}, |
{ {"no-warn-search-mismatch", no_argument, NULL, |
OPTION_NO_WARN_SEARCH_MISMATCH}, |
'\0', NULL, N_("Don't warn on finding an incompatible library"), |
TWO_DASHES}, |
{ {"no-whole-archive", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE}, |
'\0', NULL, N_("Turn off --whole-archive"), TWO_DASHES }, |
{ {"noinhibit-exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC}, |
'\0', NULL, N_("Create an output file even if errors occur"), |
TWO_DASHES }, |
{ {"noinhibit_exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC}, |
'\0', NULL, NULL, NO_HELP }, |
{ {"nostdlib", no_argument, NULL, OPTION_NOSTDLIB}, |
'\0', NULL, N_("Only use library directories specified on\n" |
" the command line"), |
ONE_DASH }, |
{ {"oformat", required_argument, NULL, OPTION_OFORMAT}, |
'\0', N_("TARGET"), N_("Specify target of output file"), |
EXACTLY_TWO_DASHES }, |
{ {"print-output-format", no_argument, NULL, OPTION_PRINT_OUTPUT_FORMAT}, |
'\0', NULL, N_("Print default output format"), TWO_DASHES }, |
{ {"qmagic", no_argument, NULL, OPTION_IGNORE}, |
'\0', NULL, N_("Ignored for Linux compatibility"), ONE_DASH }, |
{ {"reduce-memory-overheads", no_argument, NULL, |
OPTION_REDUCE_MEMORY_OVERHEADS}, |
'\0', NULL, N_("Reduce memory overheads, possibly taking much longer"), |
TWO_DASHES }, |
{ {"relax", no_argument, NULL, OPTION_RELAX}, |
'\0', NULL, N_("Reduce code size by using target specific optimizations"), TWO_DASHES }, |
{ {"no-relax", no_argument, NULL, OPTION_NO_RELAX}, |
'\0', NULL, N_("Do not use relaxation techniques to reduce code size"), TWO_DASHES }, |
{ {"retain-symbols-file", required_argument, NULL, |
OPTION_RETAIN_SYMBOLS_FILE}, |
'\0', N_("FILE"), N_("Keep only symbols listed in FILE"), TWO_DASHES }, |
{ {"rpath", required_argument, NULL, OPTION_RPATH}, |
'\0', N_("PATH"), N_("Set runtime shared library search path"), ONE_DASH }, |
{ {"rpath-link", required_argument, NULL, OPTION_RPATH_LINK}, |
'\0', N_("PATH"), N_("Set link time shared library search path"), |
ONE_DASH }, |
{ {"shared", no_argument, NULL, OPTION_SHARED}, |
'\0', NULL, N_("Create a shared library"), ONE_DASH }, |
{ {"Bshareable", no_argument, NULL, OPTION_SHARED }, /* FreeBSD. */ |
'\0', NULL, NULL, ONE_DASH }, |
{ {"pie", no_argument, NULL, OPTION_PIE}, |
'\0', NULL, N_("Create a position independent executable"), ONE_DASH }, |
{ {"pic-executable", no_argument, NULL, OPTION_PIE}, |
'\0', NULL, NULL, TWO_DASHES }, |
{ {"sort-common", optional_argument, NULL, OPTION_SORT_COMMON}, |
'\0', N_("[=ascending|descending]"), |
N_("Sort common symbols by alignment [in specified order]"), |
TWO_DASHES }, |
{ {"sort_common", no_argument, NULL, OPTION_SORT_COMMON}, |
'\0', NULL, NULL, NO_HELP }, |
{ {"sort-section", required_argument, NULL, OPTION_SORT_SECTION}, |
'\0', N_("name|alignment"), |
N_("Sort sections by name or maximum alignment"), TWO_DASHES }, |
{ {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS}, |
'\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"), |
TWO_DASHES }, |
{ {"split-by-file", optional_argument, NULL, OPTION_SPLIT_BY_FILE}, |
'\0', N_("[=SIZE]"), N_("Split output sections every SIZE octets"), |
TWO_DASHES }, |
{ {"split-by-reloc", optional_argument, NULL, OPTION_SPLIT_BY_RELOC}, |
'\0', N_("[=COUNT]"), N_("Split output sections every COUNT relocs"), |
TWO_DASHES }, |
{ {"stats", no_argument, NULL, OPTION_STATS}, |
'\0', NULL, N_("Print memory usage statistics"), TWO_DASHES }, |
{ {"target-help", no_argument, NULL, OPTION_TARGET_HELP}, |
'\0', NULL, N_("Display target specific options"), TWO_DASHES }, |
{ {"task-link", required_argument, NULL, OPTION_TASK_LINK}, |
'\0', N_("SYMBOL"), N_("Do task level linking"), TWO_DASHES }, |
{ {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT}, |
'\0', NULL, N_("Use same format as native linker"), TWO_DASHES }, |
{ {"section-start", required_argument, NULL, OPTION_SECTION_START}, |
'\0', N_("SECTION=ADDRESS"), N_("Set address of named section"), |
TWO_DASHES }, |
{ {"Tbss", required_argument, NULL, OPTION_TBSS}, |
'\0', N_("ADDRESS"), N_("Set address of .bss section"), ONE_DASH }, |
{ {"Tdata", required_argument, NULL, OPTION_TDATA}, |
'\0', N_("ADDRESS"), N_("Set address of .data section"), ONE_DASH }, |
{ {"Ttext", required_argument, NULL, OPTION_TTEXT}, |
'\0', N_("ADDRESS"), N_("Set address of .text section"), ONE_DASH }, |
{ {"Ttext-segment", required_argument, NULL, OPTION_TTEXT_SEGMENT}, |
'\0', N_("ADDRESS"), N_("Set address of text segment"), ONE_DASH }, |
{ {"Trodata-segment", required_argument, NULL, OPTION_TRODATA_SEGMENT}, |
'\0', N_("ADDRESS"), N_("Set address of rodata segment"), ONE_DASH }, |
{ {"Tldata-segment", required_argument, NULL, OPTION_TLDATA_SEGMENT}, |
'\0', N_("ADDRESS"), N_("Set address of ldata segment"), ONE_DASH }, |
{ {"unresolved-symbols=<method>", required_argument, NULL, |
OPTION_UNRESOLVED_SYMBOLS}, |
'\0', NULL, N_("How to handle unresolved symbols. <method> is:\n" |
" ignore-all, report-all, ignore-in-object-files,\n" |
" ignore-in-shared-libs"), |
TWO_DASHES }, |
{ {"verbose", optional_argument, NULL, OPTION_VERBOSE}, |
'\0', N_("[=NUMBER]"), |
N_("Output lots of information during link"), TWO_DASHES }, |
{ {"dll-verbose", no_argument, NULL, OPTION_VERBOSE}, /* Linux. */ |
'\0', NULL, NULL, NO_HELP }, |
{ {"version-script", required_argument, NULL, OPTION_VERSION_SCRIPT }, |
'\0', N_("FILE"), N_("Read version information script"), TWO_DASHES }, |
{ {"version-exports-section", required_argument, NULL, |
OPTION_VERSION_EXPORTS_SECTION }, |
'\0', N_("SYMBOL"), N_("Take export symbols list from .exports, using\n" |
" SYMBOL as the version."), |
TWO_DASHES }, |
{ {"dynamic-list-data", no_argument, NULL, OPTION_DYNAMIC_LIST_DATA}, |
'\0', NULL, N_("Add data symbols to dynamic list"), TWO_DASHES }, |
{ {"dynamic-list-cpp-new", no_argument, NULL, OPTION_DYNAMIC_LIST_CPP_NEW}, |
'\0', NULL, N_("Use C++ operator new/delete dynamic list"), TWO_DASHES }, |
{ {"dynamic-list-cpp-typeinfo", no_argument, NULL, OPTION_DYNAMIC_LIST_CPP_TYPEINFO}, |
'\0', NULL, N_("Use C++ typeinfo dynamic list"), TWO_DASHES }, |
{ {"dynamic-list", required_argument, NULL, OPTION_DYNAMIC_LIST}, |
'\0', N_("FILE"), N_("Read dynamic list"), TWO_DASHES }, |
{ {"warn-common", no_argument, NULL, OPTION_WARN_COMMON}, |
'\0', NULL, N_("Warn about duplicate common symbols"), TWO_DASHES }, |
{ {"warn-constructors", no_argument, NULL, OPTION_WARN_CONSTRUCTORS}, |
'\0', NULL, N_("Warn if global constructors/destructors are seen"), |
TWO_DASHES }, |
{ {"warn-multiple-gp", no_argument, NULL, OPTION_WARN_MULTIPLE_GP}, |
'\0', NULL, N_("Warn if the multiple GP values are used"), TWO_DASHES }, |
{ {"warn-once", no_argument, NULL, OPTION_WARN_ONCE}, |
'\0', NULL, N_("Warn only once per undefined symbol"), TWO_DASHES }, |
{ {"warn-section-align", no_argument, NULL, OPTION_WARN_SECTION_ALIGN}, |
'\0', NULL, N_("Warn if start of section changes due to alignment"), |
TWO_DASHES }, |
{ {"warn-shared-textrel", no_argument, NULL, OPTION_WARN_SHARED_TEXTREL}, |
'\0', NULL, N_("Warn if shared object has DT_TEXTREL"), |
TWO_DASHES }, |
{ {"warn-alternate-em", no_argument, NULL, OPTION_WARN_ALTERNATE_EM}, |
'\0', NULL, N_("Warn if an object has alternate ELF machine code"), |
TWO_DASHES }, |
{ {"warn-unresolved-symbols", no_argument, NULL, |
OPTION_WARN_UNRESOLVED_SYMBOLS}, |
'\0', NULL, N_("Report unresolved symbols as warnings"), TWO_DASHES }, |
{ {"error-unresolved-symbols", no_argument, NULL, |
OPTION_ERROR_UNRESOLVED_SYMBOLS}, |
'\0', NULL, N_("Report unresolved symbols as errors"), TWO_DASHES }, |
{ {"whole-archive", no_argument, NULL, OPTION_WHOLE_ARCHIVE}, |
'\0', NULL, N_("Include all objects from following archives"), |
TWO_DASHES }, |
{ {"wrap", required_argument, NULL, OPTION_WRAP}, |
'\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES }, |
{ {"ignore-unresolved-symbol", required_argument, NULL, |
OPTION_IGNORE_UNRESOLVED_SYMBOL}, |
'\0', N_("SYMBOL"), |
N_("Unresolved SYMBOL will not cause an error or warning"), TWO_DASHES }, |
}; |
#define OPTION_COUNT ARRAY_SIZE (ld_options) |
void |
parse_args (unsigned argc, char **argv) |
{ |
unsigned i; |
int is, il, irl; |
int ingroup = 0; |
char *default_dirlist = NULL; |
char *shortopts; |
struct option *longopts; |
struct option *really_longopts; |
int last_optind; |
enum report_method how_to_report_unresolved_symbols = RM_GENERATE_ERROR; |
shortopts = (char *) xmalloc (OPTION_COUNT * 3 + 2); |
longopts = (struct option *) |
xmalloc (sizeof (*longopts) * (OPTION_COUNT + 1)); |
really_longopts = (struct option *) |
malloc (sizeof (*really_longopts) * (OPTION_COUNT + 1)); |
/* Starting the short option string with '-' is for programs that |
expect options and other ARGV-elements in any order and that care about |
the ordering of the two. We describe each non-option ARGV-element |
as if it were the argument of an option with character code 1. */ |
shortopts[0] = '-'; |
is = 1; |
il = 0; |
irl = 0; |
for (i = 0; i < OPTION_COUNT; i++) |
{ |
if (ld_options[i].shortopt != '\0') |
{ |
shortopts[is] = ld_options[i].shortopt; |
++is; |
if (ld_options[i].opt.has_arg == required_argument |
|| ld_options[i].opt.has_arg == optional_argument) |
{ |
shortopts[is] = ':'; |
++is; |
if (ld_options[i].opt.has_arg == optional_argument) |
{ |
shortopts[is] = ':'; |
++is; |
} |
} |
} |
if (ld_options[i].opt.name != NULL) |
{ |
if (ld_options[i].control == EXACTLY_TWO_DASHES) |
{ |
really_longopts[irl] = ld_options[i].opt; |
++irl; |
} |
else |
{ |
longopts[il] = ld_options[i].opt; |
++il; |
} |
} |
} |
shortopts[is] = '\0'; |
longopts[il].name = NULL; |
really_longopts[irl].name = NULL; |
ldemul_add_options (is, &shortopts, il, &longopts, irl, &really_longopts); |
/* The -G option is ambiguous on different platforms. Sometimes it |
specifies the largest data size to put into the small data |
section. Sometimes it is equivalent to --shared. Unfortunately, |
the first form takes an argument, while the second does not. |
We need to permit the --shared form because on some platforms, |
such as Solaris, gcc -shared will pass -G to the linker. |
To permit either usage, we look through the argument list. If we |
find -G not followed by a number, we change it into --shared. |
This will work for most normal cases. */ |
for (i = 1; i < argc; i++) |
if (strcmp (argv[i], "-G") == 0 |
&& (i + 1 >= argc |
|| ! ISDIGIT (argv[i + 1][0]))) |
argv[i] = (char *) "--shared"; |
/* Because we permit long options to start with a single dash, and |
we have a --library option, and the -l option is conventionally |
used with an immediately following argument, we can have bad |
results if somebody tries to use -l with a library whose name |
happens to start with "ibrary", as in -li. We avoid problems by |
simply turning -l into --library. This means that users will |
have to use two dashes in order to use --library, which is OK |
since that's how it is documented. |
FIXME: It's possible that this problem can arise for other short |
options as well, although the user does always have the recourse |
of adding a space between the option and the argument. */ |
for (i = 1; i < argc; i++) |
{ |
if (argv[i][0] == '-' |
&& argv[i][1] == 'l' |
&& argv[i][2] != '\0') |
{ |
char *n; |
n = (char *) xmalloc (strlen (argv[i]) + 20); |
sprintf (n, "--library=%s", argv[i] + 2); |
argv[i] = n; |
} |
} |
last_optind = -1; |
while (1) |
{ |
int longind; |
int optc; |
static unsigned int defsym_count; |
/* Using last_optind lets us avoid calling ldemul_parse_args |
multiple times on a single option, which would lead to |
confusion in the internal static variables maintained by |
getopt. This could otherwise happen for an argument like |
-nx, in which the -n is parsed as a single option, and we |
loop around to pick up the -x. */ |
if (optind != last_optind) |
if (ldemul_parse_args (argc, argv)) |
continue; |
/* getopt_long_only is like getopt_long, but '-' as well as '--' |
can indicate a long option. */ |
opterr = 0; |
last_optind = optind; |
optc = getopt_long_only (argc, argv, shortopts, longopts, &longind); |
if (optc == '?') |
{ |
optind = last_optind; |
optc = getopt_long (argc, argv, "-", really_longopts, &longind); |
} |
if (ldemul_handle_option (optc)) |
continue; |
if (optc == -1) |
break; |
switch (optc) |
{ |
case '?': |
einfo (_("%P: unrecognized option '%s'\n"), argv[last_optind]); |
/* Fall through. */ |
default: |
einfo (_("%P%F: use the --help option for usage information\n")); |
case 1: /* File name. */ |
lang_add_input_file (optarg, lang_input_file_is_file_enum, NULL); |
break; |
case OPTION_IGNORE: |
break; |
case 'a': |
/* For HP/UX compatibility. Actually -a shared should mean |
``use only shared libraries'' but, then, we don't |
currently support shared libraries on HP/UX anyhow. */ |
if (strcmp (optarg, "archive") == 0) |
input_flags.dynamic = FALSE; |
else if (strcmp (optarg, "shared") == 0 |
|| strcmp (optarg, "default") == 0) |
input_flags.dynamic = TRUE; |
else |
einfo (_("%P%F: unrecognized -a option `%s'\n"), optarg); |
break; |
case OPTION_ASSERT: |
/* FIXME: We just ignore these, but we should handle them. */ |
if (strcmp (optarg, "definitions") == 0) |
; |
else if (strcmp (optarg, "nodefinitions") == 0) |
; |
else if (strcmp (optarg, "nosymbolic") == 0) |
; |
else if (strcmp (optarg, "pure-text") == 0) |
; |
else |
einfo (_("%P%F: unrecognized -assert option `%s'\n"), optarg); |
break; |
case 'A': |
ldfile_add_arch (optarg); |
break; |
case 'b': |
lang_add_target (optarg); |
break; |
case 'c': |
ldfile_open_command_file (optarg); |
parser_input = input_mri_script; |
yyparse (); |
break; |
case OPTION_CALL_SHARED: |
input_flags.dynamic = TRUE; |
break; |
case OPTION_NON_SHARED: |
input_flags.dynamic = FALSE; |
break; |
case OPTION_CREF: |
command_line.cref = TRUE; |
link_info.notice_all = TRUE; |
break; |
case 'd': |
command_line.force_common_definition = TRUE; |
break; |
case OPTION_DEFSYM: |
lex_string = optarg; |
lex_redirect (optarg, "--defsym", ++defsym_count); |
parser_input = input_defsym; |
yyparse (); |
lex_string = NULL; |
break; |
case OPTION_DEMANGLE: |
demangling = TRUE; |
if (optarg != NULL) |
{ |
enum demangling_styles style; |
style = cplus_demangle_name_to_style (optarg); |
if (style == unknown_demangling) |
einfo (_("%F%P: unknown demangling style `%s'\n"), |
optarg); |
cplus_demangle_set_style (style); |
} |
break; |
case 'I': /* Used on Solaris. */ |
case OPTION_DYNAMIC_LINKER: |
command_line.interpreter = optarg; |
break; |
case OPTION_SYSROOT: |
/* Already handled in ldmain.c. */ |
break; |
case OPTION_EB: |
command_line.endian = ENDIAN_BIG; |
break; |
case OPTION_EL: |
command_line.endian = ENDIAN_LITTLE; |
break; |
case OPTION_EMBEDDED_RELOCS: |
command_line.embedded_relocs = TRUE; |
break; |
case OPTION_EXPORT_DYNAMIC: |
case 'E': /* HP/UX compatibility. */ |
link_info.export_dynamic = TRUE; |
break; |
case OPTION_NO_EXPORT_DYNAMIC: |
link_info.export_dynamic = FALSE; |
break; |
case 'e': |
lang_add_entry (optarg, TRUE); |
break; |
case 'f': |
if (command_line.auxiliary_filters == NULL) |
{ |
command_line.auxiliary_filters = (char **) |
xmalloc (2 * sizeof (char *)); |
command_line.auxiliary_filters[0] = optarg; |
command_line.auxiliary_filters[1] = NULL; |
} |
else |
{ |
int c; |
char **p; |
c = 0; |
for (p = command_line.auxiliary_filters; *p != NULL; p++) |
++c; |
command_line.auxiliary_filters = (char **) |
xrealloc (command_line.auxiliary_filters, |
(c + 2) * sizeof (char *)); |
command_line.auxiliary_filters[c] = optarg; |
command_line.auxiliary_filters[c + 1] = NULL; |
} |
break; |
case 'F': |
command_line.filter_shlib = optarg; |
break; |
case OPTION_FORCE_EXE_SUFFIX: |
command_line.force_exe_suffix = TRUE; |
break; |
case 'G': |
{ |
char *end; |
g_switch_value = strtoul (optarg, &end, 0); |
if (*end) |
einfo (_("%P%F: invalid number `%s'\n"), optarg); |
} |
break; |
case 'g': |
/* Ignore. */ |
break; |
case OPTION_GC_SECTIONS: |
link_info.gc_sections = TRUE; |
break; |
case OPTION_PRINT_GC_SECTIONS: |
link_info.print_gc_sections = TRUE; |
break; |
case OPTION_HELP: |
help (); |
xexit (0); |
break; |
case 'L': |
ldfile_add_library_path (optarg, TRUE); |
break; |
case 'l': |
lang_add_input_file (optarg, lang_input_file_is_l_enum, NULL); |
break; |
case 'M': |
config.map_filename = "-"; |
break; |
case 'm': |
/* Ignore. Was handled in a pre-parse. */ |
break; |
case OPTION_MAP: |
config.map_filename = optarg; |
break; |
case 'N': |
config.text_read_only = FALSE; |
config.magic_demand_paged = FALSE; |
input_flags.dynamic = FALSE; |
break; |
case OPTION_NO_OMAGIC: |
config.text_read_only = TRUE; |
config.magic_demand_paged = TRUE; |
/* NB/ Does not set input_flags.dynamic to TRUE. |
Use --call-shared or -Bdynamic for this. */ |
break; |
case 'n': |
config.magic_demand_paged = FALSE; |
input_flags.dynamic = FALSE; |
break; |
case OPTION_NO_DEFINE_COMMON: |
command_line.inhibit_common_definition = TRUE; |
break; |
case OPTION_NO_DEMANGLE: |
demangling = FALSE; |
break; |
case OPTION_NO_GC_SECTIONS: |
link_info.gc_sections = FALSE; |
break; |
case OPTION_NO_PRINT_GC_SECTIONS: |
link_info.print_gc_sections = FALSE; |
break; |
case OPTION_NO_KEEP_MEMORY: |
link_info.keep_memory = FALSE; |
break; |
case OPTION_NO_UNDEFINED: |
link_info.unresolved_syms_in_objects |
= how_to_report_unresolved_symbols; |
break; |
case OPTION_ALLOW_SHLIB_UNDEFINED: |
link_info.unresolved_syms_in_shared_libs = RM_IGNORE; |
break; |
case OPTION_NO_ALLOW_SHLIB_UNDEFINED: |
link_info.unresolved_syms_in_shared_libs |
= how_to_report_unresolved_symbols; |
break; |
case OPTION_UNRESOLVED_SYMBOLS: |
if (strcmp (optarg, "ignore-all") == 0) |
{ |
link_info.unresolved_syms_in_objects = RM_IGNORE; |
link_info.unresolved_syms_in_shared_libs = RM_IGNORE; |
} |
else if (strcmp (optarg, "report-all") == 0) |
{ |
link_info.unresolved_syms_in_objects |
= how_to_report_unresolved_symbols; |
link_info.unresolved_syms_in_shared_libs |
= how_to_report_unresolved_symbols; |
} |
else if (strcmp (optarg, "ignore-in-object-files") == 0) |
{ |
link_info.unresolved_syms_in_objects = RM_IGNORE; |
link_info.unresolved_syms_in_shared_libs |
= how_to_report_unresolved_symbols; |
} |
else if (strcmp (optarg, "ignore-in-shared-libs") == 0) |
{ |
link_info.unresolved_syms_in_objects |
= how_to_report_unresolved_symbols; |
link_info.unresolved_syms_in_shared_libs = RM_IGNORE; |
} |
else |
einfo (_("%P%F: bad --unresolved-symbols option: %s\n"), optarg); |
break; |
case OPTION_WARN_UNRESOLVED_SYMBOLS: |
how_to_report_unresolved_symbols = RM_GENERATE_WARNING; |
if (link_info.unresolved_syms_in_objects == RM_GENERATE_ERROR) |
link_info.unresolved_syms_in_objects = RM_GENERATE_WARNING; |
if (link_info.unresolved_syms_in_shared_libs == RM_GENERATE_ERROR) |
link_info.unresolved_syms_in_shared_libs = RM_GENERATE_WARNING; |
break; |
case OPTION_ERROR_UNRESOLVED_SYMBOLS: |
how_to_report_unresolved_symbols = RM_GENERATE_ERROR; |
if (link_info.unresolved_syms_in_objects == RM_GENERATE_WARNING) |
link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; |
if (link_info.unresolved_syms_in_shared_libs == RM_GENERATE_WARNING) |
link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR; |
break; |
case OPTION_ALLOW_MULTIPLE_DEFINITION: |
link_info.allow_multiple_definition = TRUE; |
break; |
case OPTION_NO_UNDEFINED_VERSION: |
link_info.allow_undefined_version = FALSE; |
break; |
case OPTION_DEFAULT_SYMVER: |
link_info.create_default_symver = TRUE; |
break; |
case OPTION_DEFAULT_IMPORTED_SYMVER: |
link_info.default_imported_symver = TRUE; |
break; |
case OPTION_NO_WARN_MISMATCH: |
command_line.warn_mismatch = FALSE; |
break; |
case OPTION_NO_WARN_SEARCH_MISMATCH: |
command_line.warn_search_mismatch = FALSE; |
break; |
case OPTION_NOINHIBIT_EXEC: |
force_make_executable = TRUE; |
break; |
case OPTION_NOSTDLIB: |
config.only_cmd_line_lib_dirs = TRUE; |
break; |
case OPTION_NO_WHOLE_ARCHIVE: |
input_flags.whole_archive = FALSE; |
break; |
case 'O': |
/* FIXME "-O<non-digits> <value>" used to set the address of |
section <non-digits>. Was this for compatibility with |
something, or can we create a new option to do that |
(with a syntax similar to -defsym)? |
getopt can't handle two args to an option without kludges. */ |
/* Enable optimizations of output files. */ |
link_info.optimize = strtoul (optarg, NULL, 0) ? TRUE : FALSE; |
break; |
case 'o': |
lang_add_output (optarg, 0); |
break; |
case OPTION_OFORMAT: |
lang_add_output_format (optarg, NULL, NULL, 0); |
break; |
case OPTION_PRINT_OUTPUT_FORMAT: |
command_line.print_output_format = TRUE; |
break; |
#ifdef ENABLE_PLUGINS |
case OPTION_PLUGIN: |
plugin_opt_plugin (optarg); |
break; |
case OPTION_PLUGIN_OPT: |
if (plugin_opt_plugin_arg (optarg)) |
einfo(_("%P%F: bad -plugin-opt option\n")); |
break; |
#endif /* ENABLE_PLUGINS */ |
case 'q': |
link_info.emitrelocations = TRUE; |
break; |
case 'i': |
case 'r': |
if (optind == last_optind) |
/* This can happen if the user put "-rpath,a" on the command |
line. (Or something similar. The comma is important). |
Getopt becomes confused and thinks that this is a -r option |
but it cannot parse the text after the -r so it refuses to |
increment the optind counter. Detect this case and issue |
an error message here. We cannot just make this a warning, |
increment optind, and continue because getopt is too confused |
and will seg-fault the next time around. */ |
einfo(_("%P%F: bad -rpath option\n")); |
link_info.relocatable = TRUE; |
config.build_constructors = FALSE; |
config.magic_demand_paged = FALSE; |
config.text_read_only = FALSE; |
input_flags.dynamic = FALSE; |
break; |
case 'R': |
/* The GNU linker traditionally uses -R to mean to include |
only the symbols from a file. The Solaris linker uses -R |
to set the path used by the runtime linker to find |
libraries. This is the GNU linker -rpath argument. We |
try to support both simultaneously by checking the file |
named. If it is a directory, rather than a regular file, |
we assume -rpath was meant. */ |
{ |
struct stat s; |
if (stat (optarg, &s) >= 0 |
&& ! S_ISDIR (s.st_mode)) |
{ |
lang_add_input_file (optarg, |
lang_input_file_is_symbols_only_enum, |
NULL); |
break; |
} |
} |
/* Fall through. */ |
case OPTION_RPATH: |
if (command_line.rpath == NULL) |
command_line.rpath = xstrdup (optarg); |
else |
{ |
size_t rpath_len = strlen (command_line.rpath); |
size_t optarg_len = strlen (optarg); |
char *buf; |
char *cp = command_line.rpath; |
/* First see whether OPTARG is already in the path. */ |
do |
{ |
if (strncmp (optarg, cp, optarg_len) == 0 |
&& (cp[optarg_len] == 0 |
|| cp[optarg_len] == config.rpath_separator)) |
/* We found it. */ |
break; |
/* Not yet found. */ |
cp = strchr (cp, config.rpath_separator); |
if (cp != NULL) |
++cp; |
} |
while (cp != NULL); |
if (cp == NULL) |
{ |
buf = (char *) xmalloc (rpath_len + optarg_len + 2); |
sprintf (buf, "%s%c%s", command_line.rpath, |
config.rpath_separator, optarg); |
free (command_line.rpath); |
command_line.rpath = buf; |
} |
} |
break; |
case OPTION_RPATH_LINK: |
if (command_line.rpath_link == NULL) |
command_line.rpath_link = xstrdup (optarg); |
else |
{ |
char *buf; |
buf = (char *) xmalloc (strlen (command_line.rpath_link) |
+ strlen (optarg) |
+ 2); |
sprintf (buf, "%s%c%s", command_line.rpath_link, |
config.rpath_separator, optarg); |
free (command_line.rpath_link); |
command_line.rpath_link = buf; |
} |
break; |
case OPTION_NO_RELAX: |
DISABLE_RELAXATION; |
break; |
case OPTION_RELAX: |
ENABLE_RELAXATION; |
break; |
case OPTION_RETAIN_SYMBOLS_FILE: |
add_keepsyms_file (optarg); |
break; |
case 'S': |
link_info.strip = strip_debugger; |
break; |
case 's': |
link_info.strip = strip_all; |
break; |
case OPTION_STRIP_DISCARDED: |
link_info.strip_discarded = TRUE; |
break; |
case OPTION_NO_STRIP_DISCARDED: |
link_info.strip_discarded = FALSE; |
break; |
case OPTION_SHARED: |
if (config.has_shared) |
{ |
link_info.shared = TRUE; |
/* When creating a shared library, the default |
behaviour is to ignore any unresolved references. */ |
if (link_info.unresolved_syms_in_objects == RM_NOT_YET_SET) |
link_info.unresolved_syms_in_objects = RM_IGNORE; |
if (link_info.unresolved_syms_in_shared_libs == RM_NOT_YET_SET) |
link_info.unresolved_syms_in_shared_libs = RM_IGNORE; |
} |
else |
einfo (_("%P%F: -shared not supported\n")); |
break; |
case OPTION_PIE: |
if (config.has_shared) |
{ |
link_info.shared = TRUE; |
link_info.pie = TRUE; |
} |
else |
einfo (_("%P%F: -pie not supported\n")); |
break; |
case 'h': /* Used on Solaris. */ |
case OPTION_SONAME: |
command_line.soname = optarg; |
break; |
case OPTION_SORT_COMMON: |
if (optarg == NULL |
|| strcmp (optarg, N_("descending")) == 0) |
config.sort_common = sort_descending; |
else if (strcmp (optarg, N_("ascending")) == 0) |
config.sort_common = sort_ascending; |
else |
einfo (_("%P%F: invalid common section sorting option: %s\n"), |
optarg); |
break; |
case OPTION_SORT_SECTION: |
if (strcmp (optarg, N_("name")) == 0) |
sort_section = by_name; |
else if (strcmp (optarg, N_("alignment")) == 0) |
sort_section = by_alignment; |
else |
einfo (_("%P%F: invalid section sorting option: %s\n"), |
optarg); |
break; |
case OPTION_STATS: |
config.stats = TRUE; |
break; |
case OPTION_SYMBOLIC: |
command_line.symbolic = symbolic; |
break; |
case OPTION_SYMBOLIC_FUNCTIONS: |
command_line.symbolic = symbolic_functions; |
break; |
case 't': |
trace_files = TRUE; |
break; |
case 'T': |
previous_script_handle = saved_script_handle; |
ldfile_open_command_file (optarg); |
parser_input = input_script; |
yyparse (); |
previous_script_handle = NULL; |
break; |
case OPTION_DEFAULT_SCRIPT: |
command_line.default_script = optarg; |
break; |
case OPTION_SECTION_START: |
{ |
char *optarg2; |
char *sec_name; |
int len; |
/* Check for <something>=<somthing>... */ |
optarg2 = strchr (optarg, '='); |
if (optarg2 == NULL) |
einfo (_("%P%F: invalid argument to option" |
" \"--section-start\"\n")); |
optarg2++; |
/* So far so good. Are all the args present? */ |
if ((*optarg == '\0') || (*optarg2 == '\0')) |
einfo (_("%P%F: missing argument(s) to option" |
" \"--section-start\"\n")); |
/* We must copy the section name as set_section_start |
doesn't do it for us. */ |
len = optarg2 - optarg; |
sec_name = (char *) xmalloc (len); |
memcpy (sec_name, optarg, len - 1); |
sec_name[len - 1] = 0; |
/* Then set it... */ |
set_section_start (sec_name, optarg2); |
} |
break; |
case OPTION_TARGET_HELP: |
/* Mention any target specific options. */ |
ldemul_list_emulation_options (stdout); |
exit (0); |
case OPTION_TBSS: |
set_segment_start (".bss", optarg); |
break; |
case OPTION_TDATA: |
set_segment_start (".data", optarg); |
break; |
case OPTION_TTEXT: |
set_segment_start (".text", optarg); |
break; |
case OPTION_TTEXT_SEGMENT: |
set_segment_start (".text-segment", optarg); |
break; |
case OPTION_TRODATA_SEGMENT: |
set_segment_start (".rodata-segment", optarg); |
break; |
case OPTION_TLDATA_SEGMENT: |
set_segment_start (".ldata-segment", optarg); |
break; |
case OPTION_TRADITIONAL_FORMAT: |
link_info.traditional_format = TRUE; |
break; |
case OPTION_TASK_LINK: |
link_info.task_link = TRUE; |
/* Fall through - do an implied -r option. */ |
case OPTION_UR: |
link_info.relocatable = TRUE; |
config.build_constructors = TRUE; |
config.magic_demand_paged = FALSE; |
config.text_read_only = FALSE; |
input_flags.dynamic = FALSE; |
break; |
case 'u': |
ldlang_add_undef (optarg, TRUE); |
break; |
case OPTION_UNIQUE: |
if (optarg != NULL) |
lang_add_unique (optarg); |
else |
config.unique_orphan_sections = TRUE; |
break; |
case OPTION_VERBOSE: |
ldversion (1); |
version_printed = TRUE; |
verbose = TRUE; |
overflow_cutoff_limit = -2; |
if (optarg != NULL) |
{ |
char *end; |
int level ATTRIBUTE_UNUSED = strtoul (optarg, &end, 0); |
if (*end) |
einfo (_("%P%F: invalid number `%s'\n"), optarg); |
#ifdef ENABLE_PLUGINS |
report_plugin_symbols = level > 1; |
#endif /* ENABLE_PLUGINS */ |
} |
break; |
case 'v': |
ldversion (0); |
version_printed = TRUE; |
break; |
case 'V': |
ldversion (1); |
version_printed = TRUE; |
break; |
case OPTION_VERSION: |
ldversion (2); |
xexit (0); |
break; |
case OPTION_VERSION_SCRIPT: |
/* This option indicates a small script that only specifies |
version information. Read it, but don't assume that |
we've seen a linker script. */ |
{ |
FILE *hold_script_handle; |
hold_script_handle = saved_script_handle; |
ldfile_open_command_file (optarg); |
saved_script_handle = hold_script_handle; |
parser_input = input_version_script; |
yyparse (); |
} |
break; |
case OPTION_VERSION_EXPORTS_SECTION: |
/* This option records a version symbol to be applied to the |
symbols listed for export to be found in the object files |
.exports sections. */ |
command_line.version_exports_section = optarg; |
break; |
case OPTION_DYNAMIC_LIST_DATA: |
command_line.dynamic_list = dynamic_list_data; |
if (command_line.symbolic == symbolic) |
command_line.symbolic = symbolic_unset; |
break; |
case OPTION_DYNAMIC_LIST_CPP_TYPEINFO: |
lang_append_dynamic_list_cpp_typeinfo (); |
if (command_line.dynamic_list != dynamic_list_data) |
command_line.dynamic_list = dynamic_list; |
if (command_line.symbolic == symbolic) |
command_line.symbolic = symbolic_unset; |
break; |
case OPTION_DYNAMIC_LIST_CPP_NEW: |
lang_append_dynamic_list_cpp_new (); |
if (command_line.dynamic_list != dynamic_list_data) |
command_line.dynamic_list = dynamic_list; |
if (command_line.symbolic == symbolic) |
command_line.symbolic = symbolic_unset; |
break; |
case OPTION_DYNAMIC_LIST: |
/* This option indicates a small script that only specifies |
a dynamic list. Read it, but don't assume that we've |
seen a linker script. */ |
{ |
FILE *hold_script_handle; |
hold_script_handle = saved_script_handle; |
ldfile_open_command_file (optarg); |
saved_script_handle = hold_script_handle; |
parser_input = input_dynamic_list; |
yyparse (); |
} |
if (command_line.dynamic_list != dynamic_list_data) |
command_line.dynamic_list = dynamic_list; |
if (command_line.symbolic == symbolic) |
command_line.symbolic = symbolic_unset; |
break; |
case OPTION_WARN_COMMON: |
config.warn_common = TRUE; |
break; |
case OPTION_WARN_CONSTRUCTORS: |
config.warn_constructors = TRUE; |
break; |
case OPTION_WARN_FATAL: |
config.fatal_warnings = TRUE; |
break; |
case OPTION_NO_WARN_FATAL: |
config.fatal_warnings = FALSE; |
break; |
case OPTION_WARN_MULTIPLE_GP: |
config.warn_multiple_gp = TRUE; |
break; |
case OPTION_WARN_ONCE: |
config.warn_once = TRUE; |
break; |
case OPTION_WARN_SECTION_ALIGN: |
config.warn_section_align = TRUE; |
break; |
case OPTION_WARN_SHARED_TEXTREL: |
link_info.warn_shared_textrel = TRUE; |
break; |
case OPTION_WARN_ALTERNATE_EM: |
link_info.warn_alternate_em = TRUE; |
break; |
case OPTION_WHOLE_ARCHIVE: |
input_flags.whole_archive = TRUE; |
break; |
case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC: |
input_flags.add_DT_NEEDED_for_dynamic = TRUE; |
break; |
case OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC: |
input_flags.add_DT_NEEDED_for_dynamic = FALSE; |
break; |
case OPTION_ADD_DT_NEEDED_FOR_REGULAR: |
input_flags.add_DT_NEEDED_for_regular = TRUE; |
break; |
case OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR: |
input_flags.add_DT_NEEDED_for_regular = FALSE; |
break; |
case OPTION_WRAP: |
add_wrap (optarg); |
break; |
case OPTION_IGNORE_UNRESOLVED_SYMBOL: |
add_ignoresym (&link_info, optarg); |
break; |
case OPTION_DISCARD_NONE: |
link_info.discard = discard_none; |
break; |
case 'X': |
link_info.discard = discard_l; |
break; |
case 'x': |
link_info.discard = discard_all; |
break; |
case 'Y': |
if (CONST_STRNEQ (optarg, "P,")) |
optarg += 2; |
if (default_dirlist != NULL) |
free (default_dirlist); |
default_dirlist = xstrdup (optarg); |
break; |
case 'y': |
add_ysym (optarg); |
break; |
case OPTION_SPARE_DYNAMIC_TAGS: |
link_info.spare_dynamic_tags = strtoul (optarg, NULL, 0); |
break; |
case OPTION_SPLIT_BY_RELOC: |
if (optarg != NULL) |
config.split_by_reloc = strtoul (optarg, NULL, 0); |
else |
config.split_by_reloc = 32768; |
break; |
case OPTION_SPLIT_BY_FILE: |
if (optarg != NULL) |
config.split_by_file = bfd_scan_vma (optarg, NULL, 0); |
else |
config.split_by_file = 1; |
break; |
case OPTION_CHECK_SECTIONS: |
command_line.check_section_addresses = 1; |
break; |
case OPTION_NO_CHECK_SECTIONS: |
command_line.check_section_addresses = 0; |
break; |
case OPTION_ACCEPT_UNKNOWN_INPUT_ARCH: |
command_line.accept_unknown_input_arch = TRUE; |
break; |
case OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH: |
command_line.accept_unknown_input_arch = FALSE; |
break; |
case '(': |
lang_enter_group (); |
ingroup++; |
break; |
case ')': |
if (! ingroup) |
einfo (_("%P%F: group ended before it began (--help for usage)\n")); |
lang_leave_group (); |
ingroup--; |
break; |
case OPTION_INIT: |
link_info.init_function = optarg; |
break; |
case OPTION_FINI: |
link_info.fini_function = optarg; |
break; |
case OPTION_REDUCE_MEMORY_OVERHEADS: |
link_info.reduce_memory_overheads = TRUE; |
if (config.hash_table_size == 0) |
config.hash_table_size = 1021; |
break; |
case OPTION_HASH_SIZE: |
{ |
bfd_size_type new_size; |
new_size = strtoul (optarg, NULL, 0); |
if (new_size) |
config.hash_table_size = new_size; |
else |
einfo (_("%P%X: --hash-size needs a numeric argument\n")); |
} |
break; |
} |
} |
while (ingroup) |
{ |
lang_leave_group (); |
ingroup--; |
} |
if (default_dirlist != NULL) |
{ |
set_default_dirlist (default_dirlist); |
free (default_dirlist); |
} |
if (link_info.unresolved_syms_in_objects == RM_NOT_YET_SET) |
/* FIXME: Should we allow emulations a chance to set this ? */ |
link_info.unresolved_syms_in_objects = how_to_report_unresolved_symbols; |
if (link_info.unresolved_syms_in_shared_libs == RM_NOT_YET_SET) |
/* FIXME: Should we allow emulations a chance to set this ? */ |
link_info.unresolved_syms_in_shared_libs = how_to_report_unresolved_symbols; |
if (link_info.relocatable) |
{ |
if (command_line.check_section_addresses < 0) |
command_line.check_section_addresses = 0; |
if (link_info.shared) |
einfo (_("%P%F: -r and -shared may not be used together\n")); |
} |
/* We may have -Bsymbolic, -Bsymbolic-functions, --dynamic-list-data, |
--dynamic-list-cpp-new, --dynamic-list-cpp-typeinfo and |
--dynamic-list FILE. -Bsymbolic and -Bsymbolic-functions are |
for shared libraries. -Bsymbolic overrides all others and vice |
versa. */ |
switch (command_line.symbolic) |
{ |
case symbolic_unset: |
break; |
case symbolic: |
/* -Bsymbolic is for shared library only. */ |
if (link_info.shared) |
{ |
link_info.symbolic = TRUE; |
/* Should we free the unused memory? */ |
link_info.dynamic_list = NULL; |
command_line.dynamic_list = dynamic_list_unset; |
} |
break; |
case symbolic_functions: |
/* -Bsymbolic-functions is for shared library only. */ |
if (link_info.shared) |
command_line.dynamic_list = dynamic_list_data; |
break; |
} |
switch (command_line.dynamic_list) |
{ |
case dynamic_list_unset: |
break; |
case dynamic_list_data: |
link_info.dynamic_data = TRUE; |
case dynamic_list: |
link_info.dynamic = TRUE; |
break; |
} |
if (! link_info.shared) |
{ |
if (command_line.filter_shlib) |
einfo (_("%P%F: -F may not be used without -shared\n")); |
if (command_line.auxiliary_filters) |
einfo (_("%P%F: -f may not be used without -shared\n")); |
} |
if (! link_info.shared || link_info.pie) |
link_info.executable = TRUE; |
/* Treat ld -r -s as ld -r -S -x (i.e., strip all local symbols). I |
don't see how else this can be handled, since in this case we |
must preserve all externally visible symbols. */ |
if (link_info.relocatable && link_info.strip == strip_all) |
{ |
link_info.strip = strip_debugger; |
if (link_info.discard == discard_sec_merge) |
link_info.discard = discard_all; |
} |
} |
/* Add the (colon-separated) elements of DIRLIST_PTR to the |
library search path. */ |
static void |
set_default_dirlist (char *dirlist_ptr) |
{ |
char *p; |
while (1) |
{ |
p = strchr (dirlist_ptr, PATH_SEPARATOR); |
if (p != NULL) |
*p = '\0'; |
if (*dirlist_ptr != '\0') |
ldfile_add_library_path (dirlist_ptr, TRUE); |
if (p == NULL) |
break; |
dirlist_ptr = p + 1; |
} |
} |
static void |
set_section_start (char *sect, char *valstr) |
{ |
const char *end; |
bfd_vma val = bfd_scan_vma (valstr, &end, 16); |
if (*end) |
einfo (_("%P%F: invalid hex number `%s'\n"), valstr); |
lang_section_start (sect, exp_intop (val), NULL); |
} |
static void |
set_segment_start (const char *section, char *valstr) |
{ |
const char *name; |
const char *end; |
segment_type *seg; |
bfd_vma val = bfd_scan_vma (valstr, &end, 16); |
if (*end) |
einfo (_("%P%F: invalid hex number `%s'\n"), valstr); |
/* If we already have an entry for this segment, update the existing |
value. */ |
name = section + 1; |
for (seg = segments; seg; seg = seg->next) |
if (strcmp (seg->name, name) == 0) |
{ |
seg->value = val; |
return; |
} |
/* There was no existing value so we must create a new segment |
entry. */ |
seg = (segment_type *) stat_alloc (sizeof (*seg)); |
seg->name = name; |
seg->value = val; |
seg->used = FALSE; |
/* Add it to the linked list of segments. */ |
seg->next = segments; |
segments = seg; |
/* Historically, -Ttext and friends set the base address of a |
particular section. For backwards compatibility, we still do |
that. If a SEGMENT_START directive is seen, the section address |
assignment will be disabled. */ |
lang_section_start (section, exp_intop (val), seg); |
} |
/* Print help messages for the options. */ |
static void |
help (void) |
{ |
unsigned i; |
const char **targets, **pp; |
int len; |
printf (_("Usage: %s [options] file...\n"), program_name); |
printf (_("Options:\n")); |
for (i = 0; i < OPTION_COUNT; i++) |
{ |
if (ld_options[i].doc != NULL) |
{ |
bfd_boolean comma; |
unsigned j; |
printf (" "); |
comma = FALSE; |
len = 2; |
j = i; |
do |
{ |
if (ld_options[j].shortopt != '\0' |
&& ld_options[j].control != NO_HELP) |
{ |
printf ("%s-%c", comma ? ", " : "", ld_options[j].shortopt); |
len += (comma ? 2 : 0) + 2; |
if (ld_options[j].arg != NULL) |
{ |
if (ld_options[j].opt.has_arg != optional_argument) |
{ |
printf (" "); |
++len; |
} |
printf ("%s", _(ld_options[j].arg)); |
len += strlen (_(ld_options[j].arg)); |
} |
comma = TRUE; |
} |
++j; |
} |
while (j < OPTION_COUNT && ld_options[j].doc == NULL); |
j = i; |
do |
{ |
if (ld_options[j].opt.name != NULL |
&& ld_options[j].control != NO_HELP) |
{ |
int two_dashes = |
(ld_options[j].control == TWO_DASHES |
|| ld_options[j].control == EXACTLY_TWO_DASHES); |
printf ("%s-%s%s", |
comma ? ", " : "", |
two_dashes ? "-" : "", |
ld_options[j].opt.name); |
len += ((comma ? 2 : 0) |
+ 1 |
+ (two_dashes ? 1 : 0) |
+ strlen (ld_options[j].opt.name)); |
if (ld_options[j].arg != NULL) |
{ |
printf (" %s", _(ld_options[j].arg)); |
len += 1 + strlen (_(ld_options[j].arg)); |
} |
comma = TRUE; |
} |
++j; |
} |
while (j < OPTION_COUNT && ld_options[j].doc == NULL); |
if (len >= 30) |
{ |
printf ("\n"); |
len = 0; |
} |
for (; len < 30; len++) |
putchar (' '); |
printf ("%s\n", _(ld_options[i].doc)); |
} |
} |
printf (_(" @FILE")); |
for (len = strlen (" @FILE"); len < 30; len++) |
putchar (' '); |
printf (_("Read options from FILE\n")); |
/* Note: Various tools (such as libtool) depend upon the |
format of the listings below - do not change them. */ |
/* xgettext:c-format */ |
printf (_("%s: supported targets:"), program_name); |
targets = bfd_target_list (); |
for (pp = targets; *pp != NULL; pp++) |
printf (" %s", *pp); |
free (targets); |
printf ("\n"); |
/* xgettext:c-format */ |
printf (_("%s: supported emulations: "), program_name); |
ldemul_list_emulations (stdout); |
printf ("\n"); |
/* xgettext:c-format */ |
printf (_("%s: emulation specific options:\n"), program_name); |
ldemul_list_emulation_options (stdout); |
printf ("\n"); |
if (REPORT_BUGS_TO[0]) |
printf (_("Report bugs to %s\n"), REPORT_BUGS_TO); |
} |
/contrib/toolchain/binutils/ld/mri.c |
---|
0,0 → 1,319 |
/* mri.c -- handle MRI style linker scripts |
Copyright 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000, 2001, |
2002, 2003, 2004, 2005, 2007, 2011 Free Software Foundation, Inc. |
Contributed by Steve Chamberlain <sac@cygnus.com>. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This bit does the tree decoration when MRI style link scripts |
are parsed. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "ld.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldmisc.h" |
#include "mri.h" |
#include <ldgram.h> |
#include "libiberty.h" |
struct section_name_struct { |
struct section_name_struct *next; |
const char *name; |
const char *alias; |
etree_type *vma; |
etree_type *align; |
etree_type *subalign; |
int ok_to_load; |
}; |
static unsigned int symbol_truncate = 10000; |
static struct section_name_struct *order; |
static struct section_name_struct *only_load; |
static struct section_name_struct *address; |
static struct section_name_struct *alias; |
static struct section_name_struct *alignment; |
static struct section_name_struct *subalignment; |
static struct section_name_struct ** |
lookup (const char *name, struct section_name_struct **list) |
{ |
struct section_name_struct **ptr = list; |
while (*ptr) |
{ |
if (strcmp (name, (*ptr)->name) == 0) |
/* If this is a match, delete it, we only keep the last instance |
of any name. */ |
*ptr = (*ptr)->next; |
else |
ptr = &((*ptr)->next); |
} |
*ptr = (struct section_name_struct *) |
xmalloc (sizeof (struct section_name_struct)); |
return ptr; |
} |
static void |
mri_add_to_list (struct section_name_struct **list, |
const char *name, |
etree_type *vma, |
const char *zalias, |
etree_type *align, |
etree_type *subalign) |
{ |
struct section_name_struct **ptr = lookup (name, list); |
(*ptr)->name = name; |
(*ptr)->vma = vma; |
(*ptr)->next = NULL; |
(*ptr)->ok_to_load = 0; |
(*ptr)->alias = zalias; |
(*ptr)->align = align; |
(*ptr)->subalign = subalign; |
} |
void |
mri_output_section (const char *name, etree_type *vma) |
{ |
mri_add_to_list (&address, name, vma, 0, 0, 0); |
} |
/* If any ABSOLUTE <name> are in the script, only load those files |
marked thus. */ |
void |
mri_only_load (const char *name) |
{ |
mri_add_to_list (&only_load, name, 0, 0, 0, 0); |
} |
void |
mri_base (etree_type *exp) |
{ |
base = exp; |
} |
static int done_tree = 0; |
void |
mri_draw_tree (void) |
{ |
if (done_tree) |
return; |
/* Now build the statements for the ldlang machine. */ |
/* Attach the addresses of any which have addresses, |
and add the ones not mentioned. */ |
if (address != NULL) |
{ |
struct section_name_struct *alist; |
struct section_name_struct *olist; |
if (order == NULL) |
order = address; |
for (alist = address; |
alist != NULL; |
alist = alist->next) |
{ |
int done = 0; |
for (olist = order; done == 0 && olist != NULL; olist = olist->next) |
{ |
if (strcmp (alist->name, olist->name) == 0) |
{ |
olist->vma = alist->vma; |
done = 1; |
} |
} |
if (!done) |
{ |
/* Add this onto end of order list. */ |
mri_add_to_list (&order, alist->name, alist->vma, 0, 0, 0); |
} |
} |
} |
/* If we're only supposed to load a subset of them in, then prune |
the list. */ |
if (only_load != NULL) |
{ |
struct section_name_struct *ptr1; |
struct section_name_struct *ptr2; |
if (order == NULL) |
order = only_load; |
/* See if this name is in the list, if it is then we can load it. */ |
for (ptr1 = only_load; ptr1; ptr1 = ptr1->next) |
for (ptr2 = order; ptr2; ptr2 = ptr2->next) |
if (strcmp (ptr2->name, ptr1->name) == 0) |
ptr2->ok_to_load = 1; |
} |
else |
{ |
/* No only load list, so everything is ok to load. */ |
struct section_name_struct *ptr; |
for (ptr = order; ptr; ptr = ptr->next) |
ptr->ok_to_load = 1; |
} |
/* Create the order of sections to load. */ |
if (order != NULL) |
{ |
/* Been told to output the sections in a certain order. */ |
struct section_name_struct *p = order; |
while (p) |
{ |
struct section_name_struct *aptr; |
etree_type *align = 0; |
etree_type *subalign = 0; |
struct wildcard_list *tmp; |
/* See if an alignment has been specified. */ |
for (aptr = alignment; aptr; aptr = aptr->next) |
if (strcmp (aptr->name, p->name) == 0) |
align = aptr->align; |
for (aptr = subalignment; aptr; aptr = aptr->next) |
if (strcmp (aptr->name, p->name) == 0) |
subalign = aptr->subalign; |
if (base == 0) |
base = p->vma ? p->vma : exp_nameop (NAME, "."); |
lang_enter_output_section_statement (p->name, base, |
p->ok_to_load ? normal_section : noload_section, |
align, subalign, NULL, 0, 0); |
base = 0; |
tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); |
tmp->next = NULL; |
tmp->spec.name = p->name; |
tmp->spec.exclude_name_list = NULL; |
tmp->spec.sorted = none; |
tmp->spec.section_flag_list = NULL; |
lang_add_wild (NULL, tmp, FALSE); |
/* If there is an alias for this section, add it too. */ |
for (aptr = alias; aptr; aptr = aptr->next) |
if (strcmp (aptr->alias, p->name) == 0) |
{ |
tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); |
tmp->next = NULL; |
tmp->spec.name = aptr->name; |
tmp->spec.exclude_name_list = NULL; |
tmp->spec.sorted = none; |
tmp->spec.section_flag_list = NULL; |
lang_add_wild (NULL, tmp, FALSE); |
} |
lang_leave_output_section_statement (0, "*default*", NULL, NULL); |
p = p->next; |
} |
} |
done_tree = 1; |
} |
void |
mri_load (const char *name) |
{ |
base = 0; |
lang_add_input_file (name, lang_input_file_is_file_enum, NULL); |
} |
void |
mri_order (const char *name) |
{ |
mri_add_to_list (&order, name, 0, 0, 0, 0); |
} |
void |
mri_alias (const char *want, const char *is, int isn) |
{ |
if (!is) |
{ |
char buf[20]; |
/* Some sections are digits. */ |
sprintf (buf, "%d", isn); |
is = xstrdup (buf); |
if (is == NULL) |
abort (); |
} |
mri_add_to_list (&alias, is, 0, want, 0, 0); |
} |
void |
mri_name (const char *name) |
{ |
lang_add_output (name, 1); |
} |
void |
mri_format (const char *name) |
{ |
if (strcmp (name, "S") == 0) |
lang_add_output_format ("srec", NULL, NULL, 1); |
else if (strcmp (name, "IEEE") == 0) |
lang_add_output_format ("ieee", NULL, NULL, 1); |
else if (strcmp (name, "COFF") == 0) |
lang_add_output_format ("coff-m68k", NULL, NULL, 1); |
else |
einfo (_("%P%F: unknown format type %s\n"), name); |
} |
void |
mri_public (const char *name, etree_type *exp) |
{ |
lang_add_assignment (exp_assign (name, exp, FALSE)); |
} |
void |
mri_align (const char *name, etree_type *exp) |
{ |
mri_add_to_list (&alignment, name, 0, 0, exp, 0); |
} |
void |
mri_alignmod (const char *name, etree_type *exp) |
{ |
mri_add_to_list (&subalignment, name, 0, 0, 0, exp); |
} |
void |
mri_truncate (unsigned int exp) |
{ |
symbol_truncate = exp; |
} |
/contrib/toolchain/binutils/ld/mri.h |
---|
0,0 → 1,38 |
/* mri.h -- header file for MRI scripting functions |
Copyright 1993, 1995, 1996, 2003, 2005, 2007 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef MRI_H |
#define MRI_H |
extern void mri_output_section (const char *, etree_type *); |
extern void mri_only_load (const char *); |
extern void mri_base (etree_type *); |
extern void mri_load (const char *); |
extern void mri_order (const char *); |
extern void mri_alias (const char *, const char *, int); |
extern void mri_name (const char *); |
extern void mri_format (const char *); |
extern void mri_public (const char *, etree_type *); |
extern void mri_align (const char *, etree_type *); |
extern void mri_alignmod (const char *, etree_type *); |
extern void mri_truncate (unsigned int); |
extern void mri_draw_tree (void); |
#endif |
/contrib/toolchain/binutils/ld/pe-dll.c |
---|
0,0 → 1,3452 |
/* Routines to help build PEI-format DLLs (Win32 etc) |
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
Written by DJ Delorie <dj@cygnus.com> |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libiberty.h" |
#include "filenames.h" |
#include "safe-ctype.h" |
#include <time.h> |
#include "ld.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldwrite.h" |
#include "ldmisc.h" |
#include <ldgram.h> |
#include "ldmain.h" |
#include "ldfile.h" |
#include "ldemul.h" |
#include "coff/internal.h" |
#include "../bfd/libcoff.h" |
#include "deffile.h" |
#ifdef pe_use_x86_64 |
#define PE_IDATA4_SIZE 8 |
#define PE_IDATA5_SIZE 8 |
#include "pep-dll.h" |
#undef AOUTSZ |
#define AOUTSZ PEPAOUTSZ |
#define PEAOUTHDR PEPAOUTHDR |
#else |
#include "pe-dll.h" |
#endif |
#ifndef PE_IDATA4_SIZE |
#define PE_IDATA4_SIZE 4 |
#endif |
#ifndef PE_IDATA5_SIZE |
#define PE_IDATA5_SIZE 4 |
#endif |
/* This file turns a regular Windows PE image into a DLL. Because of |
the complexity of this operation, it has been broken down into a |
number of separate modules which are all called by the main function |
at the end of this file. This function is not re-entrant and is |
normally only called once, so static variables are used to reduce |
the number of parameters and return values required. |
See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ |
/* Auto-import feature by Paul Sokolovsky |
Quick facts: |
1. With this feature on, DLL clients can import variables from DLL |
without any concern from their side (for example, without any source |
code modifications). |
2. This is done completely in bounds of the PE specification (to be fair, |
there's a place where it pokes nose out of, but in practice it works). |
So, resulting module can be used with any other PE compiler/linker. |
3. Auto-import is fully compatible with standard import method and they |
can be mixed together. |
4. Overheads: space: 8 bytes per imported symbol, plus 20 for each |
reference to it; load time: negligible; virtual/physical memory: should be |
less than effect of DLL relocation, and I sincerely hope it doesn't affect |
DLL sharability (too much). |
Idea |
The obvious and only way to get rid of dllimport insanity is to make client |
access variable directly in the DLL, bypassing extra dereference. I.e., |
whenever client contains something like |
mov dll_var,%eax, |
address of dll_var in the command should be relocated to point into loaded |
DLL. The aim is to make OS loader do so, and than make ld help with that. |
Import section of PE made following way: there's a vector of structures |
each describing imports from particular DLL. Each such structure points |
to two other parallel vectors: one holding imported names, and one which |
will hold address of corresponding imported name. So, the solution is |
de-vectorize these structures, making import locations be sparse and |
pointing directly into code. Before continuing, it is worth a note that, |
while authors strives to make PE act ELF-like, there're some other people |
make ELF act PE-like: elfvector, ;-) . |
Implementation |
For each reference of data symbol to be imported from DLL (to set of which |
belong symbols with name <sym>, if __imp_<sym> is found in implib), the |
import fixup entry is generated. That entry is of type |
IMAGE_IMPORT_DESCRIPTOR and stored in .idata$2 subsection. Each |
fixup entry contains pointer to symbol's address within .text section |
(marked with __fuN_<sym> symbol, where N is integer), pointer to DLL name |
(so, DLL name is referenced by multiple entries), and pointer to symbol |
name thunk. Symbol name thunk is singleton vector (__nm_th_<symbol>) |
pointing to IMAGE_IMPORT_BY_NAME structure (__nm_<symbol>) directly |
containing imported name. Here comes that "on the edge" problem mentioned |
above: PE specification rambles that name vector (OriginalFirstThunk) |
should run in parallel with addresses vector (FirstThunk), i.e. that they |
should have same number of elements and terminated with zero. We violate |
this, since FirstThunk points directly into machine code. But in practice, |
OS loader implemented the sane way: it goes thru OriginalFirstThunk and |
puts addresses to FirstThunk, not something else. It once again should be |
noted that dll and symbol name structures are reused across fixup entries |
and should be there anyway to support standard import stuff, so sustained |
overhead is 20 bytes per reference. Other question is whether having several |
IMAGE_IMPORT_DESCRIPTORS for the same DLL is possible. Answer is yes, it is |
done even by native compiler/linker (libth32's functions are in fact reside |
in windows9x kernel32.dll, so if you use it, you have two |
IMAGE_IMPORT_DESCRIPTORS for kernel32.dll). Yet other question is whether |
referencing the same PE structures several times is valid. The answer is why |
not, prohibiting that (detecting violation) would require more work on |
behalf of loader than not doing it. |
See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ |
static void add_bfd_to_link (bfd *, const char *, struct bfd_link_info *); |
/* For emultempl/pe.em. */ |
def_file * pe_def_file = 0; |
int pe_dll_export_everything = 0; |
int pe_dll_exclude_all_symbols = 0; |
int pe_dll_do_default_excludes = 1; |
int pe_dll_kill_ats = 0; |
int pe_dll_stdcall_aliases = 0; |
int pe_dll_warn_dup_exports = 0; |
int pe_dll_compat_implib = 0; |
int pe_dll_extra_pe_debug = 0; |
int pe_use_nul_prefixed_import_tables = 0; |
int pe_use_coff_long_section_names = -1; |
int pe_leading_underscore = -1; |
/* Static variables and types. */ |
static bfd_vma image_base; |
static bfd *filler_bfd; |
static struct bfd_section *edata_s, *reloc_s; |
static unsigned char *edata_d, *reloc_d; |
static size_t edata_sz, reloc_sz; |
static int runtime_pseudo_relocs_created = 0; |
static int runtime_pseudp_reloc_v2_init = 0; |
typedef struct |
{ |
const char *name; |
int len; |
} |
autofilter_entry_type; |
typedef struct |
{ |
const char *target_name; |
const char *object_target; |
unsigned int imagebase_reloc; |
int pe_arch; |
int bfd_arch; |
bfd_boolean underscored; |
const autofilter_entry_type* autofilter_symbollist; |
} |
pe_details_type; |
static const autofilter_entry_type autofilter_symbollist_generic[] = |
{ |
{ STRING_COMMA_LEN ("_NULL_IMPORT_DESCRIPTOR") }, |
/* Entry point symbols. */ |
{ STRING_COMMA_LEN ("DllMain") }, |
{ STRING_COMMA_LEN ("DllMainCRTStartup") }, |
{ STRING_COMMA_LEN ("_DllMainCRTStartup") }, |
/* Runtime pseudo-reloc. */ |
{ STRING_COMMA_LEN ("_pei386_runtime_relocator") }, |
{ STRING_COMMA_LEN ("do_pseudo_reloc") }, |
{ NULL, 0 } |
}; |
static const autofilter_entry_type autofilter_symbollist_i386[] = |
{ |
{ STRING_COMMA_LEN ("_NULL_IMPORT_DESCRIPTOR") }, |
/* Entry point symbols, and entry hooks. */ |
{ STRING_COMMA_LEN ("cygwin_crt0") }, |
#ifdef pe_use_x86_64 |
{ STRING_COMMA_LEN ("DllMain") }, |
{ STRING_COMMA_LEN ("DllEntryPoint") }, |
{ STRING_COMMA_LEN ("DllMainCRTStartup") }, |
{ STRING_COMMA_LEN ("_cygwin_dll_entry") }, |
{ STRING_COMMA_LEN ("_cygwin_crt0_common") }, |
{ STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry") }, |
#else |
{ STRING_COMMA_LEN ("DllMain@12") }, |
{ STRING_COMMA_LEN ("DllEntryPoint@0") }, |
{ STRING_COMMA_LEN ("DllMainCRTStartup@12") }, |
{ STRING_COMMA_LEN ("_cygwin_dll_entry@12") }, |
{ STRING_COMMA_LEN ("_cygwin_crt0_common@8") }, |
{ STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry@12") }, |
{ STRING_COMMA_LEN ("cygwin_attach_dll") }, |
#endif |
{ STRING_COMMA_LEN ("cygwin_premain0") }, |
{ STRING_COMMA_LEN ("cygwin_premain1") }, |
{ STRING_COMMA_LEN ("cygwin_premain2") }, |
{ STRING_COMMA_LEN ("cygwin_premain3") }, |
/* Runtime pseudo-reloc. */ |
{ STRING_COMMA_LEN ("_pei386_runtime_relocator") }, |
{ STRING_COMMA_LEN ("do_pseudo_reloc") }, |
/* Global vars that should not be exported. */ |
{ STRING_COMMA_LEN ("impure_ptr") }, |
{ STRING_COMMA_LEN ("_impure_ptr") }, |
{ STRING_COMMA_LEN ("_fmode") }, |
{ STRING_COMMA_LEN ("environ") }, |
{ NULL, 0 } |
}; |
#define PE_ARCH_i386 1 |
#define PE_ARCH_sh 2 |
#define PE_ARCH_mips 3 |
#define PE_ARCH_arm 4 |
#define PE_ARCH_arm_epoc 5 |
#define PE_ARCH_arm_wince 6 |
/* Don't make it constant as underscore mode gets possibly overriden |
by target or -(no-)leading-underscore option. */ |
static pe_details_type pe_detail_list[] = |
{ |
{ |
#ifdef pe_use_x86_64 |
"pei-x86-64", |
"pe-x86-64", |
3 /* R_IMAGEBASE */, |
#else |
"pei-i386", |
"pe-i386", |
7 /* R_IMAGEBASE */, |
#endif |
PE_ARCH_i386, |
bfd_arch_i386, |
#ifdef pe_use_x86_64 |
FALSE, |
#else |
TRUE, |
#endif |
autofilter_symbollist_i386 |
}, |
{ |
"pei-shl", |
"pe-shl", |
16 /* R_SH_IMAGEBASE */, |
PE_ARCH_sh, |
bfd_arch_sh, |
TRUE, |
autofilter_symbollist_generic |
}, |
{ |
"pei-mips", |
"pe-mips", |
34 /* MIPS_R_RVA */, |
PE_ARCH_mips, |
bfd_arch_mips, |
FALSE, |
autofilter_symbollist_generic |
}, |
{ |
"pei-arm-little", |
"pe-arm-little", |
11 /* ARM_RVA32 */, |
PE_ARCH_arm, |
bfd_arch_arm, |
TRUE, |
autofilter_symbollist_generic |
}, |
{ |
"epoc-pei-arm-little", |
"epoc-pe-arm-little", |
11 /* ARM_RVA32 */, |
PE_ARCH_arm_epoc, |
bfd_arch_arm, |
FALSE, |
autofilter_symbollist_generic |
}, |
{ |
"pei-arm-wince-little", |
"pe-arm-wince-little", |
2, /* ARM_RVA32 on Windows CE, see bfd/coff-arm.c. */ |
PE_ARCH_arm_wince, |
bfd_arch_arm, |
FALSE, |
autofilter_symbollist_generic |
}, |
{ NULL, NULL, 0, 0, 0, FALSE, NULL } |
}; |
static const pe_details_type *pe_details; |
/* Do not specify library suffix explicitly, to allow for dllized versions. */ |
static const autofilter_entry_type autofilter_liblist[] = |
{ |
{ STRING_COMMA_LEN ("libcegcc") }, |
{ STRING_COMMA_LEN ("libcygwin") }, |
{ STRING_COMMA_LEN ("libgcc") }, |
{ STRING_COMMA_LEN ("libgcc_s") }, |
{ STRING_COMMA_LEN ("libstdc++") }, |
{ STRING_COMMA_LEN ("libmingw32") }, |
{ STRING_COMMA_LEN ("libmingwex") }, |
{ STRING_COMMA_LEN ("libg2c") }, |
{ STRING_COMMA_LEN ("libsupc++") }, |
{ STRING_COMMA_LEN ("libobjc") }, |
{ STRING_COMMA_LEN ("libgcj") }, |
{ NULL, 0 } |
}; |
/* Regardless of the suffix issue mentioned above, we must ensure that |
we do not falsely match on a leading substring, such as when libtool |
builds libstdc++ as a DLL using libsupc++convenience.a as an intermediate. |
This routine ensures that the leading part of the name matches and that |
it is followed by only an optional version suffix and a file extension, |
returning zero if so or -1 if not. */ |
static int libnamencmp (const char *libname, const autofilter_entry_type *afptr) |
{ |
if (filename_ncmp (libname, afptr->name, afptr->len)) |
return -1; |
libname += afptr->len; |
/* Be liberal in interpreting what counts as a version suffix; we |
accept anything that has a dash to separate it from the name and |
begins with a digit. */ |
if (libname[0] == '-') |
{ |
if (!ISDIGIT (*++libname)) |
return -1; |
/* Ensure the filename has an extension. */ |
while (*++libname != '.') |
if (!*libname) |
return -1; |
} |
else if (libname[0] != '.') |
return -1; |
return 0; |
} |
static const autofilter_entry_type autofilter_objlist[] = |
{ |
{ STRING_COMMA_LEN ("crt0.o") }, |
{ STRING_COMMA_LEN ("crt1.o") }, |
{ STRING_COMMA_LEN ("crt2.o") }, |
{ STRING_COMMA_LEN ("dllcrt1.o") }, |
{ STRING_COMMA_LEN ("dllcrt2.o") }, |
{ STRING_COMMA_LEN ("gcrt0.o") }, |
{ STRING_COMMA_LEN ("gcrt1.o") }, |
{ STRING_COMMA_LEN ("gcrt2.o") }, |
{ STRING_COMMA_LEN ("crtbegin.o") }, |
{ STRING_COMMA_LEN ("crtend.o") }, |
{ NULL, 0 } |
}; |
static const autofilter_entry_type autofilter_symbolprefixlist[] = |
{ |
/* _imp_ is treated specially, as it is always underscored. */ |
/* { STRING_COMMA_LEN ("_imp_") }, */ |
/* Don't export some c++ symbols. */ |
{ STRING_COMMA_LEN ("__rtti_") }, |
{ STRING_COMMA_LEN ("__builtin_") }, |
/* Don't re-export auto-imported symbols. */ |
{ STRING_COMMA_LEN ("__nm_") }, |
/* Don't export symbols specifying internal DLL layout. */ |
{ STRING_COMMA_LEN ("_head_") }, |
{ STRING_COMMA_LEN ("_IMPORT_DESCRIPTOR_") }, |
/* Don't export section labels or artificial symbols |
(eg ".weak.foo". */ |
{ STRING_COMMA_LEN (".") }, |
{ NULL, 0 } |
}; |
static const autofilter_entry_type autofilter_symbolsuffixlist[] = |
{ |
{ STRING_COMMA_LEN ("_iname") }, |
{ STRING_COMMA_LEN ("_NULL_THUNK_DATA") }, |
{ NULL, 0 } |
}; |
#define U(str) (pe_details->underscored ? "_" str : str) |
void |
pe_dll_id_target (const char *target) |
{ |
int i; |
for (i = 0; pe_detail_list[i].target_name; i++) |
if (strcmp (pe_detail_list[i].target_name, target) == 0 |
|| strcmp (pe_detail_list[i].object_target, target) == 0) |
{ |
int u = pe_leading_underscore; /* Underscoring mode. -1 for use default. */ |
if (u == -1) |
bfd_get_target_info (target, NULL, NULL, &u, NULL); |
if (u == -1) |
abort (); |
pe_detail_list[i].underscored = (u != 0 ? TRUE : FALSE); |
pe_details = pe_detail_list + i; |
pe_leading_underscore = (u != 0 ? 1 : 0); |
return; |
} |
einfo (_("%XUnsupported PEI architecture: %s\n"), target); |
exit (1); |
} |
/* Helper functions for qsort. Relocs must be sorted so that we can write |
them out by pages. */ |
typedef struct |
{ |
bfd_vma vma; |
char type; |
short extra; |
} |
reloc_data_type; |
static int |
reloc_sort (const void *va, const void *vb) |
{ |
bfd_vma a = ((const reloc_data_type *) va)->vma; |
bfd_vma b = ((const reloc_data_type *) vb)->vma; |
return (a > b) ? 1 : ((a < b) ? -1 : 0); |
} |
static int |
pe_export_sort (const void *va, const void *vb) |
{ |
const def_file_export *a = va; |
const def_file_export *b = vb; |
char *an = a->name; |
char *bn = b->name; |
if (a->its_name) |
an = a->its_name; |
if (b->its_name) |
bn = b->its_name; |
return strcmp (an, bn); |
} |
/* Read and process the .DEF file. */ |
/* These correspond to the entries in pe_def_file->exports[]. I use |
exported_symbol_sections[i] to tag whether or not the symbol was |
defined, since we can't export symbols we don't have. */ |
static bfd_vma *exported_symbol_offsets; |
static struct bfd_section **exported_symbol_sections; |
static int export_table_size; |
static int count_exported; |
static int count_exported_byname; |
static int count_with_ordinals; |
static const char *dll_name; |
static int min_ordinal, max_ordinal; |
static int *exported_symbols; |
typedef struct exclude_list_struct |
{ |
char *string; |
struct exclude_list_struct *next; |
exclude_type type; |
} |
exclude_list_struct; |
static struct exclude_list_struct *excludes = 0; |
void |
pe_dll_add_excludes (const char *new_excludes, const exclude_type type) |
{ |
char *local_copy; |
char *exclude_string; |
local_copy = xstrdup (new_excludes); |
exclude_string = strtok (local_copy, ",:"); |
for (; exclude_string; exclude_string = strtok (NULL, ",:")) |
{ |
struct exclude_list_struct *new_exclude; |
new_exclude = xmalloc (sizeof (struct exclude_list_struct)); |
new_exclude->string = xmalloc (strlen (exclude_string) + 1); |
strcpy (new_exclude->string, exclude_string); |
new_exclude->type = type; |
new_exclude->next = excludes; |
excludes = new_exclude; |
} |
free (local_copy); |
} |
static bfd_boolean |
is_import (const char* n) |
{ |
return (CONST_STRNEQ (n, "__imp_")); |
} |
/* abfd is a bfd containing n (or NULL) |
It can be used for contextual checks. */ |
static int |
auto_export (bfd *abfd, def_file *d, const char *n) |
{ |
def_file_export key; |
struct exclude_list_struct *ex; |
const autofilter_entry_type *afptr; |
const char * libname = NULL; |
if (abfd && abfd->my_archive) |
libname = lbasename (abfd->my_archive->filename); |
key.name = key.its_name = (char *) n; |
/* Return false if n is in the d->exports table. */ |
if (bsearch (&key, d->exports, d->num_exports, |
sizeof (pe_def_file->exports[0]), pe_export_sort)) |
return 0; |
if (pe_dll_do_default_excludes) |
{ |
const char * p; |
int len; |
if (pe_dll_extra_pe_debug) |
printf ("considering exporting: %s, abfd=%p, abfd->my_arc=%p\n", |
n, abfd, abfd->my_archive); |
/* First of all, make context checks: |
Don't export anything from standard libs. */ |
if (libname) |
{ |
afptr = autofilter_liblist; |
while (afptr->name) |
{ |
if (libnamencmp (libname, afptr) == 0 ) |
return 0; |
afptr++; |
} |
} |
/* Next, exclude symbols from certain startup objects. */ |
if (abfd && (p = lbasename (abfd->filename))) |
{ |
afptr = autofilter_objlist; |
while (afptr->name) |
{ |
if (strcmp (p, afptr->name) == 0) |
return 0; |
afptr++; |
} |
} |
/* Don't try to blindly exclude all symbols |
that begin with '__'; this was tried and |
it is too restrictive. Instead we have |
a target specific list to use: */ |
afptr = pe_details->autofilter_symbollist; |
while (afptr->name) |
{ |
if (strcmp (n, afptr->name) == 0) |
return 0; |
afptr++; |
} |
/* Next, exclude symbols starting with ... */ |
afptr = autofilter_symbolprefixlist; |
while (afptr->name) |
{ |
if (strncmp (n, afptr->name, afptr->len) == 0) |
return 0; |
afptr++; |
} |
/* Finally, exclude symbols ending with ... */ |
len = strlen (n); |
afptr = autofilter_symbolsuffixlist; |
while (afptr->name) |
{ |
if ((len >= afptr->len) |
/* Add 1 to insure match with trailing '\0'. */ |
&& strncmp (n + len - afptr->len, afptr->name, |
afptr->len + 1) == 0) |
return 0; |
afptr++; |
} |
} |
for (ex = excludes; ex; ex = ex->next) |
{ |
if (ex->type == EXCLUDELIBS) |
{ |
if (libname |
&& ((filename_cmp (libname, ex->string) == 0) |
|| (strcasecmp ("ALL", ex->string) == 0))) |
return 0; |
} |
else if (ex->type == EXCLUDEFORIMPLIB) |
{ |
if (filename_cmp (abfd->filename, ex->string) == 0) |
return 0; |
} |
else if (strcmp (n, ex->string) == 0) |
return 0; |
} |
return 1; |
} |
static void |
process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
{ |
int i, j; |
struct bfd_link_hash_entry *blhe; |
bfd *b; |
struct bfd_section *s; |
def_file_export *e = 0; |
bfd_boolean resort_needed; |
if (!pe_def_file) |
pe_def_file = def_file_empty (); |
/* First, run around to all the objects looking for the .drectve |
sections, and push those into the def file too. */ |
for (b = info->input_bfds; b; b = b->link_next) |
{ |
s = bfd_get_section_by_name (b, ".drectve"); |
if (s) |
{ |
long size = s->size; |
char *buf = xmalloc (size); |
bfd_get_section_contents (b, s, buf, 0, size); |
def_file_add_directive (pe_def_file, buf, size); |
free (buf); |
} |
} |
/* Process aligned common symbol information from the |
.drectve sections now; common symbol allocation is |
done before final link, so it will be too late to |
process them in process_embedded_commands() called |
from _bfd_coff_link_input_bfd(). */ |
if (pe_def_file->aligncomms) |
{ |
def_file_aligncomm *ac = pe_def_file->aligncomms; |
while (ac) |
{ |
struct coff_link_hash_entry *sym_hash; |
sym_hash = coff_link_hash_lookup (coff_hash_table (info), |
ac->symbol_name, FALSE, FALSE, FALSE); |
if (sym_hash && sym_hash->root.type == bfd_link_hash_common |
&& sym_hash->root.u.c.p->alignment_power < (unsigned) ac->alignment) |
{ |
sym_hash->root.u.c.p->alignment_power = (unsigned) ac->alignment; |
} |
ac = ac->next; |
} |
} |
/* If we are building an executable and there is nothing |
to export, we do not build an export table at all. */ |
if (info->executable && pe_def_file->num_exports == 0 |
&& (!pe_dll_export_everything || pe_dll_exclude_all_symbols)) |
return; |
/* Now, maybe export everything else the default way. */ |
if ((pe_dll_export_everything || pe_def_file->num_exports == 0) |
&& !pe_dll_exclude_all_symbols) |
{ |
for (b = info->input_bfds; b; b = b->link_next) |
{ |
asymbol **symbols; |
int nsyms; |
if (!bfd_generic_link_read_symbols (b)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), b); |
return; |
} |
symbols = bfd_get_outsymbols (b); |
nsyms = bfd_get_symcount (b); |
for (j = 0; j < nsyms; j++) |
{ |
/* We should export symbols which are either global or not |
anything at all. (.bss data is the latter) |
We should not export undefined symbols. */ |
bfd_boolean would_export |
= (symbols[j]->section != bfd_und_section_ptr |
&& ((symbols[j]->flags & BSF_GLOBAL) |
|| (symbols[j]->flags == 0))); |
if (link_info.version_info && would_export) |
would_export |
= !bfd_hide_sym_by_version (link_info.version_info, |
symbols[j]->name); |
if (would_export) |
{ |
const char *sn = symbols[j]->name; |
/* We should not re-export imported stuff. */ |
{ |
char *name; |
if (is_import (sn)) |
continue; |
name = xmalloc (strlen ("__imp_") + strlen (sn) + 1); |
sprintf (name, "%s%s", "__imp_", sn); |
blhe = bfd_link_hash_lookup (info->hash, name, |
FALSE, FALSE, FALSE); |
free (name); |
if (blhe && blhe->type == bfd_link_hash_defined) |
continue; |
} |
if (pe_details->underscored && *sn == '_') |
sn++; |
if (auto_export (b, pe_def_file, sn)) |
{ |
int is_dup = 0; |
def_file_export *p; |
p = def_file_add_export (pe_def_file, sn, 0, -1, |
NULL, &is_dup); |
/* Fill data flag properly, from dlltool.c. */ |
if (!is_dup) |
p->flag_data = !(symbols[j]->flags & BSF_FUNCTION); |
} |
} |
} |
} |
} |
#undef NE |
#define NE pe_def_file->num_exports |
/* Don't create an empty export table. */ |
if (NE == 0) |
return; |
resort_needed = FALSE; |
/* Canonicalize the export list. */ |
if (pe_dll_kill_ats) |
{ |
for (i = 0; i < NE; i++) |
{ |
/* Check for fastcall/stdcall-decoration, but ignore |
C++ mangled names. */ |
if (pe_def_file->exports[i].name[0] != '?' |
&& strchr (pe_def_file->exports[i].name, '@')) |
{ |
/* This will preserve internal_name, which may have been |
pointing to the same memory as name, or might not |
have. */ |
int lead_at = (*pe_def_file->exports[i].name == '@'); |
char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); |
char *tmp_at = strrchr (tmp, '@'); |
if (tmp_at) |
*tmp_at = 0; |
else |
einfo (_("%XCannot export %s: invalid export name\n"), |
pe_def_file->exports[i].name); |
pe_def_file->exports[i].name = tmp; |
resort_needed = TRUE; |
} |
} |
} |
/* Re-sort the exports table as we have possibly changed the order |
by removing leading @. */ |
if (resort_needed) |
qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), |
pe_export_sort); |
if (pe_dll_stdcall_aliases) |
{ |
for (i = 0; i < NE; i++) |
{ |
if (is_import (pe_def_file->exports[i].name)) |
continue; |
if (strchr (pe_def_file->exports[i].name, '@')) |
{ |
int is_dup = 1; |
int lead_at = (*pe_def_file->exports[i].name == '@'); |
char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); |
*(strchr (tmp, '@')) = 0; |
if (auto_export (NULL, pe_def_file, tmp)) |
def_file_add_export (pe_def_file, tmp, |
pe_def_file->exports[i].internal_name, |
-1, NULL, &is_dup); |
if (is_dup) |
free (tmp); |
} |
} |
} |
/* Convenience, but watch out for it changing. */ |
e = pe_def_file->exports; |
for (i = 0, j = 0; i < NE; i++) |
{ |
if (i > 0 && strcmp (e[i].name, e[i - 1].name) == 0) |
{ |
/* This is a duplicate. */ |
if (e[j - 1].ordinal != -1 |
&& e[i].ordinal != -1 |
&& e[j - 1].ordinal != e[i].ordinal) |
{ |
if (pe_dll_warn_dup_exports) |
/* xgettext:c-format */ |
einfo (_("%XError, duplicate EXPORT with ordinals: %s (%d vs %d)\n"), |
e[j - 1].name, e[j - 1].ordinal, e[i].ordinal); |
} |
else |
{ |
if (pe_dll_warn_dup_exports) |
/* xgettext:c-format */ |
einfo (_("Warning, duplicate EXPORT: %s\n"), |
e[j - 1].name); |
} |
if (e[i].ordinal != -1) |
e[j - 1].ordinal = e[i].ordinal; |
e[j - 1].flag_private |= e[i].flag_private; |
e[j - 1].flag_constant |= e[i].flag_constant; |
e[j - 1].flag_noname |= e[i].flag_noname; |
e[j - 1].flag_data |= e[i].flag_data; |
if (e[i].name) |
free (e[i].name); |
if (e[i].internal_name) |
free (e[i].internal_name); |
if (e[i].its_name) |
free (e[i].its_name); |
} |
else |
{ |
if (i != j) |
e[j] = e[i]; |
j++; |
} |
} |
pe_def_file->num_exports = j; /* == NE */ |
exported_symbol_offsets = xmalloc (NE * sizeof (bfd_vma)); |
exported_symbol_sections = xmalloc (NE * sizeof (struct bfd_section *)); |
memset (exported_symbol_sections, 0, NE * sizeof (struct bfd_section *)); |
max_ordinal = 0; |
min_ordinal = 65536; |
count_exported = 0; |
count_exported_byname = 0; |
count_with_ordinals = 0; |
for (i = 0; i < NE; i++) |
{ |
char *name; |
name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); |
if (pe_details->underscored |
&& (*pe_def_file->exports[i].internal_name != '@')) |
{ |
*name = '_'; |
strcpy (name + 1, pe_def_file->exports[i].internal_name); |
} |
else |
strcpy (name, pe_def_file->exports[i].internal_name); |
blhe = bfd_link_hash_lookup (info->hash, |
name, |
FALSE, FALSE, TRUE); |
if (blhe |
&& (blhe->type == bfd_link_hash_defined |
|| (blhe->type == bfd_link_hash_common))) |
{ |
count_exported++; |
if (!pe_def_file->exports[i].flag_noname) |
count_exported_byname++; |
/* Only fill in the sections. The actual offsets are computed |
in fill_exported_offsets() after common symbols are laid |
out. */ |
if (blhe->type == bfd_link_hash_defined) |
exported_symbol_sections[i] = blhe->u.def.section; |
else |
exported_symbol_sections[i] = blhe->u.c.p->section; |
if (pe_def_file->exports[i].ordinal != -1) |
{ |
if (max_ordinal < pe_def_file->exports[i].ordinal) |
max_ordinal = pe_def_file->exports[i].ordinal; |
if (min_ordinal > pe_def_file->exports[i].ordinal) |
min_ordinal = pe_def_file->exports[i].ordinal; |
count_with_ordinals++; |
} |
} |
/* Check for forward exports. These are indicated in DEF files by an |
export directive of the form NAME1 = MODULE-NAME.EXTERNAL-NAME |
but we must take care not to be fooled when the user wants to export |
a symbol that actually really has a dot in it, so we only check |
for them here, after real defined symbols have already been matched. */ |
else if (strchr (pe_def_file->exports[i].internal_name, '.')) |
{ |
count_exported++; |
if (!pe_def_file->exports[i].flag_noname) |
count_exported_byname++; |
pe_def_file->exports[i].flag_forward = 1; |
if (pe_def_file->exports[i].ordinal != -1) |
{ |
if (max_ordinal < pe_def_file->exports[i].ordinal) |
max_ordinal = pe_def_file->exports[i].ordinal; |
if (min_ordinal > pe_def_file->exports[i].ordinal) |
min_ordinal = pe_def_file->exports[i].ordinal; |
count_with_ordinals++; |
} |
} |
else if (blhe && blhe->type == bfd_link_hash_undefined) |
{ |
/* xgettext:c-format */ |
einfo (_("%XCannot export %s: symbol not defined\n"), |
pe_def_file->exports[i].internal_name); |
} |
else if (blhe) |
{ |
/* xgettext:c-format */ |
einfo (_("%XCannot export %s: symbol wrong type (%d vs %d)\n"), |
pe_def_file->exports[i].internal_name, |
blhe->type, bfd_link_hash_defined); |
} |
else |
{ |
/* xgettext:c-format */ |
einfo (_("%XCannot export %s: symbol not found\n"), |
pe_def_file->exports[i].internal_name); |
} |
free (name); |
} |
} |
/* Build the bfd that will contain .edata and .reloc sections. */ |
static void |
build_filler_bfd (int include_edata) |
{ |
lang_input_statement_type *filler_file; |
filler_file = lang_add_input_file ("dll stuff", |
lang_input_file_is_fake_enum, |
NULL); |
filler_file->the_bfd = filler_bfd = bfd_create ("dll stuff", |
link_info.output_bfd); |
if (filler_bfd == NULL |
|| !bfd_set_arch_mach (filler_bfd, |
bfd_get_arch (link_info.output_bfd), |
bfd_get_mach (link_info.output_bfd))) |
{ |
einfo ("%X%P: can not create BFD: %E\n"); |
return; |
} |
if (include_edata) |
{ |
edata_s = bfd_make_section_old_way (filler_bfd, ".edata"); |
if (edata_s == NULL |
|| !bfd_set_section_flags (filler_bfd, edata_s, |
(SEC_HAS_CONTENTS |
| SEC_ALLOC |
| SEC_LOAD |
| SEC_KEEP |
| SEC_IN_MEMORY))) |
{ |
einfo ("%X%P: can not create .edata section: %E\n"); |
return; |
} |
bfd_set_section_size (filler_bfd, edata_s, edata_sz); |
} |
reloc_s = bfd_make_section_old_way (filler_bfd, ".reloc"); |
if (reloc_s == NULL |
|| !bfd_set_section_flags (filler_bfd, reloc_s, |
(SEC_HAS_CONTENTS |
| SEC_ALLOC |
| SEC_LOAD |
| SEC_KEEP |
| SEC_IN_MEMORY))) |
{ |
einfo ("%X%P: can not create .reloc section: %E\n"); |
return; |
} |
bfd_set_section_size (filler_bfd, reloc_s, 0); |
ldlang_add_file (filler_file); |
} |
/* Gather all the exported symbols and build the .edata section. */ |
static void |
generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
int i, next_ordinal; |
int name_table_size = 0; |
const char *dlnp; |
/* First, we need to know how many exported symbols there are, |
and what the range of ordinals is. */ |
if (pe_def_file->name) |
dll_name = pe_def_file->name; |
else |
{ |
dll_name = abfd->filename; |
for (dlnp = dll_name; *dlnp; dlnp++) |
if (*dlnp == '\\' || *dlnp == '/' || *dlnp == ':') |
dll_name = dlnp + 1; |
} |
if (count_with_ordinals && max_ordinal > count_exported) |
{ |
if (min_ordinal > max_ordinal - count_exported + 1) |
min_ordinal = max_ordinal - count_exported + 1; |
} |
else |
{ |
min_ordinal = 1; |
max_ordinal = count_exported; |
} |
export_table_size = max_ordinal - min_ordinal + 1; |
exported_symbols = xmalloc (export_table_size * sizeof (int)); |
for (i = 0; i < export_table_size; i++) |
exported_symbols[i] = -1; |
/* Now we need to assign ordinals to those that don't have them. */ |
for (i = 0; i < NE; i++) |
{ |
if (exported_symbol_sections[i] || |
pe_def_file->exports[i].flag_forward) |
{ |
if (pe_def_file->exports[i].ordinal != -1) |
{ |
int ei = pe_def_file->exports[i].ordinal - min_ordinal; |
int pi = exported_symbols[ei]; |
if (pi != -1) |
{ |
/* xgettext:c-format */ |
einfo (_("%XError, ordinal used twice: %d (%s vs %s)\n"), |
pe_def_file->exports[i].ordinal, |
pe_def_file->exports[i].name, |
pe_def_file->exports[pi].name); |
} |
exported_symbols[ei] = i; |
} |
if (pe_def_file->exports[i].its_name) |
name_table_size += strlen (pe_def_file->exports[i].its_name) + 1; |
else |
name_table_size += strlen (pe_def_file->exports[i].name) + 1; |
} |
/* Reserve space for the forward name. */ |
if (pe_def_file->exports[i].flag_forward) |
{ |
name_table_size += strlen (pe_def_file->exports[i].internal_name) + 1; |
} |
} |
next_ordinal = min_ordinal; |
for (i = 0; i < NE; i++) |
if ((exported_symbol_sections[i] || |
pe_def_file->exports[i].flag_forward) && |
pe_def_file->exports[i].ordinal == -1) |
{ |
while (exported_symbols[next_ordinal - min_ordinal] != -1) |
next_ordinal++; |
exported_symbols[next_ordinal - min_ordinal] = i; |
pe_def_file->exports[i].ordinal = next_ordinal; |
} |
/* OK, now we can allocate some memory. */ |
edata_sz = (40 /* directory */ |
+ 4 * export_table_size /* addresses */ |
+ 4 * count_exported_byname /* name ptrs */ |
+ 2 * count_exported_byname /* ordinals */ |
+ name_table_size + strlen (dll_name) + 1); |
} |
/* Fill the exported symbol offsets. The preliminary work has already |
been done in process_def_file_and_drectve(). */ |
static void |
fill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
{ |
int i; |
struct bfd_link_hash_entry *blhe; |
for (i = 0; i < pe_def_file->num_exports; i++) |
{ |
char *name; |
name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); |
if (pe_details->underscored |
&& *pe_def_file->exports[i].internal_name != '@') |
{ |
*name = '_'; |
strcpy (name + 1, pe_def_file->exports[i].internal_name); |
} |
else |
strcpy (name, pe_def_file->exports[i].internal_name); |
blhe = bfd_link_hash_lookup (info->hash, |
name, |
FALSE, FALSE, TRUE); |
if (blhe && blhe->type == bfd_link_hash_defined) |
exported_symbol_offsets[i] = blhe->u.def.value; |
free (name); |
} |
} |
static void |
fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
int s, hint; |
unsigned char *edirectory; |
unsigned char *eaddresses; |
unsigned char *enameptrs; |
unsigned char *eordinals; |
char *enamestr; |
edata_d = xmalloc (edata_sz); |
/* Note use of array pointer math here. */ |
edirectory = edata_d; |
eaddresses = edirectory + 40; |
enameptrs = eaddresses + 4 * export_table_size; |
eordinals = enameptrs + 4 * count_exported_byname; |
enamestr = (char *) eordinals + 2 * count_exported_byname; |
#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) \ |
+ edata_s->output_section->vma - image_base) |
memset (edata_d, 0, edata_sz); |
if (pe_data (abfd)->insert_timestamp) |
H_PUT_32 (abfd, time (0), edata_d + 4); |
if (pe_def_file->version_major != -1) |
{ |
bfd_put_16 (abfd, pe_def_file->version_major, edata_d + 8); |
bfd_put_16 (abfd, pe_def_file->version_minor, edata_d + 10); |
} |
bfd_put_32 (abfd, ERVA (enamestr), edata_d + 12); |
strcpy (enamestr, dll_name); |
enamestr += strlen (enamestr) + 1; |
bfd_put_32 (abfd, min_ordinal, edata_d + 16); |
bfd_put_32 (abfd, export_table_size, edata_d + 20); |
bfd_put_32 (abfd, count_exported_byname, edata_d + 24); |
bfd_put_32 (abfd, ERVA (eaddresses), edata_d + 28); |
bfd_put_32 (abfd, ERVA (enameptrs), edata_d + 32); |
bfd_put_32 (abfd, ERVA (eordinals), edata_d + 36); |
fill_exported_offsets (abfd, info); |
/* Ok, now for the filling in part. |
Scan alphabetically - ie the ordering in the exports[] table, |
rather than by ordinal - the ordering in the exported_symbol[] |
table. See dlltool.c and: |
http://sources.redhat.com/ml/binutils/2003-04/msg00379.html |
for more information. */ |
hint = 0; |
for (s = 0; s < NE; s++) |
{ |
struct bfd_section *ssec = exported_symbol_sections[s]; |
if (pe_def_file->exports[s].ordinal != -1 && |
(pe_def_file->exports[s].flag_forward || ssec != NULL)) |
{ |
int ord = pe_def_file->exports[s].ordinal; |
if (pe_def_file->exports[s].flag_forward) |
{ |
bfd_put_32 (abfd, ERVA (enamestr), |
eaddresses + 4 * (ord - min_ordinal)); |
strcpy (enamestr, pe_def_file->exports[s].internal_name); |
enamestr += strlen (pe_def_file->exports[s].internal_name) + 1; |
} |
else |
{ |
bfd_vma srva = (exported_symbol_offsets[s] |
+ ssec->output_section->vma |
+ ssec->output_offset); |
bfd_put_32 (abfd, srva - image_base, |
eaddresses + 4 * (ord - min_ordinal)); |
} |
if (!pe_def_file->exports[s].flag_noname) |
{ |
char *ename = pe_def_file->exports[s].name; |
if (pe_def_file->exports[s].its_name) |
ename = pe_def_file->exports[s].its_name; |
bfd_put_32 (abfd, ERVA (enamestr), enameptrs); |
enameptrs += 4; |
strcpy (enamestr, ename); |
enamestr += strlen (enamestr) + 1; |
bfd_put_16 (abfd, ord - min_ordinal, eordinals); |
eordinals += 2; |
pe_def_file->exports[s].hint = hint++; |
} |
} |
} |
} |
static struct bfd_section *current_sec; |
void |
pe_walk_relocs_of_symbol (struct bfd_link_info *info, |
const char *name, |
int (*cb) (arelent *, asection *)) |
{ |
bfd *b; |
asection *s; |
for (b = info->input_bfds; b; b = b->link_next) |
{ |
asymbol **symbols; |
if (!bfd_generic_link_read_symbols (b)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), b); |
return; |
} |
symbols = bfd_get_outsymbols (b); |
for (s = b->sections; s; s = s->next) |
{ |
arelent **relocs; |
int relsize, nrelocs, i; |
int flags = bfd_get_section_flags (b, s); |
/* Skip discarded linkonce sections. */ |
if (flags & SEC_LINK_ONCE |
&& s->output_section == bfd_abs_section_ptr) |
continue; |
current_sec = s; |
relsize = bfd_get_reloc_upper_bound (b, s); |
relocs = xmalloc (relsize); |
nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); |
for (i = 0; i < nrelocs; i++) |
{ |
struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; |
if (!strcmp (name, sym->name)) |
cb (relocs[i], s); |
} |
free (relocs); |
/* Warning: the allocated symbols are remembered in BFD and reused |
later, so don't free them! */ |
/* free (symbols); */ |
} |
} |
} |
/* Gather all the relocations and build the .reloc section. */ |
static void |
generate_reloc (bfd *abfd, struct bfd_link_info *info) |
{ |
/* For .reloc stuff. */ |
reloc_data_type *reloc_data; |
int total_relocs = 0; |
int i; |
bfd_vma sec_page = (bfd_vma) -1; |
bfd_vma page_ptr, page_count; |
int bi; |
bfd *b; |
struct bfd_section *s; |
total_relocs = 0; |
for (b = info->input_bfds; b; b = b->link_next) |
for (s = b->sections; s; s = s->next) |
total_relocs += s->reloc_count; |
reloc_data = xmalloc (total_relocs * sizeof (reloc_data_type)); |
total_relocs = 0; |
bi = 0; |
for (bi = 0, b = info->input_bfds; b; bi++, b = b->link_next) |
{ |
arelent **relocs; |
int relsize, nrelocs; |
for (s = b->sections; s; s = s->next) |
{ |
bfd_vma sec_vma = s->output_section->vma + s->output_offset; |
asymbol **symbols; |
/* If it's not loaded, we don't need to relocate it this way. */ |
if (!(s->output_section->flags & SEC_LOAD)) |
continue; |
/* I don't know why there would be a reloc for these, but I've |
seen it happen - DJ */ |
if (s->output_section == bfd_abs_section_ptr) |
continue; |
if (s->output_section->vma == 0) |
{ |
/* Huh? Shouldn't happen, but punt if it does. */ |
einfo ("DJ: zero vma section reloc detected: `%s' #%d f=%d\n", |
s->output_section->name, s->output_section->index, |
s->output_section->flags); |
continue; |
} |
if (!bfd_generic_link_read_symbols (b)) |
{ |
einfo (_("%B%F: could not read symbols: %E\n"), b); |
return; |
} |
symbols = bfd_get_outsymbols (b); |
relsize = bfd_get_reloc_upper_bound (b, s); |
relocs = xmalloc (relsize); |
nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); |
for (i = 0; i < nrelocs; i++) |
{ |
if (pe_dll_extra_pe_debug) |
{ |
struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; |
printf ("rel: %s\n", sym->name); |
} |
if (!relocs[i]->howto->pc_relative |
&& relocs[i]->howto->type != pe_details->imagebase_reloc) |
{ |
struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; |
/* Don't create relocs for undefined weak symbols. */ |
if (sym->flags == BSF_WEAK) |
{ |
struct bfd_link_hash_entry *blhe |
= bfd_wrapped_link_hash_lookup (abfd, info, sym->name, |
FALSE, FALSE, FALSE); |
if (blhe && blhe->type == bfd_link_hash_undefweak) |
{ |
/* Check aux sym and see if it is defined or not. */ |
struct coff_link_hash_entry *h, *h2; |
h = (struct coff_link_hash_entry *)blhe; |
if (h->symbol_class != C_NT_WEAK || h->numaux != 1) |
continue; |
h2 = h->auxbfd->tdata.coff_obj_data->sym_hashes |
[h->aux->x_sym.x_tagndx.l]; |
/* We don't want a base reloc if the aux sym is not |
found, undefined, or if it is the constant ABS |
zero default value. (We broaden that slightly by |
not testing the value, just the section; there's |
no reason we'd want a reference to any absolute |
address to get relocated during rebasing). */ |
if (!h2 || h2->root.type == bfd_link_hash_undefined |
|| h2->root.u.def.section == bfd_abs_section_ptr) |
continue; |
} |
else if (!blhe || blhe->type != bfd_link_hash_defined) |
continue; |
} |
/* Nor for Dwarf FDE references to discarded sections. */ |
else if (bfd_is_abs_section (sym->section->output_section)) |
{ |
/* We only ignore relocs from .eh_frame sections, as |
they are discarded by the final link rather than |
resolved against the kept section. */ |
if (!strcmp (s->name, ".eh_frame")) |
continue; |
} |
reloc_data[total_relocs].vma = sec_vma + relocs[i]->address; |
#define BITS_AND_SHIFT(bits, shift) (bits * 1000 | shift) |
switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, |
relocs[i]->howto->rightshift) |
{ |
#ifdef pe_use_x86_64 |
case BITS_AND_SHIFT (64, 0): |
reloc_data[total_relocs].type = 10; |
total_relocs++; |
break; |
#endif |
case BITS_AND_SHIFT (32, 0): |
reloc_data[total_relocs].type = 3; |
total_relocs++; |
break; |
case BITS_AND_SHIFT (16, 0): |
reloc_data[total_relocs].type = 2; |
total_relocs++; |
break; |
case BITS_AND_SHIFT (16, 16): |
reloc_data[total_relocs].type = 4; |
/* FIXME: we can't know the symbol's right value |
yet, but we probably can safely assume that |
CE will relocate us in 64k blocks, so leaving |
it zero is safe. */ |
reloc_data[total_relocs].extra = 0; |
total_relocs++; |
break; |
case BITS_AND_SHIFT (26, 2): |
reloc_data[total_relocs].type = 5; |
total_relocs++; |
break; |
case BITS_AND_SHIFT (24, 2): |
/* FIXME: 0 is ARM_26D, it is defined in bfd/coff-arm.c |
Those ARM_xxx definitions should go in proper |
header someday. */ |
if (relocs[i]->howto->type == 0 |
/* Older GNU linkers used 5 instead of 0 for this reloc. */ |
|| relocs[i]->howto->type == 5) |
/* This is an ARM_26D reloc, which is an ARM_26 reloc |
that has already been fully processed during a |
previous link stage, so ignore it here. */ |
break; |
/* Fall through. */ |
default: |
/* xgettext:c-format */ |
einfo (_("%XError: %d-bit reloc in dll\n"), |
relocs[i]->howto->bitsize); |
break; |
} |
} |
} |
free (relocs); |
/* Warning: the allocated symbols are remembered in BFD and |
reused later, so don't free them! */ |
} |
} |
/* At this point, we have total_relocs relocation addresses in |
reloc_addresses, which are all suitable for the .reloc section. |
We must now create the new sections. */ |
qsort (reloc_data, total_relocs, sizeof (*reloc_data), reloc_sort); |
for (i = 0; i < total_relocs; i++) |
{ |
bfd_vma this_page = (reloc_data[i].vma >> 12); |
if (this_page != sec_page) |
{ |
reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ |
reloc_sz += 8; |
sec_page = this_page; |
} |
reloc_sz += 2; |
if (reloc_data[i].type == 4) |
reloc_sz += 2; |
} |
reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ |
reloc_d = xmalloc (reloc_sz); |
sec_page = (bfd_vma) -1; |
reloc_sz = 0; |
page_ptr = (bfd_vma) -1; |
page_count = 0; |
for (i = 0; i < total_relocs; i++) |
{ |
bfd_vma rva = reloc_data[i].vma - image_base; |
bfd_vma this_page = (rva & ~0xfff); |
if (this_page != sec_page) |
{ |
while (reloc_sz & 3) |
reloc_d[reloc_sz++] = 0; |
if (page_ptr != (bfd_vma) -1) |
bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); |
bfd_put_32 (abfd, this_page, reloc_d + reloc_sz); |
page_ptr = reloc_sz; |
reloc_sz += 8; |
sec_page = this_page; |
page_count = 0; |
} |
bfd_put_16 (abfd, (rva & 0xfff) + (reloc_data[i].type << 12), |
reloc_d + reloc_sz); |
reloc_sz += 2; |
if (reloc_data[i].type == 4) |
{ |
bfd_put_16 (abfd, reloc_data[i].extra, reloc_d + reloc_sz); |
reloc_sz += 2; |
} |
page_count++; |
} |
while (reloc_sz & 3) |
reloc_d[reloc_sz++] = 0; |
if (page_ptr != (bfd_vma) -1) |
bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); |
while (reloc_sz < reloc_s->size) |
reloc_d[reloc_sz++] = 0; |
} |
/* Given the exiting def_file structure, print out a .DEF file that |
corresponds to it. */ |
static void |
quoteput (char *s, FILE *f, int needs_quotes) |
{ |
char *cp; |
for (cp = s; *cp; cp++) |
if (*cp == '\'' |
|| *cp == '"' |
|| *cp == '\\' |
|| ISSPACE (*cp) |
|| *cp == ',' |
|| *cp == ';') |
needs_quotes = 1; |
if (needs_quotes) |
{ |
putc ('"', f); |
while (*s) |
{ |
if (*s == '"' || *s == '\\') |
putc ('\\', f); |
putc (*s, f); |
s++; |
} |
putc ('"', f); |
} |
else |
fputs (s, f); |
} |
void |
pe_dll_generate_def_file (const char *pe_out_def_filename) |
{ |
int i; |
FILE *out = fopen (pe_out_def_filename, "w"); |
if (out == NULL) |
/* xgettext:c-format */ |
einfo (_("%s: Can't open output def file %s\n"), |
program_name, pe_out_def_filename); |
if (pe_def_file) |
{ |
if (pe_def_file->name) |
{ |
if (pe_def_file->is_dll) |
fprintf (out, "LIBRARY "); |
else |
fprintf (out, "NAME "); |
quoteput (pe_def_file->name, out, 1); |
if (pe_data (link_info.output_bfd)->pe_opthdr.ImageBase) |
{ |
fprintf (out, " BASE=0x"); |
fprintf_vma (out, ((bfd_vma) pe_data (link_info.output_bfd)->pe_opthdr.ImageBase)); |
} |
fprintf (out, "\n"); |
} |
if (pe_def_file->description) |
{ |
fprintf (out, "DESCRIPTION "); |
quoteput (pe_def_file->description, out, 1); |
fprintf (out, "\n"); |
} |
if (pe_def_file->version_minor != -1) |
fprintf (out, "VERSION %d.%d\n", pe_def_file->version_major, |
pe_def_file->version_minor); |
else if (pe_def_file->version_major != -1) |
fprintf (out, "VERSION %d\n", pe_def_file->version_major); |
if (pe_def_file->stack_reserve != -1 || pe_def_file->heap_reserve != -1) |
fprintf (out, "\n"); |
if (pe_def_file->stack_commit != -1) |
fprintf (out, "STACKSIZE 0x%x,0x%x\n", |
pe_def_file->stack_reserve, pe_def_file->stack_commit); |
else if (pe_def_file->stack_reserve != -1) |
fprintf (out, "STACKSIZE 0x%x\n", pe_def_file->stack_reserve); |
if (pe_def_file->heap_commit != -1) |
fprintf (out, "HEAPSIZE 0x%x,0x%x\n", |
pe_def_file->heap_reserve, pe_def_file->heap_commit); |
else if (pe_def_file->heap_reserve != -1) |
fprintf (out, "HEAPSIZE 0x%x\n", pe_def_file->heap_reserve); |
if (pe_def_file->num_section_defs > 0) |
{ |
fprintf (out, "\nSECTIONS\n\n"); |
for (i = 0; i < pe_def_file->num_section_defs; i++) |
{ |
fprintf (out, " "); |
quoteput (pe_def_file->section_defs[i].name, out, 0); |
if (pe_def_file->section_defs[i].class) |
{ |
fprintf (out, " CLASS "); |
quoteput (pe_def_file->section_defs[i].class, out, 0); |
} |
if (pe_def_file->section_defs[i].flag_read) |
fprintf (out, " READ"); |
if (pe_def_file->section_defs[i].flag_write) |
fprintf (out, " WRITE"); |
if (pe_def_file->section_defs[i].flag_execute) |
fprintf (out, " EXECUTE"); |
if (pe_def_file->section_defs[i].flag_shared) |
fprintf (out, " SHARED"); |
fprintf (out, "\n"); |
} |
} |
if (pe_def_file->num_exports > 0) |
{ |
fprintf (out, "EXPORTS\n"); |
for (i = 0; i < pe_def_file->num_exports; i++) |
{ |
def_file_export *e = pe_def_file->exports + i; |
fprintf (out, " "); |
quoteput (e->name, out, 0); |
if (e->internal_name && strcmp (e->internal_name, e->name)) |
{ |
fprintf (out, " = "); |
quoteput (e->internal_name, out, 0); |
} |
if (e->ordinal != -1) |
fprintf (out, " @%d", e->ordinal); |
if (e->flag_private) |
fprintf (out, " PRIVATE"); |
if (e->flag_constant) |
fprintf (out, " CONSTANT"); |
if (e->flag_noname) |
fprintf (out, " NONAME"); |
if (e->flag_data) |
fprintf (out, " DATA"); |
fprintf (out, "\n"); |
} |
} |
if (pe_def_file->num_imports > 0) |
{ |
fprintf (out, "\nIMPORTS\n\n"); |
for (i = 0; i < pe_def_file->num_imports; i++) |
{ |
def_file_import *im = pe_def_file->imports + i; |
fprintf (out, " "); |
if (im->internal_name |
&& (!im->name || strcmp (im->internal_name, im->name))) |
{ |
quoteput (im->internal_name, out, 0); |
fprintf (out, " = "); |
} |
quoteput (im->module->name, out, 0); |
fprintf (out, "."); |
if (im->name) |
quoteput (im->name, out, 0); |
else |
fprintf (out, "%d", im->ordinal); |
if (im->its_name) |
{ |
fprintf (out, " == "); |
quoteput (im->its_name, out, 0); |
} |
fprintf (out, "\n"); |
} |
} |
} |
else |
fprintf (out, _("; no contents available\n")); |
if (fclose (out) == EOF) |
/* xgettext:c-format */ |
einfo (_("%P: Error closing file `%s'\n"), pe_out_def_filename); |
} |
/* Generate the import library. */ |
static asymbol **symtab; |
static int symptr; |
static int tmp_seq; |
static int tmp_seq2; |
static const char *dll_filename; |
static char *dll_symname; |
#define UNDSEC bfd_und_section_ptr |
static asection * |
quick_section (bfd *abfd, const char *name, int flags, int align) |
{ |
asection *sec; |
asymbol *sym; |
sec = bfd_make_section_old_way (abfd, name); |
bfd_set_section_flags (abfd, sec, flags | SEC_ALLOC | SEC_LOAD | SEC_KEEP); |
bfd_set_section_alignment (abfd, sec, align); |
/* Remember to undo this before trying to link internally! */ |
sec->output_section = sec; |
sym = bfd_make_empty_symbol (abfd); |
symtab[symptr++] = sym; |
sym->name = sec->name; |
sym->section = sec; |
sym->flags = BSF_LOCAL; |
sym->value = 0; |
return sec; |
} |
static void |
quick_symbol (bfd *abfd, |
const char *n1, |
const char *n2, |
const char *n3, |
asection *sec, |
int flags, |
int addr) |
{ |
asymbol *sym; |
char *name = xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); |
strcpy (name, n1); |
strcat (name, n2); |
strcat (name, n3); |
sym = bfd_make_empty_symbol (abfd); |
sym->name = name; |
sym->section = sec; |
sym->flags = flags; |
sym->value = addr; |
symtab[symptr++] = sym; |
} |
static arelent *reltab = 0; |
static int relcount = 0, relsize = 0; |
static void |
quick_reloc (bfd *abfd, bfd_size_type address, int which_howto, int symidx) |
{ |
if (relcount >= relsize - 1) |
{ |
relsize += 10; |
if (reltab) |
reltab = xrealloc (reltab, relsize * sizeof (arelent)); |
else |
reltab = xmalloc (relsize * sizeof (arelent)); |
} |
reltab[relcount].address = address; |
reltab[relcount].addend = 0; |
reltab[relcount].howto = bfd_reloc_type_lookup (abfd, which_howto); |
reltab[relcount].sym_ptr_ptr = symtab + symidx; |
relcount++; |
} |
static void |
save_relocs (asection *sec) |
{ |
int i; |
sec->relocation = reltab; |
sec->reloc_count = relcount; |
sec->orelocation = xmalloc ((relcount + 1) * sizeof (arelent *)); |
for (i = 0; i < relcount; i++) |
sec->orelocation[i] = sec->relocation + i; |
sec->orelocation[relcount] = 0; |
sec->flags |= SEC_RELOC; |
reltab = 0; |
relcount = relsize = 0; |
} |
/* .section .idata$2 |
.global __head_my_dll |
__head_my_dll: |
.rva hname |
.long 0 |
.long 0 |
.rva __my_dll_iname |
.rva fthunk |
.section .idata$5 |
.long 0 |
fthunk: |
.section .idata$4 |
.long 0 |
hname: */ |
static bfd * |
make_head (bfd *parent) |
{ |
asection *id2, *id5, *id4; |
unsigned char *d2, *d5, *d4; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "d%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (6 * sizeof (asymbol *)); |
id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); |
id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); |
id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, U ("_head_"), dll_symname, "", id2, BSF_GLOBAL, 0); |
quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); |
/* OK, pay attention here. I got confused myself looking back at |
it. We create a four-byte section to mark the beginning of the |
list, and we include an offset of 4 in the section, so that the |
pointer to the list points to the *end* of this section, which is |
the start of the list of sections from other objects. */ |
bfd_set_section_size (abfd, id2, 20); |
d2 = xmalloc (20); |
id2->contents = d2; |
memset (d2, 0, 20); |
if (pe_use_nul_prefixed_import_tables) |
d2[0] = d2[16] = PE_IDATA5_SIZE; /* Reloc addend. */ |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); |
quick_reloc (abfd, 12, BFD_RELOC_RVA, 4); |
quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); |
save_relocs (id2); |
if (pe_use_nul_prefixed_import_tables) |
bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); |
else |
bfd_set_section_size (abfd, id5, 0); |
d5 = xmalloc (PE_IDATA5_SIZE); |
id5->contents = d5; |
memset (d5, 0, PE_IDATA5_SIZE); |
if (pe_use_nul_prefixed_import_tables) |
bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); |
else |
bfd_set_section_size (abfd, id4, 0); |
d4 = xmalloc (PE_IDATA4_SIZE); |
id4->contents = d4; |
memset (d4, 0, PE_IDATA4_SIZE); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, id2, d2, 0, 20); |
if (pe_use_nul_prefixed_import_tables) |
{ |
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); |
bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); |
} |
else |
{ |
bfd_set_section_contents (abfd, id5, d5, 0, 0); |
bfd_set_section_contents (abfd, id4, d4, 0, 0); |
} |
bfd_make_readable (abfd); |
return abfd; |
} |
/* .section .idata$4 |
.long 0 |
[.long 0] for PE+ |
.section .idata$5 |
.long 0 |
[.long 0] for PE+ |
.section idata$7 |
.global __my_dll_iname |
__my_dll_iname: |
.asciz "my.dll" */ |
static bfd * |
make_tail (bfd *parent) |
{ |
asection *id4, *id5, *id7; |
unsigned char *d4, *d5, *d7; |
int len; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "d%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (5 * sizeof (asymbol *)); |
id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); |
id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); |
id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, U (""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); |
bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); |
d4 = xmalloc (PE_IDATA4_SIZE); |
id4->contents = d4; |
memset (d4, 0, PE_IDATA4_SIZE); |
bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); |
d5 = xmalloc (PE_IDATA5_SIZE); |
id5->contents = d5; |
memset (d5, 0, PE_IDATA5_SIZE); |
len = strlen (dll_filename) + 1; |
if (len & 1) |
len++; |
bfd_set_section_size (abfd, id7, len); |
d7 = xmalloc (len); |
id7->contents = d7; |
strcpy ((char *) d7, dll_filename); |
/* If len was odd, the above |
strcpy leaves behind an undefined byte. That is harmless, |
but we set it to 0 just so the binary dumps are pretty. */ |
d7[len - 1] = 0; |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); |
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); |
bfd_set_section_contents (abfd, id7, d7, 0, len); |
bfd_make_readable (abfd); |
return abfd; |
} |
/* .text |
.global _function |
.global ___imp_function |
.global __imp__function |
_function: |
jmp *__imp__function: |
.section idata$7 |
.long __head_my_dll |
.section .idata$5 |
___imp_function: |
__imp__function: |
iat? |
.section .idata$4 |
iat? |
.section .idata$6 |
ID<ordinal>: |
.short <hint> |
.asciz "function" xlate? (add underscore, kill at) */ |
static const unsigned char jmp_ix86_bytes[] = |
{ |
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 |
}; |
/* _function: |
mov.l ip+8,r0 |
mov.l @r0,r0 |
jmp @r0 |
nop |
.dw __imp_function */ |
static const unsigned char jmp_sh_bytes[] = |
{ |
0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 |
}; |
/* _function: |
lui $t0,<high:__imp_function> |
lw $t0,<low:__imp_function> |
jr $t0 |
nop */ |
static const unsigned char jmp_mips_bytes[] = |
{ |
0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d, |
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 |
}; |
static const unsigned char jmp_arm_bytes[] = |
{ |
0x00, 0xc0, 0x9f, 0xe5, /* ldr ip, [pc] */ |
0x00, 0xf0, 0x9c, 0xe5, /* ldr pc, [ip] */ |
0, 0, 0, 0 |
}; |
static bfd * |
make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) |
{ |
asection *tx, *id7, *id5, *id4, *id6; |
unsigned char *td = NULL, *d7, *d5, *d4, *d6 = NULL; |
int len; |
char *oname; |
bfd *abfd; |
const unsigned char *jmp_bytes = NULL; |
int jmp_byte_count = 0; |
/* Include the jump stub section only if it is needed. A jump |
stub is needed if the symbol being imported <sym> is a function |
symbol and there is at least one undefined reference to that |
symbol. In other words, if all the import references to <sym> are |
explicitly through _declspec(dllimport) then the jump stub is not |
needed. */ |
if (include_jmp_stub) |
{ |
switch (pe_details->pe_arch) |
{ |
case PE_ARCH_i386: |
jmp_bytes = jmp_ix86_bytes; |
jmp_byte_count = sizeof (jmp_ix86_bytes); |
break; |
case PE_ARCH_sh: |
jmp_bytes = jmp_sh_bytes; |
jmp_byte_count = sizeof (jmp_sh_bytes); |
break; |
case PE_ARCH_mips: |
jmp_bytes = jmp_mips_bytes; |
jmp_byte_count = sizeof (jmp_mips_bytes); |
break; |
case PE_ARCH_arm: |
case PE_ARCH_arm_epoc: |
case PE_ARCH_arm_wince: |
jmp_bytes = jmp_arm_bytes; |
jmp_byte_count = sizeof (jmp_arm_bytes); |
break; |
default: |
abort (); |
} |
} |
oname = xmalloc (20); |
sprintf (oname, "d%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (12 * sizeof (asymbol *)); |
tx = quick_section (abfd, ".text", SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY, 2); |
id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); |
id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); |
id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); |
id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); |
if (*exp->internal_name == '@') |
{ |
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, |
BSF_GLOBAL, 0); |
if (include_jmp_stub) |
quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0); |
quick_symbol (abfd, "__imp_", exp->internal_name, "", id5, |
BSF_GLOBAL, 0); |
/* Fastcall applies only to functions, |
so no need for auto-import symbol. */ |
} |
else |
{ |
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, |
BSF_GLOBAL, 0); |
if (include_jmp_stub) |
quick_symbol (abfd, U (""), exp->internal_name, "", tx, |
BSF_GLOBAL, 0); |
quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5, |
BSF_GLOBAL, 0); |
/* Symbol to reference ord/name of imported |
data symbol, used to implement auto-import. */ |
if (exp->flag_data) |
quick_symbol (abfd, "__nm_", U (""), exp->internal_name, id6, |
BSF_GLOBAL,0); |
} |
if (pe_dll_compat_implib) |
quick_symbol (abfd, "___imp_", exp->internal_name, "", id5, |
BSF_GLOBAL, 0); |
if (include_jmp_stub) |
{ |
bfd_set_section_size (abfd, tx, jmp_byte_count); |
td = xmalloc (jmp_byte_count); |
tx->contents = td; |
memcpy (td, jmp_bytes, jmp_byte_count); |
switch (pe_details->pe_arch) |
{ |
case PE_ARCH_i386: |
#ifdef pe_use_x86_64 |
quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2); |
#else |
/* Mark this object as SAFESEH compatible. */ |
quick_symbol (abfd, "", "@feat.00", "", bfd_abs_section_ptr, |
BSF_LOCAL, 1); |
quick_reloc (abfd, 2, BFD_RELOC_32, 2); |
#endif |
break; |
case PE_ARCH_sh: |
quick_reloc (abfd, 8, BFD_RELOC_32, 2); |
break; |
case PE_ARCH_mips: |
quick_reloc (abfd, 0, BFD_RELOC_HI16_S, 2); |
quick_reloc (abfd, 0, BFD_RELOC_LO16, 0); /* MIPS_R_PAIR */ |
quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); |
break; |
case PE_ARCH_arm: |
case PE_ARCH_arm_epoc: |
case PE_ARCH_arm_wince: |
quick_reloc (abfd, 8, BFD_RELOC_32, 2); |
break; |
default: |
abort (); |
} |
save_relocs (tx); |
} |
else |
bfd_set_section_size (abfd, tx, 0); |
bfd_set_section_size (abfd, id7, 4); |
d7 = xmalloc (4); |
id7->contents = d7; |
memset (d7, 0, 4); |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); |
save_relocs (id7); |
bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); |
d5 = xmalloc (PE_IDATA5_SIZE); |
id5->contents = d5; |
memset (d5, 0, PE_IDATA5_SIZE); |
if (exp->flag_noname) |
{ |
d5[0] = exp->ordinal; |
d5[1] = exp->ordinal >> 8; |
d5[PE_IDATA5_SIZE - 1] = 0x80; |
} |
else |
{ |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); |
save_relocs (id5); |
} |
bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); |
d4 = xmalloc (PE_IDATA4_SIZE); |
id4->contents = d4; |
memset (d4, 0, PE_IDATA4_SIZE); |
if (exp->flag_noname) |
{ |
d4[0] = exp->ordinal; |
d4[1] = exp->ordinal >> 8; |
d4[PE_IDATA4_SIZE - 1] = 0x80; |
} |
else |
{ |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); |
save_relocs (id4); |
} |
if (exp->flag_noname) |
{ |
len = 0; |
bfd_set_section_size (abfd, id6, 0); |
} |
else |
{ |
/* { short, asciz } */ |
if (exp->its_name) |
len = 2 + strlen (exp->its_name) + 1; |
else |
len = 2 + strlen (exp->name) + 1; |
if (len & 1) |
len++; |
bfd_set_section_size (abfd, id6, len); |
d6 = xmalloc (len); |
id6->contents = d6; |
memset (d6, 0, len); |
d6[0] = exp->hint & 0xff; |
d6[1] = exp->hint >> 8; |
if (exp->its_name) |
strcpy ((char*) d6 + 2, exp->its_name); |
else |
strcpy ((char *) d6 + 2, exp->name); |
} |
bfd_set_symtab (abfd, symtab, symptr); |
if (include_jmp_stub) |
bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count); |
bfd_set_section_contents (abfd, id7, d7, 0, 4); |
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); |
bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); |
if (!exp->flag_noname) |
bfd_set_section_contents (abfd, id6, d6, 0, len); |
bfd_make_readable (abfd); |
return abfd; |
} |
static bfd * |
make_singleton_name_imp (const char *import, bfd *parent) |
{ |
/* Name thunks go to idata$4. */ |
asection *id5; |
unsigned char *d5; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "nmimp%06d.o", tmp_seq2); |
tmp_seq2++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (3 * sizeof (asymbol *)); |
id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, "__imp_", import, "", id5, BSF_GLOBAL, 0); |
/* We need space for the real thunk and for the null terminator. */ |
bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE * 2); |
d5 = xmalloc (PE_IDATA5_SIZE * 2); |
id5->contents = d5; |
memset (d5, 0, PE_IDATA5_SIZE * 2); |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); |
save_relocs (id5); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA4_SIZE * 2); |
bfd_make_readable (abfd); |
return abfd; |
} |
static bfd * |
make_singleton_name_thunk (const char *import, bfd *parent) |
{ |
/* Name thunks go to idata$4. */ |
asection *id4; |
unsigned char *d4; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "nmth%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (3 * sizeof (asymbol *)); |
id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, "__nm_thnk_", import, "", id4, BSF_GLOBAL, 0); |
quick_symbol (abfd, "__nm_", import, "", UNDSEC, BSF_GLOBAL, 0); |
/* We need space for the real thunk and for the null terminator. */ |
bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE * 2); |
d4 = xmalloc (PE_IDATA4_SIZE * 2); |
id4->contents = d4; |
memset (d4, 0, PE_IDATA4_SIZE * 2); |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); |
save_relocs (id4); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE * 2); |
bfd_make_readable (abfd); |
return abfd; |
} |
static char * |
make_import_fixup_mark (arelent *rel) |
{ |
/* We convert reloc to symbol, for later reference. */ |
static int counter; |
static char *fixup_name = NULL; |
static size_t buffer_len = 0; |
struct bfd_symbol *sym = *rel->sym_ptr_ptr; |
bfd *abfd = bfd_asymbol_bfd (sym); |
struct bfd_link_hash_entry *bh; |
if (!fixup_name) |
{ |
fixup_name = xmalloc (384); |
buffer_len = 384; |
} |
if (strlen (sym->name) + 25 > buffer_len) |
/* Assume 25 chars for "__fu" + counter + "_". If counter is |
bigger than 20 digits long, we've got worse problems than |
overflowing this buffer... */ |
{ |
free (fixup_name); |
/* New buffer size is length of symbol, plus 25, but |
then rounded up to the nearest multiple of 128. */ |
buffer_len = ((strlen (sym->name) + 25) + 127) & ~127; |
fixup_name = xmalloc (buffer_len); |
} |
sprintf (fixup_name, "__fu%d_%s", counter++, sym->name); |
bh = NULL; |
bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, |
current_sec, /* sym->section, */ |
rel->address, NULL, TRUE, FALSE, &bh); |
return fixup_name; |
} |
/* .section .idata$2 |
.rva __nm_thnk_SYM (singleton thunk with name of func) |
.long 0 |
.long 0 |
.rva __my_dll_iname (name of dll) |
.rva __fuNN_SYM (pointer to reference (address) in text) */ |
static bfd * |
make_import_fixup_entry (const char *name, |
const char *fixup_name, |
const char *symname, |
bfd *parent) |
{ |
asection *id2; |
unsigned char *d2; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "fu%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (6 * sizeof (asymbol *)); |
id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, "__nm_thnk_", name, "", UNDSEC, BSF_GLOBAL, 0); |
quick_symbol (abfd, U (""), symname, "_iname", UNDSEC, BSF_GLOBAL, 0); |
/* For relocator v2 we have to use the .idata$5 element and not |
fixup_name. */ |
if (link_info.pei386_runtime_pseudo_reloc == 2) |
quick_symbol (abfd, "__imp_", name, "", UNDSEC, BSF_GLOBAL, 0); |
else |
quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); |
bfd_set_section_size (abfd, id2, 20); |
d2 = xmalloc (20); |
id2->contents = d2; |
memset (d2, 0, 20); |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); |
quick_reloc (abfd, 12, BFD_RELOC_RVA, 2); |
quick_reloc (abfd, 16, BFD_RELOC_RVA, 3); |
save_relocs (id2); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, id2, d2, 0, 20); |
bfd_make_readable (abfd); |
return abfd; |
} |
/* .section .rdata_runtime_pseudo_reloc |
.long addend |
.rva __fuNN_SYM (pointer to reference (address) in text) */ |
static bfd * |
make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, |
const char *fixup_name, |
bfd_vma addend ATTRIBUTE_UNUSED, |
bfd_vma bitsize, |
bfd *parent) |
{ |
asection *rt_rel; |
unsigned char *rt_rel_d; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "rtr%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
if (link_info.pei386_runtime_pseudo_reloc == 2) |
{ |
symtab = xmalloc ((runtime_pseudp_reloc_v2_init ? 3 : 6) * sizeof (asymbol *)); |
} |
else |
{ |
symtab = xmalloc (2 * sizeof (asymbol *)); |
} |
rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", |
SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); |
if (link_info.pei386_runtime_pseudo_reloc == 2) |
{ |
size_t size = 12; |
if (! runtime_pseudp_reloc_v2_init) |
{ |
size += 12; |
runtime_pseudp_reloc_v2_init = 1; |
} |
quick_symbol (abfd, "__imp_", name, "", UNDSEC, BSF_GLOBAL, 0); |
bfd_set_section_size (abfd, rt_rel, size); |
rt_rel_d = xmalloc (size); |
rt_rel->contents = rt_rel_d; |
memset (rt_rel_d, 0, size); |
quick_reloc (abfd, size - 8, BFD_RELOC_RVA, 1); |
quick_reloc (abfd, size - 12, BFD_RELOC_RVA, 2); |
bfd_put_32 (abfd, bitsize, rt_rel_d + (size - 4)); |
if (size != 12) |
bfd_put_32 (abfd, 1, rt_rel_d + 8); |
save_relocs (rt_rel); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, size); |
} |
else |
{ |
bfd_set_section_size (abfd, rt_rel, 8); |
rt_rel_d = xmalloc (8); |
rt_rel->contents = rt_rel_d; |
memset (rt_rel_d, 0, 8); |
bfd_put_32 (abfd, addend, rt_rel_d); |
quick_reloc (abfd, 4, BFD_RELOC_RVA, 1); |
save_relocs (rt_rel); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8); |
} |
bfd_make_readable (abfd); |
return abfd; |
} |
/* .section .rdata |
.rva __pei386_runtime_relocator */ |
static bfd * |
pe_create_runtime_relocator_reference (bfd *parent) |
{ |
asection *extern_rt_rel; |
unsigned char *extern_rt_rel_d; |
char *oname; |
bfd *abfd; |
oname = xmalloc (20); |
sprintf (oname, "ertr%06d.o", tmp_seq); |
tmp_seq++; |
abfd = bfd_create (oname, parent); |
bfd_find_target (pe_details->object_target, abfd); |
bfd_make_writable (abfd); |
bfd_set_format (abfd, bfd_object); |
bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); |
symptr = 0; |
symtab = xmalloc (2 * sizeof (asymbol *)); |
extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2); |
quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC, |
BSF_NO_FLAGS, 0); |
bfd_set_section_size (abfd, extern_rt_rel, PE_IDATA5_SIZE); |
extern_rt_rel_d = xmalloc (PE_IDATA5_SIZE); |
extern_rt_rel->contents = extern_rt_rel_d; |
quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); |
save_relocs (extern_rt_rel); |
bfd_set_symtab (abfd, symtab, symptr); |
bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, PE_IDATA5_SIZE); |
bfd_make_readable (abfd); |
return abfd; |
} |
void |
pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend) |
{ |
char buf[300]; |
struct bfd_symbol *sym = *rel->sym_ptr_ptr; |
struct bfd_link_hash_entry *name_thunk_sym; |
struct bfd_link_hash_entry *name_imp_sym; |
const char *name = sym->name; |
char *fixup_name = make_import_fixup_mark (rel); |
bfd *b; |
int need_import_table = 1; |
sprintf (buf, "__imp_%s", name); |
name_imp_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); |
sprintf (buf, "__nm_thnk_%s", name); |
name_thunk_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); |
/* For version 2 pseudo relocation we don't need to add an import |
if the import symbol is already present. */ |
if (link_info.pei386_runtime_pseudo_reloc == 2 |
&& name_imp_sym |
&& name_imp_sym->type == bfd_link_hash_defined) |
need_import_table = 0; |
if (need_import_table == 1 |
&& (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined)) |
{ |
b = make_singleton_name_thunk (name, link_info.output_bfd); |
add_bfd_to_link (b, b->filename, &link_info); |
/* If we ever use autoimport, we have to cast text section writable. |
But not for version 2. */ |
if (link_info.pei386_runtime_pseudo_reloc != 2) |
{ |
config.text_read_only = FALSE; |
link_info.output_bfd->flags &= ~WP_TEXT; |
} |
if (link_info.pei386_runtime_pseudo_reloc == 2) |
{ |
b = make_singleton_name_imp (name, link_info.output_bfd); |
add_bfd_to_link (b, b->filename, &link_info); |
} |
} |
if ((addend == 0 || link_info.pei386_runtime_pseudo_reloc) |
&& need_import_table == 1) |
{ |
extern char * pe_data_import_dll; |
char * symname = pe_data_import_dll ? pe_data_import_dll : "unknown"; |
b = make_import_fixup_entry (name, fixup_name, symname, |
link_info.output_bfd); |
add_bfd_to_link (b, b->filename, &link_info); |
} |
if ((link_info.pei386_runtime_pseudo_reloc != 0 && addend != 0) |
|| link_info.pei386_runtime_pseudo_reloc == 2) |
{ |
if (pe_dll_extra_pe_debug) |
printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", |
fixup_name, (int) addend); |
b = make_runtime_pseudo_reloc (name, fixup_name, addend, rel->howto->bitsize, |
link_info.output_bfd); |
add_bfd_to_link (b, b->filename, &link_info); |
if (runtime_pseudo_relocs_created == 0) |
{ |
b = pe_create_runtime_relocator_reference (link_info.output_bfd); |
add_bfd_to_link (b, b->filename, &link_info); |
} |
runtime_pseudo_relocs_created++; |
} |
else if (addend != 0) |
{ |
einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), |
s->owner, s, rel->address, sym->name); |
einfo ("%X"); |
} |
} |
void |
pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_info *info) |
{ |
int i; |
bfd *ar_head; |
bfd *ar_tail; |
bfd *outarch; |
bfd *ibfd; |
bfd *head = 0; |
dll_filename = (def->name) ? def->name : dll_name; |
dll_symname = xstrdup (dll_filename); |
for (i = 0; dll_symname[i]; i++) |
if (!ISALNUM (dll_symname[i])) |
dll_symname[i] = '_'; |
unlink_if_ordinary (impfilename); |
outarch = bfd_openw (impfilename, 0); |
if (!outarch) |
{ |
/* xgettext:c-format */ |
einfo (_("%XCan't open .lib file: %s\n"), impfilename); |
return; |
} |
if (verbose) |
/* xgettext:c-format */ |
info_msg (_("Creating library file: %s\n"), impfilename); |
bfd_set_format (outarch, bfd_archive); |
outarch->has_armap = 1; |
/* Work out a reasonable size of things to put onto one line. */ |
ar_head = make_head (outarch); |
/* Iterate the input BFDs, looking for exclude-modules-for-implib. */ |
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) |
{ |
/* Iterate the exclude list. */ |
struct exclude_list_struct *ex; |
char found; |
for (ex = excludes, found = 0; ex && !found; ex = ex->next) |
{ |
if (ex->type != EXCLUDEFORIMPLIB) |
continue; |
found = (filename_cmp (ex->string, ibfd->filename) == 0); |
} |
/* If it matched, we must open a fresh BFD for it (the original |
input BFD is still needed for the DLL's final link) and add |
it into the archive member chain. */ |
if (found) |
{ |
bfd *newbfd = bfd_openr (ibfd->my_archive |
? ibfd->my_archive->filename : ibfd->filename, NULL); |
if (!newbfd) |
{ |
einfo (_("%Xbfd_openr %s: %E\n"), ibfd->filename); |
return; |
} |
if (ibfd->my_archive) |
{ |
/* Must now iterate through archive until we find the |
required member. A minor shame that we'll open the |
archive once per member that we require from it, and |
leak those archive bfds rather than reuse them. */ |
bfd *arbfd = newbfd; |
if (!bfd_check_format_matches (arbfd, bfd_archive, NULL)) |
{ |
einfo (_("%X%s(%s): can't find member in non-archive file"), |
ibfd->my_archive->filename, ibfd->filename); |
return; |
} |
newbfd = NULL; |
while ((newbfd = bfd_openr_next_archived_file (arbfd, newbfd)) != 0) |
{ |
if (filename_cmp (newbfd->filename, ibfd->filename) == 0) |
break; |
} |
if (!newbfd) |
{ |
einfo (_("%X%s(%s): can't find member in archive"), |
ibfd->my_archive->filename, ibfd->filename); |
return; |
} |
} |
newbfd->archive_next = head; |
head = newbfd; |
} |
} |
for (i = 0; i < def->num_exports; i++) |
{ |
/* The import library doesn't know about the internal name. */ |
char *internal = def->exports[i].internal_name; |
bfd *n; |
/* Don't add PRIVATE entries to import lib. */ |
if (pe_def_file->exports[i].flag_private) |
continue; |
def->exports[i].internal_name = def->exports[i].name; |
n = make_one (def->exports + i, outarch, |
! (def->exports + i)->flag_data); |
n->archive_next = head; |
head = n; |
def->exports[i].internal_name = internal; |
} |
ar_tail = make_tail (outarch); |
if (ar_head == NULL || ar_tail == NULL) |
return; |
/* Now stick them all into the archive. */ |
ar_head->archive_next = head; |
ar_tail->archive_next = ar_head; |
head = ar_tail; |
if (! bfd_set_archive_head (outarch, head)) |
einfo ("%Xbfd_set_archive_head: %E\n"); |
if (! bfd_close (outarch)) |
einfo ("%Xbfd_close %s: %E\n", impfilename); |
while (head != NULL) |
{ |
bfd *n = head->archive_next; |
bfd_close (head); |
head = n; |
} |
} |
static int undef_count = 0; |
struct key_value |
{ |
char *key; |
const char *oname; |
}; |
static struct key_value *udef_table; |
static int undef_sort_cmp (const void *l1, const void *r1) |
{ |
const struct key_value *l = l1; |
const struct key_value *r = r1; |
return strcmp (l->key, r->key); |
} |
static struct bfd_link_hash_entry * |
pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) |
{ |
struct bfd_link_hash_entry *h = NULL; |
struct key_value *kv; |
struct key_value key; |
char *at, *lname = (char *) alloca (strlen (name) + 3); |
strcpy (lname, name); |
at = strchr (lname + (lname[0] == '@'), '@'); |
if (at) |
at[1] = 0; |
key.key = lname; |
kv = bsearch (&key, udef_table, undef_count, sizeof (struct key_value), |
undef_sort_cmp); |
if (kv) |
{ |
h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); |
if (h->type == bfd_link_hash_undefined) |
return h; |
} |
if (lname[0] == '?') |
return NULL; |
if (at || lname[0] == '@') |
{ |
if (lname[0] == '@') |
{ |
if (pe_details->underscored) |
lname[0] = '_'; |
else |
strcpy (lname, lname + 1); |
key.key = lname; |
kv = bsearch (&key, udef_table, undef_count, |
sizeof (struct key_value), undef_sort_cmp); |
if (kv) |
{ |
h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); |
if (h->type == bfd_link_hash_undefined) |
return h; |
} |
} |
if (at) |
*strchr (lname, '@') = 0; |
key.key = lname; |
kv = bsearch (&key, udef_table, undef_count, |
sizeof (struct key_value), undef_sort_cmp); |
if (kv) |
{ |
h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); |
if (h->type == bfd_link_hash_undefined) |
return h; |
} |
return NULL; |
} |
strcat (lname, "@"); |
key.key = lname; |
kv = bsearch (&key, udef_table, undef_count, |
sizeof (struct key_value), undef_sort_cmp); |
if (kv) |
{ |
h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); |
if (h->type == bfd_link_hash_undefined) |
return h; |
} |
if (lname[0] == '_' && pe_details->underscored) |
lname[0] = '@'; |
else |
{ |
memmove (lname + 1, lname, strlen (lname) + 1); |
lname[0] = '@'; |
} |
key.key = lname; |
kv = bsearch (&key, udef_table, undef_count, |
sizeof (struct key_value), undef_sort_cmp); |
if (kv) |
{ |
h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); |
if (h->type == bfd_link_hash_undefined) |
return h; |
} |
return NULL; |
} |
static bfd_boolean |
pe_undef_count (struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED, |
void *inf ATTRIBUTE_UNUSED) |
{ |
if (h->type == bfd_link_hash_undefined) |
undef_count++; |
return TRUE; |
} |
static bfd_boolean |
pe_undef_fill (struct bfd_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) |
{ |
if (h->type == bfd_link_hash_undefined) |
{ |
char *at; |
udef_table[undef_count].key = xstrdup (h->root.string); |
at = strchr (udef_table[undef_count].key |
+ (udef_table[undef_count].key[0] == '@'), '@'); |
if (at) |
at[1] = 0; |
udef_table[undef_count].oname = h->root.string; |
undef_count++; |
} |
return TRUE; |
} |
static void |
pe_create_undef_table (void) |
{ |
undef_count = 0; |
/* count undefined symbols */ |
bfd_link_hash_traverse (link_info.hash, pe_undef_count, ""); |
/* create and fill the corresponding table */ |
udef_table = xmalloc (undef_count * sizeof (struct key_value)); |
undef_count = 0; |
bfd_link_hash_traverse (link_info.hash, pe_undef_fill, ""); |
/* sort items */ |
qsort (udef_table, undef_count, sizeof (struct key_value), undef_sort_cmp); |
} |
static void |
add_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *linfo) |
{ |
lang_input_statement_type *fake_file; |
fake_file = lang_add_input_file (name, |
lang_input_file_is_fake_enum, |
NULL); |
fake_file->the_bfd = abfd; |
ldlang_add_file (fake_file); |
if (!bfd_link_add_symbols (abfd, linfo)) |
einfo ("%Xaddsym %s: %E\n", name); |
} |
void |
pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo) |
{ |
int i, j; |
def_file_module *module; |
def_file_import *imp; |
pe_dll_id_target (bfd_get_target (output_bfd)); |
if (!pe_def_file) |
return; |
imp = pe_def_file->imports; |
pe_create_undef_table (); |
for (module = pe_def_file->modules; module; module = module->next) |
{ |
int do_this_dll = 0; |
for (i = 0; i < pe_def_file->num_imports && imp[i].module != module; i++) |
; |
if (i >= pe_def_file->num_imports) |
continue; |
dll_filename = module->name; |
dll_symname = xstrdup (module->name); |
for (j = 0; dll_symname[j]; j++) |
if (!ISALNUM (dll_symname[j])) |
dll_symname[j] = '_'; |
for (; i < pe_def_file->num_imports && imp[i].module == module; i++) |
{ |
def_file_export exp; |
struct bfd_link_hash_entry *blhe; |
int lead_at = (*imp[i].internal_name == '@'); |
/* See if we need this import. */ |
size_t len = strlen (imp[i].internal_name); |
char *name = xmalloc (len + 2 + 6); |
bfd_boolean include_jmp_stub = FALSE; |
bfd_boolean is_cdecl = FALSE; |
bfd_boolean is_undef = FALSE; |
if (!lead_at && strchr (imp[i].internal_name, '@') == NULL) |
is_cdecl = TRUE; |
if (lead_at) |
sprintf (name, "%s", imp[i].internal_name); |
else |
sprintf (name, "%s%s",U (""), imp[i].internal_name); |
blhe = bfd_link_hash_lookup (linfo->hash, name, |
FALSE, FALSE, FALSE); |
/* Include the jump stub for <sym> only if the <sym> |
is undefined. */ |
if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)) |
{ |
if (lead_at) |
sprintf (name, "%s%s", "__imp_", imp[i].internal_name); |
else |
sprintf (name, "%s%s%s", "__imp_", U (""), |
imp[i].internal_name); |
blhe = bfd_link_hash_lookup (linfo->hash, name, |
FALSE, FALSE, FALSE); |
if (blhe) |
is_undef = (blhe->type == bfd_link_hash_undefined); |
} |
else |
{ |
include_jmp_stub = TRUE; |
is_undef = (blhe->type == bfd_link_hash_undefined); |
} |
if (is_cdecl && (!blhe || (blhe && blhe->type != bfd_link_hash_undefined))) |
{ |
sprintf (name, "%s%s",U (""), imp[i].internal_name); |
blhe = pe_find_cdecl_alias_match (linfo, name); |
include_jmp_stub = TRUE; |
if (blhe) |
is_undef = (blhe->type == bfd_link_hash_undefined); |
} |
free (name); |
if (is_undef) |
{ |
bfd *one; |
/* We do. */ |
if (!do_this_dll) |
{ |
bfd *ar_head = make_head (output_bfd); |
add_bfd_to_link (ar_head, ar_head->filename, linfo); |
do_this_dll = 1; |
} |
exp.internal_name = imp[i].internal_name; |
exp.name = imp[i].name; |
exp.its_name = imp[i].its_name; |
exp.ordinal = imp[i].ordinal; |
exp.hint = exp.ordinal >= 0 ? exp.ordinal : 0; |
exp.flag_private = 0; |
exp.flag_constant = 0; |
exp.flag_data = imp[i].data; |
exp.flag_noname = exp.name ? 0 : 1; |
one = make_one (&exp, output_bfd, (! exp.flag_data) && include_jmp_stub); |
add_bfd_to_link (one, one->filename, linfo); |
} |
} |
if (do_this_dll) |
{ |
bfd *ar_tail = make_tail (output_bfd); |
add_bfd_to_link (ar_tail, ar_tail->filename, linfo); |
} |
free (dll_symname); |
} |
while (undef_count) |
{ |
--undef_count; |
free (udef_table[undef_count].key); |
} |
free (udef_table); |
} |
/* We were handed a *.DLL file. Parse it and turn it into a set of |
IMPORTS directives in the def file. Return TRUE if the file was |
handled, FALSE if not. */ |
static unsigned int |
pe_get16 (bfd *abfd, int where) |
{ |
unsigned char b[2]; |
bfd_seek (abfd, (file_ptr) where, SEEK_SET); |
bfd_bread (b, (bfd_size_type) 2, abfd); |
return b[0] + (b[1] << 8); |
} |
static unsigned int |
pe_get32 (bfd *abfd, int where) |
{ |
unsigned char b[4]; |
bfd_seek (abfd, (file_ptr) where, SEEK_SET); |
bfd_bread (b, (bfd_size_type) 4, abfd); |
return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); |
} |
static unsigned int |
pe_as32 (void *ptr) |
{ |
unsigned char *b = ptr; |
return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); |
} |
bfd_boolean |
pe_implied_import_dll (const char *filename) |
{ |
bfd *dll; |
bfd_vma pe_header_offset, opthdr_ofs, num_entries, i; |
bfd_vma export_rva, export_size, nsections, secptr, expptr; |
bfd_vma exp_funcbase; |
unsigned char *expdata; |
char *erva; |
bfd_vma name_rvas, nexp; |
const char *dllname; |
/* Initialization with start > end guarantees that is_data |
will not be set by mistake, and avoids compiler warning. */ |
bfd_vma data_start = 1; |
bfd_vma data_end = 0; |
bfd_vma rdata_start = 1; |
bfd_vma rdata_end = 0; |
bfd_vma bss_start = 1; |
bfd_vma bss_end = 0; |
/* No, I can't use bfd here. kernel32.dll puts its export table in |
the middle of the .rdata section. */ |
dll = bfd_openr (filename, pe_details->target_name); |
if (!dll) |
{ |
einfo ("%Xopen %s: %E\n", filename); |
return FALSE; |
} |
/* PEI dlls seem to be bfd_objects. */ |
if (!bfd_check_format (dll, bfd_object)) |
{ |
einfo ("%X%s: this doesn't appear to be a DLL\n", filename); |
return FALSE; |
} |
/* Get pe_header, optional header and numbers of directory entries. */ |
pe_header_offset = pe_get32 (dll, 0x3c); |
opthdr_ofs = pe_header_offset + 4 + 20; |
#ifdef pe_use_x86_64 |
num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /* & NumberOfRvaAndSizes. */ |
#else |
num_entries = pe_get32 (dll, opthdr_ofs + 92); |
#endif |
/* No import or export directory entry. */ |
if (num_entries < 1) |
return FALSE; |
#ifdef pe_use_x86_64 |
export_rva = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4); |
export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4); |
#else |
export_rva = pe_get32 (dll, opthdr_ofs + 96); |
export_size = pe_get32 (dll, opthdr_ofs + 100); |
#endif |
/* No export table - nothing to export. */ |
if (export_size == 0) |
return FALSE; |
nsections = pe_get16 (dll, pe_header_offset + 4 + 2); |
secptr = (pe_header_offset + 4 + 20 + |
pe_get16 (dll, pe_header_offset + 4 + 16)); |
expptr = 0; |
/* Get the rva and size of the export section. */ |
for (i = 0; i < nsections; i++) |
{ |
char sname[8]; |
bfd_vma secptr1 = secptr + 40 * i; |
bfd_vma vaddr = pe_get32 (dll, secptr1 + 12); |
bfd_vma vsize = pe_get32 (dll, secptr1 + 16); |
bfd_vma fptr = pe_get32 (dll, secptr1 + 20); |
bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); |
bfd_bread (sname, (bfd_size_type) 8, dll); |
if (vaddr <= export_rva && vaddr + vsize > export_rva) |
{ |
expptr = fptr + (export_rva - vaddr); |
if (export_rva + export_size > vaddr + vsize) |
export_size = vsize - (export_rva - vaddr); |
break; |
} |
} |
/* Scan sections and store the base and size of the |
data and bss segments in data/base_start/end. */ |
for (i = 0; i < nsections; i++) |
{ |
bfd_vma secptr1 = secptr + 40 * i; |
bfd_vma vsize = pe_get32 (dll, secptr1 + 8); |
bfd_vma vaddr = pe_get32 (dll, secptr1 + 12); |
bfd_vma flags = pe_get32 (dll, secptr1 + 36); |
char sec_name[9]; |
sec_name[8] = '\0'; |
bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); |
bfd_bread (sec_name, (bfd_size_type) 8, dll); |
if (strcmp(sec_name,".data") == 0) |
{ |
data_start = vaddr; |
data_end = vaddr + vsize; |
if (pe_dll_extra_pe_debug) |
printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", |
__FUNCTION__, sec_name, (unsigned long) vaddr, |
(unsigned long) (vaddr + vsize), (unsigned long) flags); |
} |
else if (strcmp(sec_name,".rdata") == 0) |
{ |
rdata_start = vaddr; |
rdata_end = vaddr + vsize; |
if (pe_dll_extra_pe_debug) |
printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", |
__FUNCTION__, sec_name, (unsigned long) vaddr, |
(unsigned long) (vaddr + vsize), (unsigned long) flags); |
} |
else if (strcmp (sec_name,".bss") == 0) |
{ |
bss_start = vaddr; |
bss_end = vaddr + vsize; |
if (pe_dll_extra_pe_debug) |
printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", |
__FUNCTION__, sec_name, (unsigned long) vaddr, |
(unsigned long) (vaddr + vsize), (unsigned long) flags); |
} |
} |
expdata = xmalloc (export_size); |
bfd_seek (dll, (file_ptr) expptr, SEEK_SET); |
bfd_bread (expdata, (bfd_size_type) export_size, dll); |
erva = (char *) expdata - export_rva; |
if (pe_def_file == 0) |
pe_def_file = def_file_empty (); |
nexp = pe_as32 (expdata + 24); |
name_rvas = pe_as32 (expdata + 32); |
exp_funcbase = pe_as32 (expdata + 28); |
/* Use internal dll name instead of filename |
to enable symbolic dll linking. */ |
dllname = erva + pe_as32 (expdata + 12); |
/* Check to see if the dll has already been added to |
the definition list and if so return without error. |
This avoids multiple symbol definitions. */ |
if (def_get_module (pe_def_file, dllname)) |
{ |
if (pe_dll_extra_pe_debug) |
printf ("%s is already loaded\n", dllname); |
return TRUE; |
} |
/* Iterate through the list of symbols. */ |
for (i = 0; i < nexp; i++) |
{ |
/* Pointer to the names vector. */ |
bfd_vma name_rva = pe_as32 (erva + name_rvas + i * 4); |
def_file_import *imp; |
/* Pointer to the function address vector. */ |
bfd_vma func_rva = pe_as32 (erva + exp_funcbase + i * 4); |
int is_data = 0; |
/* Skip unwanted symbols, which are |
exported in buggy auto-import releases. */ |
if (! CONST_STRNEQ (erva + name_rva, "__nm_")) |
{ |
int is_dup = 0; |
/* is_data is true if the address is in the data, rdata or bss |
segment. */ |
is_data = |
(func_rva >= data_start && func_rva < data_end) |
|| (func_rva >= rdata_start && func_rva < rdata_end) |
|| (func_rva >= bss_start && func_rva < bss_end); |
imp = def_file_add_import (pe_def_file, erva + name_rva, |
dllname, i, NULL, NULL, &is_dup); |
/* Mark symbol type. */ |
if (!is_dup) |
imp->data = is_data; |
if (pe_dll_extra_pe_debug) |
printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", |
__FUNCTION__, dllname, erva + name_rva, |
(unsigned long) func_rva, is_data ? "(data)" : ""); |
} |
} |
return TRUE; |
} |
void |
pe_output_file_set_long_section_names (bfd *abfd) |
{ |
if (pe_use_coff_long_section_names < 0) |
return; |
if (!bfd_coff_set_long_section_names (abfd, pe_use_coff_long_section_names)) |
einfo (_("%XError: can't use long section names on this arch\n")); |
} |
/* These are the main functions, called from the emulation. The first |
is called after the bfds are read, so we can guess at how much space |
we need. The second is called after everything is placed, so we |
can put the right values in place. */ |
void |
pe_dll_build_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
pe_dll_id_target (bfd_get_target (abfd)); |
pe_output_file_set_long_section_names (abfd); |
process_def_file_and_drectve (abfd, info); |
if (pe_def_file->num_exports == 0 && !info->shared) |
return; |
generate_edata (abfd, info); |
build_filler_bfd (1); |
pe_output_file_set_long_section_names (filler_bfd); |
} |
void |
pe_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
pe_dll_id_target (bfd_get_target (abfd)); |
pe_output_file_set_long_section_names (abfd); |
build_filler_bfd (0); |
pe_output_file_set_long_section_names (filler_bfd); |
} |
void |
pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
pe_dll_id_target (bfd_get_target (abfd)); |
pe_output_file_set_long_section_names (abfd); |
image_base = pe_data (abfd)->pe_opthdr.ImageBase; |
generate_reloc (abfd, info); |
if (reloc_sz > 0) |
{ |
bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); |
/* Resize the sections. */ |
lang_reset_memory_regions (); |
lang_size_sections (NULL, TRUE); |
/* Redo special stuff. */ |
ldemul_after_allocation (); |
/* Do the assignments again. */ |
lang_do_assignments (lang_final_phase_enum); |
} |
fill_edata (abfd, info); |
if (info->shared && !info->pie) |
pe_data (abfd)->dll = 1; |
edata_s->contents = edata_d; |
reloc_s->contents = reloc_d; |
} |
void |
pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
pe_dll_id_target (bfd_get_target (abfd)); |
pe_output_file_set_long_section_names (abfd); |
image_base = pe_data (abfd)->pe_opthdr.ImageBase; |
generate_reloc (abfd, info); |
if (reloc_sz > 0) |
{ |
bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); |
/* Resize the sections. */ |
lang_reset_memory_regions (); |
lang_size_sections (NULL, TRUE); |
/* Redo special stuff. */ |
ldemul_after_allocation (); |
/* Do the assignments again. */ |
lang_do_assignments (lang_final_phase_enum); |
} |
reloc_s->contents = reloc_d; |
} |
bfd_boolean |
pe_bfd_is_dll (bfd *abfd) |
{ |
return (bfd_get_format (abfd) == bfd_object |
&& obj_pe (abfd) |
&& pe_data (abfd)->dll); |
} |
/contrib/toolchain/binutils/ld/pe-dll.h |
---|
0,0 → 1,74 |
/* pe-dll.h: Header file for routines used to build Windows DLLs. |
Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef PE_DLL_H |
#define PE_DLL_H |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "deffile.h" |
extern def_file *pe_def_file; |
extern int pe_dll_export_everything; |
extern int pe_dll_exclude_all_symbols; |
extern int pe_dll_do_default_excludes; |
extern int pe_dll_kill_ats; |
extern int pe_dll_stdcall_aliases; |
extern int pe_dll_warn_dup_exports; |
extern int pe_dll_compat_implib; |
extern int pe_dll_extra_pe_debug; |
extern int pe_use_nul_prefixed_import_tables; |
extern int pe_use_coff_long_section_names; |
extern int pe_leading_underscore; |
typedef enum { EXCLUDESYMS, EXCLUDELIBS, EXCLUDEFORIMPLIB } exclude_type; |
extern void pe_dll_id_target |
(const char *); |
extern void pe_dll_add_excludes |
(const char *, const exclude_type); |
extern void pe_dll_generate_def_file |
(const char *); |
extern void pe_dll_generate_implib |
(def_file *, const char *, struct bfd_link_info *); |
extern void pe_process_import_defs |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean pe_implied_import_dll |
(const char *); |
extern void pe_dll_build_sections |
(bfd *, struct bfd_link_info *); |
extern void pe_exe_build_sections |
(bfd *, struct bfd_link_info *); |
extern void pe_dll_fill_sections |
(bfd *, struct bfd_link_info *); |
extern void pe_exe_fill_sections |
(bfd *, struct bfd_link_info *); |
extern void pe_walk_relocs_of_symbol |
(struct bfd_link_info *, const char *, int (*) (arelent *, asection *)); |
extern void pe_create_import_fixup |
(arelent * rel, asection *, bfd_vma); |
extern bfd_boolean pe_bfd_is_dll |
(bfd *); |
extern void pe_output_file_set_long_section_names |
(bfd *); |
#endif /* PE_DLL_H */ |
/contrib/toolchain/binutils/ld/plugin.c |
---|
0,0 → 1,1041 |
/* Plugin control for the GNU linker. |
Copyright 2010, 2011, 2012, 2013 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "libiberty.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "bfdver.h" |
#include "ld.h" |
#include "ldmain.h" |
#include "ldmisc.h" |
#include "ldexp.h" |
#include "ldlang.h" |
#include "ldfile.h" |
#include "plugin.h" |
#include "plugin-api.h" |
#include "elf-bfd.h" |
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
#include <windows.h> |
#endif |
/* Report plugin symbols. */ |
bfd_boolean report_plugin_symbols; |
/* The suffix to append to the name of the real (claimed) object file |
when generating a dummy BFD to hold the IR symbols sent from the |
plugin. For cosmetic use only; appears in maps, crefs etc. */ |
#define IRONLY_SUFFIX " (symbol from plugin)" |
/* Stores a single argument passed to a plugin. */ |
typedef struct plugin_arg |
{ |
struct plugin_arg *next; |
const char *arg; |
} plugin_arg_t; |
/* Holds all details of a single plugin. */ |
typedef struct plugin |
{ |
/* Next on the list of plugins, or NULL at end of chain. */ |
struct plugin *next; |
/* The argument string given to --plugin. */ |
const char *name; |
/* The shared library handle returned by dlopen. */ |
void *dlhandle; |
/* The list of argument string given to --plugin-opt. */ |
plugin_arg_t *args; |
/* Number of args in the list, for convenience. */ |
size_t n_args; |
/* The plugin's event handlers. */ |
ld_plugin_claim_file_handler claim_file_handler; |
ld_plugin_all_symbols_read_handler all_symbols_read_handler; |
ld_plugin_cleanup_handler cleanup_handler; |
/* TRUE if the cleanup handlers have been called. */ |
bfd_boolean cleanup_done; |
} plugin_t; |
/* The master list of all plugins. */ |
static plugin_t *plugins_list = NULL; |
/* We keep a tail pointer for easy linking on the end. */ |
static plugin_t **plugins_tail_chain_ptr = &plugins_list; |
/* The last plugin added to the list, for receiving args. */ |
static plugin_t *last_plugin = NULL; |
/* The tail of the arg chain of the last plugin added to the list. */ |
static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL; |
/* The plugin which is currently having a callback executed. */ |
static plugin_t *called_plugin = NULL; |
/* Last plugin to cause an error, if any. */ |
static const char *error_plugin = NULL; |
/* State of linker "notice" interface before we poked at it. */ |
static bfd_boolean orig_notice_all; |
/* Original linker callbacks, and the plugin version. */ |
static const struct bfd_link_callbacks *orig_callbacks; |
static struct bfd_link_callbacks plugin_callbacks; |
/* Set at all symbols read time, to avoid recursively offering the plugin |
its own newly-added input files and libs to claim. */ |
bfd_boolean no_more_claiming = FALSE; |
/* List of tags to set in the constant leading part of the tv array. */ |
static const enum ld_plugin_tag tv_header_tags[] = |
{ |
LDPT_MESSAGE, |
LDPT_API_VERSION, |
LDPT_GNU_LD_VERSION, |
LDPT_LINKER_OUTPUT, |
LDPT_OUTPUT_NAME, |
LDPT_REGISTER_CLAIM_FILE_HOOK, |
LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, |
LDPT_REGISTER_CLEANUP_HOOK, |
LDPT_ADD_SYMBOLS, |
LDPT_GET_INPUT_FILE, |
LDPT_RELEASE_INPUT_FILE, |
LDPT_GET_SYMBOLS, |
LDPT_GET_SYMBOLS_V2, |
LDPT_ADD_INPUT_FILE, |
LDPT_ADD_INPUT_LIBRARY, |
LDPT_SET_EXTRA_LIBRARY_PATH |
}; |
/* How many entries in the constant leading part of the tv array. */ |
static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); |
/* Forward references. */ |
static bfd_boolean plugin_notice (struct bfd_link_info *, |
struct bfd_link_hash_entry *, bfd *, |
asection *, bfd_vma, flagword, const char *); |
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
#define RTLD_NOW 0 /* Dummy value. */ |
static void * |
dlopen (const char *file, int mode ATTRIBUTE_UNUSED) |
{ |
return LoadLibrary (file); |
} |
static void * |
dlsym (void *handle, const char *name) |
{ |
return GetProcAddress (handle, name); |
} |
static int |
dlclose (void *handle) |
{ |
FreeLibrary (handle); |
return 0; |
} |
#endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */ |
#ifndef HAVE_DLFCN_H |
static const char * |
dlerror (void) |
{ |
return ""; |
} |
#endif |
/* Helper function for exiting with error status. */ |
static int |
set_plugin_error (const char *plugin) |
{ |
error_plugin = plugin; |
return -1; |
} |
/* Test if an error occurred. */ |
static bfd_boolean |
plugin_error_p (void) |
{ |
return error_plugin != NULL; |
} |
/* Return name of plugin which caused an error if any. */ |
const char * |
plugin_error_plugin (void) |
{ |
return error_plugin ? error_plugin : _("<no plugin>"); |
} |
/* Handle -plugin arg: find and load plugin, or return error. */ |
void |
plugin_opt_plugin (const char *plugin) |
{ |
plugin_t *newplug; |
newplug = xmalloc (sizeof *newplug); |
memset (newplug, 0, sizeof *newplug); |
newplug->name = plugin; |
newplug->dlhandle = dlopen (plugin, RTLD_NOW); |
if (!newplug->dlhandle) |
einfo (_("%P%F: %s: error loading plugin: %s\n"), plugin, dlerror ()); |
/* Chain on end, so when we run list it is in command-line order. */ |
*plugins_tail_chain_ptr = newplug; |
plugins_tail_chain_ptr = &newplug->next; |
/* Record it as current plugin for receiving args. */ |
last_plugin = newplug; |
last_plugin_args_tail_chain_ptr = &newplug->args; |
} |
/* Accumulate option arguments for last-loaded plugin, or return |
error if none. */ |
int |
plugin_opt_plugin_arg (const char *arg) |
{ |
plugin_arg_t *newarg; |
if (!last_plugin) |
return set_plugin_error (_("<no plugin>")); |
newarg = xmalloc (sizeof *newarg); |
newarg->arg = arg; |
newarg->next = NULL; |
/* Chain on end to preserve command-line order. */ |
*last_plugin_args_tail_chain_ptr = newarg; |
last_plugin_args_tail_chain_ptr = &newarg->next; |
last_plugin->n_args++; |
return 0; |
} |
/* Create a dummy BFD. */ |
bfd * |
plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) |
{ |
bfd *abfd; |
bfd_use_reserved_id = 1; |
abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL), |
srctemplate); |
if (abfd != NULL) |
{ |
abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; |
bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); |
bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); |
if (bfd_make_writable (abfd) |
&& bfd_copy_private_bfd_data (srctemplate, abfd)) |
{ |
flagword flags; |
/* Create section to own the symbols. */ |
flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); |
if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) |
return abfd; |
} |
} |
einfo (_("could not create dummy IR bfd: %F%E\n")); |
return NULL; |
} |
/* Check if the BFD passed in is an IR dummy object file. */ |
static bfd_boolean |
is_ir_dummy_bfd (const bfd *abfd) |
{ |
/* ABFD can sometimes legitimately be NULL, e.g. when called from one |
of the linker callbacks for a symbol in the *ABS* or *UND* sections. |
Likewise, the usrdata field may be NULL if ABFD was added by the |
backend without a corresponding input statement, as happens e.g. |
when processing DT_NEEDED dependencies. */ |
return (abfd |
&& abfd->usrdata |
&& ((lang_input_statement_type *)(abfd->usrdata))->flags.claimed); |
} |
/* Helpers to convert between BFD and GOLD symbol formats. */ |
static enum ld_plugin_status |
asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, |
const struct ld_plugin_symbol *ldsym) |
{ |
flagword flags = BSF_NO_FLAGS; |
struct bfd_section *section; |
asym->the_bfd = abfd; |
asym->name = (ldsym->version |
? concat (ldsym->name, "@", ldsym->version, (const char *) NULL) |
: ldsym->name); |
asym->value = 0; |
switch (ldsym->def) |
{ |
case LDPK_WEAKDEF: |
flags = BSF_WEAK; |
/* FALLTHRU */ |
case LDPK_DEF: |
flags |= BSF_GLOBAL; |
if (ldsym->comdat_key) |
{ |
char *name = concat (".gnu.linkonce.t.", ldsym->comdat_key, |
(const char *) NULL); |
section = bfd_get_section_by_name (abfd, name); |
if (section != NULL) |
free (name); |
else |
{ |
flagword sflags; |
sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE |
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD); |
section = bfd_make_section_anyway_with_flags (abfd, name, sflags); |
if (section == NULL) |
return LDPS_ERR; |
} |
} |
else |
section = bfd_get_section_by_name (abfd, ".text"); |
break; |
case LDPK_WEAKUNDEF: |
flags = BSF_WEAK; |
/* FALLTHRU */ |
case LDPK_UNDEF: |
section = bfd_und_section_ptr; |
break; |
case LDPK_COMMON: |
flags = BSF_GLOBAL; |
section = bfd_com_section_ptr; |
asym->value = ldsym->size; |
/* For ELF targets, set alignment of common symbol to 1. */ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
{ |
((elf_symbol_type *) asym)->internal_elf_sym.st_shndx = SHN_COMMON; |
((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1; |
} |
break; |
default: |
return LDPS_ERR; |
} |
asym->flags = flags; |
asym->section = section; |
/* Visibility only applies on ELF targets. */ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
{ |
elf_symbol_type *elfsym = elf_symbol_from (abfd, asym); |
unsigned char visibility; |
if (!elfsym) |
einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!\n"), asym->name); |
switch (ldsym->visibility) |
{ |
default: |
einfo (_("%P%F: unknown ELF symbol visibility: %d!\n"), |
ldsym->visibility); |
case LDPV_DEFAULT: |
visibility = STV_DEFAULT; |
break; |
case LDPV_PROTECTED: |
visibility = STV_PROTECTED; |
break; |
case LDPV_INTERNAL: |
visibility = STV_INTERNAL; |
break; |
case LDPV_HIDDEN: |
visibility = STV_HIDDEN; |
break; |
} |
elfsym->internal_elf_sym.st_other |
= (visibility | (elfsym->internal_elf_sym.st_other |
& ~ELF_ST_VISIBILITY (-1))); |
} |
return LDPS_OK; |
} |
/* Register a claim-file handler. */ |
static enum ld_plugin_status |
register_claim_file (ld_plugin_claim_file_handler handler) |
{ |
ASSERT (called_plugin); |
called_plugin->claim_file_handler = handler; |
return LDPS_OK; |
} |
/* Register an all-symbols-read handler. */ |
static enum ld_plugin_status |
register_all_symbols_read (ld_plugin_all_symbols_read_handler handler) |
{ |
ASSERT (called_plugin); |
called_plugin->all_symbols_read_handler = handler; |
return LDPS_OK; |
} |
/* Register a cleanup handler. */ |
static enum ld_plugin_status |
register_cleanup (ld_plugin_cleanup_handler handler) |
{ |
ASSERT (called_plugin); |
called_plugin->cleanup_handler = handler; |
return LDPS_OK; |
} |
/* Add symbols from a plugin-claimed input file. */ |
static enum ld_plugin_status |
add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms) |
{ |
asymbol **symptrs; |
bfd *abfd = handle; |
int n; |
ASSERT (called_plugin); |
symptrs = xmalloc (nsyms * sizeof *symptrs); |
for (n = 0; n < nsyms; n++) |
{ |
enum ld_plugin_status rv; |
asymbol *bfdsym; |
bfdsym = bfd_make_empty_symbol (abfd); |
symptrs[n] = bfdsym; |
rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n); |
if (rv != LDPS_OK) |
return rv; |
} |
bfd_set_symtab (abfd, symptrs, nsyms); |
return LDPS_OK; |
} |
/* Get the input file information with an open (possibly re-opened) |
file descriptor. */ |
static enum ld_plugin_status |
get_input_file (const void *handle ATTRIBUTE_UNUSED, |
struct ld_plugin_input_file *file ATTRIBUTE_UNUSED) |
{ |
ASSERT (called_plugin); |
return LDPS_ERR; |
} |
/* Release the input file. */ |
static enum ld_plugin_status |
release_input_file (const void *handle ATTRIBUTE_UNUSED) |
{ |
ASSERT (called_plugin); |
return LDPS_ERR; |
} |
/* Return TRUE if a defined symbol might be reachable from outside the |
universe of claimed objects. */ |
static inline bfd_boolean |
is_visible_from_outside (struct ld_plugin_symbol *lsym, |
struct bfd_link_hash_entry *blhe) |
{ |
struct bfd_sym_chain *sym; |
if (link_info.relocatable) |
return TRUE; |
if (link_info.export_dynamic || !link_info.executable) |
{ |
/* Check if symbol is hidden by version script. */ |
if (bfd_hide_sym_by_version (link_info.version_info, |
blhe->root.string)) |
return FALSE; |
/* Only ELF symbols really have visibility. */ |
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) |
{ |
struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe; |
int vis = ELF_ST_VISIBILITY (el->other); |
return vis == STV_DEFAULT || vis == STV_PROTECTED; |
} |
/* On non-ELF targets, we can safely make inferences by considering |
what visibility the plugin would have liked to apply when it first |
sent us the symbol. During ELF symbol processing, visibility only |
ever becomes more restrictive, not less, when symbols are merged, |
so this is a conservative estimate; it may give false positives, |
declaring something visible from outside when it in fact would |
not have been, but this will only lead to missed optimisation |
opportunities during LTRANS at worst; it will not give false |
negatives, which can lead to the disastrous conclusion that the |
related symbol is IRONLY. (See GCC PR46319 for an example.) */ |
return (lsym->visibility == LDPV_DEFAULT |
|| lsym->visibility == LDPV_PROTECTED); |
} |
for (sym = &entry_symbol; sym != NULL; sym = sym->next) |
if (sym->name |
&& strcmp (sym->name, blhe->root.string) == 0) |
return TRUE; |
return FALSE; |
} |
/* Get the symbol resolution info for a plugin-claimed input file. */ |
static enum ld_plugin_status |
get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, |
int def_ironly_exp) |
{ |
const bfd *abfd = handle; |
int n; |
ASSERT (called_plugin); |
for (n = 0; n < nsyms; n++) |
{ |
struct bfd_link_hash_entry *blhe; |
asection *owner_sec; |
int res; |
if (syms[n].def != LDPK_UNDEF) |
blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name, |
FALSE, FALSE, TRUE); |
else |
blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, |
syms[n].name, FALSE, FALSE, TRUE); |
if (!blhe) |
{ |
res = LDPR_UNKNOWN; |
goto report_symbol; |
} |
/* Determine resolution from blhe type and symbol's original type. */ |
if (blhe->type == bfd_link_hash_undefined |
|| blhe->type == bfd_link_hash_undefweak) |
{ |
res = LDPR_UNDEF; |
goto report_symbol; |
} |
if (blhe->type != bfd_link_hash_defined |
&& blhe->type != bfd_link_hash_defweak |
&& blhe->type != bfd_link_hash_common) |
{ |
/* We should not have a new, indirect or warning symbol here. */ |
einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)\n", |
called_plugin->name, blhe->type); |
} |
/* Find out which section owns the symbol. Since it's not undef, |
it must have an owner; if it's not a common symbol, both defs |
and weakdefs keep it in the same place. */ |
owner_sec = (blhe->type == bfd_link_hash_common |
? blhe->u.c.p->section |
: blhe->u.def.section); |
/* If it was originally undefined or common, then it has been |
resolved; determine how. */ |
if (syms[n].def == LDPK_UNDEF |
|| syms[n].def == LDPK_WEAKUNDEF |
|| syms[n].def == LDPK_COMMON) |
{ |
if (owner_sec->owner == link_info.output_bfd) |
res = LDPR_RESOLVED_EXEC; |
else if (owner_sec->owner == abfd) |
res = LDPR_PREVAILING_DEF_IRONLY; |
else if (is_ir_dummy_bfd (owner_sec->owner)) |
res = LDPR_RESOLVED_IR; |
else if (owner_sec->owner != NULL |
&& (owner_sec->owner->flags & DYNAMIC) != 0) |
res = LDPR_RESOLVED_DYN; |
else |
res = LDPR_RESOLVED_EXEC; |
} |
/* Was originally def, or weakdef. Does it prevail? If the |
owner is the original dummy bfd that supplied it, then this |
is the definition that has prevailed. */ |
else if (owner_sec->owner == link_info.output_bfd) |
res = LDPR_PREEMPTED_REG; |
else if (owner_sec->owner == abfd) |
res = LDPR_PREVAILING_DEF_IRONLY; |
/* Was originally def, weakdef, or common, but has been pre-empted. */ |
else if (is_ir_dummy_bfd (owner_sec->owner)) |
res = LDPR_PREEMPTED_IR; |
else |
res = LDPR_PREEMPTED_REG; |
if (res == LDPR_PREVAILING_DEF_IRONLY) |
{ |
/* We need to know if the sym is referenced from non-IR files. Or |
even potentially-referenced, perhaps in a future final link if |
this is a partial one, perhaps dynamically at load-time if the |
symbol is externally visible. */ |
if (blhe->non_ir_ref) |
res = LDPR_PREVAILING_DEF; |
else if (is_visible_from_outside (&syms[n], blhe)) |
res = def_ironly_exp; |
} |
report_symbol: |
syms[n].resolution = res; |
if (report_plugin_symbols) |
einfo (_("%P: %B: symbol `%s' " |
"definition: %d, visibility: %d, resolution: %d\n"), |
abfd, syms[n].name, |
syms[n].def, syms[n].visibility, res); |
} |
return LDPS_OK; |
} |
static enum ld_plugin_status |
get_symbols_v1 (const void *handle, int nsyms, struct ld_plugin_symbol *syms) |
{ |
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF); |
} |
static enum ld_plugin_status |
get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms) |
{ |
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF_IRONLY_EXP); |
} |
/* Add a new (real) input file generated by a plugin. */ |
static enum ld_plugin_status |
add_input_file (const char *pathname) |
{ |
ASSERT (called_plugin); |
if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, |
NULL)) |
return LDPS_ERR; |
return LDPS_OK; |
} |
/* Add a new (real) library required by a plugin. */ |
static enum ld_plugin_status |
add_input_library (const char *pathname) |
{ |
ASSERT (called_plugin); |
if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, |
NULL)) |
return LDPS_ERR; |
return LDPS_OK; |
} |
/* Set the extra library path to be used by libraries added via |
add_input_library. */ |
static enum ld_plugin_status |
set_extra_library_path (const char *path) |
{ |
ASSERT (called_plugin); |
ldfile_add_library_path (xstrdup (path), FALSE); |
return LDPS_OK; |
} |
/* Issue a diagnostic message from a plugin. */ |
static enum ld_plugin_status |
message (int level, const char *format, ...) |
{ |
va_list args; |
va_start (args, format); |
switch (level) |
{ |
case LDPL_INFO: |
vfinfo (stdout, format, args, FALSE); |
putchar ('\n'); |
break; |
case LDPL_WARNING: |
vfinfo (stdout, format, args, TRUE); |
putchar ('\n'); |
break; |
case LDPL_FATAL: |
case LDPL_ERROR: |
default: |
{ |
char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ", |
format, "\n", (const char *) NULL)); |
fflush (stdout); |
vfinfo (stderr, newfmt, args, TRUE); |
fflush (stderr); |
} |
break; |
} |
va_end (args); |
return LDPS_OK; |
} |
/* Helper to size leading part of tv array and set it up. */ |
static void |
set_tv_header (struct ld_plugin_tv *tv) |
{ |
size_t i; |
/* Version info. */ |
static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL); |
static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100; |
for (i = 0; i < tv_header_size; i++) |
{ |
tv[i].tv_tag = tv_header_tags[i]; |
#define TVU(x) tv[i].tv_u.tv_ ## x |
switch (tv[i].tv_tag) |
{ |
case LDPT_MESSAGE: |
TVU(message) = message; |
break; |
case LDPT_API_VERSION: |
TVU(val) = LD_PLUGIN_API_VERSION; |
break; |
case LDPT_GNU_LD_VERSION: |
TVU(val) = major * 100 + minor; |
break; |
case LDPT_LINKER_OUTPUT: |
TVU(val) = (link_info.relocatable |
? LDPO_REL |
: (link_info.executable |
? (link_info.pie ? LDPO_PIE : LDPO_EXEC) |
: LDPO_DYN)); |
break; |
case LDPT_OUTPUT_NAME: |
TVU(string) = output_filename; |
break; |
case LDPT_REGISTER_CLAIM_FILE_HOOK: |
TVU(register_claim_file) = register_claim_file; |
break; |
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: |
TVU(register_all_symbols_read) = register_all_symbols_read; |
break; |
case LDPT_REGISTER_CLEANUP_HOOK: |
TVU(register_cleanup) = register_cleanup; |
break; |
case LDPT_ADD_SYMBOLS: |
TVU(add_symbols) = add_symbols; |
break; |
case LDPT_GET_INPUT_FILE: |
TVU(get_input_file) = get_input_file; |
break; |
case LDPT_RELEASE_INPUT_FILE: |
TVU(release_input_file) = release_input_file; |
break; |
case LDPT_GET_SYMBOLS: |
TVU(get_symbols) = get_symbols_v1; |
break; |
case LDPT_GET_SYMBOLS_V2: |
TVU(get_symbols) = get_symbols_v2; |
break; |
case LDPT_ADD_INPUT_FILE: |
TVU(add_input_file) = add_input_file; |
break; |
case LDPT_ADD_INPUT_LIBRARY: |
TVU(add_input_library) = add_input_library; |
break; |
case LDPT_SET_EXTRA_LIBRARY_PATH: |
TVU(set_extra_library_path) = set_extra_library_path; |
break; |
default: |
/* Added a new entry to the array without adding |
a new case to set up its value is a bug. */ |
FAIL (); |
} |
#undef TVU |
} |
} |
/* Append the per-plugin args list and trailing LDPT_NULL to tv. */ |
static void |
set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv) |
{ |
plugin_arg_t *arg = plugin->args; |
while (arg) |
{ |
tv->tv_tag = LDPT_OPTION; |
tv->tv_u.tv_string = arg->arg; |
arg = arg->next; |
tv++; |
} |
tv->tv_tag = LDPT_NULL; |
tv->tv_u.tv_val = 0; |
} |
/* Return true if any plugins are active this run. Only valid |
after options have been processed. */ |
bfd_boolean |
plugin_active_plugins_p (void) |
{ |
return plugins_list != NULL; |
} |
/* Load up and initialise all plugins after argument parsing. */ |
void |
plugin_load_plugins (void) |
{ |
struct ld_plugin_tv *my_tv; |
unsigned int max_args = 0; |
plugin_t *curplug = plugins_list; |
/* If there are no plugins, we need do nothing this run. */ |
if (!curplug) |
return; |
/* First pass over plugins to find max # args needed so that we |
can size and allocate the tv array. */ |
while (curplug) |
{ |
if (curplug->n_args > max_args) |
max_args = curplug->n_args; |
curplug = curplug->next; |
} |
/* Allocate tv array and initialise constant part. */ |
my_tv = xmalloc ((max_args + 1 + tv_header_size) * sizeof *my_tv); |
set_tv_header (my_tv); |
/* Pass over plugins again, activating them. */ |
curplug = plugins_list; |
while (curplug) |
{ |
enum ld_plugin_status rv; |
ld_plugin_onload onloadfn; |
onloadfn = (ld_plugin_onload) dlsym (curplug->dlhandle, "onload"); |
if (!onloadfn) |
onloadfn = (ld_plugin_onload) dlsym (curplug->dlhandle, "_onload"); |
if (!onloadfn) |
einfo (_("%P%F: %s: error loading plugin: %s\n"), |
curplug->name, dlerror ()); |
set_tv_plugin_args (curplug, &my_tv[tv_header_size]); |
called_plugin = curplug; |
rv = (*onloadfn) (my_tv); |
called_plugin = NULL; |
if (rv != LDPS_OK) |
einfo (_("%P%F: %s: plugin error: %d\n"), curplug->name, rv); |
curplug = curplug->next; |
} |
/* Since plugin(s) inited ok, assume they're going to want symbol |
resolutions, which needs us to track which symbols are referenced |
by non-IR files using the linker's notice callback. */ |
orig_notice_all = link_info.notice_all; |
orig_callbacks = link_info.callbacks; |
plugin_callbacks = *orig_callbacks; |
plugin_callbacks.notice = &plugin_notice; |
link_info.notice_all = TRUE; |
link_info.callbacks = &plugin_callbacks; |
} |
/* Call 'claim file' hook for all plugins. */ |
static int |
plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) |
{ |
plugin_t *curplug = plugins_list; |
*claimed = FALSE; |
if (no_more_claiming) |
return 0; |
while (curplug && !*claimed) |
{ |
if (curplug->claim_file_handler) |
{ |
enum ld_plugin_status rv; |
called_plugin = curplug; |
rv = (*curplug->claim_file_handler) (file, claimed); |
called_plugin = NULL; |
if (rv != LDPS_OK) |
set_plugin_error (curplug->name); |
} |
curplug = curplug->next; |
} |
return plugin_error_p () ? -1 : 0; |
} |
void |
plugin_maybe_claim (struct ld_plugin_input_file *file, |
lang_input_statement_type *entry) |
{ |
int claimed = 0; |
/* We create a dummy BFD, initially empty, to house whatever symbols |
the plugin may want to add. */ |
file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename, |
entry->the_bfd); |
if (plugin_call_claim_file (file, &claimed)) |
einfo (_("%P%F: %s: plugin reported error claiming file\n"), |
plugin_error_plugin ()); |
/* fd belongs to us, not the plugin; but we don't need it. */ |
close (file->fd); |
if (claimed) |
{ |
/* Discard the real file's BFD and substitute the dummy one. */ |
/* BFD archive handling caches elements so we can't call |
bfd_close for archives. */ |
if (entry->the_bfd->my_archive == NULL) |
bfd_close (entry->the_bfd); |
entry->the_bfd = file->handle; |
entry->flags.claimed = TRUE; |
bfd_make_readable (entry->the_bfd); |
} |
else |
{ |
/* If plugin didn't claim the file, we don't need the dummy bfd. |
Can't avoid speculatively creating it, alas. */ |
bfd_close_all_done (file->handle); |
entry->flags.claimed = FALSE; |
} |
} |
/* Call 'all symbols read' hook for all plugins. */ |
int |
plugin_call_all_symbols_read (void) |
{ |
plugin_t *curplug = plugins_list; |
/* Disable any further file-claiming. */ |
no_more_claiming = TRUE; |
while (curplug) |
{ |
if (curplug->all_symbols_read_handler) |
{ |
enum ld_plugin_status rv; |
called_plugin = curplug; |
rv = (*curplug->all_symbols_read_handler) (); |
called_plugin = NULL; |
if (rv != LDPS_OK) |
set_plugin_error (curplug->name); |
} |
curplug = curplug->next; |
} |
return plugin_error_p () ? -1 : 0; |
} |
/* Call 'cleanup' hook for all plugins at exit. */ |
void |
plugin_call_cleanup (void) |
{ |
plugin_t *curplug = plugins_list; |
while (curplug) |
{ |
if (curplug->cleanup_handler && !curplug->cleanup_done) |
{ |
enum ld_plugin_status rv; |
curplug->cleanup_done = TRUE; |
called_plugin = curplug; |
rv = (*curplug->cleanup_handler) (); |
called_plugin = NULL; |
if (rv != LDPS_OK) |
info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"), |
curplug->name, rv); |
dlclose (curplug->dlhandle); |
} |
curplug = curplug->next; |
} |
} |
/* To determine which symbols should be resolved LDPR_PREVAILING_DEF |
and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as |
the linker adds them to the linker hash table. Mark those |
referenced from a non-IR file with non_ir_ref. We have to |
notice_all symbols, because we won't necessarily know until later |
which ones will be contributed by IR files. */ |
static bfd_boolean |
plugin_notice (struct bfd_link_info *info, |
struct bfd_link_hash_entry *h, |
bfd *abfd, |
asection *section, |
bfd_vma value, |
flagword flags, |
const char *string) |
{ |
if (h != NULL) |
{ |
bfd *sym_bfd; |
/* Nothing to do here if this def/ref is from an IR dummy BFD. */ |
if (is_ir_dummy_bfd (abfd)) |
; |
/* Making an indirect symbol counts as a reference unless this |
is a brand new symbol. */ |
else if (bfd_is_ind_section (section) |
|| (flags & BSF_INDIRECT) != 0) |
{ |
if (h->type != bfd_link_hash_new) |
{ |
struct bfd_link_hash_entry *inh; |
h->non_ir_ref = TRUE; |
inh = bfd_wrapped_link_hash_lookup (abfd, info, string, FALSE, |
FALSE, FALSE); |
if (inh != NULL) |
inh->non_ir_ref = TRUE; |
} |
} |
/* Nothing to do here for warning symbols. */ |
else if ((flags & BSF_WARNING) != 0) |
; |
/* Nothing to do here for constructor symbols. */ |
else if ((flags & BSF_CONSTRUCTOR) != 0) |
; |
/* If this is a ref, set non_ir_ref. */ |
else if (bfd_is_und_section (section)) |
{ |
/* Replace the undefined dummy bfd with the real one. */ |
if ((h->type == bfd_link_hash_undefined |
|| h->type == bfd_link_hash_undefweak) |
&& (h->u.undef.abfd == NULL |
|| (h->u.undef.abfd->flags & BFD_PLUGIN) != 0)) |
h->u.undef.abfd = abfd; |
h->non_ir_ref = TRUE; |
} |
/* Otherwise, it must be a new def. Ensure any symbol defined |
in an IR dummy BFD takes on a new value from a real BFD. |
Weak symbols are not normally overridden by a new weak |
definition, and strong symbols will normally cause multiple |
definition errors. Avoid this by making the symbol appear |
to be undefined. */ |
else if (((h->type == bfd_link_hash_defweak |
|| h->type == bfd_link_hash_defined) |
&& is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner)) |
|| (h->type == bfd_link_hash_common |
&& is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner))) |
{ |
h->type = bfd_link_hash_undefweak; |
h->u.undef.abfd = sym_bfd; |
} |
} |
/* Continue with cref/nocrossref/trace-sym processing. */ |
if (h == NULL |
|| orig_notice_all |
|| (info->notice_hash != NULL |
&& bfd_hash_lookup (info->notice_hash, h->root.string, |
FALSE, FALSE) != NULL)) |
return (*orig_callbacks->notice) (info, h, |
abfd, section, value, flags, string); |
return TRUE; |
} |
/* Return true if bfd is a dynamic library that should be reloaded. */ |
bfd_boolean |
plugin_should_reload (bfd *abfd) |
{ |
return ((abfd->flags & DYNAMIC) != 0 |
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& bfd_get_format (abfd) == bfd_object |
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0); |
} |
/contrib/toolchain/binutils/ld/plugin.h |
---|
0,0 → 1,72 |
/* Plugin control for the GNU linker. |
Copyright 2010, 2011 Free Software Foundation, Inc. |
This file is part of the GNU Binutils. |
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 3 of the License, 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, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef GLD_PLUGIN_H |
#define GLD_PLUGIN_H |
/* Report plugin symbols. */ |
extern bfd_boolean report_plugin_symbols; |
/* Set at all symbols read time, to avoid recursively offering the plugin |
its own newly-added input files and libs to claim. */ |
extern bfd_boolean no_more_claiming; |
/* This is the only forward declaration we need to avoid having |
to include the plugin-api.h header in order to use this file. */ |
struct ld_plugin_input_file; |
/* Handle -plugin arg: find and load plugin. */ |
extern void plugin_opt_plugin (const char *plugin); |
/* Accumulate option arguments for last-loaded plugin, or return |
error if none. */ |
extern int plugin_opt_plugin_arg (const char *arg); |
/* Return true if any plugins are active this run. Only valid |
after options have been processed. */ |
extern bfd_boolean plugin_active_plugins_p (void); |
/* Load up and initialise all plugins after argument parsing. */ |
extern void plugin_load_plugins (void); |
/* Return name of plugin which caused an error in any of the above. */ |
extern const char *plugin_error_plugin (void); |
/* Call 'claim file' hook for all plugins. */ |
extern void plugin_maybe_claim (struct ld_plugin_input_file *, |
lang_input_statement_type *); |
/* Call 'all symbols read' hook for all plugins. */ |
extern int plugin_call_all_symbols_read (void); |
/* Call 'cleanup' hook for all plugins at exit. */ |
extern void plugin_call_cleanup (void); |
/* Generate a dummy BFD to represent an IR file, for any callers of |
plugin_call_claim_file to use as the handle in the ld_plugin_input_file |
struct that they build to pass in. The BFD is initially writable, so |
that symbols can be added to it; it must be made readable after the |
add_symbols hook has been called so that it can be read when linking. */ |
extern bfd *plugin_get_ir_dummy_bfd (const char *name, bfd *template); |
/* Return true if bfd is a dynamic library that should be reloaded. */ |
extern bfd_boolean plugin_should_reload (bfd *); |
#endif /* !def GLD_PLUGIN_H */ |