diff options
Diffstat (limited to 'binutils-2.21/ld/emultempl')
52 files changed, 20641 insertions, 0 deletions
diff --git a/binutils-2.21/ld/emultempl/README b/binutils-2.21/ld/emultempl/README new file mode 100644 index 0000000..30ec0ab --- /dev/null +++ b/binutils-2.21/ld/emultempl/README @@ -0,0 +1,3 @@ +The files in this directory are sourced by genscripts.sh, after +setting some variables to substitute in, to produce +C source files that contain jump tables for each emulation. diff --git a/binutils-2.21/ld/emultempl/aix.em b/binutils-2.21/ld/emultempl/aix.em new file mode 100644 index 0000000..4dc36c3 --- /dev/null +++ b/binutils-2.21/ld/emultempl/aix.em @@ -0,0 +1,1472 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* AIX emulation code for ${EMULATION_NAME} + Copyright 1991, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + Written by Steve Chamberlain <sac@cygnus.com> + AIX support by Ian Lance Taylor <ian@cygnus.com> + AIX 64 bit support by Tom Rix <trix@redhat.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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "getopt.h" +#include "obstack.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldctor.h" +#include <ldgram.h> + +#include "coff/internal.h" +#include "coff/xcoff.h" +#include "libcoff.h" +#include "libxcoff.h" + +static void gld${EMULATION_NAME}_read_file (const char *, bfd_boolean); +static void gld${EMULATION_NAME}_free (void *); +static void gld${EMULATION_NAME}_find_relocs (lang_statement_union_type *); +static void gld${EMULATION_NAME}_find_exp_assignment (etree_type *); + + +/* The file alignment required for each section. */ +static unsigned long file_align; + +/* The maximum size the stack is permitted to grow. This is stored in + the a.out header. */ +static unsigned long maxstack; + +/* The maximum data size. This is stored in the a.out header. */ +static unsigned long maxdata; + +/* Whether to perform garbage collection. */ +static int gc = 1; + +/* The module type to use. */ +static unsigned short modtype = ('1' << 8) | 'L'; + +/* Whether the .text section must be read-only (i.e., no relocs + permitted). */ +static int textro; + +/* A mask of XCOFF_EXPALL and XCOFF_EXPFULL flags, as set by their + associated -b and -bno options. */ +static unsigned int auto_export_flags; + +/* A mask of auto_export_flags bits that were explicitly set on the + command line. */ +static unsigned int explicit_auto_export_flags; + +/* Whether to implement Unix like linker semantics. */ +static int unix_ld; + +/* Structure used to hold import file list. */ + +struct filelist +{ + struct filelist *next; + const char *name; +}; + +/* List of import files. */ +static struct filelist *import_files; + +/* List of export symbols read from the export files. */ + +struct export_symbol_list +{ + struct export_symbol_list *next; + const char *name; +}; + +static struct export_symbol_list *export_symbols; + +/* Maintains the 32 or 64 bit mode state of import file */ +static unsigned int symbol_mode = 0x04; + +/* Which symbol modes are valid */ +static unsigned int symbol_mode_mask = 0x0d; + +/* Whether this is a 64 bit link */ +static int is_64bit = 0; + +/* Which syscalls from import file are valid */ +static unsigned int syscall_mask = 0x77; + +/* fake file for -binitfini support */ +static lang_input_statement_type *initfini_file; + +/* Whether to do run time linking + -brtl enables, -bnortl and -bnortllib disable. */ +static int rtld; + +/* Explicit command line library path, -blibpath */ +static char *command_line_blibpath = NULL; + +/* This routine is called before anything else is done. */ + +static void +gld${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + + config.dynamic_link = TRUE; + config.has_shared = TRUE; + + /* The link_info.[init|fini]_functions are initialized in ld/lexsup.c. + Override them here so we can use the link_info.init_function as a + state flag that lets the backend know that -binitfini has been done. */ + + link_info.init_function = NULL; + link_info.fini_function = NULL; +} + +/* Handle AIX specific options. */ + +enum + { + OPTION_IGNORE = 300, + OPTION_AUTOIMP, + OPTION_ERNOTOK, + OPTION_EROK, + OPTION_EXPALL, + OPTION_EXPFULL, + OPTION_EXPORT, + OPTION_IMPORT, + OPTION_INITFINI, + OPTION_LOADMAP, + OPTION_MAXDATA, + OPTION_MAXSTACK, + OPTION_MODTYPE, + OPTION_NOAUTOIMP, + OPTION_NOEXPALL, + OPTION_NOEXPFULL, + OPTION_NOSTRCMPCT, + OPTION_PD, + OPTION_PT, + OPTION_STRCMPCT, + OPTION_UNIX, + OPTION_32, + OPTION_64, + OPTION_LIBPATH, + OPTION_NOLIBPATH, + }; + +static void +gld${EMULATION_NAME}_add_options + (int ns, char **shortopts, int nl, struct option **longopts, + int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED) +{ + static const char xtra_short[] = "D:H:KT:z"; + static const struct option xtra_long[] = { + /* -binitfini has special handling in the linker backend. The native linker + uses the arguemnts to generate a table of init and fini functions for + the executable. The important use for this option is to support aix 4.2+ + c++ constructors and destructors. This is tied into gcc via collect2.c. + + The function table is accessed by the runtime linker/loader by checking if + the first symbol in the loader symbol table is __rtinit. The gnu linker + generates this symbol and makes it the first loader symbol. */ + + {"basis", no_argument, NULL, OPTION_IGNORE}, + {"bautoimp", no_argument, NULL, OPTION_AUTOIMP}, + {"bcomprld", no_argument, NULL, OPTION_IGNORE}, + {"bcrld", no_argument, NULL, OPTION_IGNORE}, + {"bcror31", no_argument, NULL, OPTION_IGNORE}, + {"bD", required_argument, NULL, OPTION_MAXDATA}, + {"bE", required_argument, NULL, OPTION_EXPORT}, + {"bernotok", no_argument, NULL, OPTION_ERNOTOK}, + {"berok", no_argument, NULL, OPTION_EROK}, + {"berrmsg", no_argument, NULL, OPTION_IGNORE}, + {"bexpall", no_argument, NULL, OPTION_EXPALL}, + {"bexpfull", no_argument, NULL, OPTION_EXPFULL}, + {"bexport", required_argument, NULL, OPTION_EXPORT}, + {"bf", no_argument, NULL, OPTION_ERNOTOK}, + {"bgc", no_argument, &gc, 1}, + {"bh", required_argument, NULL, OPTION_IGNORE}, + {"bhalt", required_argument, NULL, OPTION_IGNORE}, + {"bI", required_argument, NULL, OPTION_IMPORT}, + {"bimport", required_argument, NULL, OPTION_IMPORT}, + {"binitfini", required_argument, NULL, OPTION_INITFINI}, + {"bl", required_argument, NULL, OPTION_LOADMAP}, + {"bloadmap", required_argument, NULL, OPTION_LOADMAP}, + {"bmaxdata", required_argument, NULL, OPTION_MAXDATA}, + {"bmaxstack", required_argument, NULL, OPTION_MAXSTACK}, + {"bM", required_argument, NULL, OPTION_MODTYPE}, + {"bmodtype", required_argument, NULL, OPTION_MODTYPE}, + {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP}, + {"bnoexpall", no_argument, NULL, OPTION_NOEXPALL}, + {"bnoexpfull", no_argument, NULL, OPTION_NOEXPFULL}, + {"bnodelcsect", no_argument, NULL, OPTION_IGNORE}, + {"bnoentry", no_argument, NULL, OPTION_IGNORE}, + {"bnogc", no_argument, &gc, 0}, + {"bnso", no_argument, NULL, OPTION_NOAUTOIMP}, + {"bnostrcmpct", no_argument, NULL, OPTION_NOSTRCMPCT}, + {"bnotextro", no_argument, &textro, 0}, + {"bnro", no_argument, &textro, 0}, + {"bpD", required_argument, NULL, OPTION_PD}, + {"bpT", required_argument, NULL, OPTION_PT}, + {"bro", no_argument, &textro, 1}, + {"brtl", no_argument, &rtld, 1}, + {"bnortl", no_argument, &rtld, 0}, + {"bnortllib", no_argument, &rtld, 0}, + {"bS", required_argument, NULL, OPTION_MAXSTACK}, + {"bso", no_argument, NULL, OPTION_AUTOIMP}, + {"bstrcmpct", no_argument, NULL, OPTION_STRCMPCT}, + {"btextro", no_argument, &textro, 1}, + {"b32", no_argument, NULL, OPTION_32}, + {"b64", no_argument, NULL, OPTION_64}, + {"static", no_argument, NULL, OPTION_NOAUTOIMP}, + {"unix", no_argument, NULL, OPTION_UNIX}, + {"blibpath", required_argument, NULL, OPTION_LIBPATH}, + {"bnolibpath", required_argument, NULL, OPTION_NOLIBPATH}, + {NULL, no_argument, NULL, 0} + }; + + /* Options supported by the AIX linker which we do not support: -f, + -S, -v, -Z, -bbindcmds, -bbinder, -bbindopts, -bcalls, -bcaps, + -bcror15, -bdebugopt, -bdbg, -bdelcsect, -bex?, -bfilelist, -bfl, + -bgcbypass, -bglink, -binsert, -bi, -bloadmap, -bl, -bmap, -bnl, + -bnobind, -bnocomprld, -bnocrld, -bnoerrmsg, -bnoglink, + -bnoloadmap, -bnl, -bnoobjreorder, -bnoquiet, -bnoreorder, + -bnotypchk, -bnox, -bquiet, -bR, -brename, -breorder, -btypchk, + -bx, -bX, -bxref. */ + + *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short)); + memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short)); + *longopts = xrealloc (*longopts, + nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +static bfd_boolean +gld${EMULATION_NAME}_parse_args (int argc, char **argv) +{ + int indx; + + /* If the current option starts with -b, change the first : to an =. + The AIX linker uses : to separate the option from the argument; + changing it to = lets us treat it as a getopt option. */ + indx = optind; + if (indx == 0) + indx = 1; + + if (indx < argc && CONST_STRNEQ (argv[indx], "-b")) + { + char *s; + + for (s = argv[indx]; *s != '\0'; s++) + { + if (*s == ':') + { + *s = '='; + break; + } + } + } + return FALSE; +} + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + bfd_signed_vma val; + const char *end; + + switch (optc) + { + default: + return FALSE; + + case 0: + /* Long option which just sets a flag. */ + break; + + case 'D': + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -D number %s\n", optarg); + else if (val != -1) + lang_section_start (".data", exp_intop (val), NULL); + break; + + case 'H': + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0' || (val & (val - 1)) != 0) + einfo ("%P: warning: ignoring invalid -H number %s\n", optarg); + else + file_align = val; + break; + + case 'K': + case 'z': + /* FIXME: This should use the page size for the target system. */ + file_align = 4096; + break; + + case 'T': + /* On AIX this is the same as GNU ld -Ttext. When we see -T + number, we assume the AIX option is intended. Otherwise, we + assume the usual GNU ld -T option is intended. We can't just + ignore the AIX option, because gcc passes it to the linker. */ + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + return FALSE; + lang_section_start (".text", exp_intop (val), NULL); + break; + + case OPTION_IGNORE: + break; + + case OPTION_INITFINI: + { + /* + * The aix linker init fini has the format : + * + * -binitfini:[ Initial][:Termination][:Priority] + * + * it allows the Termination and Priority to be optional. + * + * Since we support only one init/fini pair, we ignore the Priority. + * + * Define the special symbol __rtinit. + * + * strtok does not correctly handle the case of -binitfini::fini: so + * do it by hand + */ + char *t, *i, *f; + + i = t = optarg; + while (*t && ':' != *t) + t++; + if (*t) + *t++ = 0; + + if (0 != strlen (i)) + link_info.init_function = i; + + f = t; + while (*t && ':' != *t) + t++; + *t = 0; + + if (0 != strlen (f)) + link_info.fini_function = f; + } + break; + + case OPTION_AUTOIMP: + link_info.static_link = FALSE; + break; + + case OPTION_ERNOTOK: + link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; + link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR; + break; + + case OPTION_EROK: + link_info.unresolved_syms_in_objects = RM_IGNORE; + link_info.unresolved_syms_in_shared_libs = RM_IGNORE; + break; + + case OPTION_EXPALL: + auto_export_flags |= XCOFF_EXPALL; + explicit_auto_export_flags |= XCOFF_EXPALL; + break; + + case OPTION_EXPFULL: + auto_export_flags |= XCOFF_EXPFULL; + explicit_auto_export_flags |= XCOFF_EXPFULL; + break; + + case OPTION_EXPORT: + gld${EMULATION_NAME}_read_file (optarg, FALSE); + break; + + case OPTION_IMPORT: + { + struct filelist *n; + struct filelist **flpp; + + n = (struct filelist *) xmalloc (sizeof (struct filelist)); + n->next = NULL; + n->name = optarg; + flpp = &import_files; + while (*flpp != NULL) + flpp = &(*flpp)->next; + *flpp = n; + } + break; + + case OPTION_LOADMAP: + config.map_filename = optarg; + break; + + case OPTION_MAXDATA: + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -bmaxdata number %s\n", optarg); + else + maxdata = val; + break; + + case OPTION_MAXSTACK: + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -bmaxstack number %s\n", + optarg); + else + maxstack = val; + break; + + case OPTION_MODTYPE: + if (*optarg == 'S') + { + link_info.shared = TRUE; + ++optarg; + } + if (*optarg == '\0' || optarg[1] == '\0') + einfo ("%P: warning: ignoring invalid module type %s\n", optarg); + else + modtype = (*optarg << 8) | optarg[1]; + break; + + case OPTION_NOAUTOIMP: + link_info.static_link = TRUE; + break; + + case OPTION_NOEXPALL: + auto_export_flags &= ~XCOFF_EXPALL; + explicit_auto_export_flags |= XCOFF_EXPALL; + break; + + case OPTION_NOEXPFULL: + auto_export_flags &= ~XCOFF_EXPFULL; + explicit_auto_export_flags |= XCOFF_EXPFULL; + break; + + case OPTION_NOSTRCMPCT: + link_info.traditional_format = TRUE; + break; + + case OPTION_PD: + /* This sets the page that the .data section is supposed to + start on. The offset within the page should still be the + offset within the file, so we need to build an appropriate + expression. */ + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -pD number %s\n", optarg); + else + { + etree_type *t; + + t = exp_binop ('+', + exp_intop (val), + exp_binop ('&', + exp_nameop (NAME, "."), + exp_intop (0xfff))); + t = exp_binop ('&', + exp_binop ('+', t, exp_intop (31)), + exp_intop (~(bfd_vma) 31)); + lang_section_start (".data", t, NULL); + } + break; + + case OPTION_PT: + /* This set the page that the .text section is supposed to start + on. The offset within the page should still be the offset + within the file. */ + val = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -pT number %s\n", optarg); + else + { + etree_type *t; + + t = exp_binop ('+', + exp_intop (val), + exp_nameop (SIZEOF_HEADERS, NULL)); + t = exp_binop ('&', + exp_binop ('+', t, exp_intop (31)), + exp_intop (~(bfd_vma) 31)); + lang_section_start (".text", t, NULL); + } + break; + + case OPTION_STRCMPCT: + link_info.traditional_format = FALSE; + break; + + case OPTION_UNIX: + unix_ld = TRUE; + break; + + case OPTION_32: + is_64bit = 0; + syscall_mask = 0x77; + symbol_mode_mask = 0x0d; + break; + + case OPTION_64: + is_64bit = 1; + syscall_mask = 0xcc; + symbol_mode_mask = 0x0e; + break; + + case OPTION_LIBPATH: + command_line_blibpath = optarg; + break; + + case OPTION_NOLIBPATH: + command_line_blibpath = NULL; + break; + + } + + return TRUE; +} + +/* This is called when an input file can not be recognized as a BFD + object or an archive. If the file starts with #!, we must treat it + as an import file. This is for AIX compatibility. */ + +static bfd_boolean +gld${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry) +{ + FILE *e; + bfd_boolean ret; + + e = fopen (entry->filename, FOPEN_RT); + if (e == NULL) + return FALSE; + + ret = FALSE; + + if (getc (e) == '#' && getc (e) == '!') + { + struct filelist *n; + struct filelist **flpp; + + n = (struct filelist *) xmalloc (sizeof (struct filelist)); + n->next = NULL; + n->name = entry->filename; + flpp = &import_files; + while (*flpp != NULL) + flpp = &(*flpp)->next; + *flpp = n; + + ret = TRUE; + entry->loaded = TRUE; + } + + fclose (e); + + return ret; +} + +/* This is called after the input files have been opened. */ + +static void +gld${EMULATION_NAME}_after_open (void) +{ + bfd_boolean r; + struct set_info *p; + + /* Call ldctor_build_sets, after pretending that this is a + relocatable link. We do this because AIX requires relocation + entries for all references to symbols, even in a final + executable. Of course, we only want to do this if we are + producing an XCOFF output file. */ + r = link_info.relocatable; + if (strstr (bfd_get_target (link_info.output_bfd), "xcoff") != NULL) + link_info.relocatable = TRUE; + ldctor_build_sets (); + link_info.relocatable = r; + + /* For each set, record the size, so that the XCOFF backend can + output the correct csect length. */ + for (p = sets; p != (struct set_info *) NULL; p = p->next) + { + bfd_size_type 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; + + if (p->reloc != BFD_RELOC_CTOR) + { + /* Handle this if we need to. */ + abort (); + } + + size = (p->count + 2) * 4; + if (!bfd_xcoff_link_record_set (link_info.output_bfd, &link_info, + p->h, size)) + einfo ("%F%P: bfd_xcoff_link_record_set failed: %E\n"); + } +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + struct filelist *fl; + struct export_symbol_list *el; + char *libpath; + asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS]; + static const char *const must_keep_sections[] = { + ".text", + ".data", + ".bss" + }; + unsigned int i, flags; + + /* Handle the import and export files, if any. */ + for (fl = import_files; fl != NULL; fl = fl->next) + gld${EMULATION_NAME}_read_file (fl->name, TRUE); + for (el = export_symbols; el != NULL; el = el->next) + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, el->name, FALSE, FALSE, FALSE); + if (h == NULL) + einfo ("%P%F: bfd_link_hash_lookup of export symbol failed: %E\n"); + if (!bfd_xcoff_export_symbol (link_info.output_bfd, &link_info, h)) + einfo ("%P%F: bfd_xcoff_export_symbol failed: %E\n"); + } + + /* Track down all relocations called for by the linker script (these + are typically constructor/destructor entries created by + CONSTRUCTORS) and let the backend know it will need to create + .loader relocs for them. */ + lang_for_each_statement (gld${EMULATION_NAME}_find_relocs); + + /* Precedence of LIBPATH + -blibpath: native support always first + -rpath: gnu extension + -L build from command line -L's */ + if (command_line_blibpath != NULL) + libpath = command_line_blibpath; + else if (command_line.rpath != NULL) + libpath = command_line.rpath; + else if (search_head == NULL) + libpath = (char *) ""; + else + { + size_t len; + search_dirs_type *search; + + /* PR ld/4023: Strip sysroot prefix from any paths + being inserted into the output binary's DT_RPATH. */ + if (ld_sysroot != NULL + && * ld_sysroot != 0) + { + const char * name = search_head->name; + size_t ld_sysroot_len = strlen (ld_sysroot); + + if (strncmp (name, ld_sysroot, ld_sysroot_len) == 0) + name += ld_sysroot_len; + + len = strlen (name); + libpath = xmalloc (len + 1); + strcpy (libpath, name); + + for (search = search_head->next; search != NULL; search = search->next) + { + size_t nlen; + + name = search->name; + if (strncmp (name, ld_sysroot, ld_sysroot_len) == 0) + name += ld_sysroot_len; + + nlen = strlen (name); + libpath = xrealloc (libpath, len + nlen + 2); + libpath[len] = ':'; + strcpy (libpath + len + 1, name); + len += nlen + 1; + } + } + else + { + len = strlen (search_head->name); + libpath = xmalloc (len + 1); + strcpy (libpath, search_head->name); + + for (search = search_head->next; search != NULL; search = search->next) + { + size_t nlen; + + nlen = strlen (search->name); + libpath = xrealloc (libpath, len + nlen + 2); + libpath[len] = ':'; + strcpy (libpath + len + 1, search->name); + len += nlen + 1; + } + } + } + + /* Default to -bexpfull for SVR4-like semantics. */ + flags = (unix_ld ? XCOFF_EXPFULL : 0); + flags &= ~explicit_auto_export_flags; + flags |= auto_export_flags; + + /* Let the XCOFF backend set up the .loader section. */ + if (!bfd_xcoff_size_dynamic_sections + (link_info.output_bfd, &link_info, libpath, entry_symbol.name, file_align, + maxstack, maxdata, gc && !unix_ld ? TRUE : FALSE, + modtype, textro ? TRUE : FALSE, flags, special_sections, + rtld ? TRUE : FALSE)) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); + + /* Look through the special sections, and put them in the right + place in the link ordering. This is especially magic. */ + for (i = 0; i < XCOFF_NUMBER_OF_SPECIAL_SECTIONS; i++) + { + asection *sec; + lang_output_section_statement_type *os; + lang_statement_union_type **pls; + lang_input_section_type *is; + const char *oname; + bfd_boolean start; + + sec = special_sections[i]; + if (sec == NULL) + continue; + + /* Remove this section from the list of the output section. + This assumes we know what the script looks like. */ + is = NULL; + os = lang_output_section_find (sec->output_section->name); + if (os == NULL) + einfo ("%P%F: can't find output section %s\n", + sec->output_section->name); + + for (pls = &os->children.head; *pls != NULL; pls = &(*pls)->header.next) + { + if ((*pls)->header.type == lang_input_section_enum + && (*pls)->input_section.section == sec) + { + is = (lang_input_section_type *) * pls; + *pls = (*pls)->header.next; + break; + } + + if ((*pls)->header.type == lang_wild_statement_enum) + { + lang_statement_union_type **pwls; + + for (pwls = &(*pls)->wild_statement.children.head; + *pwls != NULL; pwls = &(*pwls)->header.next) + { + + if ((*pwls)->header.type == lang_input_section_enum + && (*pwls)->input_section.section == sec) + { + is = (lang_input_section_type *) * pwls; + *pwls = (*pwls)->header.next; + break; + } + } + + if (is != NULL) + break; + } + } + + if (is == NULL) + { + einfo ("%P%F: can't find %s in output section\n", + bfd_get_section_name (sec->owner, sec)); + } + + /* Now figure out where the section should go. */ + switch (i) + { + + default: /* to avoid warnings */ + case XCOFF_SPECIAL_SECTION_TEXT: + /* _text */ + oname = ".text"; + start = TRUE; + break; + + case XCOFF_SPECIAL_SECTION_ETEXT: + /* _etext */ + oname = ".text"; + start = FALSE; + break; + + case XCOFF_SPECIAL_SECTION_DATA: + /* _data */ + oname = ".data"; + start = TRUE; + break; + + case XCOFF_SPECIAL_SECTION_EDATA: + /* _edata */ + oname = ".data"; + start = FALSE; + break; + + case XCOFF_SPECIAL_SECTION_END: + case XCOFF_SPECIAL_SECTION_END2: + /* _end and end */ + oname = ".bss"; + start = FALSE; + break; + } + + os = lang_output_section_find (oname); + + if (start) + { + is->header.next = os->children.head; + os->children.head = (lang_statement_union_type *) is; + } + else + { + is->header.next = NULL; + lang_statement_append (&os->children, + (lang_statement_union_type *) is, + &is->header.next); + } + } + + /* Executables and shared objects must always have .text, .data + and .bss output sections, so that the header can refer to them. + The kernel refuses to load objects that have missing sections. */ + if (!link_info.relocatable) + for (i = 0; i < ARRAY_SIZE (must_keep_sections); i++) + { + asection *sec; + + sec = bfd_get_section_by_name (link_info.output_bfd, + must_keep_sections[i]); + if (sec == NULL) + einfo ("%P: can't find required output section %s\n", must_keep_sections[i]); + else + sec->flags |= SEC_KEEP; + } + + before_allocation_default (); +} + +static char * +gld${EMULATION_NAME}_choose_target (int argc, char **argv) +{ + int i, j, jmax; + static char *from_outside; + static char *from_inside; + static char *argv_to_target[][2] = { + {NULL, "${OUTPUT_FORMAT}"}, + {"-b32", "${OUTPUT_FORMAT_32BIT}"}, + {"-b64", "${OUTPUT_FORMAT_64BIT}"}, + }; + + jmax = 3; + + from_outside = getenv (TARGET_ENVIRON); + if (from_outside != (char *) NULL) + return from_outside; + + /* Set to default. */ + from_inside = argv_to_target[0][1]; + for (i = 1; i < argc; i++) + { + for (j = 1; j < jmax; j++) + { + if (0 == strcmp (argv[i], argv_to_target[j][0])) + from_inside = argv_to_target[j][1]; + } + } + + return from_inside; +} + +/* Returns + 1 : state changed + 0 : no change */ +static int +change_symbol_mode (char *input) +{ + char *symbol_mode_string[] = { + "# 32", /* 0x01 */ + "# 64", /* 0x02 */ + "# no32", /* 0x04 */ + "# no64", /* 0x08 */ + NULL, + }; + + unsigned int bit; + char *string; + + for (bit = 0;; bit++) + { + string = symbol_mode_string[bit]; + if (string == NULL) + return 0; + + if (0 == strcmp (input, string)) + { + symbol_mode = (1 << bit); + return 1; + } + } + /* should not be here */ + return 0; +} + +/* Returns + 1 : yes + 0 : ignore + -1 : error, try something else */ +static int +is_syscall (char *input, unsigned int *flag) +{ + unsigned int bit; + char *string; + + struct sc { + char *syscall_string; + unsigned int flag; + } s [] = { + { "svc" /* 0x01 */, XCOFF_SYSCALL32 }, + { "svc32" /* 0x02 */, XCOFF_SYSCALL32 }, + { "svc3264" /* 0x04 */, XCOFF_SYSCALL32 | XCOFF_SYSCALL64 }, + { "svc64" /* 0x08 */, XCOFF_SYSCALL64 }, + { "syscall" /* 0x10 */, XCOFF_SYSCALL32 }, + { "syscall32" /* 0x20 */, XCOFF_SYSCALL32 }, + { "syscall3264" /* 0x40 */, XCOFF_SYSCALL32 | XCOFF_SYSCALL64 }, + { "syscall64" /* 0x80 */, XCOFF_SYSCALL64 }, + { NULL, 0 }, + }; + + *flag = 0; + + for (bit = 0;; bit++) + { + string = s[bit].syscall_string; + if (string == NULL) + return -1; + + if (0 == strcmp (input, string)) + { + if (1 << bit & syscall_mask) + { + *flag = s[bit].flag; + return 1; + } + else + { + return 0; + } + } + } + /* should not be here */ + return -1; +} + +/* Read an import or export file. For an import file, this is called + by the before_allocation emulation routine. For an export file, + this is called by the handle_option emulation routine. */ + +static void +gld${EMULATION_NAME}_read_file (const char *filename, bfd_boolean import) +{ + struct obstack *o; + FILE *f; + int lineno; + int c; + bfd_boolean keep; + const char *imppath; + const char *impfile; + const char *impmember; + + o = (struct obstack *) xmalloc (sizeof (struct obstack)); + obstack_specify_allocation (o, 0, 0, xmalloc, gld${EMULATION_NAME}_free); + + f = fopen (filename, FOPEN_RT); + if (f == NULL) + { + bfd_set_error (bfd_error_system_call); + einfo ("%F%s: %E\n", filename); + } + + keep = FALSE; + + imppath = NULL; + impfile = NULL; + impmember = NULL; + + lineno = 0; + + /* Default to 32 and 64 bit mode + symbols at top of /lib/syscalls.exp do not have a mode modifier and they + are not repeated, assume 64 bit routines also want to use them. + See the routine change_symbol_mode for more information. */ + + symbol_mode = 0x04; + + while ((c = getc (f)) != EOF) + { + char *s; + char *symname; + unsigned int syscall_flag = 0; + bfd_vma address; + struct bfd_link_hash_entry *h; + + if (c != '\n') + { + obstack_1grow (o, c); + continue; + } + + obstack_1grow (o, '\0'); + ++lineno; + + s = (char *) obstack_base (o); + while (ISSPACE (*s)) + ++s; + if (*s == '\0' + || *s == '*' + || change_symbol_mode (s) + || (*s == '#' && s[1] == ' ') + || (!import && *s == '#' && s[1] == '!')) + { + obstack_free (o, obstack_base (o)); + continue; + } + + if (*s == '#' && s[1] == '!') + { + s += 2; + while (ISSPACE (*s)) + ++s; + if (*s == '\0') + { + imppath = NULL; + impfile = NULL; + impmember = NULL; + obstack_free (o, obstack_base (o)); + } + else if (*s == '(') + einfo ("%F%s%d: #! ([member]) is not supported in import files\n", + filename, lineno); + else + { + char cs; + char *start; + + (void) obstack_finish (o); + keep = TRUE; + start = s; + while (!ISSPACE (*s) && *s != '(' && *s != '\0') + ++s; + cs = *s; + *s = '\0'; + if (!bfd_xcoff_split_import_path (link_info.output_bfd, + start, &imppath, &impfile)) + einfo ("%F%P: Could not parse import path: %E\n"); + while (ISSPACE (cs)) + { + ++s; + cs = *s; + } + if (cs != '(') + { + impmember = ""; + if (cs != '\0') + einfo ("%s:%d: warning: syntax error in import file\n", + filename, lineno); + } + else + { + ++s; + impmember = s; + while (*s != ')' && *s != '\0') + ++s; + if (*s == ')') + *s = '\0'; + else + einfo ("%s:%d: warning: syntax error in import file\n", + filename, lineno); + } + } + + continue; + } + + if (symbol_mode & symbol_mode_mask) + { + /* This is a symbol to be imported or exported. */ + symname = s; + syscall_flag = 0; + address = (bfd_vma) -1; + + while (!ISSPACE (*s) && *s != '\0') + ++s; + if (*s != '\0') + { + char *se; + + *s++ = '\0'; + + while (ISSPACE (*s)) + ++s; + + se = s; + while (!ISSPACE (*se) && *se != '\0') + ++se; + if (*se != '\0') + { + *se++ = '\0'; + while (ISSPACE (*se)) + ++se; + if (*se != '\0') + einfo ("%s%d: warning: syntax error in import/export file\n", + filename, lineno); + } + + if (s != se) + { + int status; + const char *end; + + status = is_syscall (s, &syscall_flag); + + if (0 > status) + { + /* not a system call, check for address */ + address = bfd_scan_vma (s, &end, 0); + if (*end != '\0') + { + einfo ("%s:%d: warning: syntax error in import/export file\n", + filename, lineno); + + } + } + } + } + + if (!import) + { + struct export_symbol_list *n; + + ldlang_add_undef (symname, TRUE); + n = ((struct export_symbol_list *) + xmalloc (sizeof (struct export_symbol_list))); + n->next = export_symbols; + n->name = xstrdup (symname); + export_symbols = n; + } + else + { + h = bfd_link_hash_lookup (link_info.hash, symname, FALSE, FALSE, + TRUE); + if (h == NULL || h->type == bfd_link_hash_new) + { + /* We can just ignore attempts to import an unreferenced + symbol. */ + } + else + { + if (!bfd_xcoff_import_symbol (link_info.output_bfd, + &link_info, h, + address, imppath, impfile, + impmember, syscall_flag)) + einfo ("%X%s:%d: failed to import symbol %s: %E\n", + filename, lineno, symname); + } + } + } + obstack_free (o, obstack_base (o)); + } + + if (obstack_object_size (o) > 0) + { + einfo ("%s:%d: warning: ignoring unterminated last line\n", + filename, lineno); + obstack_free (o, obstack_base (o)); + } + + if (!keep) + { + obstack_free (o, NULL); + free (o); + } +} + +/* This routine saves us from worrying about declaring free. */ + +static void +gld${EMULATION_NAME}_free (void *p) +{ + free (p); +} + +/* This is called by the before_allocation routine via + lang_for_each_statement. It looks for relocations and assignments + to symbols. */ + +static void +gld${EMULATION_NAME}_find_relocs (lang_statement_union_type *s) +{ + if (s->header.type == lang_reloc_statement_enum) + { + lang_reloc_statement_type *rs; + + rs = &s->reloc_statement; + if (rs->name == NULL) + einfo ("%F%P: only relocations against symbols are permitted\n"); + if (!bfd_xcoff_link_count_reloc (link_info.output_bfd, &link_info, + rs->name)) + einfo ("%F%P: bfd_xcoff_link_count_reloc failed: %E\n"); + } + + if (s->header.type == lang_assignment_statement_enum) + gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); +} + +/* Look through an expression for an assignment statement. */ + +static void +gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) +{ + struct bfd_link_hash_entry *h; + + switch (exp->type.node_class) + { + case etree_provide: + h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst, + FALSE, FALSE, FALSE); + if (h == NULL) + break; + /* Fall through. */ + case etree_assign: + if (strcmp (exp->assign.dst, ".") != 0) + { + if (!bfd_xcoff_record_link_assignment (link_info.output_bfd, + &link_info, + exp->assign.dst)) + einfo ("%P%F: failed to record assignment to %s: %E\n", + exp->assign.dst); + } + gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); + break; + + case etree_binary: + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); + break; + + case etree_trinary: + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); + break; + + case etree_unary: + gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); + break; + + default: + break; + } +} + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f ${srcdir}/emultempl/ostring.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +static void +gld${EMULATION_NAME}_create_output_section_statements (void) +{ + /* __rtinit */ + if ((bfd_get_flavour (link_info.output_bfd) == bfd_target_xcoff_flavour) + && (link_info.init_function != NULL + || link_info.fini_function != NULL + || rtld)) + { + initfini_file = lang_add_input_file ("initfini", + lang_input_file_is_file_enum, + NULL); + + initfini_file->the_bfd = bfd_create ("initfini", link_info.output_bfd); + if (initfini_file->the_bfd == NULL + || ! bfd_set_arch_mach (initfini_file->the_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; + } + + /* Call backend to fill in the rest */ + if (! bfd_xcoff_link_generate_rtinit (initfini_file->the_bfd, + link_info.init_function, + link_info.fini_function, + rtld)) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + /* __rtld defined in /lib/librtl.a */ + if (rtld) + lang_add_input_file ("rtl", lang_input_file_is_l_enum, NULL); + } +} + +static void +gld${EMULATION_NAME}_set_output_arch (void) +{ + bfd_set_arch_mach (link_info.output_bfd, + bfd_xcoff_architecture (link_info.output_bfd), + bfd_xcoff_machine (link_info.output_bfd)); + + ldfile_output_architecture = bfd_get_arch (link_info.output_bfd); + ldfile_output_machine = bfd_get_mach (link_info.output_bfd); + ldfile_output_machine_name = bfd_printable_name (link_info.output_bfd); +} + +static bfd_boolean +gld${EMULATION_NAME}_open_dynamic_archive (const char *arch, + search_dirs_type *search, + lang_input_statement_type *entry) +{ + char *path; + + if (!entry->is_archive) + return FALSE; + + path = concat (search->name, "/lib", entry->filename, arch, ".a", NULL); + if (!ldfile_try_open_bfd (path, entry)) + { + free (path); + return FALSE; + } + /* Don't include the searched directory in the import path. */ + bfd_xcoff_set_archive_import_path (&link_info, entry->the_bfd, + path + strlen (search->name) + 1); + entry->filename = path; + return TRUE; +} + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { + gld${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + gld${EMULATION_NAME}_after_open, + after_allocation_default, + gld${EMULATION_NAME}_set_output_arch, + gld${EMULATION_NAME}_choose_target, + gld${EMULATION_NAME}_before_allocation, + gld${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + gld${EMULATION_NAME}_create_output_section_statements, + gld${EMULATION_NAME}_open_dynamic_archive, + 0, /* place_orphan */ + 0, /* set_symbols */ + gld${EMULATION_NAME}_parse_args, + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + gld${EMULATION_NAME}_unrecognized_file, + NULL, /* list_options */ + NULL, /* recognized_file */ + NULL, /* find potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/alphaelf.em b/binutils-2.21/ld/emultempl/alphaelf.em new file mode 100644 index 0000000..21064ad --- /dev/null +++ b/binutils-2.21/ld/emultempl/alphaelf.em @@ -0,0 +1,148 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003, 2004, 2005, 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. +# + +# This file is sourced from elf32.em, and defines extra alpha +# specific routines. +# +fragment <<EOF + +#include "elf/internal.h" +#include "elf/alpha.h" +#include "elf-bfd.h" + +static bfd_boolean limit_32bit; + +extern bfd_boolean elf64_alpha_use_secureplt; + + +/* Set the start address as in the Tru64 ld. */ +#define ALPHA_TEXT_START_32BIT 0x12000000 + +static void +alpha_after_open (void) +{ + if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && elf_object_id (link_info.output_bfd) == ALPHA_ELF_DATA) + { + unsigned int num_plt; + lang_output_section_statement_type *os; + lang_output_section_statement_type *plt_os[2]; + + num_plt = 0; + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { + if (os->constraint == SPECIAL && strcmp (os->name, ".plt") == 0) + { + if (num_plt < 2) + plt_os[num_plt] = os; + ++num_plt; + } + } + + if (num_plt == 2) + { + plt_os[0]->constraint = elf64_alpha_use_secureplt ? 0 : -1; + plt_os[1]->constraint = elf64_alpha_use_secureplt ? -1 : 0; + } + } + + gld${EMULATION_NAME}_after_open (); +} + +static void +alpha_after_parse (void) +{ + if (limit_32bit && !link_info.shared && !link_info.relocatable) + lang_section_start (".interp", + exp_binop ('+', + exp_intop (ALPHA_TEXT_START_32BIT), + exp_nameop (SIZEOF_HEADERS, NULL)), + NULL); + + after_parse_default (); +} + +static void +alpha_before_allocation (void) +{ + /* Call main function; we're just extending it. */ + gld${EMULATION_NAME}_before_allocation (); + + /* Add -relax if -O, not -r, and not explicitly disabled. */ + if (link_info.optimize && !link_info.relocatable && ! RELAXATION_DISABLED_BY_USER) + ENABLE_RELAXATION; +} + +static void +alpha_finish (void) +{ + if (limit_32bit) + elf_elfheader (link_info.output_bfd)->e_flags |= EF_ALPHA_32BIT; + + finish_default (); +} +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_TASO 300 +#define OPTION_SECUREPLT (OPTION_TASO + 1) +#define OPTION_NO_SECUREPLT (OPTION_SECUREPLT + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "taso", no_argument, NULL, OPTION_TASO }, + { "secureplt", no_argument, NULL, OPTION_SECUREPLT }, + { "no-secureplt", no_argument, NULL, OPTION_NO_SECUREPLT }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --taso Load executable in the lower 31-bit addressable\n\ + virtual address range.\n\ + --secureplt Force PLT in text segment.\n\ + --no-secureplt Force PLT in data segment.\n\ +")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_TASO: + limit_32bit = 1; + break; + case OPTION_SECUREPLT: + elf64_alpha_use_secureplt = TRUE; + break; + case OPTION_NO_SECUREPLT: + elf64_alpha_use_secureplt = FALSE; + break; +' + +# Put these extra alpha routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=alpha_after_open +LDEMUL_AFTER_PARSE=alpha_after_parse +LDEMUL_BEFORE_ALLOCATION=alpha_before_allocation +LDEMUL_FINISH=alpha_finish diff --git a/binutils-2.21/ld/emultempl/armcoff.em b/binutils-2.21/ld/emultempl/armcoff.em new file mode 100644 index 0000000..b3cdde9 --- /dev/null +++ b/binutils-2.21/ld/emultempl/armcoff.em @@ -0,0 +1,283 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* emulate the original gld for the given ${EMULATION_NAME} + Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007, 2008 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" + +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +/* If TRUE, then interworking stubs which support calls to old, + non-interworking aware ARM code should be generated. */ + +static int support_old_code = 0; +static char * thumb_entry_symbol = NULL; + +#define OPTION_SUPPORT_OLD_CODE 300 +#define OPTION_THUMB_ENTRY 301 + +static void +gld${EMULATION_NAME}_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[] = { + {"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, + {"thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY}, + {NULL, no_argument, NULL, 0} + }; + + *longopts = xrealloc (*longopts, + nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +static void +gld${EMULATION_NAME}_list_options (FILE *file) +{ + fprintf (file, _(" --support-old-code Support interworking with old code\n")); + fprintf (file, _(" --thumb-entry=<sym> Set the entry point to be Thumb symbol <sym>\n")); +} + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + switch (optc) + { + default: + return FALSE; + + case OPTION_SUPPORT_OLD_CODE: + support_old_code = 1; + break; + + case OPTION_THUMB_ENTRY: + thumb_entry_symbol = optarg; + break; + } + + return TRUE; +} + +static void +gld${EMULATION_NAME}_before_parse (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + /* 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"), is->filename); + } + } + } + + /* We have seen it all. Allocate it, and carry on */ + bfd_arm_allocate_interworking_sections (& link_info); + + before_allocation_default (); +} + +static void +gld${EMULATION_NAME}_after_open (void) +{ + 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; + } + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (bfd_arm_get_bfd_for_interworking (is->the_bfd, & link_info)) + break; + } + } +} + +static void +gld${EMULATION_NAME}_finish (void) +{ + if (thumb_entry_symbol != NULL) + { + struct bfd_link_hash_entry * h; + + 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); + } + + finish_default (); +} + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + gld${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld${EMULATION_NAME}_before_allocation, + gld${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + gld${EMULATION_NAME}_finish, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + NULL, /* unrecognised file */ + gld${EMULATION_NAME}_list_options, + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/armelf.em b/binutils-2.21/ld/emultempl/armelf.em new file mode 100644 index 0000000..91aa8e9 --- /dev/null +++ b/binutils-2.21/ld/emultempl/armelf.em @@ -0,0 +1,684 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +# 2004, 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. +# + +# This file is sourced from elf32.em, and defines extra arm-elf +# specific routines. +# +test -z "$TARGET2_TYPE" && TARGET2_TYPE="rel" +fragment <<EOF + +#include "ldctor.h" +#include "elf/arm.h" + +static char *thumb_entry_symbol = NULL; +static int byteswap_code = 0; +static int target1_is_rel = 0${TARGET1_IS_REL}; +static char *target2_type = "${TARGET2_TYPE}"; +static int fix_v4bx = 0; +static int use_blx = 0; +static bfd_arm_vfp11_fix vfp11_denorm_fix = BFD_ARM_VFP11_FIX_DEFAULT; +static int fix_cortex_a8 = -1; +static int no_enum_size_warning = 0; +static int no_wchar_size_warning = 0; +static int pic_veneer = 0; +static int merge_exidx_entries = -1; + +static void +gld${EMULATION_NAME}_before_parse (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ + config.dynamic_link = ${DYNAMIC_LINK-TRUE}; + config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; +} + +static void +arm_elf_before_allocation (void) +{ + bfd_elf32_arm_set_byteswap_code (&link_info, byteswap_code); + + /* Choose type of VFP11 erratum fix, or warn if specified fix is unnecessary + due to architecture version. */ + bfd_elf32_arm_set_vfp11_fix (link_info.output_bfd, &link_info); + + /* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified. */ + bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info); + + /* We should be able to set the size of the interworking stub section. We + can't do it until later if we have dynamic sections, though. */ + if (! elf_hash_table (&link_info)->dynamic_sections_created) + { + /* Here we rummage through the found bfds to collect glue information. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + /* Initialise mapping tables for code/data. */ + bfd_elf32_arm_init_maps (is->the_bfd); + + if (!bfd_elf32_arm_process_before_allocation (is->the_bfd, + &link_info) + || !bfd_elf32_arm_vfp11_erratum_scan (is->the_bfd, &link_info)) + /* xgettext:c-format */ + einfo (_("Errors encountered processing file %s"), is->filename); + } + + /* We have seen it all. Allocate it, and carry on. */ + bfd_elf32_arm_allocate_interworking_sections (& link_info); + } + + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_before_allocation (); +} + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; + +/* Whether we need to call gldarm_layout_sections_again. */ +static int need_laying_out = 0; + +/* Maximum size of a group of input sections that can be handled by + one stub section. A value of +/-1 indicates the bfd back-end + should use a suitable default size. */ +static bfd_signed_vma group_size = 1; + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + after its associated input section. */ + *(info->add.tail) = l->header.next; + l->header.next = info->add.head; + return TRUE; + } + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + + +/* Call-back for elf32_arm_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately after INPUT_SECTION. */ + +static asection * +elf32_arm_add_stub_section (const char *stub_sec_name, + asection *input_section) +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + stub_sec_name, flags); + if (stub_sec == NULL) + goto err_ret; + + bfd_set_section_alignment (stub_file->the_bfd, stub_sec, 3); + + output_section = input_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + info.input_section = input_section; + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, os); + + if (info.add.head == NULL) + goto err_ret; + + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + +/* Another call-back for elf_arm_size_stubs. */ + +static void +gldarm_layout_sections_again (void) +{ + /* If we have changed sizes of the stub sections, then we need + to recalculate all the section offsets. This may mean we need to + add even more stubs. */ + gld${EMULATION_NAME}_map_segments (TRUE); + need_laying_out = -1; +} + +static void +build_section_lists (lang_statement_union_type *statement) +{ + if (statement->header.type == lang_input_section_enum) + { + asection *i = statement->input_section.section; + + if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag + && (i->flags & SEC_EXCLUDE) == 0 + && i->output_section != NULL + && i->output_section->owner == link_info.output_bfd) + elf32_arm_next_input_section (& link_info, i); + } +} + +static int +compare_output_sec_vma (const void *a, const void *b) +{ + asection *asec = *(asection **) a, *bsec = *(asection **) b; + asection *aout = asec->output_section, *bout = bsec->output_section; + bfd_vma avma, bvma; + + /* If there's no output section for some reason, compare equal. */ + if (!aout || !bout) + return 0; + + avma = aout->vma + asec->output_offset; + bvma = bout->vma + bsec->output_offset; + + if (avma > bvma) + return 1; + else if (avma < bvma) + return -1; + + return 0; +} + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + if (!link_info.relocatable) + { + /* Build a sorted list of input text sections, then use that to process + the unwind table index. */ + unsigned int list_size = 10; + asection **sec_list = (asection **) + xmalloc (list_size * sizeof (asection *)); + unsigned int sec_count = 0; + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + bfd *abfd = is->the_bfd; + asection *sec; + + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + continue; + + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + asection *out_sec = sec->output_section; + + if (out_sec + && elf_section_data (sec) + && elf_section_type (sec) == SHT_PROGBITS + && (elf_section_flags (sec) & SHF_EXECINSTR) != 0 + && (sec->flags & SEC_EXCLUDE) == 0 + && sec->sec_info_type != ELF_INFO_TYPE_JUST_SYMS + && out_sec != bfd_abs_section_ptr) + { + if (sec_count == list_size) + { + list_size *= 2; + sec_list = (asection **) + xrealloc (sec_list, list_size * sizeof (asection *)); + } + + sec_list[sec_count++] = sec; + } + } + } + + qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma); + + if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info, + merge_exidx_entries)) + need_laying_out = 1; + + free (sec_list); + } + + /* bfd_elf32_discard_info just plays with debugging sections, + ie. doesn't affect any code, so we can delay resizing the + sections. It's likely we'll resize everything in the process of + adding stubs. */ + if (bfd_elf_discard_info (link_info.output_bfd, & link_info)) + need_laying_out = 1; + + /* If generating a relocatable output file, then we don't + have to examine the relocs. */ + if (stub_file != NULL && !link_info.relocatable) + { + int ret = elf32_arm_setup_section_lists (link_info.output_bfd, & link_info); + + if (ret != 0) + { + if (ret < 0) + { + einfo ("%X%P: could not compute sections lists for stub generation: %E\n"); + return; + } + + lang_for_each_statement (build_section_lists); + + /* Call into the BFD backend to do the real work. */ + if (! elf32_arm_size_stubs (link_info.output_bfd, + stub_file->the_bfd, + & link_info, + group_size, + & elf32_arm_add_stub_section, + & gldarm_layout_sections_again)) + { + einfo ("%X%P: cannot size stub section: %E\n"); + return; + } + } + } + + if (need_laying_out != -1) + gld${EMULATION_NAME}_map_segments (need_laying_out); +} + +static void +gld${EMULATION_NAME}_finish (void) +{ + struct bfd_link_hash_entry * h; + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + /* Figure out where VFP11 erratum veneers (and the labels returning + from same) have been placed. */ + bfd_elf32_arm_vfp11_fix_veneer_locations (is->the_bfd, &link_info); + } + } + + if (! link_info.relocatable) + { + /* Now build the linker stubs. */ + if (stub_file->the_bfd->sections != NULL) + { + if (! elf32_arm_build_stubs (& link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } + } + + finish_default (); + + if (thumb_entry_symbol) + { + h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, + FALSE, FALSE, TRUE); + } + else + { + struct elf_link_hash_entry * eh; + + if (!entry_symbol.name) + return; + + h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name, + FALSE, FALSE, TRUE); + eh = (struct elf_link_hash_entry *)h; + if (!h || ELF_ST_TYPE(eh->type) != STT_ARM_TFUNC) + return; + } + + + 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 (thumb_entry_symbol != NULL && 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); +} + +/* This is a convenient point to tell BFD about target specific flags. + After the output has been created, but before inputs are read. */ +static void +arm_elf_create_output_section_statements (void) +{ + 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; + } + + bfd_elf32_arm_set_target_relocs (link_info.output_bfd, &link_info, + target1_is_rel, + target2_type, fix_v4bx, use_blx, + vfp11_denorm_fix, no_enum_size_warning, + no_wchar_size_warning, + pic_veneer, fix_cortex_a8); + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || ! bfd_set_arch_mach (stub_file->the_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; + } + + stub_file->the_bfd->flags |= BFD_LINKER_CREATED; + ldlang_add_file (stub_file); + + /* Also use the stub file for stubs placed in a single output section. */ + bfd_elf32_arm_add_glue_sections_to_bfd (stub_file->the_bfd, &link_info); + bfd_elf32_arm_get_bfd_for_interworking (stub_file->the_bfd, &link_info); +} + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void arm_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +arm_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&arm_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file arm_lang_for_each_input_file + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_THUMB_ENTRY 301 +#define OPTION_BE8 302 +#define OPTION_TARGET1_REL 303 +#define OPTION_TARGET1_ABS 304 +#define OPTION_TARGET2 305 +#define OPTION_FIX_V4BX 306 +#define OPTION_USE_BLX 307 +#define OPTION_VFP11_DENORM_FIX 308 +#define OPTION_NO_ENUM_SIZE_WARNING 309 +#define OPTION_PIC_VENEER 310 +#define OPTION_FIX_V4BX_INTERWORKING 311 +#define OPTION_STUBGROUP_SIZE 312 +#define OPTION_NO_WCHAR_SIZE_WARNING 313 +#define OPTION_FIX_CORTEX_A8 314 +#define OPTION_NO_FIX_CORTEX_A8 315 +#define OPTION_NO_MERGE_EXIDX_ENTRIES 316 +#define OPTION_ICF 399 +' + +PARSE_AND_LIST_SHORTOPTS=p + +PARSE_AND_LIST_LONGOPTS=' + { "no-pipeline-knowledge", no_argument, NULL, '\'p\''}, + { "thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY}, + { "be8", no_argument, NULL, OPTION_BE8}, + { "target1-rel", no_argument, NULL, OPTION_TARGET1_REL}, + { "target1-abs", no_argument, NULL, OPTION_TARGET1_ABS}, + { "target2", required_argument, NULL, OPTION_TARGET2}, + { "fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX}, + { "fix-v4bx-interworking", no_argument, NULL, OPTION_FIX_V4BX_INTERWORKING}, + { "use-blx", no_argument, NULL, OPTION_USE_BLX}, + { "vfp11-denorm-fix", required_argument, NULL, OPTION_VFP11_DENORM_FIX}, + { "no-enum-size-warning", no_argument, NULL, OPTION_NO_ENUM_SIZE_WARNING}, + { "pic-veneer", no_argument, NULL, OPTION_PIC_VENEER}, + { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE }, + { "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING}, + { "fix-cortex-a8", no_argument, NULL, OPTION_FIX_CORTEX_A8 }, + { "no-fix-cortex-a8", no_argument, NULL, OPTION_NO_FIX_CORTEX_A8 }, + { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES }, + { "icf", required_argument, NULL, OPTION_ICF }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --thumb-entry=<sym> Set the entry point to be Thumb symbol <sym>\n")); + fprintf (file, _(" --be8 Output BE8 format image\n")); + fprintf (file, _(" --target1-rel Interpret R_ARM_TARGET1 as R_ARM_REL32\n")); + fprintf (file, _(" --target1-abs Interpret R_ARM_TARGET1 as R_ARM_ABS32\n")); + fprintf (file, _(" --target2=<type> Specify definition of R_ARM_TARGET2\n")); + fprintf (file, _(" --fix-v4bx Rewrite BX rn as MOV pc, rn for ARMv4\n")); + fprintf (file, _(" --fix-v4bx-interworking Rewrite BX rn branch to ARMv4 interworking veneer\n")); + fprintf (file, _(" --use-blx Enable use of BLX instructions\n")); + fprintf (file, _(" --vfp11-denorm-fix Specify how to fix VFP11 denorm erratum\n")); + fprintf (file, _(" --no-enum-size-warning Don'\''t warn about objects with incompatible\n" + " enum sizes\n")); + fprintf (file, _(" --no-wchar-size-warning Don'\''t warn about objects with incompatible" + " wchar_t sizes\n")); + fprintf (file, _(" --pic-veneer Always generate PIC interworking veneers\n")); + fprintf (file, _("\ + --stub-group-size=N Maximum size of a group of input sections that can be\n\ + handled by one stub section. A negative value\n\ + locates all stubs after their branches (with a\n\ + group size of -N), while a positive value allows\n\ + two groups of input sections, one before, and one\n\ + after each stub section. Values of +/-1 indicate\n\ + the linker should choose suitable defaults.\n" + )); + fprintf (file, _(" --[no-]fix-cortex-a8 Disable/enable Cortex-A8 Thumb-2 branch erratum fix\n")); + fprintf (file, _(" --no-merge-exidx-entries Disable merging exidx entries\n")); + fprintf (file, _(" --icf=<value> Ignored for compatibility with gold.\n")); + +' + +PARSE_AND_LIST_ARGS_CASES=' + case '\'p\'': + /* Only here for backwards compatibility. */ + break; + + case OPTION_THUMB_ENTRY: + thumb_entry_symbol = optarg; + break; + + case OPTION_BE8: + byteswap_code = 1; + break; + + case OPTION_TARGET1_REL: + target1_is_rel = 1; + break; + + case OPTION_TARGET1_ABS: + target1_is_rel = 0; + break; + + case OPTION_TARGET2: + target2_type = optarg; + break; + + case OPTION_FIX_V4BX: + fix_v4bx = 1; + break; + + case OPTION_FIX_V4BX_INTERWORKING: + fix_v4bx = 2; + break; + + case OPTION_USE_BLX: + use_blx = 1; + break; + + case OPTION_VFP11_DENORM_FIX: + if (strcmp (optarg, "none") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_NONE; + else if (strcmp (optarg, "scalar") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_SCALAR; + else if (strcmp (optarg, "vector") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_VECTOR; + else + einfo (_("Unrecognized VFP11 fix type '\''%s'\''.\n"), optarg); + break; + + case OPTION_NO_ENUM_SIZE_WARNING: + no_enum_size_warning = 1; + break; + + case OPTION_NO_WCHAR_SIZE_WARNING: + no_wchar_size_warning = 1; + break; + + case OPTION_PIC_VENEER: + pic_veneer = 1; + break; + + case OPTION_STUBGROUP_SIZE: + { + const char *end; + + group_size = bfd_scan_vma (optarg, &end, 0); + if (*end) + einfo (_("%P%F: invalid number `%s'\''\n"), optarg); + } + break; + + case OPTION_FIX_CORTEX_A8: + fix_cortex_a8 = 1; + break; + + case OPTION_NO_FIX_CORTEX_A8: + fix_cortex_a8 = 0; + break; + + case OPTION_NO_MERGE_EXIDX_ENTRIES: + merge_exidx_entries = 0; + + case OPTION_ICF: + /* For compatibility with gold. */ + break; +' + +# We have our own before_allocation etc. functions, but they call +# the standard routines, so give them a different name. +LDEMUL_BEFORE_ALLOCATION=arm_elf_before_allocation +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=arm_elf_create_output_section_statements + +# Replace the elf before_parse function with our own. +LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse + +# Call the extra arm-elf function +LDEMUL_FINISH=gld${EMULATION_NAME}_finish diff --git a/binutils-2.21/ld/emultempl/astring.sed b/binutils-2.21/ld/emultempl/astring.sed new file mode 100644 index 0000000..08bd8a6 --- /dev/null +++ b/binutils-2.21/ld/emultempl/astring.sed @@ -0,0 +1,13 @@ +s/["\\]/\\&/g +s/$/\\n\\/ +1 s/^/"/ +25s/\\$/"/ +26s/^/"/ +50s/\\$/"/ +51s/^/"/ +75s/\\$/"/ +76s/^/"/ +100s/\\$/"/ +101s/^/"/ +$ s/$/n"/ +$ s/\\n"n"$/\\n"/ diff --git a/binutils-2.21/ld/emultempl/avrelf.em b/binutils-2.21/ld/emultempl/avrelf.em new file mode 100644 index 0000000..84f1633 --- /dev/null +++ b/binutils-2.21/ld/emultempl/avrelf.em @@ -0,0 +1,265 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. + + +# This file is sourced from elf32.em, and defines extra avr-elf specific +# routines. It is used to generate the trampolines for the avr6 family +# of devices where one needs to address the issue that it is not possible +# to reach the whole program memory by using 16 bit pointers. + +fragment <<EOF + +#include "elf32-avr.h" +#include "ldctor.h" + +/* The fake file and it's corresponding section meant to hold + the linker stubs if needed. */ + +static lang_input_statement_type *stub_file; +static asection *avr_stub_section; + +/* Variables set by the command-line parameters and transfered + to the bfd without use of global shared variables. */ + +static bfd_boolean avr_no_stubs = FALSE; +static bfd_boolean avr_debug_relax = FALSE; +static bfd_boolean avr_debug_stubs = FALSE; +static bfd_boolean avr_replace_call_ret_sequences = TRUE; +static bfd_vma avr_pc_wrap_around = 0x10000000; + +/* Transfers information to the bfd frontend. */ + +static void +avr_elf_set_global_bfd_parameters (void) +{ + elf32_avr_setup_params (& link_info, + stub_file->the_bfd, + avr_stub_section, + avr_no_stubs, + avr_debug_stubs, + avr_debug_relax, + avr_pc_wrap_around, + avr_replace_call_ret_sequences); +} + + +/* Makes a conservative estimate of the trampoline section size that could + be corrected later on. */ + +static void +avr_elf_${EMULATION_NAME}_before_allocation (void) +{ + int ret; + + gld${EMULATION_NAME}_before_allocation (); + + /* We only need stubs for the avr6 family. */ + if (strcmp ("${EMULATION_NAME}","avr6")) + avr_no_stubs = TRUE; + + avr_elf_set_global_bfd_parameters (); + + /* If generating a relocatable output file, then + we don't have to generate the trampolines. */ + if (link_info.relocatable) + avr_no_stubs = TRUE; + + if (avr_no_stubs) + return; + + ret = elf32_avr_setup_section_lists (link_info.output_bfd, &link_info); + + if (ret < 0) + einfo ("%X%P: can not setup the input section list: %E\n"); + + if (ret <= 0) + return; + + /* Call into the BFD backend to do the real "stub"-work. */ + if (! elf32_avr_size_stubs (link_info.output_bfd, &link_info, TRUE)) + einfo ("%X%P: can not size stub section: %E\n"); +} + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub section and generate the section itself. */ + +static void +avr_elf_create_output_section_statements (void) +{ + flagword flags; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || !bfd_set_arch_mach (stub_file->the_bfd, + bfd_get_arch (link_info.output_bfd), + bfd_get_mach (link_info.output_bfd))) + { + einfo ("%X%P: can not create stub BFD %E\n"); + return; + } + + /* Now we add the stub section. */ + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + avr_stub_section = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + ".trampolines", + flags); + if (avr_stub_section == NULL) + goto err_ret; + + avr_stub_section->alignment_power = 1; + + ldlang_add_file (stub_file); + + return; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return; +} + +/* Re-calculates the size of the stubs so that we won't waste space. */ + +static void +avr_elf_after_allocation (void) +{ + if (!avr_no_stubs && ! RELAXATION_ENABLED) + { + /* If relaxing, elf32_avr_size_stubs will be called from + elf32_avr_relax_section. */ + if (!elf32_avr_size_stubs (link_info.output_bfd, &link_info, FALSE)) + einfo ("%X%P: can not size stub section: %E\n"); + } + + gld${EMULATION_NAME}_after_allocation (); + + /* Now build the linker stubs. */ + if (!avr_no_stubs) + { + if (!elf32_avr_build_stubs (&link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } +} + + +EOF + + +PARSE_AND_LIST_PROLOGUE=' + +#define OPTION_NO_CALL_RET_REPLACEMENT 301 +#define OPTION_PMEM_WRAP_AROUND 302 +#define OPTION_NO_STUBS 303 +#define OPTION_DEBUG_STUBS 304 +#define OPTION_DEBUG_RELAX 305 +' + +PARSE_AND_LIST_LONGOPTS=' + { "no-call-ret-replacement", no_argument, + NULL, OPTION_NO_CALL_RET_REPLACEMENT}, + { "pmem-wrap-around", required_argument, + NULL, OPTION_PMEM_WRAP_AROUND}, + { "no-stubs", no_argument, + NULL, OPTION_NO_STUBS}, + { "debug-stubs", no_argument, + NULL, OPTION_DEBUG_STUBS}, + { "debug-relax", no_argument, + NULL, OPTION_DEBUG_RELAX}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --pmem-wrap-around=<val> " + "Make the linker relaxation machine assume that a\n" + " " + " program counter wrap-around occures at address\n" + " " + " <val>. Supported values: 8k, 16k, 32k and 64k.\n")); + fprintf (file, _(" --no-call-ret-replacement " + "The relaxation machine normally will\n" + " " + " substitute two immediately following call/ret\n" + " " + " instructions by a single jump instruction.\n" + " " + " This option disables this optimization.\n")); + fprintf (file, _(" --no-stubs " + "If the linker detects to attempt to access\n" + " " + " an instruction beyond 128k by a reloc that\n" + " " + " is limited to 128k max, it inserts a jump\n" + " " + " stub. You can de-active this with this switch.\n")); + fprintf (file, _(" --debug-stubs " + "Used for debugging avr-ld.\n")); + fprintf (file, _(" --debug-relax " + "Used for debugging avr-ld.\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + + case OPTION_PMEM_WRAP_AROUND: + { + /* This variable is defined in the bfd library. */ + if ((!strcmp (optarg,"32k")) || (!strcmp (optarg,"32K"))) + avr_pc_wrap_around = 32768; + else if ((!strcmp (optarg,"8k")) || (!strcmp (optarg,"8K"))) + avr_pc_wrap_around = 8192; + else if ((!strcmp (optarg,"16k")) || (!strcmp (optarg,"16K"))) + avr_pc_wrap_around = 16384; + else if ((!strcmp (optarg,"64k")) || (!strcmp (optarg,"64K"))) + avr_pc_wrap_around = 0x10000; + else + return FALSE; + } + break; + + case OPTION_DEBUG_STUBS: + avr_debug_stubs = TRUE; + break; + + case OPTION_DEBUG_RELAX: + avr_debug_relax = TRUE; + break; + + case OPTION_NO_STUBS: + avr_no_stubs = TRUE; + break; + + case OPTION_NO_CALL_RET_REPLACEMENT: + { + /* This variable is defined in the bfd library. */ + avr_replace_call_ret_sequences = FALSE; + } + break; +' + +# +# Put these extra avr-elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_BEFORE_ALLOCATION=avr_elf_${EMULATION_NAME}_before_allocation +LDEMUL_AFTER_ALLOCATION=avr_elf_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=avr_elf_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/beos.em b/binutils-2.21/ld/emultempl/beos.em new file mode 100644 index 0000000..370dbac --- /dev/null +++ b/binutils-2.21/ld/emultempl/beos.em @@ -0,0 +1,783 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is part of GLD, the Gnu Linker. + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 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. */ + + +/* 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. */ + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" +#include "libiberty.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" +#include "../bfd/libcoff.h" + +#define TARGET_IS_${EMULATION_NAME} + +static struct internal_extra_pe_aouthdr pe; +static int dll; + +extern const char *output_filename; + +static void +gld_${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + output_filename = "a.exe"; +} + +/* 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) + +static void +gld${EMULATION_NAME}_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}, + {NULL, no_argument, NULL, 0} + }; + + *longopts = (struct option *) + 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; +} definfo; + +#define D(field,symbol,def) {&pe.field,sizeof(pe.field), def, symbol,0} + +static definfo init[] = +{ + /* imagebase must be first */ +#define IMAGEBASEOFF 0 + D(ImageBase,"__image_base__", BEOS_EXE_IMAGE_BASE), +#define DLLOFF 1 + {&dll, sizeof(dll), 0, "__dll__", 0}, + D(SectionAlignment,"__section_alignment__", PE_DEF_SECTION_ALIGNMENT), + D(FileAlignment,"__file_alignment__", PE_DEF_FILE_ALIGNMENT), + D(MajorOperatingSystemVersion,"__major_os_version__", 4), + D(MinorOperatingSystemVersion,"__minor_os_version__", 0), + D(MajorImageVersion,"__major_image_version__", 1), + D(MinorImageVersion,"__minor_image_version__", 0), + D(MajorSubsystemVersion,"__major_subsystem_version__", 4), + D(MinorSubsystemVersion,"__minor_subsystem_version__", 0), + D(Subsystem,"__subsystem__", 3), + D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x2000000), + D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000), + D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000), + D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000), + D(LoaderFlags,"__loader_flags__", 0x0), + { NULL, 0, 0, NULL, 0 } +}; + + +static void +set_pe_name (char *name, long val) +{ + int i; + /* Find the name and set it. */ + for (i = 0; init[i].ptr; i++) + { + if (strcmp (name, init[i].symbol) == 0) + { + init[i].value = val; + init[i].inited = 1; + return; + } + } + abort(); +} + + +static void +set_pe_subsystem (void) +{ + const char *sver; + int len; + int i; + static const struct + { + const char *name; + const int value; + const char *entry; + } + v[] = + { + { "native", 1, "_NtProcessStartup" }, + { "windows", 2, "_WinMainCRTStartup" }, + { "wwindows", 2, "_wWinMainCRTStartup" }, + { "console", 3, "_mainCRTStartup" }, + { "wconsole", 3, "_wmainCRTStartup" }, + { "posix", 7, "___PosixProcessStartup"}, + { 0, 0, 0 } + }; + + sver = strchr (optarg, ':'); + if (sver == NULL) + len = strlen (optarg); + else + { + char *end; + + 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"); + } + + for (i = 0; v[i].name; i++) + { + if (strncmp (optarg, v[i].name, len) == 0 + && v[i].name[len] == '\0') + { + set_pe_name ("__subsystem__", v[i].value); + + /* If the subsystem is windows, we use a different entry + point. */ + lang_default_entry (v[i].entry); + + return; + } + } + einfo ("%P%F: invalid subsystem type %s\n", optarg); +} + + +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 +gld${EMULATION_NAME}_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) + { + fprintf (stderr, "%s: Can't open base file %s\n", + program_name, optarg); + xexit (1); + } + 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; + } + return TRUE; +} + +/* Assign values to the special symbols before the linker script is + read. */ + +static void +gld_${EMULATION_NAME}_set_symbols (void) +{ + /* Run through and invent symbols for all the + names and insert the defaults. */ + int j; + + if (!init[IMAGEBASEOFF].inited) + { + if (link_info.relocatable) + init[IMAGEBASEOFF].value = 0; + else if (init[DLLOFF].value) + init[IMAGEBASEOFF].value = BEOS_DLL_IMAGE_BASE; + else + init[IMAGEBASEOFF].value = BEOS_EXE_IMAGE_BASE; + } + + /* 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_add_assignment (exp_assop ('=', init[j].symbol, exp_intop (val))); + 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(); + } + /* Restore the pointer. */ + pop_stat_ptr (); + + if (pe.FileAlignment > + pe.SectionAlignment) + { + einfo ("%P: warning, file alignment > section alignment.\n"); + } +} + +static void +gld_${EMULATION_NAME}_after_open (void) +{ + /* 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)->pe) + { + einfo ("%F%P: PE operations on non PE file.\n"); + } + + pe_data(link_info.output_bfd)->pe_opthdr = pe; + pe_data(link_info.output_bfd)->dll = init[DLLOFF].value; + +} + +/* Callback functions for qsort in sort_sections. */ + +static int +sort_by_file_name (const void *a, const void *b) +{ + const lang_statement_union_type *const *ra = a; + const lang_statement_union_type *const *rb = b; + int i, a_sec, b_sec; + + i = strcmp ((*ra)->input_section.section->owner->my_archive->filename, + (*rb)->input_section.section->owner->my_archive->filename); + if (i != 0) + return i; + + i = strcmp ((*ra)->input_section.section->owner->filename, + (*rb)->input_section.section->owner->filename); + if (i != 0) + return i; + /* the tail idata4/5 are the only ones without relocs to an + idata$6 section unless we are importing by ordinal, + so sort them to last to terminate the IAT + and HNT properly. if no reloc this one is import by ordinal + so we have to sort by section contents */ + + if ( ((*ra)->input_section.section->reloc_count + (*rb)->input_section.section->reloc_count) ) + { + i = (((*ra)->input_section.section->reloc_count > + (*rb)->input_section.section->reloc_count) ? -1 : 0); + if ( i != 0) + return i; + + return (((*ra)->input_section.section->reloc_count > + (*rb)->input_section.section->reloc_count) ? 0 : 1); + } + else + { + if ( (strcmp( (*ra)->input_section.section->name, ".idata$6") == 0) ) + return 0; /* don't sort .idata$6 or .idata$7 FIXME dlltool eliminate .idata$7 */ + + if (! bfd_get_section_contents ((*ra)->input_section.section->owner, + (*ra)->input_section.section, &a_sec, (file_ptr) 0, (bfd_size_type)sizeof(a_sec))) + einfo ("%F%B: Can't read contents of section .idata: %E\n", + (*ra)->input_section.section->owner); + + if (! bfd_get_section_contents ((*rb)->input_section.section->owner, + (*rb)->input_section.section, &b_sec, (file_ptr) 0, (bfd_size_type)sizeof(b_sec) )) + einfo ("%F%B: Can't read contents of section .idata: %E\n", + (*rb)->input_section.section->owner); + + i = ((a_sec < b_sec) ? -1 : 0); + if ( i != 0) + return i; + return ((a_sec < b_sec) ? 0 : 1); + } +return 0; +} + +static int +sort_by_section_name (const void *a, const void *b) +{ + const lang_statement_union_type *const *ra = a; + const lang_statement_union_type *const *rb = b; + int i; + i = strcmp ((*ra)->input_section.section->name, + (*rb)->input_section.section->name); + /* This is a hack to make .stab and .stabstr last, so we don't have + to fix strip/objcopy for .reloc sections. + FIXME stripping images with a .rsrc section still needs to be fixed. */ + if (i != 0) + { + if ((CONST_STRNEQ ((*ra)->input_section.section->name, ".stab")) + && (! CONST_STRNEQ ((*rb)->input_section.section->name, ".stab"))) + return 1; + } + return i; +} + +/* Subroutine of sort_sections to a contiguous subset of a list of sections. + NEXT_AFTER is the element after the last one to sort. + The result is a pointer to the last element's "next" pointer. */ + +static lang_statement_union_type ** +sort_sections_1 (lang_statement_union_type **startptr, + lang_statement_union_type *next_after, + int count, + int (*sort_func) (const void *, const void *)) +{ + lang_statement_union_type **vec; + lang_statement_union_type *p; + int i; + lang_statement_union_type **ret; + + if (count == 0) + return startptr; + + vec = ((lang_statement_union_type **) + xmalloc (count * sizeof (lang_statement_union_type *))); + + for (p = *startptr, i = 0; i < count; i++, p = p->header.next) + vec[i] = p; + + qsort (vec, count, sizeof (vec[0]), sort_func); + + /* Fill in the next pointers again. */ + *startptr = vec[0]; + for (i = 0; i < count - 1; i++) + vec[i]->header.next = vec[i + 1]; + vec[i]->header.next = next_after; + ret = &vec[i]->header.next; + free (vec); + return ret; +} + +/* Sort the .idata\$foo input sections of archives into filename order. + The reason is so dlltool can arrange to have the pe dll import information + generated correctly - the head of the list goes into dh.o, the tail into + dt.o, and the guts into ds[nnnn].o. Note that this is only needed for the + .idata section. + FIXME: This may no longer be necessary with grouped sections. Instead of + sorting on dh.o, ds[nnnn].o, dt.o, one could, for example, have dh.o use + .idata\$4h, have ds[nnnn].o use .idata\$4s[nnnn], and have dt.o use .idata\$4t. + This would have to be elaborated upon to handle multiple dll's + [assuming such an eloboration is possible of course]. + + We also sort sections in '\$' wild statements. These are created by the + place_orphans routine to implement grouped sections. */ + +static void +sort_sections (lang_statement_union_type *s) +{ + for (; s ; s = s->header.next) + switch (s->header.type) + { + case lang_output_section_statement_enum: + sort_sections (s->output_section_statement.children.head); + break; + case lang_wild_statement_enum: + { + lang_statement_union_type **p = &s->wild_statement.children.head; + struct wildcard_list *sec; + + for (sec = s->wild_statement.section_list; sec; sec = sec->next) + { + /* Is this the .idata section? */ + if (sec->spec.name != NULL + && CONST_STRNEQ (sec->spec.name, ".idata")) + { + /* Sort the children. We want to sort any objects in + the same archive. In order to handle the case of + including a single archive multiple times, we sort + all the children by archive name and then by object + name. After sorting them, we re-thread the pointer + chain. */ + + while (*p) + { + lang_statement_union_type *start = *p; + if (start->header.type != lang_input_section_enum + || !start->input_section.section->owner->my_archive) + p = &(start->header.next); + else + { + lang_statement_union_type *end; + int count; + + for (end = start, count = 0; + end && (end->header.type + == lang_input_section_enum); + end = end->header.next) + count++; + + p = sort_sections_1 (p, end, count, + sort_by_file_name); + } + } + break; + } + + /* If this is a collection of grouped sections, sort them. + The linker script must explicitly mention "*(.foo\$)" or + "*(.foo\$*)". Don't sort them if \$ is not the last + character (not sure if this is really useful, but it + allows explicitly mentioning some \$ sections and letting + the linker handle the rest). */ + if (sec->spec.name != NULL) + { + char *q = strchr (sec->spec.name, '\$'); + + if (q != NULL + && (q[1] == '\0' + || (q[1] == '*' && q[2] == '\0'))) + { + lang_statement_union_type *end; + int count; + + for (end = *p, count = 0; end; end = end->header.next) + { + if (end->header.type != lang_input_section_enum) + abort (); + count++; + } + (void) sort_sections_1 (p, end, count, + sort_by_section_name); + } + break; + } + } + } + break; + default: + break; + } +} + +static void +gld_${EMULATION_NAME}_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)) + { + 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); +#else +#ifdef TARGET_IS_armpe + /* 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 (!arm_process_before_allocation (is->the_bfd, & link_info)) + { + einfo ("Errors encountered processing file %s", is->filename); + } + } + } + + /* We have seen it all. Allocate it, and carry on */ + arm_allocate_interworking_sections (& link_info); +#endif /* TARGET_IS_armpe */ +#endif /* TARGET_IS_ppcpe */ + + sort_sections (stat_ptr->head); + + before_allocation_default (); +} + +/* Place an orphan section. We use this to put sections with a '\$' in them + into the right place. Any section with a '\$' in them (e.g. .text\$foo) + gets mapped to the output section with everything from the '\$' on stripped + (e.g. .text). + See the Microsoft Portable Executable and Common Object File Format + Specification 4.1, section 4.2, Grouped Sections. + + FIXME: This is now handled by the linker script using wildcards, + but I'm leaving this here in case we want to enable it for sections + which are not mentioned in the linker script. */ + +static lang_output_section_statement_type * +gld${EMULATION_NAME}_place_orphan (asection *s, + const char *secname, + int constraint) +{ + char *output_secname, *ps; + lang_output_section_statement_type *os; + lang_statement_union_type *l; + + if ((s->flags & SEC_ALLOC) == 0) + return NULL; + + /* Don't process grouped sections unless doing a final link. + If they're marked as COMDAT sections, we don't want .text\$foo to + end up in .text and then have .text disappear because it's marked + link-once-discard. */ + if (link_info.relocatable) + return NULL; + + /* Everything from the '\$' on gets deleted so don't allow '\$' as the + first character. */ + if (*secname == '\$') + einfo ("%P%F: section %s has '\$' as first character\n", secname); + if (strchr (secname + 1, '\$') == NULL) + return NULL; + + /* Look up the output section. The Microsoft specs say sections names in + image files never contain a '\$'. Fortunately, lang_..._lookup creates + the section if it doesn't exist. */ + output_secname = xstrdup (secname); + ps = strchr (output_secname + 1, '\$'); + *ps = 0; + os = lang_output_section_statement_lookup (output_secname, constraint, TRUE); + + /* Find the '\$' wild statement for this section. We currently require the + linker script to explicitly mention "*(.foo\$)". + FIXME: ppcpe.sc has .CRT\$foo in the .rdata section. According to the + Microsoft docs this isn't correct so it's not (currently) handled. */ + + ps[0] = '\$'; + ps[1] = 0; + for (l = os->children.head; l; l = l->header.next) + if (l->header.type == lang_wild_statement_enum) + { + struct wildcard_list *sec; + + for (sec = l->wild_statement.section_list; sec; sec = sec->next) + if (sec->spec.name && strcmp (sec->spec.name, output_secname) == 0) + break; + if (sec) + break; + } + ps[0] = 0; + if (l == NULL) + einfo ("%P%F: *(%s\$) missing from linker script\n", output_secname); + + /* Link the input section in and we're done for now. + The sections still have to be sorted, but that has to wait until + all such sections have been processed by us. The sorting is done by + sort_sections. */ + lang_add_section (&l->wild_statement.children, s, os); + + return os; +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +# Scripts compiled in. +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +fragment <<EOF + + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + gld_${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld_${EMULATION_NAME}_before_allocation, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + gld${EMULATION_NAME}_place_orphan, + gld_${EMULATION_NAME}_set_symbols, + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/cr16elf.em b/binutils-2.21/ld/emultempl/cr16elf.em new file mode 100644 index 0000000..9850bda --- /dev/null +++ b/binutils-2.21/ld/emultempl/cr16elf.em @@ -0,0 +1,183 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +# Contributed by M R Swami Reddy <MR.Swami.Reddy@nsc.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 is sourced from elf32.em, and defines extra cr16-elf +# specific routines. +# +fragment <<EOF + +#include "ldctor.h" + +static void check_sections (bfd *, asection *, void *); + + +/* This function is run after all the input files have been opened. */ + +static void +cr16_elf_after_open (void) +{ + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_open (); + + if (command_line.embedded_relocs + && (! link_info.relocatable)) + { + bfd *abfd; + + /* In the embedded relocs mode we create a .emreloc section for each + input file with a nonzero .data section. The BFD backend will fill in + these sections with magic numbers which can be used to relocate the + data section at run time. */ + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec; + + /* As first-order business, make sure that each input BFD is either + COFF or ELF. We need to call a special BFD backend function to + generate the embedded relocs, and we have such functions only for + COFF and ELF. */ + if (bfd_get_flavour (abfd) != bfd_target_coff_flavour + && bfd_get_flavour (abfd) != bfd_target_elf_flavour) + einfo ("%F%B: all input objects must be COFF or ELF for --embedded-relocs\n"); + + datasec = bfd_get_section_by_name (abfd, ".data.rel"); + + /* Note that we assume that the reloc_count field has already + been set up. We could call bfd_get_reloc_upper_bound, but + that returns the size of a memory buffer rather than a reloc + count. We do not want to call bfd_canonicalize_reloc, + because although it would always work it would force us to + read in the relocs into BFD canonical form, which would waste + a significant amount of time and memory. */ + if (datasec != NULL && datasec->reloc_count > 0) + { + asection *relsec; + + relsec = bfd_make_section (abfd, ".emreloc"); + if (relsec == NULL + || ! bfd_set_section_flags (abfd, relsec, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY)) + || ! bfd_set_section_alignment (abfd, relsec, 2) + || ! bfd_set_section_size (abfd, relsec, + datasec->reloc_count * 8)) + einfo ("%F%B: can not create .emreloc section: %E\n"); + } + + /* Double check that all other data sections are empty, as is + required for embedded PIC code. */ + bfd_map_over_sections (abfd, check_sections, datasec); + } + } +} + +/* Check that of the data sections, only the .data section has + relocs. This is called via bfd_map_over_sections. */ + +static void +check_sections (bfd *abfd, asection *sec, void *datasec) +{ + if ((strncmp (bfd_get_section_name (abfd, sec), ".data.rel", 9) == 0) + && sec != datasec + && sec->reloc_count == 0 ) + einfo ("%B%X: section %s has relocs; can not use --embedded-relocs\n", + abfd, bfd_get_section_name (abfd, sec)); +} + +static void +cr16elf_after_parse (void) +{ + /* Always behave as if called with --sort-common command line + option. + This is to emulate the CRTools' method of keeping variables + of different alignment in separate sections. */ + config.sort_common = TRUE; + + /* Don't create a demand-paged executable, since this feature isn't + meaninful in CR16 embedded systems. Moreover, when magic_demand_paged + is true the link sometimes fails. */ + config.magic_demand_paged = FALSE; + + after_parse_default (); +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +cr16elf_before_allocation (void) +{ + /* Call the default first. */ + gld${EMULATION_NAME}_before_allocation (); + + if (command_line.embedded_relocs + && (! link_info.relocatable)) + { + + bfd *abfd; + + /* If we are generating embedded relocs, call a special BFD backend + routine to do the work. */ + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec, *relsec; + char *errmsg; + + datasec = bfd_get_section_by_name (abfd, ".data.rel"); + + if (datasec == NULL || datasec->reloc_count == 0) + continue; + + relsec = bfd_get_section_by_name (abfd, ".emreloc"); + ASSERT (relsec != NULL); + + if (! bfd_cr16_elf32_create_embedded_relocs (abfd, &link_info, + datasec, relsec, + &errmsg)) + { + if (errmsg == NULL) + einfo ("%B%X: can not create runtime reloc information: %E\n", + abfd); + else + einfo ("%X%B: can not create runtime reloc information: %s\n", + abfd, errmsg); + } + } + } + + /* Enable relaxation by default if the "--no-relax" option was not + specified. This is done here instead of in the before_parse hook + because there is a check in main() to prohibit use of --relax and + -r together. */ + if (RELAXATION_DISABLED_BY_DEFAULT) + ENABLE_RELAXATION; +} + +EOF + +# Put these extra cr16-elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=cr16_elf_after_open +LDEMUL_AFTER_PARSE=cr16elf_after_parse +LDEMUL_BEFORE_ALLOCATION=cr16elf_before_allocation diff --git a/binutils-2.21/ld/emultempl/crxelf.em b/binutils-2.21/ld/emultempl/crxelf.em new file mode 100644 index 0000000..c6d5a8d --- /dev/null +++ b/binutils-2.21/ld/emultempl/crxelf.em @@ -0,0 +1,71 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2004, 2005, 2007, 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. +# + +# This file is sourced from elf32.em, and defines extra crx-elf +# specific routines. +# +fragment <<EOF + +#include "ldctor.h" + +static void crxelf_after_parse (void); + +static void +crxelf_after_parse (void) +{ + /* Always behave as if called with --sort-common command line + option. + This is to emulate the CRTools' method of keeping variables + of different alignment in separate sections. */ + config.sort_common = TRUE; + + /* Don't create a demand-paged executable, since this feature isn't + meaninful in CRX embedded systems. Moreover, when magic_demand_paged + is true the link sometimes fails. */ + config.magic_demand_paged = FALSE; + + after_parse_default (); +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +crxelf_before_allocation (void) +{ + /* Call the default first. */ + gld${EMULATION_NAME}_before_allocation (); + + /* Enable relaxation by default if the "--no-relax" option was not + specified. This is done here instead of in the before_parse hook + because there is a check in main() to prohibit use of --relax and + -r together. */ + if (RELAXATION_DISABLED_BY_DEFAULT) + ENABLE_RELAXATION; +} + +EOF + +# Put these extra crx-elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_PARSE=crxelf_after_parse +LDEMUL_BEFORE_ALLOCATION=crxelf_before_allocation diff --git a/binutils-2.21/ld/emultempl/elf-generic.em b/binutils-2.21/ld/emultempl/elf-generic.em new file mode 100644 index 0000000..cf4c2c8 --- /dev/null +++ b/binutils-2.21/ld/emultempl/elf-generic.em @@ -0,0 +1,73 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. +# + +# This file is sourced from elf32.em and from ELF targets that use +# generic.em. +# +fragment <<EOF + +static void +gld${EMULATION_NAME}_map_segments (bfd_boolean need_layout) +{ + int tries = 10; + + do + { + lang_relax_sections (need_layout); + need_layout = FALSE; + + if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour + && !link_info.relocatable) + { + bfd_size_type phdr_size; + + phdr_size = elf_tdata (link_info.output_bfd)->program_header_size; + /* If we don't have user supplied phdrs, throw away any + previous linker generated program headers. */ + if (lang_phdr_list == NULL) + elf_tdata (link_info.output_bfd)->segment_map = NULL; + if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd, + &link_info)) + einfo ("%F%P: map sections to segments failed: %E\n"); + + if (phdr_size + != elf_tdata (link_info.output_bfd)->program_header_size) + { + if (tries > 6) + /* The first few times we allow any change to + phdr_size . */ + need_layout = TRUE; + else if (phdr_size + < elf_tdata (link_info.output_bfd)->program_header_size) + /* After that we only allow the size to grow. */ + need_layout = TRUE; + else + elf_tdata (link_info.output_bfd)->program_header_size + = phdr_size; + } + } + } + while (need_layout && --tries); + + if (tries == 0) + einfo (_("%P%F: looping in map_segments")); +} +EOF diff --git a/binutils-2.21/ld/emultempl/elf32.em b/binutils-2.21/ld/emultempl/elf32.em new file mode 100644 index 0000000..1950efe --- /dev/null +++ b/binutils-2.21/ld/emultempl/elf32.em @@ -0,0 +1,2495 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +# This file is now misnamed, because it supports both 32 bit and 64 bit +# ELF emulations. +test -z "${ELFSIZE}" && ELFSIZE=32 +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} + Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. + Written by Steve Chamberlain <sac@cygnus.com> + ELF support 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "getopt.h" +#include "md5.h" +#include "sha1.h" +#include <fcntl.h> + +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include <ldgram.h> +#include "elf/common.h" +#include "elf-bfd.h" +#include "filenames.h" + +/* Declare functions used by various EXTRA_EM_FILEs. */ +static void gld${EMULATION_NAME}_before_parse (void); +static void gld${EMULATION_NAME}_after_open (void); +static void gld${EMULATION_NAME}_before_allocation (void); +static void gld${EMULATION_NAME}_after_allocation (void); +static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan + (asection *, const char *, int); +EOF + +if [ "x${USE_LIBPATH}" = xyes ] ; then + case ${target} in + *-*-linux-* | *-*-k*bsd*-*) + fragment <<EOF +#ifdef HAVE_GLOB +#include <glob.h> +#endif +EOF + ;; + esac +fi + +# Import any needed special functions and/or overrides. +# +source_em ${srcdir}/emultempl/elf-generic.em +if test -n "$EXTRA_EM_FILE" ; then + source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em +fi + +# Functions in this file can be overridden by setting the LDEMUL_* shell +# variables. If the name of the overriding function is the same as is +# defined in this file, then don't output this file's version. +# If a different overriding name is given then output the standard function +# as presumably it is called from the overriding function. +# +if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then +fragment <<EOF + +static void +gld${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + config.dynamic_link = ${DYNAMIC_LINK-TRUE}; + config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; +} + +EOF +fi + +if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then +fragment <<EOF +/* Handle the generation of DT_NEEDED tags. */ + +static bfd_boolean +gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry) +{ + int link_class = 0; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file, unless it is used to resolve + references in a regular object. */ + if (entry->add_DT_NEEDED_for_regular) + link_class = DYN_AS_NEEDED; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for any dynamic library in DT_NEEDED tags from + this file at all. */ + if (!entry->add_DT_NEEDED_for_dynamic) + link_class |= DYN_NO_ADD_NEEDED; + + if (entry->just_syms_flag + && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) + einfo (_("%P%F: --just-symbols may not be used on DSO: %B\n"), + entry->the_bfd); + + if (link_class == 0 + || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) + return FALSE; + + bfd_elf_set_dyn_lib_class (entry->the_bfd, + (enum dynamic_lib_link_class) link_class); + + /* Continue on with normal load_symbols processing. */ + return FALSE; +} +EOF +fi + +fragment <<EOF + +/* These variables are required to pass information back and forth + between after_open and check_needed and stat_needed and vercheck. */ + +static struct bfd_link_needed_list *global_needed; +static struct stat global_stat; +static lang_input_statement_type *global_found; +static struct bfd_link_needed_list *global_vercheck_needed; +static bfd_boolean global_vercheck_failed; + +/* These variables are used to implement target options */ + +static char *audit; /* colon (typically) separated list of libs */ +static char *depaudit; /* colon (typically) separated list of libs */ + +/* On Linux, it's possible to have different versions of the same + shared library linked against different versions of libc. The + dynamic linker somehow tags which libc version to use in + /etc/ld.so.cache, and, based on the libc that it sees in the + executable, chooses which version of the shared library to use. + + We try to do a similar check here by checking whether this shared + library needs any other shared libraries which may conflict with + libraries we have already included in the link. If it does, we + skip it, and try to find another shared library farther on down the + link path. + + This is called via lang_for_each_input_file. + GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object + which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find + a conflicting version. */ + +static void +gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s) +{ + const char *soname; + struct bfd_link_needed_list *l; + + if (global_vercheck_failed) + return; + if (s->the_bfd == NULL + || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) + return; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (bfd_get_filename (s->the_bfd)); + + for (l = global_vercheck_needed; l != NULL; l = l->next) + { + const char *suffix; + + if (strcmp (soname, l->name) == 0) + { + /* Probably can't happen, but it's an easy check. */ + continue; + } + + if (strchr (l->name, '/') != NULL) + continue; + + suffix = strstr (l->name, ".so."); + if (suffix == NULL) + continue; + + suffix += sizeof ".so." - 1; + + if (strncmp (soname, l->name, suffix - l->name) == 0) + { + /* Here we know that S is a dynamic object FOO.SO.VER1, and + the object we are considering needs a dynamic object + FOO.SO.VER2, and VER1 and VER2 are different. This + appears to be a version mismatch, so we tell the caller + to try a different version of this library. */ + global_vercheck_failed = TRUE; + return; + } + } +} + + +/* See if an input file matches a DT_NEEDED entry by running stat on + the file. */ + +static void +gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) +{ + struct stat st; + const char *suffix; + const char *soname; + + if (global_found != NULL) + return; + if (s->the_bfd == NULL) + return; + + /* If this input file was an as-needed entry, and wasn't found to be + needed at the stage it was linked, then don't say we have loaded it. */ + if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) + return; + + if (bfd_stat (s->the_bfd, &st) != 0) + { + einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); + return; + } + + /* Some operating systems, e.g. Windows, do not provide a meaningful + st_ino; they always set it to zero. (Windows does provide a + meaningful st_dev.) Do not indicate a duplicate library in that + case. While there is no guarantee that a system that provides + meaningful inode numbers will never set st_ino to zero, this is + merely an optimization, so we do not need to worry about false + negatives. */ + if (st.st_dev == global_stat.st_dev + && st.st_ino == global_stat.st_ino + && st.st_ino != 0) + { + global_found = s; + return; + } + + /* We issue a warning if it looks like we are including two + different versions of the same shared library. For example, + there may be a problem if -lc picks up libc.so.6 but some other + shared library has a DT_NEEDED entry of libc.so.5. This is a + heuristic test, and it will only work if the name looks like + NAME.so.VERSION. FIXME: Depending on file names is error-prone. + If we really want to issue warnings about mixing version numbers + of shared libraries, we need to find a better way. */ + + if (strchr (global_needed->name, '/') != NULL) + return; + suffix = strstr (global_needed->name, ".so."); + if (suffix == NULL) + return; + suffix += sizeof ".so." - 1; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (s->filename); + + if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0) + einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", + global_needed->name, global_needed->by, soname); +} + +struct dt_needed +{ + bfd *by; + const char *name; +}; + +/* This function is called for each possible name for a dynamic object + named by a DT_NEEDED entry. The FORCE parameter indicates whether + to skip the check for a conflicting version. */ + +static bfd_boolean +gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, + int force) +{ + bfd *abfd; + const char *name = needed->name; + const char *soname; + int link_class; + + abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); + if (abfd == NULL) + return FALSE; + + /* Linker needs to decompress sections. */ + abfd->flags |= BFD_DECOMPRESS; + + if (! bfd_check_format (abfd, bfd_object)) + { + bfd_close (abfd); + return FALSE; + } + if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) + { + bfd_close (abfd); + return FALSE; + } + + /* For DT_NEEDED, they have to match. */ + if (abfd->xvec != link_info.output_bfd->xvec) + { + bfd_close (abfd); + return FALSE; + } + + /* Check whether this object would include any conflicting library + versions. If FORCE is set, then we skip this check; we use this + the second time around, if we couldn't find any compatible + instance of the shared library. */ + + if (! force) + { + struct bfd_link_needed_list *needs; + + if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) + einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); + + if (needs != NULL) + { + global_vercheck_needed = needs; + global_vercheck_failed = FALSE; + lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); + if (global_vercheck_failed) + { + bfd_close (abfd); + /* Return FALSE to force the caller to move on to try + another file on the search path. */ + return FALSE; + } + + /* But wait! It gets much worse. On Linux, if a shared + library does not use libc at all, we are supposed to skip + it the first time around in case we encounter a shared + library later on with the same name which does use the + version of libc that we want. This is much too horrible + to use on any system other than Linux. */ + +EOF +case ${target} in + *-*-linux-* | *-*-k*bsd*-*) + fragment <<EOF + { + struct bfd_link_needed_list *l; + + for (l = needs; l != NULL; l = l->next) + if (CONST_STRNEQ (l->name, "libc.so")) + break; + if (l == NULL) + { + bfd_close (abfd); + return FALSE; + } + } + +EOF + ;; +esac +fragment <<EOF + } + } + + /* We've found a dynamic object matching the DT_NEEDED entry. */ + + /* We have already checked that there is no other input file of the + same name. We must now check again that we are not including the + same file twice. We need to do this because on many systems + libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will + reference libc.so.1. If we have already included libc.so, we + don't want to include libc.so.1 if they are the same file, and we + can only check that using stat. */ + + if (bfd_stat (abfd, &global_stat) != 0) + einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd); + + /* First strip off everything before the last '/'. */ + soname = lbasename (abfd->filename); + + if (trace_file_tries) + info_msg (_("found %s at %s\n"), soname, name); + + global_found = NULL; + lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); + if (global_found != NULL) + { + /* Return TRUE to indicate that we found the file, even though + we aren't going to do anything with it. */ + return TRUE; + } + + /* Specify the soname to use. */ + bfd_elf_set_dt_needed_name (abfd, soname); + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file, unless it is used to resolve + references in a regular object. */ + link_class = DYN_DT_NEEDED; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file at all if the entry is from a file + with DYN_NO_ADD_NEEDED. */ + if (needed->by != NULL + && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) + link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; + + bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); + + /* Add this file into the symbol table. */ + if (! bfd_link_add_symbols (abfd, &link_info)) + einfo ("%F%B: could not read symbols: %E\n", abfd); + + return TRUE; +} + + +/* Search for a needed file in a path. */ + +static bfd_boolean +gld${EMULATION_NAME}_search_needed (const char *path, + struct dt_needed *n, int force) +{ + const char *s; + const char *name = n->name; + size_t len; + struct dt_needed needed; + + if (name[0] == '/') + return gld${EMULATION_NAME}_try_needed (n, force); + + if (path == NULL || *path == '\0') + return FALSE; + + needed.by = n->by; + needed.name = n->name; + + len = strlen (name); + while (1) + { + char *filename, *sset; + + s = strchr (path, config.rpath_separator); + if (s == NULL) + s = path + strlen (path); + +#if HAVE_DOS_BASED_FILE_SYSTEM + /* Assume a match on the second char is part of drive specifier. */ + else if (config.rpath_separator == ':' + && s == path + 1 + && ISALPHA (*path)) + { + s = strchr (s + 1, config.rpath_separator); + if (s == NULL) + s = path + strlen (path); + } +#endif + filename = (char *) xmalloc (s - path + len + 2); + if (s == path) + sset = filename; + else + { + memcpy (filename, path, s - path); + filename[s - path] = '/'; + sset = filename + (s - path) + 1; + } + strcpy (sset, name); + + needed.name = filename; + if (gld${EMULATION_NAME}_try_needed (&needed, force)) + return TRUE; + + free (filename); + + if (*s == '\0') + break; + path = s + 1; + } + + return FALSE; +} + +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then + fragment <<EOF + +/* Add the sysroot to every entry in a path separated by + config.rpath_separator. */ + +static char * +gld${EMULATION_NAME}_add_sysroot (const char *path) +{ + int len, colons, i; + char *ret, *p; + + len = strlen (path); + colons = 0; + i = 0; + while (path[i]) + if (path[i++] == config.rpath_separator) + colons++; + + if (path[i]) + colons++; + + len = len + (colons + 1) * strlen (ld_sysroot); + ret = xmalloc (len + 1); + strcpy (ret, ld_sysroot); + p = ret + strlen (ret); + i = 0; + while (path[i]) + if (path[i] == config.rpath_separator) + { + *p++ = path[i++]; + strcpy (p, ld_sysroot); + p = p + strlen (p); + } + else + *p++ = path[i++]; + + *p = 0; + return ret; +} + +EOF + case ${target} in + *-*-freebsd* | *-*-dragonfly*) + fragment <<EOF +/* Read the system search path the FreeBSD way rather than the Linux way. */ +#ifdef HAVE_ELF_HINTS_H +#include <elf-hints.h> +#else +#include "elf-hints-local.h" +#endif + +static bfd_boolean +gld${EMULATION_NAME}_check_ld_elf_hints (const char *name, int force) +{ + static bfd_boolean initialized; + static char *ld_elf_hints; + struct dt_needed needed; + + if (!initialized) + { + FILE *f; + char *tmppath; + + tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); + f = fopen (tmppath, FOPEN_RB); + free (tmppath); + if (f != NULL) + { + struct elfhints_hdr hdr; + + if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr) + && hdr.magic == ELFHINTS_MAGIC + && hdr.version == 1) + { + if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1) + { + char *b; + + b = xmalloc (hdr.dirlistlen + 1); + if (fread (b, 1, hdr.dirlistlen + 1, f) == + hdr.dirlistlen + 1) + ld_elf_hints = gld${EMULATION_NAME}_add_sysroot (b); + + free (b); + } + } + fclose (f); + } + + initialized = TRUE; + } + + if (ld_elf_hints == NULL) + return FALSE; + + needed.by = NULL; + needed.name = name; + return gld${EMULATION_NAME}_search_needed (ld_elf_hints, & needed, + force); +} +EOF + # FreeBSD + ;; + + *-*-linux-* | *-*-k*bsd*-*) + fragment <<EOF +/* For a native linker, check the file /etc/ld.so.conf for directories + in which we may find shared libraries. /etc/ld.so.conf is really + only meaningful on Linux. */ + +struct gld${EMULATION_NAME}_ld_so_conf +{ + char *path; + size_t len, alloc; +}; + +static bfd_boolean +gld${EMULATION_NAME}_parse_ld_so_conf + (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename); + +static void +gld${EMULATION_NAME}_parse_ld_so_conf_include + (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename, + const char *pattern) +{ + char *newp = NULL; +#ifdef HAVE_GLOB + glob_t gl; +#endif + + if (pattern[0] != '/') + { + char *p = strrchr (filename, '/'); + size_t patlen = strlen (pattern) + 1; + + newp = xmalloc (p - filename + 1 + patlen); + memcpy (newp, filename, p - filename + 1); + memcpy (newp + (p - filename + 1), pattern, patlen); + pattern = newp; + } + +#ifdef HAVE_GLOB + if (glob (pattern, 0, NULL, &gl) == 0) + { + size_t i; + + for (i = 0; i < gl.gl_pathc; ++i) + gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]); + globfree (&gl); + } +#else + /* If we do not have glob, treat the pattern as a literal filename. */ + gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern); +#endif + + if (newp) + free (newp); +} + +static bfd_boolean +gld${EMULATION_NAME}_parse_ld_so_conf + (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename) +{ + FILE *f = fopen (filename, FOPEN_RT); + char *line; + size_t linelen; + + if (f == NULL) + return FALSE; + + linelen = 256; + line = xmalloc (linelen); + do + { + char *p = line, *q; + + /* Normally this would use getline(3), but we need to be portable. */ + while ((q = fgets (p, linelen - (p - line), f)) != NULL + && strlen (q) == linelen - (p - line) - 1 + && line[linelen - 2] != '\n') + { + line = xrealloc (line, 2 * linelen); + p = line + linelen - 1; + linelen += linelen; + } + + if (q == NULL && p == line) + break; + + p = strchr (line, '\n'); + if (p) + *p = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + p = strchr (line, '#'); + if (p) + *p = '\0'; + + /* Remove leading whitespace. NUL is no whitespace character. */ + p = line; + while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v') + ++p; + + /* If the line is blank it is ignored. */ + if (p[0] == '\0') + continue; + + if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t')) + { + char *dir, c; + p += 8; + do + { + while (*p == ' ' || *p == '\t') + ++p; + + if (*p == '\0') + break; + + dir = p; + + while (*p != ' ' && *p != '\t' && *p) + ++p; + + c = *p; + *p++ = '\0'; + if (dir[0] != '\0') + gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename, + dir); + } + while (c != '\0'); + } + else + { + char *dir = p; + while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f' + && *p != '\r' && *p != '\v') + ++p; + + while (p != dir && p[-1] == '/') + --p; + if (info->path == NULL) + { + info->alloc = p - dir + 1 + 256; + info->path = xmalloc (info->alloc); + info->len = 0; + } + else + { + if (info->len + 1 + (p - dir) >= info->alloc) + { + info->alloc += p - dir + 256; + info->path = xrealloc (info->path, info->alloc); + } + info->path[info->len++] = config.rpath_separator; + } + memcpy (info->path + info->len, dir, p - dir); + info->len += p - dir; + info->path[info->len] = '\0'; + } + } + while (! feof (f)); + free (line); + fclose (f); + return TRUE; +} + +static bfd_boolean +gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) +{ + static bfd_boolean initialized; + static char *ld_so_conf; + struct dt_needed needed; + + if (! initialized) + { + char *tmppath; + struct gld${EMULATION_NAME}_ld_so_conf info; + + info.path = NULL; + info.len = info.alloc = 0; + tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", + (const char *) NULL); + if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath)) + { + free (tmppath); + tmppath = concat (ld_sysroot, "/etc/ld.so.conf", + (const char *) NULL); + gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath); + } + free (tmppath); + + if (info.path) + { + char *d = gld${EMULATION_NAME}_add_sysroot (info.path); + free (info.path); + ld_so_conf = d; + } + initialized = TRUE; + } + + if (ld_so_conf == NULL) + return FALSE; + + + needed.by = NULL; + needed.name = name; + return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); +} + +EOF + # Linux + ;; + esac +fi +fragment <<EOF + +/* See if an input file matches a DT_NEEDED entry by name. */ + +static void +gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) +{ + const char *soname; + + /* Stop looking if we've found a loaded lib. */ + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) + & DYN_AS_NEEDED) == 0) + return; + + if (s->filename == NULL || s->the_bfd == NULL) + return; + + /* Don't look for a second non-loaded as-needed lib. */ + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) + return; + + if (strcmp (s->filename, global_needed->name) == 0) + { + global_found = s; + return; + } + + if (s->search_dirs_flag) + { + const char *f = strrchr (s->filename, '/'); + if (f != NULL + && strcmp (f + 1, global_needed->name) == 0) + { + global_found = s; + return; + } + } + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname != NULL + && strcmp (soname, global_needed->name) == 0) + { + global_found = s; + return; + } +} + +EOF + +if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then +fragment <<EOF + +static bfd_size_type +gld${EMULATION_NAME}_id_note_section_size (bfd *abfd, + struct bfd_link_info *linfo) +{ + const char *style = linfo->emit_note_gnu_build_id; + bfd_size_type size; + + abfd = abfd; + + size = offsetof (Elf_External_Note, name[sizeof "GNU"]); + size = (size + 3) & -(bfd_size_type) 4; + + if (!strcmp (style, "md5") || !strcmp (style, "uuid")) + size += 128 / 8; + else if (!strcmp (style, "sha1")) + size += 160 / 8; + else if (!strncmp (style, "0x", 2)) + { + /* ID is in string form (hex). Convert to bits. */ + const char *id = style + 2; + do + { + if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) + { + ++size; + id += 2; + } + else if (*id == '-' || *id == ':') + ++id; + else + { + size = 0; + break; + } + } while (*id != '\0'); + } + else + size = 0; + + return size; +} + +static unsigned char +read_hex (const char xdigit) +{ + if (ISDIGIT (xdigit)) + return xdigit - '0'; + if (ISUPPER (xdigit)) + return xdigit - 'A' + 0xa; + if (ISLOWER (xdigit)) + return xdigit - 'a' + 0xa; + abort (); + return 0; +} + +struct build_id_info +{ + const char *style; + asection *sec; +}; + +static bfd_boolean +gld${EMULATION_NAME}_write_build_id_section (bfd *abfd) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct build_id_info *info = (struct build_id_info *) + elf_tdata (abfd)->after_write_object_contents_info; + asection *asec; + Elf_Internal_Shdr *i_shdr; + unsigned char *contents, *id_bits; + bfd_size_type size; + Elf_External_Note *e_note; + + asec = info->sec; + if (bfd_is_abs_section (asec->output_section)) + { + einfo (_("%P: warning: .note.gnu.build-id section discarded," + " --build-id ignored.\n")); + return TRUE; + } + i_shdr = &elf_section_data (asec->output_section)->this_hdr; + + if (i_shdr->contents == NULL) + { + if (asec->contents == NULL) + asec->contents = (unsigned char *) xmalloc (asec->size); + contents = asec->contents; + } + else + contents = i_shdr->contents + asec->output_offset; + + e_note = (Elf_External_Note *) contents; + size = offsetof (Elf_External_Note, name[sizeof "GNU"]); + size = (size + 3) & -(bfd_size_type) 4; + id_bits = contents + size; + size = asec->size - size; + + bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); + bfd_h_put_32 (abfd, size, &e_note->descsz); + bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); + memcpy (e_note->name, "GNU", sizeof "GNU"); + + if (!strcmp (info->style, "md5")) + { + struct md5_ctx ctx; + md5_init_ctx (&ctx); + if (bed->s->checksum_contents (abfd, + (void (*) (const void *, size_t, void *)) + &md5_process_bytes, + &ctx)) + md5_finish_ctx (&ctx, id_bits); + else + return FALSE; + } + else if (!strcmp (info->style, "sha1")) + { + struct sha1_ctx ctx; + sha1_init_ctx (&ctx); + if (bed->s->checksum_contents (abfd, + (void (*) (const void *, size_t, void *)) + &sha1_process_bytes, + &ctx)) + sha1_finish_ctx (&ctx, id_bits); + else + return FALSE; + } + else if (!strcmp (info->style, "uuid")) + { + int n; + int fd = open ("/dev/urandom", O_RDONLY); + if (fd < 0) + return FALSE; + n = read (fd, id_bits, size); + close (fd); + if (n < (int) size) + return FALSE; + } + else if (!strncmp (info->style, "0x", 2)) + { + /* ID is in string form (hex). Convert to bits. */ + const char *id = info->style + 2; + size_t n = 0; + do + { + if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) + { + id_bits[n] = read_hex (*id++) << 4; + id_bits[n++] |= read_hex (*id++); + } + else if (*id == '-' || *id == ':') + ++id; + else + abort (); /* Should have been validated earlier. */ + } while (*id != '\0'); + } + else + abort (); /* Should have been validated earlier. */ + + size = asec->size; + return (bfd_seek (abfd, + i_shdr->sh_offset + asec->output_offset, SEEK_SET) == 0 + && bfd_bwrite (contents, size, abfd) == size); +} + + +/* This is called after all the input files have been opened. */ + +static void +gld${EMULATION_NAME}_after_open (void) +{ + struct bfd_link_needed_list *needed, *l; + struct elf_link_hash_table *htab; + + htab = elf_hash_table (&link_info); + if (!is_elf_hash_table (htab)) + return; + + if (link_info.emit_note_gnu_build_id) + { + bfd *abfd; + asection *s; + bfd_size_type size; + + /* Find an ELF input. */ + for (abfd = link_info.input_bfds; + abfd != (bfd *) NULL; abfd = abfd->link_next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + break; + + if (abfd == NULL) + { + /* PR 10555: If there are no input files do not + try to create a .note.gnu-build-id section. */ + free (link_info.emit_note_gnu_build_id); + link_info.emit_note_gnu_build_id = NULL; + } + else + { + size = gld${EMULATION_NAME}_id_note_section_size (abfd, &link_info); + if (size == 0) + { + einfo ("%P: warning: unrecognized --build-id style ignored.\n"); + free (link_info.emit_note_gnu_build_id); + link_info.emit_note_gnu_build_id = NULL; + } + else + { + s = bfd_make_section_with_flags (abfd, ".note.gnu.build-id", + SEC_ALLOC | SEC_LOAD + | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_READONLY | SEC_DATA); + if (s != NULL && bfd_set_section_alignment (abfd, s, 2)) + { + struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); + struct build_id_info *b = + (struct build_id_info *) xmalloc (sizeof *b); + + b->style = link_info.emit_note_gnu_build_id; + b->sec = s; + elf_section_type (s) = SHT_NOTE; + s->size = size; + t->after_write_object_contents + = &gld${EMULATION_NAME}_write_build_id_section; + t->after_write_object_contents_info = b; + } + else + { + einfo ("%P: warning: Cannot create .note.gnu.build-id section," + " --build-id ignored.\n"); + free (link_info.emit_note_gnu_build_id); + link_info.emit_note_gnu_build_id = NULL; + } + } + } + } + + if (link_info.relocatable) + return; + + if (link_info.eh_frame_hdr + && !link_info.traditional_format) + { + bfd *abfd, *elfbfd = NULL; + bfd_boolean warn_eh_frame = FALSE; + asection *s; + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + elfbfd = abfd; + if (!warn_eh_frame) + { + s = bfd_get_section_by_name (abfd, ".eh_frame"); + warn_eh_frame + = (s + && s->size > 8 + && !bfd_is_abs_section (s->output_section)); + } + if (elfbfd && warn_eh_frame) + break; + } + if (elfbfd) + { + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (elfbfd); + s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", + bed->dynamic_sec_flags + | SEC_READONLY); + if (s != NULL + && bfd_set_section_alignment (elfbfd, s, 2)) + { + htab->eh_info.hdr_sec = s; + warn_eh_frame = FALSE; + } + } + if (warn_eh_frame) + einfo ("%P: warning: Cannot create .eh_frame_hdr section," + " --eh-frame-hdr ignored.\n"); + } + + /* Get the list of files which appear in DT_NEEDED entries in + dynamic objects included in the link (often there will be none). + For each such file, we want to track down the corresponding + library, and include the symbol table in the link. This is what + the runtime dynamic linker will do. Tracking the files down here + permits one dynamic object to include another without requiring + special action by the person doing the link. Note that the + needed list can actually grow while we are stepping through this + loop. */ + if (!link_info.executable) + return; + needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); + for (l = needed; l != NULL; l = l->next) + { + struct bfd_link_needed_list *ll; + struct dt_needed n, nn; + int force; + + /* If the lib that needs this one was --as-needed and wasn't + found to be needed, then this lib isn't needed either. */ + if (l->by != NULL + && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0) + continue; + + /* If we've already seen this file, skip it. */ + for (ll = needed; ll != l; ll = ll->next) + if ((ll->by == NULL + || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0) + && strcmp (ll->name, l->name) == 0) + break; + if (ll != l) + continue; + + /* See if this file was included in the link explicitly. */ + global_needed = l; + global_found = NULL; + lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) + & DYN_AS_NEEDED) == 0) + continue; + + n.by = l->by; + n.name = l->name; + nn.by = l->by; + if (trace_file_tries) + info_msg (_("%s needed by %B\n"), l->name, l->by); + + /* As-needed libs specified on the command line (or linker script) + take priority over libs found in search dirs. */ + if (global_found != NULL) + { + nn.name = global_found->filename; + if (gld${EMULATION_NAME}_try_needed (&nn, TRUE)) + continue; + } + + /* We need to find this file and include the symbol table. We + want to search for the file in the same way that the dynamic + linker will search. That means that we want to use + rpath_link, rpath, then the environment variable + LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH + entries (native only), then the linker script LIB_SEARCH_DIRS. + We do not search using the -L arguments. + + We search twice. The first time, we skip objects which may + introduce version mismatches. The second time, we force + their use. See gld${EMULATION_NAME}_vercheck comment. */ + for (force = 0; force < 2; force++) + { + size_t len; + search_dirs_type *search; +EOF +if [ "x${NATIVE}" = xyes ] ; then +fragment <<EOF + const char *lib_path; +EOF +fi +if [ "x${USE_LIBPATH}" = xyes ] ; then +fragment <<EOF + struct bfd_link_needed_list *rp; + int found; +EOF +fi +fragment <<EOF + + if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, + &n, force)) + break; +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then +fragment <<EOF + if (gld${EMULATION_NAME}_search_needed (command_line.rpath, + &n, force)) + break; +EOF +fi +if [ "x${NATIVE}" = xyes ] ; then +fragment <<EOF + if (command_line.rpath_link == NULL + && command_line.rpath == NULL) + { + lib_path = (const char *) getenv ("LD_RUN_PATH"); + if (gld${EMULATION_NAME}_search_needed (lib_path, &n, + force)) + break; + } + lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); + if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force)) + break; +EOF +fi +if [ "x${USE_LIBPATH}" = xyes ] ; then +fragment <<EOF + found = 0; + rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info); + for (; !found && rp != NULL; rp = rp->next) + { + char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name); + found = (rp->by == l->by + && gld${EMULATION_NAME}_search_needed (tmpname, + &n, + force)); + free (tmpname); + } + if (found) + break; + +EOF +fi +if [ "x${USE_LIBPATH}" = xyes ] ; then + case ${target} in + *-*-freebsd* | *-*-dragonfly*) + fragment <<EOF + if (gld${EMULATION_NAME}_check_ld_elf_hints (l->name, force)) + break; +EOF + # FreeBSD + ;; + + *-*-linux-* | *-*-k*bsd*-*) + # Linux + fragment <<EOF + if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force)) + break; + +EOF + ;; + esac +fi +fragment <<EOF + len = strlen (l->name); + for (search = search_head; search != NULL; search = search->next) + { + char *filename; + + if (search->cmdline) + continue; + filename = (char *) xmalloc (strlen (search->name) + len + 2); + sprintf (filename, "%s/%s", search->name, l->name); + nn.name = filename; + if (gld${EMULATION_NAME}_try_needed (&nn, force)) + break; + free (filename); + } + if (search != NULL) + break; +EOF +fragment <<EOF + } + + if (force < 2) + continue; + + einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n", + l->name, l->by); + } +} + +EOF +fi + +fragment <<EOF + +/* Look through an expression for an assignment statement. */ + +static void +gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) +{ + bfd_boolean provide = FALSE; + + switch (exp->type.node_class) + { + case etree_provide: + case etree_provided: + provide = TRUE; + /* Fall thru */ + case etree_assign: + /* We call record_link_assignment even if the symbol is defined. + This is because if it is defined by a dynamic object, we + actually want to use the value defined by the linker script, + not the value from the dynamic object (because we are setting + symbols like etext). If the symbol is defined by a regular + object, then, as it happens, calling record_link_assignment + will do no harm. */ + if (strcmp (exp->assign.dst, ".") != 0) + { + if (!bfd_elf_record_link_assignment (link_info.output_bfd, + &link_info, + exp->assign.dst, provide, + exp->assign.hidden)) + einfo ("%P%F: failed to record assignment to %s: %E\n", + exp->assign.dst); + } + gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); + break; + + case etree_binary: + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); + break; + + case etree_trinary: + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); + break; + + case etree_unary: + gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); + break; + + default: + break; + } +} + + +/* This is called by the before_allocation routine via + lang_for_each_statement. It locates any assignment statements, and + tells the ELF backend about them, in case they are assignments to + symbols which are referred to by dynamic objects. */ + +static void +gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s) +{ + if (s->header.type == lang_assignment_statement_enum) + gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); +} + +EOF + +if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then + if test x"${ELF_INTERPRETER_NAME+set}" = xset; then + ELF_INTERPRETER_SET_DEFAULT=" + if (sinterp != NULL) + { + sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME}; + sinterp->size = strlen ((char *) sinterp->contents) + 1; + } + +" + else + ELF_INTERPRETER_SET_DEFAULT= + fi +fragment <<EOF + +/* used by before_allocation and handle_option. */ +static void +gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg) +{ + if (*to == NULL) + *to = xstrdup (op_arg); + else + { + size_t to_len = strlen (*to); + size_t op_arg_len = strlen (op_arg); + char *buf; + char *cp = *to; + + /* First see whether OPTARG is already in the path. */ + do + { + if (strncmp (op_arg, cp, op_arg_len) == 0 + && (cp[op_arg_len] == 0 + || cp[op_arg_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 = xmalloc (to_len + op_arg_len + 2); + sprintf (buf, "%s%c%s", *to, + config.rpath_separator, op_arg); + free (*to); + *to = buf; + } + } +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + const char *rpath; + asection *sinterp; + bfd *abfd; + + if (link_info.hash->type == bfd_link_elf_hash_table) + _bfd_elf_tls_setup (link_info.output_bfd, &link_info); + + /* If we are going to make any variable assignments, we need to let + the ELF backend know about them in case the variables are + referred to by dynamic objects. */ + lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); + + /* Let the ELF backend work out the sizes of any sections required + by dynamic linking. */ + rpath = command_line.rpath; + if (rpath == NULL) + rpath = (const char *) getenv ("LD_RUN_PATH"); + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + const char *audit_libs = elf_dt_audit (abfd); + + /* If the input bfd contains an audit entry, we need to add it as + a dep audit entry. */ + if (audit_libs && *audit_libs != '\0') + { + char *cp = xstrdup (audit_libs); + do + { + int more = 0; + char *cp2 = strchr (cp, config.rpath_separator); + + if (cp2) + { + *cp2 = '\0'; + more = 1; + } + + if (cp != NULL && *cp != '\0') + gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp); + + cp = more ? ++cp2 : NULL; + } + while (cp != NULL); + } + } + + if (! (bfd_elf_size_dynamic_sections + (link_info.output_bfd, command_line.soname, rpath, + command_line.filter_shlib, audit, depaudit, + (const char * const *) command_line.auxiliary_filters, + &link_info, &sinterp, lang_elf_version_info))) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); + +${ELF_INTERPRETER_SET_DEFAULT} + /* Let the user override the dynamic linker we are using. */ + if (command_line.interpreter != NULL + && sinterp != NULL) + { + sinterp->contents = (bfd_byte *) command_line.interpreter; + sinterp->size = strlen (command_line.interpreter) + 1; + } + + /* Look for any sections named .gnu.warning. As a GNU extensions, + we treat such sections as containing warning messages. We print + out the warning message, and then zero out the section size so + that it does not get copied into the output file. */ + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *s; + bfd_size_type sz; + char *msg; + bfd_boolean ret; + + if (is->just_syms_flag) + continue; + + s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); + if (s == NULL) + continue; + + sz = s->size; + msg = (char *) xmalloc ((size_t) (sz + 1)); + if (! bfd_get_section_contents (is->the_bfd, s, msg, + (file_ptr) 0, sz)) + einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", + is->the_bfd); + msg[sz] = '\0'; + ret = link_info.callbacks->warning (&link_info, msg, + (const char *) NULL, + is->the_bfd, (asection *) NULL, + (bfd_vma) 0); + ASSERT (ret); + free (msg); + + /* Clobber the section size, so that we don't waste space + copying the warning into the output file. If we've already + sized the output section, adjust its size. The adjustment + is on rawsize because targets that size sections early will + have called lang_reset_memory_regions after sizing. */ + if (s->output_section != NULL + && s->output_section->rawsize >= s->size) + s->output_section->rawsize -= s->size; + + s->size = 0; + + /* Also set SEC_EXCLUDE, so that local symbols defined in the + warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE | SEC_KEEP; + } + } + + before_allocation_default (); + + if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); +} + +EOF +fi + +if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then +fragment <<EOF + +/* Try to open a dynamic archive. This is where we know that ELF + dynamic libraries have an extension of .so (or .sl on oddball systems + like hpux). */ + +static bfd_boolean +gld${EMULATION_NAME}_open_dynamic_archive + (const char *arch, search_dirs_type *search, lang_input_statement_type *entry) +{ + const char *filename; + char *string; + + if (! entry->is_archive) + return FALSE; + + filename = entry->filename; + + /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION + is defined, but it does not seem worth the headache to optimize + away those two bytes of space. */ + string = (char *) xmalloc (strlen (search->name) + + strlen (filename) + + strlen (arch) +#ifdef EXTRA_SHLIB_EXTENSION + + strlen (EXTRA_SHLIB_EXTENSION) +#endif + + sizeof "/lib.so"); + + sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); + +#ifdef EXTRA_SHLIB_EXTENSION + /* Try the .so extension first. If that fails build a new filename + using EXTRA_SHLIB_EXTENSION. */ + if (! ldfile_try_open_bfd (string, entry)) + { + sprintf (string, "%s/lib%s%s%s", search->name, + filename, arch, EXTRA_SHLIB_EXTENSION); +#endif + + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } +#ifdef EXTRA_SHLIB_EXTENSION + } +#endif + + entry->filename = string; + + /* We have found a dynamic object to include in the link. The ELF + backend linker will create a DT_NEEDED entry in the .dynamic + section naming this file. If this file includes a DT_SONAME + entry, it will be used. Otherwise, the ELF linker will just use + the name of the file. For an archive found by searching, like + this one, the DT_NEEDED entry should consist of just the name of + the file, without the path information used to find it. Note + that we only need to do this if we have a dynamic object; an + archive will never be referenced by a DT_NEEDED entry. + + FIXME: This approach--using bfd_elf_set_dt_needed_name--is not + very pretty. I haven't been able to think of anything that is + pretty, though. */ + if (bfd_check_format (entry->the_bfd, bfd_object) + && (entry->the_bfd->flags & DYNAMIC) != 0) + { + ASSERT (entry->is_archive && entry->search_dirs_flag); + + /* Rather than duplicating the logic above. Just use the + filename we recorded earlier. */ + + filename = lbasename (entry->filename); + bfd_elf_set_dt_needed_name (entry->the_bfd, filename); + } + + return TRUE; +} + +EOF +fi + +if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then +fragment <<EOF + +/* A variant of lang_output_section_find used by place_orphan. */ + +static lang_output_section_statement_type * +output_rel_find (asection *sec, int isdyn) +{ + lang_output_section_statement_type *lookup; + lang_output_section_statement_type *last = NULL; + lang_output_section_statement_type *last_alloc = NULL; + lang_output_section_statement_type *last_ro_alloc = NULL; + lang_output_section_statement_type *last_rel = NULL; + lang_output_section_statement_type *last_rel_alloc = NULL; + int rela = sec->name[4] == 'a'; + + for (lookup = &lang_output_section_statement.head->output_section_statement; + lookup != NULL; + lookup = lookup->next) + { + if (lookup->constraint >= 0 + && CONST_STRNEQ (lookup->name, ".rel")) + { + int lookrela = lookup->name[4] == 'a'; + + /* .rel.dyn must come before all other reloc sections, to suit + GNU ld.so. */ + if (isdyn) + break; + + /* Don't place after .rel.plt as doing so results in wrong + dynamic tags. */ + if (strcmp (".plt", lookup->name + 4 + lookrela) == 0) + break; + + if (rela == lookrela || last_rel == NULL) + last_rel = lookup; + if ((rela == lookrela || last_rel_alloc == NULL) + && lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + last_rel_alloc = lookup; + } + + last = lookup; + if (lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + { + last_alloc = lookup; + if ((lookup->bfd_section->flags & SEC_READONLY) != 0) + last_ro_alloc = lookup; + } + } + + if (last_rel_alloc) + return last_rel_alloc; + + if (last_rel) + return last_rel; + + if (last_ro_alloc) + return last_ro_alloc; + + if (last_alloc) + return last_alloc; + + return last; +} + +/* Place an orphan section. We use this to put random SHF_ALLOC + sections in the right segment. */ + +static lang_output_section_statement_type * +gld${EMULATION_NAME}_place_orphan (asection *s, + const char *secname, + int constraint) +{ + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rodata", + 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 }, + { 0, + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".interp", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".sdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, + 0, 0, 0, 0 }, + { 0, + SEC_HAS_CONTENTS, + 0, 0, 0, 0 }, + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_data, + orphan_bss, + orphan_rel, + orphan_interp, + orphan_sdata, + orphan_nonalloc + }; + static int orphan_init_done = 0; + struct orphan_save *place; + lang_output_section_statement_type *after; + lang_output_section_statement_type *os; + lang_output_section_statement_type *match_by_name = NULL; + int isdyn = 0; + int iself = s->owner->xvec->flavour == bfd_target_elf_flavour; + unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL; + + if (! link_info.relocatable + && link_info.combreloc + && (s->flags & SEC_ALLOC)) + { + if (iself) + switch (sh_type) + { + case SHT_RELA: + secname = ".rela.dyn"; + isdyn = 1; + break; + case SHT_REL: + secname = ".rel.dyn"; + isdyn = 1; + break; + default: + break; + } + else if (CONST_STRNEQ (secname, ".rel")) + { + secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; + isdyn = 1; + } + } + + /* Look through the script to see where to place this section. */ + 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 + || (_bfd_elf_match_sections_by_type (link_info.output_bfd, + os->bfd_section, + s->owner, s) + && ((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 (&os->children, s, os); + return os; + } + + /* 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 (match_by_name) + { + lang_add_section (&match_by_name->children, s, match_by_name); + return match_by_name; + } + + if (!orphan_init_done) + { + lang_output_section_statement_type *lookup; + 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; + } + lookup = hold[orphan_bss].os; + if (lookup == NULL) + lookup = &lang_output_section_statement.head->output_section_statement; + for (; lookup != NULL; lookup = lookup->next) + if ((lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_DEBUGGING) != 0) + || strcmp (lookup->name, ".comment") == 0) + break; + hold[orphan_nonalloc].os = lookup ? lookup->prev : NULL; + hold[orphan_nonalloc].name = ".comment"; + orphan_init_done = 1; + } + + /* If this is a final link, then always put .gnu.warning.SYMBOL + sections into the .text section to get them out of the way. */ + if (link_info.executable + && ! link_info.relocatable + && CONST_STRNEQ (s->name, ".gnu.warning.") + && hold[orphan_text].os != NULL) + { + os = hold[orphan_text].os; + lang_add_section (&os->children, s, os); + return os; + } + + /* Decide which segment the section should go in based on the + section name and section flags. We put loadable .note sections + right after the .interp section, so that the PT_NOTE segment is + stored right after the program headers where the OS can read it + in the first page. */ + + place = NULL; + if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) + place = &hold[orphan_nonalloc]; + else if ((s->flags & SEC_ALLOC) == 0) + ; + else if ((s->flags & SEC_LOAD) != 0 + && ((iself && sh_type == SHT_NOTE) + || (!iself && CONST_STRNEQ (secname, ".note")))) + place = &hold[orphan_interp]; + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + place = &hold[orphan_bss]; + else if ((s->flags & SEC_SMALL_DATA) != 0) + place = &hold[orphan_sdata]; + else if ((s->flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; + else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL)) + || (!iself && CONST_STRNEQ (secname, ".rel"))) + && (s->flags & SEC_LOAD) != 0) + place = &hold[orphan_rel]; + else if ((s->flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; + else + place = &hold[orphan_text]; + + after = NULL; + if (place != NULL) + { + if (place->os == NULL) + { + if (place->name != NULL) + place->os = lang_output_section_find (place->name); + else + place->os = output_rel_find (s, isdyn); + } + after = place->os; + if (after == NULL) + after = lang_output_section_find_by_flags + (s, &place->os, _bfd_elf_match_sections_by_type); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = &lang_output_section_statement.head->output_section_statement; + } + + return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); +} +EOF +fi + +if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then +fragment <<EOF + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + bfd_boolean need_layout = bfd_elf_discard_info (link_info.output_bfd, + &link_info); + gld${EMULATION_NAME}_map_segments (need_layout); +} +EOF +fi + +if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then +fragment <<EOF + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +fi +if test -n "$GENERATE_PIE_SCRIPT" ; then +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c +echo ' && link_info.relro' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c +fi +echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c +fi +if test -n "$GENERATE_SHLIB_SCRIPT" ; then +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c +echo ' && link_info.relro' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c +fi +echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c +fi +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c +fi +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; +EOF +if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : +else +fragment <<EOF + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; +EOF +fi +if test -n "$GENERATE_PIE_SCRIPT" ; then +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +fragment <<EOF + else if (link_info.pie && link_info.combreloc + && link_info.relro && (link_info.flags & DF_BIND_NOW)) + return "ldscripts/${EMULATION_NAME}.xdw"; + else if (link_info.pie && link_info.combreloc) + return "ldscripts/${EMULATION_NAME}.xdc"; +EOF +fi +fragment <<EOF + else if (link_info.pie) + return "ldscripts/${EMULATION_NAME}.xd"; +EOF +fi +if test -n "$GENERATE_SHLIB_SCRIPT" ; then +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +fragment <<EOF + else if (link_info.shared && link_info.combreloc + && link_info.relro && (link_info.flags & DF_BIND_NOW)) + return "ldscripts/${EMULATION_NAME}.xsw"; + else if (link_info.shared && link_info.combreloc) + return "ldscripts/${EMULATION_NAME}.xsc"; +EOF +fi +fragment <<EOF + else if (link_info.shared) + return "ldscripts/${EMULATION_NAME}.xs"; +EOF +fi +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +fragment <<EOF + else if (link_info.combreloc && link_info.relro + && (link_info.flags & DF_BIND_NOW)) + return "ldscripts/${EMULATION_NAME}.xw"; + else if (link_info.combreloc) + return "ldscripts/${EMULATION_NAME}.xc"; +EOF +fi +fragment <<EOF + else + return "ldscripts/${EMULATION_NAME}.x"; +} + +EOF +fi +fi + +if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then + +if test -n "$PARSE_AND_LIST_PROLOGUE" ; then +fragment <<EOF + $PARSE_AND_LIST_PROLOGUE +EOF +fi + +fragment <<EOF + +#define OPTION_DISABLE_NEW_DTAGS (400) +#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1) +#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1) +#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1) +#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1) +#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1) +#define OPTION_BUILD_ID (OPTION_HASH_STYLE + 1) +#define OPTION_AUDIT (OPTION_BUILD_ID + 1) + +static void +gld${EMULATION_NAME}_add_options + (int ns, char **shortopts, int nl, struct option **longopts, + int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED) +{ + static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:P:"; + static const struct option xtra_long[] = { + {"build-id", optional_argument, NULL, OPTION_BUILD_ID}, + {"audit", required_argument, NULL, OPTION_AUDIT}, + {"depaudit", required_argument, NULL, 'P'}, +EOF + +if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then +fragment <<EOF + {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, + {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, + {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR}, + {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, + {"hash-style", required_argument, NULL, OPTION_HASH_STYLE}, + {"Bgroup", no_argument, NULL, OPTION_GROUP}, +EOF +fi + +if test -n "$PARSE_AND_LIST_LONGOPTS" ; then +fragment <<EOF + $PARSE_AND_LIST_LONGOPTS +EOF +fi + +fragment <<EOF + {NULL, no_argument, NULL, 0} + }; + + *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short)); + memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short)); + *longopts = (struct option *) + xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +#define DEFAULT_BUILD_ID_STYLE "sha1" + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + switch (optc) + { + default: + return FALSE; + + case OPTION_BUILD_ID: + if (link_info.emit_note_gnu_build_id != NULL) + { + free (link_info.emit_note_gnu_build_id); + link_info.emit_note_gnu_build_id = NULL; + } + if (optarg == NULL) + optarg = DEFAULT_BUILD_ID_STYLE; + if (strcmp (optarg, "none")) + link_info.emit_note_gnu_build_id = xstrdup (optarg); + break; + case OPTION_AUDIT: + gld${EMULATION_NAME}_append_to_separated_string (&audit, optarg); + break; + case 'P': + gld${EMULATION_NAME}_append_to_separated_string (&depaudit, optarg); + break; + +EOF + +if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then +fragment <<EOF + case OPTION_DISABLE_NEW_DTAGS: + link_info.new_dtags = FALSE; + break; + + case OPTION_ENABLE_NEW_DTAGS: + link_info.new_dtags = TRUE; + break; + + case OPTION_EH_FRAME_HDR: + link_info.eh_frame_hdr = TRUE; + break; + + case OPTION_GROUP: + link_info.flags_1 |= (bfd_vma) DF_1_GROUP; + /* Groups must be self-contained. */ + link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; + link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR; + break; + + case OPTION_EXCLUDE_LIBS: + add_excluded_libs (optarg); + break; + + case OPTION_HASH_STYLE: + link_info.emit_hash = FALSE; + link_info.emit_gnu_hash = FALSE; + if (strcmp (optarg, "sysv") == 0) + link_info.emit_hash = TRUE; + else if (strcmp (optarg, "gnu") == 0) + link_info.emit_gnu_hash = TRUE; + else if (strcmp (optarg, "both") == 0) + { + link_info.emit_hash = TRUE; + link_info.emit_gnu_hash = TRUE; + } + else + einfo (_("%P%F: invalid hash style \`%s'\n"), optarg); + break; + + case 'z': + if (strcmp (optarg, "initfirst") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST; + else if (strcmp (optarg, "interpose") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE; + else if (strcmp (optarg, "loadfltr") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR; + else if (strcmp (optarg, "nodefaultlib") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB; + else if (strcmp (optarg, "nodelete") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_NODELETE; + else if (strcmp (optarg, "nodlopen") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN; + else if (strcmp (optarg, "nodump") == 0) + link_info.flags_1 |= (bfd_vma) DF_1_NODUMP; + else if (strcmp (optarg, "now") == 0) + { + link_info.flags |= (bfd_vma) DF_BIND_NOW; + link_info.flags_1 |= (bfd_vma) DF_1_NOW; + } + else if (strcmp (optarg, "lazy") == 0) + { + link_info.flags &= ~(bfd_vma) DF_BIND_NOW; + link_info.flags_1 &= ~(bfd_vma) DF_1_NOW; + } + else if (strcmp (optarg, "origin") == 0) + { + link_info.flags |= (bfd_vma) DF_ORIGIN; + link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN; + } + else if (strcmp (optarg, "defs") == 0) + link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; + else if (strcmp (optarg, "muldefs") == 0) + link_info.allow_multiple_definition = TRUE; + else if (strcmp (optarg, "combreloc") == 0) + link_info.combreloc = TRUE; + else if (strcmp (optarg, "nocombreloc") == 0) + link_info.combreloc = FALSE; + else if (strcmp (optarg, "nocopyreloc") == 0) + link_info.nocopyreloc = TRUE; + else if (strcmp (optarg, "execstack") == 0) + { + link_info.execstack = TRUE; + link_info.noexecstack = FALSE; + } + else if (strcmp (optarg, "noexecstack") == 0) + { + link_info.noexecstack = TRUE; + link_info.execstack = FALSE; + } +EOF + + if test -n "$COMMONPAGESIZE"; then +fragment <<EOF + else if (strcmp (optarg, "relro") == 0) + link_info.relro = TRUE; + else if (strcmp (optarg, "norelro") == 0) + link_info.relro = FALSE; +EOF + fi + +fragment <<EOF + else if (CONST_STRNEQ (optarg, "max-page-size=")) + { + char *end; + + config.maxpagesize = strtoul (optarg + 14, &end, 0); + if (*end || (config.maxpagesize & (config.maxpagesize - 1)) != 0) + einfo (_("%P%F: invalid maxium page size \`%s'\n"), + optarg + 14); + } + else if (CONST_STRNEQ (optarg, "common-page-size=")) + { + char *end; + config.commonpagesize = strtoul (optarg + 17, &end, 0); + if (*end + || (config.commonpagesize & (config.commonpagesize - 1)) != 0) + einfo (_("%P%F: invalid common page size \`%s'\n"), + optarg + 17); + } + /* What about the other Solaris -z options? FIXME. */ + break; +EOF +fi + +if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then +fragment <<EOF + $PARSE_AND_LIST_ARGS_CASES +EOF +fi + +fragment <<EOF + } + + return TRUE; +} + +EOF + +if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then +fragment <<EOF + +static void +gld${EMULATION_NAME}_list_options (FILE * file) +{ + fprintf (file, _("\ + --build-id[=STYLE] Generate build ID note\n")); + fprintf (file, _("\ + --audit=AUDITLIB Specify a library to use for auditing\n")); + fprintf (file, _("\ + -P AUDITLIB, --depaudit=AUDITLIB\n" "\ + Specify a library to use for auditing dependencies\n")); +EOF + +if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then +fragment <<EOF + fprintf (file, _("\ + -Bgroup Selects group name lookup rules for DSO\n")); + fprintf (file, _("\ + --disable-new-dtags Disable new dynamic tags\n")); + fprintf (file, _("\ + --enable-new-dtags Enable new dynamic tags\n")); + fprintf (file, _("\ + --eh-frame-hdr Create .eh_frame_hdr section\n")); + fprintf (file, _("\ + --hash-style=STYLE Set hash style to sysv, gnu or both\n")); + fprintf (file, _("\ + -z combreloc Merge dynamic relocs into one section and sort\n")); + fprintf (file, _("\ + -z defs Report unresolved symbols in object files.\n")); + fprintf (file, _("\ + -z execstack Mark executable as requiring executable stack\n")); + fprintf (file, _("\ + -z initfirst Mark DSO to be initialized first at runtime\n")); + fprintf (file, _("\ + -z interpose Mark object to interpose all DSOs but executable\n")); + fprintf (file, _("\ + -z lazy Mark object lazy runtime binding (default)\n")); + fprintf (file, _("\ + -z loadfltr Mark object requiring immediate process\n")); + fprintf (file, _("\ + -z muldefs Allow multiple definitions\n")); + fprintf (file, _("\ + -z nocombreloc Don't merge dynamic relocs into one section\n")); + fprintf (file, _("\ + -z nocopyreloc Don't create copy relocs\n")); + fprintf (file, _("\ + -z nodefaultlib Mark object not to use default search paths\n")); + fprintf (file, _("\ + -z nodelete Mark DSO non-deletable at runtime\n")); + fprintf (file, _("\ + -z nodlopen Mark DSO not available to dlopen\n")); + fprintf (file, _("\ + -z nodump Mark DSO not available to dldump\n")); + fprintf (file, _("\ + -z noexecstack Mark executable as not requiring executable stack\n")); +EOF + + if test -n "$COMMONPAGESIZE"; then +fragment <<EOF + fprintf (file, _("\ + -z norelro Don't create RELRO program header\n")); +EOF + fi + +fragment <<EOF + fprintf (file, _("\ + -z now Mark object non-lazy runtime binding\n")); + fprintf (file, _("\ + -z origin Mark object requiring immediate \$ORIGIN\n\ + processing at runtime\n")); +EOF + + if test -n "$COMMONPAGESIZE"; then +fragment <<EOF + fprintf (file, _("\ + -z relro Create RELRO program header\n")); +EOF + fi + +fragment <<EOF + fprintf (file, _("\ + -z max-page-size=SIZE Set maximum page size to SIZE\n")); + fprintf (file, _("\ + -z common-page-size=SIZE Set common page size to SIZE\n")); + fprintf (file, _("\ + -z KEYWORD Ignored for Solaris compatibility\n")); +EOF +fi + +if test -n "$PARSE_AND_LIST_OPTIONS" ; then +fragment <<EOF + $PARSE_AND_LIST_OPTIONS +EOF +fi + +fragment <<EOF +} +EOF + +if test -n "$PARSE_AND_LIST_EPILOGUE" ; then +fragment <<EOF + $PARSE_AND_LIST_EPILOGUE +EOF +fi +fi +else +fragment <<EOF +#define gld${EMULATION_NAME}_add_options NULL +#define gld${EMULATION_NAME}_handle_option NULL +EOF +if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then +fragment <<EOF +#define gld${EMULATION_NAME}_list_options NULL +EOF +fi +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, + ${LDEMUL_SYSLIB-syslib_default}, + ${LDEMUL_HLL-hll_default}, + ${LDEMUL_AFTER_PARSE-after_parse_default}, + ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open}, + ${LDEMUL_AFTER_ALLOCATION-gld${EMULATION_NAME}_after_allocation}, + ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default}, + ${LDEMUL_CHOOSE_TARGET-ldemul_default_target}, + ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation}, + ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script}, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + ${LDEMUL_FINISH-finish_default}, + ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, + ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive}, + ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan}, + ${LDEMUL_SET_SYMBOLS-NULL}, + ${LDEMUL_PARSE_ARGS-NULL}, + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + ${LDEMUL_UNRECOGNIZED_FILE-NULL}, + ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options}, + ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols}, + ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, + ${LDEMUL_NEW_VERS_PATTERN-NULL} +}; +EOF diff --git a/binutils-2.21/ld/emultempl/genelf.em b/binutils-2.21/ld/emultempl/genelf.em new file mode 100644 index 0000000..62af4de --- /dev/null +++ b/binutils-2.21/ld/emultempl/genelf.em @@ -0,0 +1,69 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. +# + +# This file is sourced from generic.em +# +fragment <<EOF +#include "elf-bfd.h" + +EOF +source_em ${srcdir}/emultempl/elf-generic.em +fragment <<EOF + +static void +gld${EMULATION_NAME}_after_open (void) +{ + bfd *ibfd; + asection *sec; + asymbol **syms; + + if (link_info.relocatable) + for (ibfd = link_info.input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + if ((syms = bfd_get_outsymbols (ibfd)) != NULL + && bfd_get_flavour (ibfd) == bfd_target_elf_flavour) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP) + { + struct bfd_elf_section_data *sec_data = elf_section_data (sec); + elf_group_id (sec) = syms[sec_data->this_hdr.sh_info - 1]; + } +} + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + if (link_info.relocatable + && !_bfd_elf_size_group_sections (&link_info)) + einfo ("%X%P: can not size group sections: %E\n"); + before_allocation_default (); +} + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + gld${EMULATION_NAME}_map_segments (FALSE); +} +EOF +# Put these extra routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open +LDEMUL_BEFORE_ALLOCATION=gld${EMULATION_NAME}_before_allocation +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation diff --git a/binutils-2.21/ld/emultempl/generic.em b/binutils-2.21/ld/emultempl/generic.em new file mode 100644 index 0000000..4a84680 --- /dev/null +++ b/binutils-2.21/ld/emultempl/generic.em @@ -0,0 +1,149 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* emulate the original gld for the given ${EMULATION_NAME} + Copyright 1991, 1992, 1994, 1996, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2007 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" + +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +EOF + +# Import any needed special functions and/or overrides. +# +if test -n "$EXTRA_EM_FILE" ; then + source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em +fi + +if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then +fragment <<EOF + +static void +gld${EMULATION_NAME}_before_parse (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ +} + +EOF +fi + +if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then +fragment <<EOF + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF +fi +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, + ${LDEMUL_SYSLIB-syslib_default}, + ${LDEMUL_HLL-hll_default}, + ${LDEMUL_AFTER_PARSE-after_parse_default}, + ${LDEMUL_AFTER_OPEN-after_open_default}, + ${LDEMUL_AFTER_ALLOCATION-after_allocation_default}, + ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default}, + ${LDEMUL_CHOOSE_TARGET-ldemul_default_target}, + ${LDEMUL_BEFORE_ALLOCATION-before_allocation_default}, + ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script}, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + ${LDEMUL_FINISH-finish_default}, + ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, + ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL}, + ${LDEMUL_PLACE_ORPHAN-NULL}, + ${LDEMUL_SET_SYMBOLS-NULL}, + ${LDEMUL_PARSE_ARGS-NULL}, + NULL, /* add_options */ + NULL, /* handle_option */ + ${LDEMUL_UNRECOGNIZED_FILE-NULL}, + ${LDEMUL_LIST_OPTIONS-NULL}, + ${LDEMUL_RECOGNIZED_FILE-NULL}, + ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, + ${LDEMUL_NEW_VERS_PATTERN-NULL} +}; +EOF diff --git a/binutils-2.21/ld/emultempl/gld960.em b/binutils-2.21/ld/emultempl/gld960.em new file mode 100644 index 0000000..4ba3eec --- /dev/null +++ b/binutils-2.21/ld/emultempl/gld960.em @@ -0,0 +1,154 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* Copyright 1991, 1992, 1994, 1999, 2000, 2001, 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. */ + + +/* Emulate the Intel's port of gld. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmisc.h" +#include "ldmain.h" + +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +static void gld960_before_parse (void) +{ + char *env ; + env = getenv("G960LIB"); + if (env) { + ldfile_add_library_path(env, FALSE); + } + env = getenv("G960BASE"); + if (env) + ldfile_add_library_path (concat (env, "/lib", (const char *) NULL), FALSE); + ldfile_output_architecture = bfd_arch_i960; +} + +static void +gld960_set_output_arch (void) +{ + bfd_set_arch_mach (link_info.output_bfd, + ldfile_output_architecture, bfd_mach_i960_core); +} + +static char * +gld960_choose_target (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + char *from_outside = getenv(TARGET_ENVIRON); + output_filename = "b.out"; + + if (from_outside != (char *)NULL) + return from_outside; + + return "b.out.little"; +} + +static char * +gld960_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_gld960_emulation = +{ + gld960_before_parse, + syslib_default, + hll_default, + after_parse_default, + after_open_default, + after_allocation_default, + gld960_set_output_arch, + gld960_choose_target, + before_allocation_default, + gld960_get_script, + "960", + "", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/gld960c.em b/binutils-2.21/ld/emultempl/gld960c.em new file mode 100644 index 0000000..1999ea8 --- /dev/null +++ b/binutils-2.21/ld/emultempl/gld960c.em @@ -0,0 +1,167 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* Copyright 1991, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 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. */ + + +/* Emulate the Intel's port of gld. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmisc.h" +#include "ldmain.h" + +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +static void gld960_before_parse (void) +{ + char *env ; + env = getenv("G960LIB"); + if (env) { + ldfile_add_library_path(env, FALSE); + } + env = getenv("G960BASE"); + if (env) + ldfile_add_library_path (concat (env, "/lib", (const char *) NULL), + FALSE); + ldfile_output_architecture = bfd_arch_i960; +} + +static void +gld960_set_output_arch (void) +{ + if (ldfile_output_machine_name != NULL + && *ldfile_output_machine_name != '\0') + { + char *s, *s1; + + s = concat ("i960:", ldfile_output_machine_name, (char *) NULL); + for (s1 = s; *s1 != '\0'; s1++) + *s1 = TOLOWER (*s1); + ldfile_set_output_arch (s, bfd_arch_unknown); + free (s); + } + + set_output_arch_default (); +} + +static char * +gld960_choose_target (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + char *from_outside = getenv(TARGET_ENVIRON); + output_filename = "b.out"; + + if (from_outside != (char *)NULL) + return from_outside; + + return "coff-Intel-little"; +} + +static char * +gld960_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_gld960coff_emulation = +{ + gld960_before_parse, + syslib_default, + hll_default, + after_parse_default, + after_open_default, + after_allocation_default, + gld960_set_output_arch, + gld960_choose_target, + before_allocation_default, + gld960_get_script, + "960coff", + "", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/hppaelf.em b/binutils-2.21/ld/emultempl/hppaelf.em new file mode 100644 index 0000000..1137ba2 --- /dev/null +++ b/binutils-2.21/ld/emultempl/hppaelf.em @@ -0,0 +1,380 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 1991, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003, 2004, +# 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. +# + +# This file is sourced from elf32.em, and defines extra hppa-elf +# specific routines. +# +fragment <<EOF + +#include "ldctor.h" +#include "elf32-hppa.h" + + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; + +/* Type of import/export stubs to build. For a single sub-space model, + we can build smaller import stubs and there is no need for export + stubs. */ +static int multi_subspace = 0; + +/* Whether we need to call hppa_layout_sections_again. */ +static int need_laying_out = 0; + +/* Maximum size of a group of input sections that can be handled by + one stub section. A value of +/-1 indicates the bfd back-end + should use a suitable default size. */ +static bfd_signed_vma group_size = 1; + +/* Stops the linker merging .text sections on a relocatable link, + and adds millicode library to the list of input files. */ + +static void +hppaelf_after_parse (void) +{ + if (link_info.relocatable) + lang_add_unique (".text"); + + /* Enable this once we split millicode stuff from libgcc: + lang_add_input_file ("milli", + lang_input_file_is_l_enum, + NULL); + */ + + after_parse_default (); +} + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub sections. */ + +static void +hppaelf_create_output_section_statements (void) +{ + if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && (elf_object_id (link_info.output_bfd) == HPPA32_ELF_DATA + || elf_object_id (link_info.output_bfd) == HPPA64_ELF_DATA))) + return; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || ! bfd_set_arch_mach (stub_file->the_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; + } + + stub_file->the_bfd->flags |= BFD_LINKER_CREATED; + ldlang_add_file (stub_file); +} + + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + before its associated input section. */ + *lp = info->add.head; + *(info->add.tail) = l; + return TRUE; + } + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + + +/* Call-back for elf32_hppa_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately before INPUT_SECTION. */ + +static asection * +hppaelf_add_stub_section (const char *stub_sec_name, asection *input_section) +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + stub_sec_name, flags); + if (stub_sec == NULL) + goto err_ret; + + output_section = input_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + info.input_section = input_section; + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, os); + + if (info.add.head == NULL) + goto err_ret; + + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + + +/* Another call-back for elf32_hppa_size_stubs. */ + +static void +hppaelf_layout_sections_again (void) +{ + /* If we have changed sizes of the stub sections, then we need + to recalculate all the section offsets. This may mean we need to + add even more stubs. */ + gld${EMULATION_NAME}_map_segments (TRUE); + need_laying_out = -1; +} + + +static void +build_section_lists (lang_statement_union_type *statement) +{ + if (statement->header.type == lang_input_section_enum) + { + asection *i = statement->input_section.section; + + if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag + && (i->flags & SEC_EXCLUDE) == 0 + && i->output_section != NULL + && i->output_section->owner == link_info.output_bfd) + { + elf32_hppa_next_input_section (&link_info, i); + } + } +} + + +/* For the PA we use this opportunity to size and build linker stubs. */ + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + /* bfd_elf_discard_info just plays with data and debugging sections, + ie. doesn't affect code size, so we can delay resizing the + sections. It's likely we'll resize everything in the process of + adding stubs. */ + if (bfd_elf_discard_info (link_info.output_bfd, &link_info)) + need_laying_out = 1; + + /* If generating a relocatable output file, then we don't + have to examine the relocs. */ + if (stub_file != NULL && !link_info.relocatable) + { + int ret = elf32_hppa_setup_section_lists (link_info.output_bfd, + &link_info); + + if (ret != 0) + { + if (ret < 0) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + + lang_for_each_statement (build_section_lists); + + /* Call into the BFD backend to do the real work. */ + if (! elf32_hppa_size_stubs (link_info.output_bfd, + stub_file->the_bfd, + &link_info, + multi_subspace, + group_size, + &hppaelf_add_stub_section, + &hppaelf_layout_sections_again)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + } + } + + if (need_laying_out != -1) + gld${EMULATION_NAME}_map_segments (need_laying_out); + + if (! link_info.relocatable) + { + /* Set the global data pointer. */ + if (! elf32_hppa_set_gp (link_info.output_bfd, &link_info)) + { + einfo ("%X%P: can not set gp\n"); + return; + } + + /* Now build the linker stubs. */ + if (stub_file != NULL && stub_file->the_bfd->sections != NULL) + { + if (! elf32_hppa_build_stubs (&link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } + } +} + + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void hppa_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +hppa_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&hppa_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file hppa_lang_for_each_input_file + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_MULTI_SUBSPACE 301 +#define OPTION_STUBGROUP_SIZE (OPTION_MULTI_SUBSPACE + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "multi-subspace", no_argument, NULL, OPTION_MULTI_SUBSPACE }, + { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --multi-subspace Generate import and export stubs to support\n\ + multiple sub-space shared libraries\n" + )); + fprintf (file, _("\ + --stub-group-size=N Maximum size of a group of input sections that\n\ + can be handled by one stub section. A negative\n\ + value locates all stubs before their branches\n\ + (with a group size of -N), while a positive\n\ + value allows two groups of input sections, one\n\ + before, and one after each stub section.\n\ + Values of +/-1 indicate the linker should\n\ + choose suitable defaults.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_MULTI_SUBSPACE: + multi_subspace = 1; + break; + + case OPTION_STUBGROUP_SIZE: + { + const char *end; + group_size = bfd_scan_vma (optarg, &end, 0); + if (*end) + einfo (_("%P%F: invalid number `%s'\''\n"), optarg); + } + break; +' + +# Put these extra hppaelf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_PARSE=hppaelf_after_parse +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=hppaelf_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/ia64elf.em b/binutils-2.21/ld/emultempl/ia64elf.em new file mode 100644 index 0000000..88d5748 --- /dev/null +++ b/binutils-2.21/ld/emultempl/ia64elf.em @@ -0,0 +1,65 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003, 2005, 2006, 2007, 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. +# + +# This file is sourced from elf32.em, and defines extra ia64-elf +# specific routines. +# +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +fragment <<EOF + +/* None zero if generating binary for Intel Itanium processor. */ +static int itanium = 0; + +static void +gld${EMULATION_NAME}_after_parse (void) +{ + link_info.relax_pass = 2; + bfd_elf${ELFSIZE}_ia64_after_parse (itanium); + + after_parse_default (); +} + +EOF + +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_ITANIUM 300 +' + +PARSE_AND_LIST_LONGOPTS=' + { "itanium", no_argument, NULL, OPTION_ITANIUM}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --itanium Generate code for Intel Itanium processor\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_ITANIUM: + itanium = 1; + break; +' + +LDEMUL_AFTER_PARSE=gld${EMULATION_NAME}_after_parse +source_em ${srcdir}/emultempl/needrelax.em diff --git a/binutils-2.21/ld/emultempl/irix.em b/binutils-2.21/ld/emultempl/irix.em new file mode 100644 index 0000000..41b8ce4 --- /dev/null +++ b/binutils-2.21/ld/emultempl/irix.em @@ -0,0 +1,44 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2004, 2005, 2006, 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. +# + +fragment <<EOF + +#include "ld.h" +#include "ldmain.h" +#include "libiberty.h" + +/* The native IRIX linker will always create a DT_SONAME for shared objects. + While this shouldn't really be necessary for ABI conformance, some versions + of the native linker will segfault if the tag is missing. */ + +static void +irix_after_open (void) +{ + if (link_info.shared && command_line.soname == 0) + command_line.soname + = (char *) lbasename (bfd_get_filename (link_info.output_bfd)); + + gld${EMULATION_NAME}_after_open (); +} +EOF + +LDEMUL_AFTER_OPEN=irix_after_open +source_em "${srcdir}/emultempl/mipself.em" diff --git a/binutils-2.21/ld/emultempl/linux.em b/binutils-2.21/ld/emultempl/linux.em new file mode 100644 index 0000000..2a2a960 --- /dev/null +++ b/binutils-2.21/ld/emultempl/linux.em @@ -0,0 +1,211 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* Linux a.out emulation code for ${EMULATION_NAME} + Copyright 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. + Written by Steve Chamberlain <sac@cygnus.com> + Linux support by Eric Youngdale <ericy@cais.cais.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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +static void +gld${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + config.dynamic_link = TRUE; + config.has_shared = TRUE; +} + +/* Try to open a dynamic archive. This is where we know that Linux + dynamic libraries have an extension of .sa. */ + +static bfd_boolean +gld${EMULATION_NAME}_open_dynamic_archive + (const char *arch, search_dirs_type *search, lang_input_statement_type *entry) +{ + char *string; + + if (! entry->is_archive) + return FALSE; + + string = (char *) xmalloc (strlen (search->name) + + strlen (entry->filename) + + strlen (arch) + + sizeof "/lib.sa"); + + sprintf (string, "%s/lib%s%s.sa", search->name, entry->filename, arch); + + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + + entry->filename = string; + + return TRUE; +} + +/* This is called by the create_output_section_statements routine via + lang_for_each_statement. It locates any address assignment to + .text, and modifies it to include the size of the headers. This + causes -Ttext to mean the starting address of the header, rather + than the starting address of .text, which is compatible with other + Linux tools. */ + +static void +gld${EMULATION_NAME}_find_address_statement (lang_statement_union_type *s) +{ + if (s->header.type == lang_address_statement_enum + && strcmp (s->address_statement.section_name, ".text") == 0) + { + ASSERT (s->address_statement.address->type.node_class == etree_value); + s->address_statement.address->value.value += 0x20; + } +} + +/* This is called before opening the input BFD's. */ + +static void +gld${EMULATION_NAME}_create_output_section_statements (void) +{ + lang_for_each_statement (gld${EMULATION_NAME}_find_address_statement); +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + if (link_info.relocatable) + return; + + /* Let the backend work out the sizes of any sections required by + dynamic linking. */ + if (! bfd_${EMULATION_NAME}_size_dynamic_sections (link_info.output_bfd, + &link_info)) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); + + before_allocation_default (); +} + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + after_open_default, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld${EMULATION_NAME}_before_allocation, + gld${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + gld${EMULATION_NAME}_create_output_section_statements, + gld${EMULATION_NAME}_open_dynamic_archive, + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/lnk960.em b/binutils-2.21/ld/emultempl/lnk960.em new file mode 100644 index 0000000..e13233c --- /dev/null +++ b/binutils-2.21/ld/emultempl/lnk960.em @@ -0,0 +1,290 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* intel coff loader emulation specific stuff + Copyright 1991, 1992, 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, + 2005, 2007, 2008 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 "libiberty.h" +#include "bfd.h" +#include "bfdlink.h" + +/*#include "archures.h"*/ +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +typedef struct lib_list { + char *name; + struct lib_list *next; +} lib_list_type; + +static lib_list_type *hll_list; +static lib_list_type **hll_list_tail = &hll_list; + +static lib_list_type *syslib_list; +static lib_list_type **syslib_list_tail = &syslib_list; + + +static void +append (lib_list_type ***list, char *name) +{ + lib_list_type *element = (lib_list_type *) xmalloc (sizeof (lib_list_type)); + + element->name = name; + element->next = (lib_list_type *) NULL; + **list = element; + *list = &element->next; + +} + +static bfd_boolean had_hll = FALSE; +static bfd_boolean had_hll_name = FALSE; + +static void +lnk960_hll (char *name) +{ + had_hll = TRUE; + if (name != (char *) NULL) + { + had_hll_name = TRUE; + append (&hll_list_tail, name); + } +} + +static void +lnk960_syslib (char *name) +{ + append (&syslib_list_tail, name); +} + + +static void +lnk960_before_parse (void) +{ + char *name = getenv ("I960BASE"); + + if (name == (char *) NULL) + { + name = getenv("G960BASE"); + if (name == (char *) NULL) + einfo ("%P%F I960BASE and G960BASE not set\n"); + } + + ldfile_add_library_path (concat (name, "/lib", (const char *) NULL), FALSE); + ldfile_output_architecture = bfd_arch_i960; + ldfile_output_machine = bfd_mach_i960_core; +} + +static void +add_on (lib_list_type *list, lang_input_file_enum_type search) +{ + while (list) + { + lang_add_input_file (list->name, search, (char *) NULL); + list = list->next; + } +} + +static void +lnk960_after_parse (void) +{ + /* If there has been no arch, default to -KB */ + if (ldfile_output_machine_name[0] == 0) + ldfile_add_arch ("KB"); + + /* if there has been no hll list then add our own */ + + if (had_hll && !had_hll_name) + { + append (&hll_list_tail, "cg"); + if (ldfile_output_machine == bfd_mach_i960_ka_sa + || ldfile_output_machine == bfd_mach_i960_ca) + append (&hll_list_tail, "fpg"); + } + + add_on (hll_list, lang_input_file_is_l_enum); + add_on (syslib_list, lang_input_file_is_search_file_enum); +} + +static void +lnk960_after_allocation (void) +{ + if (!link_info.relocatable) + { + lang_abs_symbol_at_end_of (".text", "_etext"); + lang_abs_symbol_at_end_of (".data", "_edata"); + lang_abs_symbol_at_beginning_of (".bss", "_bss_start"); + lang_abs_symbol_at_end_of (".bss", "_end"); + } +} + + +static struct + { + unsigned long number; + char *name; + } +machine_table[] = +{ + { bfd_mach_i960_core ,"CORE" }, + { bfd_mach_i960_kb_sb ,"KB" }, + { bfd_mach_i960_kb_sb ,"SB" }, + { bfd_mach_i960_mc ,"MC" }, + { bfd_mach_i960_xa ,"XA" }, + { bfd_mach_i960_ca ,"CA" }, + { bfd_mach_i960_ka_sa ,"KA" }, + { bfd_mach_i960_ka_sa ,"SA" }, + { bfd_mach_i960_jx ,"JX" }, + { bfd_mach_i960_hx ,"HX" }, + + { bfd_mach_i960_core ,"core" }, + { bfd_mach_i960_kb_sb ,"kb" }, + { bfd_mach_i960_kb_sb ,"sb" }, + { bfd_mach_i960_mc ,"mc" }, + { bfd_mach_i960_xa ,"xa" }, + { bfd_mach_i960_ca ,"ca" }, + { bfd_mach_i960_ka_sa ,"ka" }, + { bfd_mach_i960_ka_sa ,"sa" }, + { bfd_mach_i960_jx ,"jx" }, + { bfd_mach_i960_hx ,"hx" }, + + { 0, (char *) NULL } +}; + +static void +lnk960_set_output_arch (void) +{ + /* Set the output architecture and machine if possible */ + unsigned int i; + ldfile_output_machine = bfd_mach_i960_core; + for (i= 0; machine_table[i].name != (char*) NULL; i++) + { + if (strcmp (ldfile_output_machine_name, machine_table[i].name) == 0) + { + ldfile_output_machine = machine_table[i].number; + break; + } + } + bfd_set_arch_mach (link_info.output_bfd, ldfile_output_architecture, + ldfile_output_machine); +} + +static char * +lnk960_choose_target (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + char *from_outside = getenv (TARGET_ENVIRON); + if (from_outside != (char *) NULL) + return from_outside; +#ifdef LNK960_LITTLE + return "coff-Intel-little"; +#else + return "coff-Intel-big"; +#endif +} + +static char * +lnk960_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_lnk960_emulation = +{ + lnk960_before_parse, + lnk960_syslib, + lnk960_hll, + lnk960_after_parse, + NULL, /* after_open */ + lnk960_after_allocation, + lnk960_set_output_arch, + lnk960_choose_target, + before_allocation_default, + lnk960_get_script, + "lnk960", + "", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/m68hc1xelf.em b/binutils-2.21/ld/emultempl/m68hc1xelf.em new file mode 100644 index 0000000..4751346 --- /dev/null +++ b/binutils-2.21/ld/emultempl/m68hc1xelf.em @@ -0,0 +1,373 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 1991, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003, 2005, 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. +# + +# This file is sourced from elf32.em, and defines extra m68hc12-elf +# and m68hc11-elf specific routines. It is used to generate the +# HC11/HC12 trampolines to call a far function by using a normal 'jsr/bsr'. +# +# - The HC11/HC12 relocations are checked to see if there is a +# R_M68HC11_16 relocation to a symbol marked with STO_M68HC12_FAR. +# This relocation cannot be made on the symbol but must be made on +# its trampoline +# The trampolines to generate are collected during this pass +# (See elf32_m68hc11_size_stubs) +# +# - The trampolines are generated in a ".tramp" section. The generation +# takes care of HC11 and HC12 specificities. +# (See elf32_m68hc11_build_stubs) +# +# - During relocation the R_M68HC11_16 relocation to the far symbols +# are redirected to the trampoline that was generated. +# +# Copied from hppaelf and adapted for M68HC11/M68HC12 specific needs. +# +fragment <<EOF + +#include "ldctor.h" +#include "elf32-m68hc1x.h" + +static asection *m68hc11elf_add_stub_section (const char *, asection *); + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; + +/* By default the HC11/HC12 trampolines to call a far function using + a normal 'bsr' and 'jsr' convention are generated during the link. + The --no-trampoline option prevents that. */ +static int no_trampoline = 0; + +/* Name of memory bank window in the MEMORY description. + This is set by --bank-window option. */ +static const char* bank_window_name = 0; + +static void +m68hc11_elf_${EMULATION_NAME}_before_allocation (void) +{ + lang_memory_region_type* region; + int ret; + + gld${EMULATION_NAME}_before_allocation (); + + /* If generating a relocatable output file, then we don't + have to generate the trampolines. */ + if (link_info.relocatable) + return; + + ret = elf32_m68hc11_setup_section_lists (link_info.output_bfd, &link_info); + if (ret != 0 && no_trampoline == 0) + { + if (ret < 0) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + + /* Call into the BFD backend to do the real work. */ + if (!elf32_m68hc11_size_stubs (link_info.output_bfd, + stub_file->the_bfd, + &link_info, + &m68hc11elf_add_stub_section)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + } + + if (bank_window_name == 0) + return; + + /* The 'bank_window_name' memory region is a special region that describes + the memory bank window to access to paged memory. For 68HC12 + this is fixed and should be: + + window (rx) : ORIGIN = 0x8000, LENGTH = 16K + + But for 68HC11 this is board specific. The definition of such + memory region allows to control how this paged memory is accessed. */ + region = lang_memory_region_lookup (bank_window_name, FALSE); + + /* Check the length to see if it was defined in the script. */ + if (region->length != 0) + { + struct m68hc11_page_info *pinfo; + unsigned i; + + /* Get default values */ + m68hc11_elf_get_bank_parameters (&link_info); + pinfo = &m68hc11_elf_hash_table (&link_info)->pinfo; + + /* And override them with the region definition. */ + pinfo->bank_size = region->length; + pinfo->bank_shift = 0; + for (i = pinfo->bank_size; i != 0; i >>= 1) + pinfo->bank_shift++; + pinfo->bank_shift--; + pinfo->bank_size = 1L << pinfo->bank_shift; + pinfo->bank_mask = (1 << pinfo->bank_shift) - 1; + pinfo->bank_physical = region->origin; + pinfo->bank_physical_end = region->origin + pinfo->bank_size; + + if (pinfo->bank_size != region->length) + { + einfo (_("warning: the size of the 'window' memory region " + "is not a power of 2\n")); + einfo (_("warning: its size %d is truncated to %d\n"), + region->length, pinfo->bank_size); + } + } +} + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub sections. */ + +static void +m68hc11elf_create_output_section_statements (void) +{ + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || !bfd_set_arch_mach (stub_file->the_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; + } + + ldlang_add_file (stub_file); +} + + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section + || strcmp (bfd_get_section_name (output_section, + l->input_section.section), + bfd_get_section_name (output_section, + info->input_section)) == 0) + { + /* We've found our section. Insert the stub immediately + before its associated input section. */ + *lp = info->add.head; + *(info->add.tail) = l; + return TRUE; + } + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + + +/* Call-back for elf32_m68hc11_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately before INPUT_SECTION. */ + +static asection * +m68hc11elf_add_stub_section (const char *stub_sec_name, + asection *tramp_section) +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + stub_sec_name, flags); + if (stub_sec == NULL) + goto err_ret; + + output_section = tramp_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + /* Try to put the new section at the same place as an existing + .tramp section. Such .tramp section exists in most cases and + contains the trampoline code. This way we put the generated trampoline + at the correct place. */ + info.input_section = tramp_section; + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, os); + + if (info.add.head == NULL) + goto err_ret; + + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + +/* For the 68HC12 we use this opportunity to build linker stubs. */ + +static void +m68hc11elf_after_allocation (void) +{ + /* Now build the linker stubs. */ + if (stub_file->the_bfd->sections != NULL) + { + /* Call again the trampoline analyzer to initialize the trampoline + stubs with the correct symbol addresses. Since there could have + been relaxation, the symbol addresses that were found during + first call may no longer be correct. */ + if (!elf32_m68hc11_size_stubs (link_info.output_bfd, + stub_file->the_bfd, + &link_info, 0)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + if (!elf32_m68hc11_build_stubs (link_info.output_bfd, &link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } + + gld${EMULATION_NAME}_after_allocation (); +} + + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void m68hc11_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +m68hc11_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&m68hc11_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file m68hc11_lang_for_each_input_file + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_NO_TRAMPOLINE 300 +#define OPTION_BANK_WINDOW 301 +' + +# The options are repeated below so that no abbreviations are allowed. +# Otherwise -s matches stub-group-size +PARSE_AND_LIST_LONGOPTS=' + { "no-trampoline", no_argument, NULL, OPTION_NO_TRAMPOLINE }, + { "bank-window", required_argument, NULL, OPTION_BANK_WINDOW }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _( +" --no-trampoline Do not generate the far trampolines used to call\n" +" a far function using 'jsr' or 'bsr'.\n" +" --bank-window NAME Specify the name of the memory region describing\n" +" the layout of the memory bank window.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_NO_TRAMPOLINE: + no_trampoline = 1; + break; + case OPTION_BANK_WINDOW: + bank_window_name = optarg; + break; +' + +# Put these extra m68hc11elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_BEFORE_ALLOCATION=m68hc11_elf_${EMULATION_NAME}_before_allocation +LDEMUL_AFTER_ALLOCATION=m68hc11elf_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=m68hc11elf_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/m68kcoff.em b/binutils-2.21/ld/emultempl/m68kcoff.em new file mode 100644 index 0000000..276c3b2 --- /dev/null +++ b/binutils-2.21/ld/emultempl/m68kcoff.em @@ -0,0 +1,243 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* Handle embedded relocs for m68k. + Copyright 2000, 2002, 2003, 2004, 2005, 2007, 2008 + Free Software Foundation, Inc. + Written by Michael Sokolov <msokolov@ivan.Harhan.ORG>, based on generic.em + by Steve Chamberlain <steve@cygnus.com>, embedded relocs code based on + mipsecoff.em 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldmisc.h" + +static void check_sections (bfd *, asection *, void *); + +static void +gld${EMULATION_NAME}_before_parse (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ +} + +/* This function is run after all the input files have been opened. + We create a .emreloc section for each input file with a non zero + .data section. The BFD backend will fill in these sections with + magic numbers which can be used to relocate the data section at run + time. */ + +static void +gld${EMULATION_NAME}_after_open (void) +{ + bfd *abfd; + + if (! command_line.embedded_relocs + || link_info.relocatable) + return; + + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec; + + /* As first-order business, make sure that each input BFD is COFF. It + better be, as we are directly calling a COFF backend function. */ + if (bfd_get_flavour (abfd) != bfd_target_coff_flavour) + einfo ("%F%B: all input objects must be COFF for --embedded-relocs\n"); + + datasec = bfd_get_section_by_name (abfd, ".data"); + + /* Note that we assume that the reloc_count field has already + been set up. We could call bfd_get_reloc_upper_bound, but + that returns the size of a memory buffer rather than a reloc + count. We do not want to call bfd_canonicalize_reloc, + because although it would always work it would force us to + read in the relocs into BFD canonical form, which would waste + a significant amount of time and memory. */ + if (datasec != NULL && datasec->reloc_count > 0) + { + asection *relsec; + + relsec = bfd_make_section_with_flags (abfd, ".emreloc", + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY)); + if (relsec == NULL + || ! bfd_set_section_alignment (abfd, relsec, 2) + || ! bfd_set_section_size (abfd, relsec, + datasec->reloc_count * 12)) + einfo ("%F%B: can not create .emreloc section: %E\n"); + } + + /* Double check that all other data sections are empty, as is + required for embedded PIC code. */ + bfd_map_over_sections (abfd, check_sections, datasec); + } +} + +/* Check that of the data sections, only the .data section has + relocs. This is called via bfd_map_over_sections. */ + +static void +check_sections (bfd *abfd, asection *sec, void *datasec) +{ + if ((bfd_get_section_flags (abfd, sec) & SEC_DATA) + && sec != datasec + && sec->reloc_count != 0) + einfo ("%B%X: section %s has relocs; can not use --embedded-relocs\n", + abfd, bfd_get_section_name (abfd, sec)); +} + +/* This function is called after the section sizes and offsets have + been set. If we are generating embedded relocs, it calls a special + BFD backend routine to do the work. */ + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + bfd *abfd; + + if (! command_line.embedded_relocs + || link_info.relocatable) + return; + + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec, *relsec; + char *errmsg; + + datasec = bfd_get_section_by_name (abfd, ".data"); + + if (datasec == NULL || datasec->reloc_count == 0) + continue; + + relsec = bfd_get_section_by_name (abfd, ".emreloc"); + ASSERT (relsec != NULL); + + if (! bfd_m68k_coff_create_embedded_relocs (abfd, &link_info, + datasec, relsec, + &errmsg)) + { + if (errmsg == NULL) + einfo ("%B%X: can not create runtime reloc information: %E\n", + abfd); + else + einfo ("%X%B: can not create runtime reloc information: %s\n", + abfd, errmsg); + } + } +} + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + gld${EMULATION_NAME}_after_open, + gld${EMULATION_NAME}_after_allocation, + set_output_arch_default, + ldemul_default_target, + before_allocation_default, + gld${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/m68kelf.em b/binutils-2.21/ld/emultempl/m68kelf.em new file mode 100644 index 0000000..48a50bc --- /dev/null +++ b/binutils-2.21/ld/emultempl/m68kelf.em @@ -0,0 +1,250 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2000, 2001, 2003, 2005, 2007, 2008, 2009 +# Free Software Foundation, Inc. +# Written by Michael Sokolov <msokolov@ivan.Harhan.ORG>, based on armelf.em +# +# 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 is sourced from elf32.em, and defines some extra routines for m68k +# embedded systems using ELF and for some other systems using m68k ELF. While +# it is sourced from elf32.em for all m68k ELF configurations, here we include +# only the features we want depending on the configuration. + +case ${target} in + m68*-*-elf) + echo "#define SUPPORT_EMBEDDED_RELOCS" >>e${EMULATION_NAME}.c + ;; +esac + +case ${target} in + *-linux*) +# Don't use multi-GOT by default due to glibc linker's assumption +# that GOT pointer points to GOT[0]. +# got_handling_target_default=GOT_HANDLING_MULTIGOT + got_handling_target_default=GOT_HANDLING_SINGLE + ;; + *) + got_handling_target_default=GOT_HANDLING_SINGLE + ;; +esac + +fragment <<EOF + +#define GOT_HANDLING_SINGLE (0) +#define GOT_HANDLING_NEGATIVE (1) +#define GOT_HANDLING_MULTIGOT (2) +#define GOT_HANDLING_TARGET_DEFAULT ${got_handling_target_default} + +/* How to generate GOT. */ +static int got_handling = GOT_HANDLING_DEFAULT; + +#ifdef SUPPORT_EMBEDDED_RELOCS +static void check_sections (bfd *, asection *, void *); +#endif + +/* This function is run after all the input files have been opened. */ + +static void +m68k_elf_after_open (void) +{ + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_open (); + +#ifdef SUPPORT_EMBEDDED_RELOCS + if (command_line.embedded_relocs + && (! link_info.relocatable)) + { + bfd *abfd; + + /* In the embedded relocs mode we create a .emreloc section for each + input file with a nonzero .data section. The BFD backend will fill in + these sections with magic numbers which can be used to relocate the + data section at run time. */ + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec; + + /* As first-order business, make sure that each input BFD is either + COFF or ELF. We need to call a special BFD backend function to + generate the embedded relocs, and we have such functions only for + COFF and ELF. */ + if (bfd_get_flavour (abfd) != bfd_target_coff_flavour + && bfd_get_flavour (abfd) != bfd_target_elf_flavour) + einfo ("%F%B: all input objects must be COFF or ELF for --embedded-relocs\n"); + + datasec = bfd_get_section_by_name (abfd, ".data"); + + /* Note that we assume that the reloc_count field has already + been set up. We could call bfd_get_reloc_upper_bound, but + that returns the size of a memory buffer rather than a reloc + count. We do not want to call bfd_canonicalize_reloc, + because although it would always work it would force us to + read in the relocs into BFD canonical form, which would waste + a significant amount of time and memory. */ + if (datasec != NULL && datasec->reloc_count > 0) + { + asection *relsec; + + relsec = bfd_make_section_with_flags (abfd, ".emreloc", + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY)); + if (relsec == NULL + || ! bfd_set_section_alignment (abfd, relsec, 2) + || ! bfd_set_section_size (abfd, relsec, + datasec->reloc_count * 12)) + einfo ("%F%B: can not create .emreloc section: %E\n"); + } + + /* Double check that all other data sections are empty, as is + required for embedded PIC code. */ + bfd_map_over_sections (abfd, check_sections, datasec); + } + } +#endif /* SUPPORT_EMBEDDED_RELOCS */ +} + +#ifdef SUPPORT_EMBEDDED_RELOCS +/* Check that of the data sections, only the .data section has + relocs. This is called via bfd_map_over_sections. */ + +static void +check_sections (bfd *abfd, asection *sec, void *datasec) +{ + if ((bfd_get_section_flags (abfd, sec) & SEC_DATA) + && sec != datasec + && sec->reloc_count != 0) + einfo ("%B%X: section %s has relocs; can not use --embedded-relocs\n", + abfd, bfd_get_section_name (abfd, sec)); +} + +#endif /* SUPPORT_EMBEDDED_RELOCS */ + +/* This function is called after the section sizes and offsets have + been set. */ + +static void +m68k_elf_after_allocation (void) +{ + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_allocation (); + +#ifdef SUPPORT_EMBEDDED_RELOCS + if (command_line.embedded_relocs + && (! link_info.relocatable)) + { + bfd *abfd; + + /* If we are generating embedded relocs, call a special BFD backend + routine to do the work. */ + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec, *relsec; + char *errmsg; + + datasec = bfd_get_section_by_name (abfd, ".data"); + + if (datasec == NULL || datasec->reloc_count == 0) + continue; + + relsec = bfd_get_section_by_name (abfd, ".emreloc"); + ASSERT (relsec != NULL); + + if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) + { + if (! bfd_m68k_coff_create_embedded_relocs (abfd, &link_info, + datasec, relsec, + &errmsg)) + { + if (errmsg == NULL) + einfo ("%B%X: can not create runtime reloc information: %E\n", + abfd); + else + einfo ("%X%B: can not create runtime reloc information: %s\n", + abfd, errmsg); + } + } + else if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + if (! bfd_m68k_elf32_create_embedded_relocs (abfd, &link_info, + datasec, relsec, + &errmsg)) + { + if (errmsg == NULL) + einfo ("%B%X: can not create runtime reloc information: %E\n", + abfd); + else + einfo ("%X%B: can not create runtime reloc information: %s\n", + abfd, errmsg); + } + } + else + abort (); + } + } +#endif /* SUPPORT_EMBEDDED_RELOCS */ +} + +/* This is a convenient point to tell BFD about target specific flags. + After the output has been created, but before inputs are read. */ + +static void +elf_m68k_create_output_section_statements (void) +{ + bfd_elf_m68k_set_target_options (&link_info, got_handling); +} + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_GOT 301 +' + +PARSE_AND_LIST_LONGOPTS=' + { "got", required_argument, NULL, OPTION_GOT}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --got=<type> Specify GOT handling scheme\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_GOT: + if (strcmp (optarg, "target") == 0) + got_handling = GOT_HANDLING_TARGET_DEFAULT; + else if (strcmp (optarg, "single") == 0) + got_handling = 0; + else if (strcmp (optarg, "negative") == 0) + got_handling = 1; + else if (strcmp (optarg, "multigot") == 0) + got_handling = 2; + else + einfo (_("Unrecognized --got argument '\''%s'\''.\n"), optarg); + break; +' + +# We have our own after_open and after_allocation functions, but they call +# the standard routines, so give them a different name. +LDEMUL_AFTER_OPEN=m68k_elf_after_open +LDEMUL_AFTER_ALLOCATION=m68k_elf_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=elf_m68k_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/mipsecoff.em b/binutils-2.21/ld/emultempl/mipsecoff.em new file mode 100644 index 0000000..809229f --- /dev/null +++ b/binutils-2.21/ld/emultempl/mipsecoff.em @@ -0,0 +1,38 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 1994, 1995, 1997, 1999, 2000, 2001, 2002, 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. +# + +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +static void +gld${EMULATION_NAME}_before_parse (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); +#endif /* not TARGET_ */ +} +EOF + +LDEMUL_BEFORE_PARSE=gld${EMULATION_NAME}_before_parse diff --git a/binutils-2.21/ld/emultempl/mipself.em b/binutils-2.21/ld/emultempl/mipself.em new file mode 100644 index 0000000..7a13d4d --- /dev/null +++ b/binutils-2.21/ld/emultempl/mipself.em @@ -0,0 +1,241 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2004, 2006, 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. + +fragment <<EOF + +#include "ldctor.h" +#include "elf/mips.h" +#include "elfxx-mips.h" + +#define is_mips_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == MIPS_ELF_DATA) + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; +static bfd *stub_bfd; + +static void +mips_after_parse (void) +{ + /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different + ways. .gnu.hash needs symbols to be grouped by hash code whereas the + MIPS ABI requires a mapping between the GOT and the symbol table. */ + if (link_info.emit_gnu_hash) + { + einfo ("%X%P: .gnu.hash is incompatible with the MIPS ABI\n"); + link_info.emit_hash = TRUE; + link_info.emit_gnu_hash = FALSE; + } + after_parse_default (); +} + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (info->input_section == NULL + || l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + before its associated input section. */ + *lp = info->add.head; + *(info->add.tail) = l; + return TRUE; + } + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + +/* Create a new stub section called STUB_SEC_NAME and arrange for it to + be linked in OUTPUT_SECTION. The section should go at the beginning of + OUTPUT_SECTION if INPUT_SECTION is null, otherwise it must go immediately + before INPUT_SECTION. */ + +static asection * +mips_add_stub_section (const char *stub_sec_name, asection *input_section, + asection *output_section) +{ + asection *stub_sec; + flagword flags; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + /* Create the stub file, if we haven't already. */ + if (stub_file == NULL) + { + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_bfd == NULL + || !bfd_set_arch_mach (stub_bfd, + bfd_get_arch (link_info.output_bfd), + bfd_get_mach (link_info.output_bfd))) + { + einfo ("%F%P: can not create BFD %E\n"); + return NULL; + } + stub_bfd->flags |= BFD_LINKER_CREATED; + stub_file->the_bfd = stub_bfd; + ldlang_add_file (stub_file); + } + + /* Create the section. */ + stub_sec = bfd_make_section_anyway (stub_bfd, stub_sec_name); + if (stub_sec == NULL) + goto err_ret; + + /* Set the flags. */ + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP); + if (!bfd_set_section_flags (stub_bfd, stub_sec, flags)) + goto err_ret; + + /* Create an output section statement. */ + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + /* Initialize a statement list that contains only the new statement. */ + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, os); + if (info.add.head == NULL) + goto err_ret; + + /* Insert the new statement in the appropriate place. */ + info.input_section = input_section; + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + +/* This is called before the input files are opened. */ + +static void +mips_create_output_section_statements (void) +{ + if (is_mips_elf (link_info.output_bfd)) + _bfd_mips_elf_init_stubs (&link_info, mips_add_stub_section); +} + +/* This is called after we have merged the private data of the input bfds. */ + +static void +mips_before_allocation (void) +{ + flagword flags; + + flags = elf_elfheader (link_info.output_bfd)->e_flags; + if (!link_info.shared + && !link_info.nocopyreloc + && (flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) + _bfd_mips_elf_use_plts_and_copy_relocs (&link_info); + + gld${EMULATION_NAME}_before_allocation (); +} + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void mips_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +mips_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&mips_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file mips_lang_for_each_input_file + +EOF + +LDEMUL_AFTER_PARSE=mips_after_parse +LDEMUL_BEFORE_ALLOCATION=mips_before_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=mips_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/mmix-elfnmmo.em b/binutils-2.21/ld/emultempl/mmix-elfnmmo.em new file mode 100644 index 0000000..0059792 --- /dev/null +++ b/binutils-2.21/ld/emultempl/mmix-elfnmmo.em @@ -0,0 +1,116 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002, 2003, 2004, 2005, 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. +# + +# This file is sourced from elf32.em and mmo.em, used to define +# MMIX-specific things common to ELF and MMO. + +fragment <<EOF +#include "elf/mmix.h" + +/* Set up handling of linker-allocated global registers. */ + +static void +mmix_before_allocation (void) +{ + /* Call the default first. */ + gld${EMULATION_NAME}_before_allocation (); + + /* There's a needrelax.em which uses this ..._before_allocation-hook and + just has the statement below as payload. It's more of a hassle to + use that than to just include these two lines and take the + maintenance burden to keep them in sync. (Of course we lose the + maintenance burden of checking that it still does what we need.) */ + + /* Force -relax on (regardless of whether we're doing a relocatable + link). */ + ENABLE_RELAXATION; + + if (!_bfd_mmix_before_linker_allocation (link_info.output_bfd, &link_info)) + einfo ("%X%P: Internal problems setting up section %s", + MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); +} + +/* We need to set the VMA of the .MMIX.reg_contents section when it has + been allocated, and produce the final settings for the linker-generated + GREGs. */ + +static void +mmix_after_allocation (void) +{ + asection *sec; + bfd_signed_vma regvma; + + gld${EMULATION_NAME}_after_allocation (); + + /* If there's no register section, we don't need to do anything. On the + other hand, if there's a non-standard linker-script without a mapping + from MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME when that section is + present (as in the ld test "NOCROSSREFS 2"), that section (1) will be + orphaned; not inserted in MMIX_REG_CONTENTS_SECTION_NAME and (2) we + will not do the necessary preparations for those relocations that + caused it to be created. We'll SEGV from the latter error. The + former error in separation will result in a non-working binary, but + that's expected when you play tricks with linker scripts. The + "NOCROSSREFS 2" test does not run the output so it does not matter + there. */ + sec = bfd_get_section_by_name (link_info.output_bfd, + MMIX_REG_CONTENTS_SECTION_NAME); + if (sec == NULL) + sec + = bfd_get_section_by_name (link_info.output_bfd, + MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); + if (sec == NULL) + return; + + regvma = 256 * 8 - sec->size - 8; + + /* If we start on a local register, we have too many global registers. + We treat this error as nonfatal (meaning processing will continue in + search for other errors), because it's a link error in the same way + as an undefined symbol. */ + if (regvma < 32 * 8) + { + einfo ("%X%P: Too many global registers: %u, max 223\n", + (unsigned) sec->size / 8); + regvma = 32 * 8; + } + + /* Set vma to correspond to first such register number * 8. */ + bfd_set_section_vma (link_info.output_bfd, sec, (bfd_vma) regvma); + + /* Simplify symbol output for the register section (without contents; + created for register symbols) by setting the output offset to 0. + This section is only present when there are register symbols. */ + sec = bfd_get_section_by_name (link_info.output_bfd, MMIX_REG_SECTION_NAME); + if (sec != NULL) + bfd_set_section_vma (abfd, sec, 0); + + if (!_bfd_mmix_after_linker_allocation (link_info.output_bfd, &link_info)) + { + /* This is a fatal error; make einfo call not return. */ + einfo ("%F%P: Can't finalize linker-allocated global registers\n"); + } +} +EOF + +LDEMUL_AFTER_ALLOCATION=mmix_after_allocation +LDEMUL_BEFORE_ALLOCATION=mmix_before_allocation diff --git a/binutils-2.21/ld/emultempl/mmixelf.em b/binutils-2.21/ld/emultempl/mmixelf.em new file mode 100644 index 0000000..a875a5c --- /dev/null +++ b/binutils-2.21/ld/emultempl/mmixelf.em @@ -0,0 +1,44 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002, 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. +# + +# This file is sourced from elf32.em and used to define MMIX and ELF +# specific things. First include what we have in common with mmo. + +source_em ${srcdir}/emultempl/mmix-elfnmmo.em + +fragment <<EOF + +static void +elfmmix_before_parse (void) +{ + gld${EMULATION_NAME}_before_parse (); + + /* Make sure we don't create a demand-paged executable. Unfortunately + this isn't changeable with a command-line option. It makes no + difference to mmo, but the sections in elf64mmix will be aligned to a + page in the linked file, which is non-intuitive. If there's ever a + full system with shared libraries and demand paging, you will want to + exclude this file. */ + config.magic_demand_paged = FALSE; +} +EOF + +LDEMUL_BEFORE_PARSE=elfmmix_before_parse diff --git a/binutils-2.21/ld/emultempl/mmo.em b/binutils-2.21/ld/emultempl/mmo.em new file mode 100644 index 0000000..d1a6f14 --- /dev/null +++ b/binutils-2.21/ld/emultempl/mmo.em @@ -0,0 +1,158 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002, 2003, 2004, 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. +# + +# This file is sourced from generic.em. + +fragment <<EOF +/* Need to have this macro defined before mmix-elfnmmo, which uses the + name for the before_allocation function, defined in ldemul.c (for + the mmo "emulation") or in elf32.em (for the elf64mmix + "emulation"). */ +#define gldmmo_before_allocation before_allocation_default + +/* We include this header *not* because we expect to handle ELF here + but because we re-use the map_segments function in elf-generic.em, + a file which is rightly somewhat ELF-centric. But this is only to + get a weird testcase right; ld-mmix/bpo-22, forcing ELF to be + output from the mmo emulation: -m mmo --oformat elf64-mmix! */ +#include "elf-bfd.h" + +static void gld${EMULATION_NAME}_after_allocation (void); +EOF + +source_em ${srcdir}/emultempl/elf-generic.em +source_em ${srcdir}/emultempl/mmix-elfnmmo.em + +fragment <<EOF + +/* Place an orphan section. We use this to put random SEC_CODE or + SEC_READONLY sections right after MMO_TEXT_SECTION_NAME. Much borrowed + from elf32.em. */ + +static lang_output_section_statement_type * +mmo_place_orphan (asection *s, + const char *secname, + int constraint ATTRIBUTE_UNUSED) +{ + static struct orphan_save hold_text = + { + MMO_TEXT_SECTION_NAME, + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 + }; + struct orphan_save *place; + lang_output_section_statement_type *after; + lang_output_section_statement_type *os; + + /* We have nothing to say for anything other than a final link. */ + if (link_info.relocatable + || (s->flags & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD) + return NULL; + + /* Only care for sections we're going to load. */ + os = lang_output_section_find (secname); + + /* We have an output section by this name. Place the section inside it + (regardless of whether the linker script lists it as input). */ + if (os != NULL) + { + lang_add_section (&os->children, s, os); + return os; + } + + /* If this section does not have .text-type section flags or there's no + MMO_TEXT_SECTION_NAME, we don't have anything to say. */ + if ((s->flags & (SEC_CODE | SEC_READONLY)) == 0) + return NULL; + + if (hold_text.os == NULL) + hold_text.os = lang_output_section_find (hold_text.name); + + place = &hold_text; + if (hold_text.os != NULL) + after = hold_text.os; + else + after = &lang_output_section_statement.head->output_section_statement; + + /* If there's an output section by this name, we'll use it, regardless + of section flags, in contrast to what's done in elf32.em. */ + os = lang_insert_orphan (s, secname, 0, after, place, NULL, NULL); + + /* We need an output section for .text as a root, so if there was none + (might happen with a peculiar linker script such as in "map + addresses", map-address.exp), we grab the output section created + above. */ + if (hold_text.os == NULL) + hold_text.os = os; + + return os; +} + +/* Remove the spurious settings of SEC_RELOC that make it to the output at + link time. We are as confused as elflink.h:elf_bfd_final_link, and + paper over the bug similarly. */ + +static void +mmo_wipe_sec_reloc_flag (bfd *abfd, asection *sec, void *ptr ATTRIBUTE_UNUSED) +{ + bfd_set_section_flags (abfd, sec, + bfd_get_section_flags (abfd, sec) & ~SEC_RELOC); +} + +/* Iterate with bfd_map_over_sections over mmo_wipe_sec_reloc_flag... */ + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + bfd_map_over_sections (link_info.output_bfd, mmo_wipe_sec_reloc_flag, NULL); + gld${EMULATION_NAME}_map_segments (FALSE); +} + +/* To get on-demand global register allocation right, we need to parse the + relocs, like what happens when linking to ELF. It needs to be done + before all input sections are supposed to be present. When linking to + ELF, it's done when reading symbols. When linking to mmo, we do it + when all input files are seen, which is equivalent. */ + +static void +mmo_after_open (void) +{ + /* When there's a mismatch between the output format and the emulation + (using weird combinations like "-m mmo --oformat elf64-mmix" for + example), we'd count relocs twice because they'd also be counted + along the usual route for ELF-only linking, which would lead to an + internal accounting error. */ + if (bfd_get_flavour (link_info.output_bfd) != bfd_target_elf_flavour) + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (bfd_get_flavour (is->the_bfd) == bfd_target_elf_flavour + && !_bfd_mmix_check_all_relocs (is->the_bfd, &link_info)) + einfo ("%X%P: Internal problems scanning %B after opening it", + is->the_bfd); + } + } +} +EOF + +LDEMUL_PLACE_ORPHAN=mmo_place_orphan +LDEMUL_AFTER_OPEN=mmo_after_open diff --git a/binutils-2.21/ld/emultempl/needrelax.em b/binutils-2.21/ld/emultempl/needrelax.em new file mode 100644 index 0000000..7f90224 --- /dev/null +++ b/binutils-2.21/ld/emultempl/needrelax.em @@ -0,0 +1,39 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002, 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. +# + +# This file is sourced from elf32.em. It is used by targets for +# which relaxation is not just an optimization, but for correctness. + +LDEMUL_BEFORE_ALLOCATION=need_relax_${EMULATION_NAME}_before_allocation + +fragment <<EOF + +static void +need_relax_${EMULATION_NAME}_before_allocation (void) +{ + /* Call main function; we're just extending it. */ + gld${EMULATION_NAME}_before_allocation (); + + /* Force -relax on if not doing a relocatable link. */ + if (! link_info.relocatable) + ENABLE_RELAXATION; +} +EOF diff --git a/binutils-2.21/ld/emultempl/netbsd.em b/binutils-2.21/ld/emultempl/netbsd.em new file mode 100644 index 0000000..99b48b0 --- /dev/null +++ b/binutils-2.21/ld/emultempl/netbsd.em @@ -0,0 +1,34 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. +# + +LDEMUL_BEFORE_PARSE=gldnetbsd_before_parse + +fragment <<EOF +static void +gld${EMULATION_NAME}_before_parse (void); + +static void +gldnetbsd_before_parse (void) +{ + gld${EMULATION_NAME}_before_parse (); + link_info.common_skip_ar_symbols = bfd_link_common_skip_text; +} +EOF diff --git a/binutils-2.21/ld/emultempl/ostring.sed b/binutils-2.21/ld/emultempl/ostring.sed new file mode 100644 index 0000000..a526d3f --- /dev/null +++ b/binutils-2.21/ld/emultempl/ostring.sed @@ -0,0 +1,4 @@ +s/["\\]/\\&/g +s/$/\\n\\/ +1 s/^/"/ +$ s/$/n"/ diff --git a/binutils-2.21/ld/emultempl/pe.em b/binutils-2.21/ld/emultempl/pe.em new file mode 100644 index 0000000..bb283c1 --- /dev/null +++ b/binutils-2.21/ld/emultempl/pe.em @@ -0,0 +1,2217 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +rm -f e${EMULATION_NAME}.c +(echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) +fragment <<EOF +/* Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 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. */ + + +/* 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_${EMULATION_NAME} + +/* 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_${EMULATION_NAME}_allocate_interworking_sections +#define bfd_arm_get_bfd_for_interworking \ + bfd_${EMULATION_NAME}_get_bfd_for_interworking +#define bfd_arm_process_before_allocation \ + bfd_${EMULATION_NAME}_process_before_allocation +#endif + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" +#include "libiberty.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 != ${OVERRIDE_SECTION_ALIGNMENT:-PE_DEF_SECTION_ALIGNMENT} +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SECTION_ALIGNMENT ${OVERRIDE_SECTION_ALIGNMENT} +#endif + +#if defined(TARGET_IS_i386pe) \ + || defined(TARGET_IS_shpe) \ + || defined(TARGET_IS_mipspe) \ + || 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 = ${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; + +#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 ("${OUTPUT_FORMAT}", NULL, NULL, &u, NULL)) + bfd_get_target_info ("${RELOCATEABLE_OUTPUT_FORMAT}", NULL, NULL, &u, NULL); + + if (u == -1) + abort (); + pe_leading_underscore = (u != 0 ? 1 : 0); + return pe_leading_underscore; +} + +static void +gld_${EMULATION_NAME}_before_parse (void) +{ + is_underscoring (); + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + output_filename = "${EXECUTABLE_NAME:-a.exe}"; +#ifdef DLL_SUPPORT + config.dynamic_link = TRUE; + config.has_shared = 1; +EOF + +# Cygwin no longer wants these noisy warnings. Other PE +# targets might like to consider adding themselves here. +case ${target} in + *-*-cygwin*) + default_auto_import=1 + default_merge_rdata=1 + ;; + i[3-7]86-*-mingw* | x86_64-*-mingw*) + default_auto_import=1 + default_merge_rdata=0 + ;; + *) + default_auto_import=-1 + default_merge_rdata=1 + ;; +esac + +fragment <<EOF + link_info.pei386_auto_import = ${default_auto_import}; + /* 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 ${default_merge_rdata} + +/* 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_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1 \ + (OPTION_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) + +static void +gld${EMULATION_NAME}_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}, +#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}, + {"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__", ${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_${EMULATION_NAME}_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")); +#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 sophistcated 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, _(" --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 +gld${EMULATION_NAME}_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) + { + /* xgettext:c-format */ + fprintf (stderr, _("%s: Can't open base file %s\n"), + program_name, optarg); + xexit (1); + } + 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; +#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_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_${EMULATION_NAME}_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_assop ('=', GET_INIT_SYMBOL_NAME (j), + exp_intop (val))); + 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_${EMULATION_NAME}_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.\n\ +This 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) +{ + if (pe_dll_extra_pe_debug) + 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_${EMULATION_NAME}_after_open (void) +{ +#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; + + /* 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 (strcmp (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 && strcmp (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 && strcmp (pnt, ".obj") == 0) + continue; + + if (strcmp (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 && (strcmp (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 && (blhe->type == bfd_link_hash_defined) + && (blhe->u.undef.next == NULL)) + stub_sec->flags |= SEC_EXCLUDE; + } + } + } + } + } + } +} + +static void +gld_${EMULATION_NAME}_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_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT + const char *ext = entry->filename + strlen (entry->filename) - 4; + + if (strcmp (ext, ".def") == 0 || strcmp (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_assop ('=', "__image_base__", + exp_intop (pe.ImageBase)); + } + + 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_${EMULATION_NAME}_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_mipspe + pe_dll_id_target ("pei-mips"); +#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_${EMULATION_NAME}_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) && !defined(TARGET_IS_mipspe) + || (!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) || defined(TARGET_IS_mipspe) + /* 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_${EMULATION_NAME}_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, 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, 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. */ + address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); + os = lang_insert_orphan (s, secname, constraint, after, place, address, + &add_child); + } + + /* 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_${EMULATION_NAME}_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->is_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_${EMULATION_NAME}_find_potential_libraries + (char *name, lang_input_statement_type *entry) +{ + return ldfile_open_file_search (name, entry, "", ".lib"); +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +# Scripts compiled in. +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +if test -n "$GENERATE_AUTO_IMPORT_SCRIPT" ; then +echo ' ; else if (link_info.pei386_auto_import == 1 && (MERGE_RDATA_V2 || link_info.pei386_runtime_pseudo_reloc != 2)) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xa >> e${EMULATION_NAME}.c +fi +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +fragment <<EOF + + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + gld_${EMULATION_NAME}_after_parse, + gld_${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld_${EMULATION_NAME}_before_allocation, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + gld_${EMULATION_NAME}_finish, + NULL, /* Create output section statements. */ + gld_${EMULATION_NAME}_open_dynamic_archive, + gld_${EMULATION_NAME}_place_orphan, + gld_${EMULATION_NAME}_set_symbols, + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + gld_${EMULATION_NAME}_unrecognized_file, + gld_${EMULATION_NAME}_list_options, + gld_${EMULATION_NAME}_recognized_file, + gld_${EMULATION_NAME}_find_potential_libraries, + NULL /* new_vers_pattern. */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/pep.em b/binutils-2.21/ld/emultempl/pep.em new file mode 100644 index 0000000..39daa07 --- /dev/null +++ b/binutils-2.21/ld/emultempl/pep.em @@ -0,0 +1,1955 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +rm -f e${EMULATION_NAME}.c +(echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) +fragment <<EOF +/* Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Written by Kai Tietz, OneVision Software GmbH&CoKg. + + 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_XP64 and higher */ +/* Based on pe.em, but modified for 64 bit support. */ + +#define TARGET_IS_${EMULATION_NAME} + +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" +#include "libiberty.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/x86_64.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" + +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +#include "deffile.h" +#include "pep-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 != ${OVERRIDE_SECTION_ALIGNMENT:-PE_DEF_SECTION_ALIGNMENT} +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SECTION_ALIGNMENT ${OVERRIDE_SECTION_ALIGNMENT} +#endif + +#ifdef TARGET_IS_i386pep +#define DLL_SUPPORT +#endif + +#if defined(TARGET_IS_i386pep) || ! defined(DLL_SUPPORT) +#define PE_DEF_SUBSYSTEM 3 +#else +#undef NT_EXE_IMAGE_BASE +#define NT_EXE_IMAGE_BASE 0x00010000 +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SUBSYSTEM 2 +#undef PE_DEF_FILE_ALIGNMENT +#define PE_DEF_FILE_ALIGNMENT 0x00000200 +#define PE_DEF_SECTION_ALIGNMENT 0x00000400 +#endif + +static struct internal_extra_pe_aouthdr pep; +static int dll; +static int pep_subsystem = ${SUBSYSTEM}; +static flagword real_flags = IMAGE_FILE_LARGE_ADDRESS_AWARE; +static int support_old_code = 0; +static lang_assignment_statement_type *image_base_statement = 0; +static unsigned short pe_dll_characteristics = 0; + +#ifdef DLL_SUPPORT +static int pep_enable_stdcall_fixup = 1; /* 0=disable 1=enable (default). */ +static char * pep_out_def_filename = NULL; +static char * pep_implib_filename = NULL; +static int pep_enable_auto_image_base = 0; +static char * pep_dll_search_prefix = NULL; +#endif + +extern const char *output_filename; + +static int is_underscoring (void) +{ + int u = 0; + if (pep_leading_underscore != -1) + return pep_leading_underscore; + if (!bfd_get_target_info ("${OUTPUT_FORMAT}", NULL, NULL, &u, NULL)) + bfd_get_target_info ("${RELOCATEABLE_OUTPUT_FORMAT}", NULL, NULL, &u, NULL); + + if (u == -1) + abort (); + pep_leading_underscore = (u != 0 ? 1 : 0); + return pep_leading_underscore; +} + + +static void +gld_${EMULATION_NAME}_before_parse (void) +{ + is_underscoring (); + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + output_filename = "${EXECUTABLE_NAME:-a.exe}"; +#ifdef DLL_SUPPORT + config.dynamic_link = TRUE; + config.has_shared = 1; + link_info.pei386_auto_import = 1; + link_info.pei386_runtime_pseudo_reloc = 2; /* Use by default version 2. */ +#endif +} + +/* PE format extra command line options. */ + +/* Used for setting flags in the PE header. */ +enum options +{ + OPTION_BASE_FILE = 300 + 1, + OPTION_DLL, + OPTION_FILE_ALIGNMENT, + OPTION_IMAGE_BASE, + OPTION_MAJOR_IMAGE_VERSION, + OPTION_MAJOR_OS_VERSION, + OPTION_MAJOR_SUBSYSTEM_VERSION, + OPTION_MINOR_IMAGE_VERSION, + OPTION_MINOR_OS_VERSION, + OPTION_MINOR_SUBSYSTEM_VERSION, + OPTION_SECTION_ALIGNMENT, + OPTION_STACK, + OPTION_SUBSYSTEM, + OPTION_HEAP, + OPTION_SUPPORT_OLD_CODE, + OPTION_OUT_DEF, + OPTION_EXPORT_ALL, + OPTION_EXCLUDE_SYMBOLS, + OPTION_EXCLUDE_ALL_SYMBOLS, + OPTION_KILL_ATS, + OPTION_STDCALL_ALIASES, + OPTION_ENABLE_STDCALL_FIXUP, + OPTION_DISABLE_STDCALL_FIXUP, + OPTION_IMPLIB_FILENAME, + OPTION_WARN_DUPLICATE_EXPORTS, + OPTION_IMP_COMPAT, + OPTION_ENABLE_AUTO_IMAGE_BASE, + OPTION_DISABLE_AUTO_IMAGE_BASE, + OPTION_DLL_SEARCH_PREFIX, + OPTION_NO_DEFAULT_EXCLUDES, + OPTION_DLL_ENABLE_AUTO_IMPORT, + OPTION_DLL_DISABLE_AUTO_IMPORT, + OPTION_ENABLE_EXTRA_PE_DEBUG, + OPTION_EXCLUDE_LIBS, + OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC, + OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC, + OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2, + OPTION_EXCLUDE_MODULES_FOR_IMPLIB, + OPTION_USE_NUL_PREFIXED_IMPORT_TABLES, + OPTION_NO_LEADING_UNDERSCORE, + OPTION_LEADING_UNDERSCORE, + OPTION_ENABLE_LONG_SECTION_NAMES, + OPTION_DISABLE_LONG_SECTION_NAMES, + OPTION_DYNAMIC_BASE, + OPTION_FORCE_INTEGRITY, + OPTION_NX_COMPAT, + OPTION_NO_ISOLATION, + OPTION_NO_SEH, + OPTION_NO_BIND, + OPTION_WDM_DRIVER, + OPTION_TERMINAL_SERVER_AWARE +}; + +static void +gld${EMULATION_NAME}_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}, + {"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}, +#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-pep-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-v2", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2}, +#endif + {"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; + bfd_vma 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 on target's + settings. */ + bfd_boolean is_c_symbol; +} definfo; + +#define GET_INIT_SYMBOL_NAME(IDX) \ + (init[(IDX)].symbol \ + + ((init[(IDX)].is_c_symbol == FALSE || (is_underscoring () == 1)) ? 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) {&pep.field,sizeof(pep.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__", 0, FALSE), + D(MinorImageVersion,"__minor_image_version__", 0, FALSE), + D(MajorSubsystemVersion,"__major_subsystem_version__", 5, FALSE), + D(MinorSubsystemVersion,"__minor_subsystem_version__", 2, FALSE), + D(Subsystem,"__subsystem__", ${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_${EMULATION_NAME}_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")); +#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 sophistcated 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-pep-debug Enable verbose debug output when building\n\ + or linking to DLLs (esp. auto-import)\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")); +#endif +} + + +static void +set_pep_name (char *name, bfd_vma 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_pep_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) + { + entry = "DllMainCRTStartup"; + } + else + { + for (i = 0; v[i].entry; i++) + if (v[i].value == pep_subsystem) + break; + + /* If no match, use the default. */ + if (v[i].entry != NULL) + entry = v[i].entry; + else + entry = default_entry; + } + + /* Now we check target's default for getting proper symbol_char. */ + 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_pep_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_pep_name ("__major_subsystem_version__", + strtoul (sver + 1, &end, 0)); + if (*end == '.') + set_pep_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. */ + pep_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; + } + + pep_subsystem = v[i].value; + } + + set_pep_name ("__subsystem__", pep_subsystem); + + return; +} + + +static void +set_pep_value (char *name) +{ + char *end; + + set_pep_name (name, (bfd_vma) strtoull (optarg, &end, 0)); + + if (end == optarg) + einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); + + optarg = end; +} + + +static void +set_pep_stack_heap (char *resname, char *comname) +{ + set_pep_value (resname); + + if (*optarg == ',') + { + optarg++; + set_pep_value (comname); + } + else if (*optarg) + einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); +} + + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + is_underscoring (); + switch (optc) + { + default: + return FALSE; + + case OPTION_BASE_FILE: + link_info.base_file = fopen (optarg, FOPEN_WB); + if (link_info.base_file == NULL) + { + /* xgettext:c-format */ + fprintf (stderr, _("%s: Can't open base file %s\n"), + program_name, optarg); + xexit (1); + } + break; + + /* PE options. */ + case OPTION_HEAP: + set_pep_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); + break; + case OPTION_STACK: + set_pep_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); + break; + case OPTION_SUBSYSTEM: + set_pep_subsystem (); + break; + case OPTION_MAJOR_OS_VERSION: + set_pep_value ("__major_os_version__"); + break; + case OPTION_MINOR_OS_VERSION: + set_pep_value ("__minor_os_version__"); + break; + case OPTION_MAJOR_SUBSYSTEM_VERSION: + set_pep_value ("__major_subsystem_version__"); + break; + case OPTION_MINOR_SUBSYSTEM_VERSION: + set_pep_value ("__minor_subsystem_version__"); + break; + case OPTION_MAJOR_IMAGE_VERSION: + set_pep_value ("__major_image_version__"); + break; + case OPTION_MINOR_IMAGE_VERSION: + set_pep_value ("__minor_image_version__"); + break; + case OPTION_FILE_ALIGNMENT: + set_pep_value ("__file_alignment__"); + break; + case OPTION_SECTION_ALIGNMENT: + set_pep_value ("__section_alignment__"); + break; + case OPTION_DLL: + set_pep_name ("__dll__", 1); + break; + case OPTION_IMAGE_BASE: + set_pep_value ("__image_base__"); + break; + case OPTION_SUPPORT_OLD_CODE: + support_old_code = 1; + break; + case OPTION_USE_NUL_PREFIXED_IMPORT_TABLES: + pep_use_nul_prefixed_import_tables = TRUE; + break; + case OPTION_NO_LEADING_UNDERSCORE: + pep_leading_underscore = 0; + break; + case OPTION_LEADING_UNDERSCORE: + pep_leading_underscore = 1; + break; +#ifdef DLL_SUPPORT + case OPTION_OUT_DEF: + pep_out_def_filename = xstrdup (optarg); + break; + case OPTION_EXPORT_ALL: + pep_dll_export_everything = 1; + break; + case OPTION_EXCLUDE_SYMBOLS: + pep_dll_add_excludes (optarg, EXCLUDESYMS); + break; + case OPTION_EXCLUDE_ALL_SYMBOLS: + pep_dll_exclude_all_symbols = 1; + break; + case OPTION_EXCLUDE_LIBS: + pep_dll_add_excludes (optarg, EXCLUDELIBS); + break; + case OPTION_EXCLUDE_MODULES_FOR_IMPLIB: + pep_dll_add_excludes (optarg, EXCLUDEFORIMPLIB); + break; + case OPTION_KILL_ATS: + pep_dll_kill_ats = 1; + break; + case OPTION_STDCALL_ALIASES: + pep_dll_stdcall_aliases = 1; + break; + case OPTION_ENABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 1; + break; + case OPTION_DISABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 0; + break; + case OPTION_IMPLIB_FILENAME: + pep_implib_filename = xstrdup (optarg); + break; + case OPTION_WARN_DUPLICATE_EXPORTS: + pep_dll_warn_dup_exports = 1; + break; + case OPTION_IMP_COMPAT: + pep_dll_compat_implib = 1; + break; + case OPTION_ENABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 1; + break; + case OPTION_DISABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 0; + break; + case OPTION_DLL_SEARCH_PREFIX: + pep_dll_search_prefix = xstrdup (optarg); + break; + case OPTION_NO_DEFAULT_EXCLUDES: + pep_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 = 2; + break; + case OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = 0; + break; + case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2: + link_info.pei386_runtime_pseudo_reloc = 2; + break; + case OPTION_ENABLE_EXTRA_PE_DEBUG: + pep_dll_extra_pe_debug = 1; + break; +#endif + case OPTION_ENABLE_LONG_SECTION_NAMES: + pep_use_coff_long_section_names = 1; + break; + case OPTION_DISABLE_LONG_SECTION_NAMES: + pep_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_pep_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 bfd_vma +compute_dll_image_base (const char *ofile) +{ + bfd_vma hash = (bfd_vma) strhash (ofile); + return 0x61300000 + ((hash << 16) & 0x0FFC0000); +} +#endif + +/* Assign values to the special symbols before the linker script is + read. */ + +static void +gld_${EMULATION_NAME}_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 = (pep_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++) + { + bfd_vma val = init[j].value; + lang_assignment_statement_type *rv; + + rv = lang_add_assignment (exp_assop ('=', GET_INIT_SYMBOL_NAME (j), + exp_intop (val))); + if (init[j].size == sizeof (short)) + *(short *) init[j].ptr = (short) val; + else if (init[j].size == sizeof (int)) + *(int *) init[j].ptr = (int) val; + else if (init[j].size == sizeof (long)) + *(long *) init[j].ptr = (long) 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 (pep.FileAlignment > pep.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_${EMULATION_NAME}_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 (); +} + +/* pep-dll.c directly accesses pep_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 * pep_data_import_dll; + +#ifdef DLL_SUPPORT +static struct bfd_link_hash_entry *pep_undef_found_sym; + +static bfd_boolean +pep_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] == '@') + { + pep_undef_found_sym = h; + return FALSE; + } + return TRUE; +} + +static void +pep_fixup_stdcalls (void) +{ + static int gave_warning_message = 0; + struct bfd_link_hash_entry *undef, *sym; + + if (pep_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 (pep_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. */ + pep_undef_found_sym = 0; + bfd_link_hash_traverse (link_info.hash, pep_undef_cdecl_match, + (char *) undef->root.string); + sym = pep_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 (pep_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[8]; + bfd_vma _addend = 0; + int suc = 0; + + if (pep_dll_extra_pe_debug) + printf ("arelent: %s@%#lx: add=%li\n", sym->name, + (unsigned long) rel->address, (long) rel->addend); + + memset (addend, 0, sizeof (addend)); + switch ((rel->howto->bitsize)) + { + case 8: + suc = bfd_get_section_contents (s->owner, s, addend, rel->address, 1); + if (suc && rel->howto->pc_relative) + _addend = (bfd_vma) ((bfd_signed_vma) ((char) bfd_get_8 (s->owner, addend))); + else if (suc) + _addend = ((bfd_vma) bfd_get_8 (s->owner, addend)) & 0xff; + break; + case 16: + suc = bfd_get_section_contents (s->owner, s, addend, rel->address, 2); + if (suc && rel->howto->pc_relative) + _addend = (bfd_vma) ((bfd_signed_vma) ((short) bfd_get_16 (s->owner, addend))); + else if (suc) + _addend = ((bfd_vma) bfd_get_16 (s->owner, addend)) & 0xffff; + break; + case 32: + suc = bfd_get_section_contents (s->owner, s, addend, rel->address, 4); + if (suc && rel->howto->pc_relative) + _addend = (bfd_vma) ((bfd_signed_vma) ((int) bfd_get_32 (s->owner, addend))); + else if (suc) + _addend = ((bfd_vma) bfd_get_32 (s->owner, addend)) & 0xffffffff; + break; + case 64: + suc = bfd_get_section_contents (s->owner, s, addend, rel->address, 8); + if (suc) + _addend = ((bfd_vma) bfd_get_64 (s->owner, addend)); + break; + } + if (! suc) + einfo (_("%C: Cannot get section contents - auto-import exception\n"), + s->owner, s, rel->address); + + if (pep_dll_extra_pe_debug) + { + printf ("import of 0x%lx(0x%lx) sec_addr=0x%lx", (long) _addend, (long) rel->addend, (long) rel->address); + if (rel->howto->pc_relative) printf (" pcrel"); + printf (" %d bit rel.\n",(int) rel->howto->bitsize); + } + pep_create_import_fixup (rel, s, _addend); + + return 1; +} + +static void +pep_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 (pep_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 (!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 (pep_dll_extra_pe_debug) + printf ("->%s\n", symbols[i]->name); + + pep_data_import_dll = (char*) (symbols[i]->name + + U_SIZE ("_head_") - 1); + break; + } + + pep_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) +{ + if (pep_dll_extra_pe_debug) + 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_${EMULATION_NAME}_after_open (void) +{ + is_underscoring (); +#ifdef DLL_SUPPORT + if (pep_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 = pep; + pe_data (link_info.output_bfd)->dll = init[DLLOFF].value; + pe_data (link_info.output_bfd)->real_flags |= real_flags; + + /* 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 (pep_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) + { + pep_use_coff_long_section_names = 1; + break; + } + } + } + + pep_output_file_set_long_section_names (link_info.output_bfd); + +#ifdef DLL_SUPPORT + if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */ + pep_fixup_stdcalls (); + + pep_process_import_defs (link_info.output_bfd, &link_info); + + pep_find_data_imports (); + + /* As possibly new symbols are added by imports, we rerun + stdcall/fastcall fixup here. */ + if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */ + pep_fixup_stdcalls (); + +#ifndef TARGET_IS_i386pep + if (link_info.shared) +#else + if (!link_info.relocatable) +#endif + pep_dll_build_sections (link_info.output_bfd, &link_info); + +#ifndef TARGET_IS_i386pep + else + pep_exe_build_sections (link_info.output_bfd, &link_info); +#endif +#endif /* DLL_SUPPORT */ + + { + /* 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 (strcmp (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 && strcmp (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 && strcmp (pnt, ".obj") == 0) + continue; + + if (strcmp (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 && (strcmp (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; + } + } + } + } +} + +static void +gld_${EMULATION_NAME}_before_allocation (void) +{ + is_underscoring (); + 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; + + is_underscoring (); + + 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_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT + const char *ext = entry->filename + strlen (entry->filename) - 4; + + if (strcmp (ext, ".def") == 0 || strcmp (ext, ".DEF") == 0) + { + pep_def_file = def_file_parse (entry->filename, pep_def_file); + + if (pep_def_file) + { + int i, buflen=0, len; + char *buf; + + for (i = 0; i < pep_def_file->num_exports; i++) + { + len = strlen (pep_def_file->exports[i].internal_name); + if (buflen < len + 2) + buflen = len + 2; + } + + buf = xmalloc (buflen); + + for (i = 0; i < pep_def_file->num_exports; i++) + { + struct bfd_link_hash_entry *h; + + sprintf (buf, "%s%s", U (""), + pep_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, pep_def_file); */ + if (pep_def_file->is_dll == 1) + link_info.shared = 1; + + if (pep_def_file->base_address != (bfd_vma)(-1)) + { + pep.ImageBase + = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase + = init[IMAGEBASEOFF].value + = pep_def_file->base_address; + init[IMAGEBASEOFF].inited = 1; + if (image_base_statement) + image_base_statement->exp = exp_assop ('=', "__image_base__", + exp_intop (pep.ImageBase)); + } + + if (pep_def_file->stack_reserve != -1 + && ! saw_option ("__size_of_stack_reserve__")) + { + pep.SizeOfStackReserve = pep_def_file->stack_reserve; + if (pep_def_file->stack_commit != -1) + pep.SizeOfStackCommit = pep_def_file->stack_commit; + } + if (pep_def_file->heap_reserve != -1 + && ! saw_option ("__size_of_heap_reserve__")) + { + pep.SizeOfHeapReserve = pep_def_file->heap_reserve; + if (pep_def_file->heap_commit != -1) + pep.SizeOfHeapCommit = pep_def_file->heap_commit; + } + return TRUE; + } + } +#endif + return FALSE; +} + +static bfd_boolean +gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ + is_underscoring (); +#ifdef DLL_SUPPORT +#ifdef TARGET_IS_i386pep + pep_dll_id_target ("pei-x86-64"); +#endif + if (pep_bfd_is_dll (entry->the_bfd)) + return pep_implied_import_dll (entry->filename); +#endif + return FALSE; +} + +static void +gld_${EMULATION_NAME}_finish (void) +{ + is_underscoring (); + finish_default (); + +#ifdef DLL_SUPPORT + if (link_info.shared + || (!link_info.relocatable && pep_def_file->num_exports != 0)) + { + pep_dll_fill_sections (link_info.output_bfd, &link_info); + if (pep_implib_filename) + pep_dll_generate_implib (pep_def_file, pep_implib_filename, &link_info); + } + + if (pep_out_def_filename) + pep_dll_generate_def_file (pep_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_${EMULATION_NAME}_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, 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, 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. */ + address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); + os = lang_insert_orphan (s, secname, constraint, after, place, address, + &add_child); + } + + /* 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_${EMULATION_NAME}_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->is_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 + + (pep_dll_search_prefix + ? strlen (pep_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 (!pep_dll_search_prefix) + continue; + sprintf (base_string, libname_fmt[i].format, pep_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_${EMULATION_NAME}_find_potential_libraries + (char *name, lang_input_statement_type *entry) +{ + return ldfile_open_file_search (name, entry, "", ".lib"); +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +# Scripts compiled in. +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +if test -n "$GENERATE_AUTO_IMPORT_SCRIPT" ; then +echo ' ; else if (link_info.pei386_auto_import == 1 && link_info.pei386_runtime_pseudo_reloc != 2) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xa >> e${EMULATION_NAME}.c +fi +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +fragment <<EOF + + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + gld_${EMULATION_NAME}_after_parse, + gld_${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld_${EMULATION_NAME}_before_allocation, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + gld_${EMULATION_NAME}_finish, + NULL, /* Create output section statements. */ + gld_${EMULATION_NAME}_open_dynamic_archive, + gld_${EMULATION_NAME}_place_orphan, + gld_${EMULATION_NAME}_set_symbols, + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + gld_${EMULATION_NAME}_unrecognized_file, + gld_${EMULATION_NAME}_list_options, + gld_${EMULATION_NAME}_recognized_file, + gld_${EMULATION_NAME}_find_potential_libraries, + NULL /* new_vers_pattern. */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/ppc32elf.em b/binutils-2.21/ld/emultempl/ppc32elf.em new file mode 100644 index 0000000..36f9df2 --- /dev/null +++ b/binutils-2.21/ld/emultempl/ppc32elf.em @@ -0,0 +1,244 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003, 2005, 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. +# + +# This file is sourced from elf32.em, and defines extra powerpc32-elf +# specific routines. +# +fragment <<EOF + +#include "libbfd.h" +#include "elf32-ppc.h" + +#define is_ppc_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_object_id (bfd) == PPC32_ELF_DATA) + +/* Whether to run tls optimization. */ +static int notlsopt = 0; +static int no_tls_get_addr_opt = 0; + +/* Whether to emit symbols for stubs. */ +static int emit_stub_syms = -1; + +/* Chooses the correct place for .plt and .got. */ +static enum ppc_elf_plt_type plt_style = PLT_UNSET; +static int old_got = 0; + +static void +ppc_after_open (void) +{ + if (is_ppc_elf (link_info.output_bfd)) + { + int new_plt; + int keep_new; + unsigned int num_plt; + unsigned int num_got; + lang_output_section_statement_type *os; + lang_output_section_statement_type *plt_os[2]; + lang_output_section_statement_type *got_os[2]; + + if (emit_stub_syms < 0) + emit_stub_syms = link_info.emitrelocations || link_info.shared; + new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info, + plt_style, emit_stub_syms); + if (new_plt < 0) + einfo ("%X%P: select_plt_layout problem %E\n"); + + num_got = 0; + num_plt = 0; + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { + if (os->constraint == SPECIAL && strcmp (os->name, ".plt") == 0) + { + if (num_plt < 2) + plt_os[num_plt] = os; + ++num_plt; + } + if (os->constraint == SPECIAL && strcmp (os->name, ".got") == 0) + { + if (num_got < 2) + got_os[num_got] = os; + ++num_got; + } + } + + keep_new = new_plt == 1 ? 0 : -1; + if (num_plt == 2) + { + plt_os[0]->constraint = keep_new; + plt_os[1]->constraint = ~keep_new; + } + if (num_got == 2) + { + if (old_got) + keep_new = -1; + got_os[0]->constraint = keep_new; + got_os[1]->constraint = ~keep_new; + } + } + + gld${EMULATION_NAME}_after_open (); +} + +static void +ppc_before_allocation (void) +{ + if (is_ppc_elf (link_info.output_bfd)) + { + if (ppc_elf_tls_setup (link_info.output_bfd, &link_info, + no_tls_get_addr_opt) + && !notlsopt) + { + if (!ppc_elf_tls_optimize (link_info.output_bfd, &link_info)) + { + einfo ("%X%P: TLS problem %E\n"); + return; + } + } + } + + gld${EMULATION_NAME}_before_allocation (); + + /* Turn on relaxation if executable sections have addresses that + might make branches overflow. */ + if (RELAXATION_DISABLED_BY_DEFAULT) + { + bfd_vma low = (bfd_vma) -1; + bfd_vma high = 0; + asection *o; + + /* 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 (o = link_info.output_bfd->sections; o != NULL; o = o->next) + { + if ((o->flags & (SEC_ALLOC | SEC_CODE)) != (SEC_ALLOC | SEC_CODE)) + continue; + if (o->rawsize == 0) + continue; + if (low > o->vma) + low = o->vma; + if (high < o->vma + o->rawsize - 1) + high = o->vma + o->rawsize - 1; + } + if (high > low && high - low > (1 << 25) - 1) + ENABLE_RELAXATION; + } +} + +EOF + +if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then + fragment <<EOF +/* Special handling for embedded SPU executables. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); +static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); + +static bfd_boolean +ppc_recognized_file (lang_input_statement_type *entry) +{ + if (embedded_spu_file (entry, "-m32")) + return TRUE; + + return gld${EMULATION_NAME}_load_symbols (entry); +} + +EOF +LDEMUL_RECOGNIZED_FILE=ppc_recognized_file +fi + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_NO_TLS_OPT 301 +#define OPTION_NO_TLS_GET_ADDR_OPT (OPTION_NO_TLS_OPT + 1) +#define OPTION_NEW_PLT (OPTION_NO_TLS_GET_ADDR_OPT + 1) +#define OPTION_OLD_PLT (OPTION_NEW_PLT + 1) +#define OPTION_OLD_GOT (OPTION_OLD_PLT + 1) +#define OPTION_STUBSYMS (OPTION_OLD_GOT + 1) +#define OPTION_NO_STUBSYMS (OPTION_STUBSYMS + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS }, + { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS }, + { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, + { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT }, + { "secure-plt", no_argument, NULL, OPTION_NEW_PLT }, + { "bss-plt", no_argument, NULL, OPTION_OLD_PLT }, + { "sdata-got", no_argument, NULL, OPTION_OLD_GOT }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --emit-stub-syms Label linker stubs with a symbol.\n\ + --no-emit-stub-syms Don'\''t label linker stubs with a symbol.\n\ + --no-tls-optimize Don'\''t try to optimize TLS accesses.\n\ + --no-tls-get-addr-optimize Don'\''t use a special __tls_get_addr call.\n\ + --secure-plt Use new-style PLT if possible.\n\ + --bss-plt Force old-style BSS PLT.\n\ + --sdata-got Force GOT location just before .sdata.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_STUBSYMS: + emit_stub_syms = 1; + break; + + case OPTION_NO_STUBSYMS: + emit_stub_syms = 0; + break; + + case OPTION_NO_TLS_OPT: + notlsopt = 1; + break; + + case OPTION_NO_TLS_GET_ADDR_OPT: + no_tls_get_addr_opt = 1; + break; + + case OPTION_NEW_PLT: + plt_style = PLT_NEW; + break; + + case OPTION_OLD_PLT: + plt_style = PLT_OLD; + break; + + case OPTION_OLD_GOT: + old_got = 1; + break; +' + +# Put these extra ppc32elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=ppc_after_open +LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation diff --git a/binutils-2.21/ld/emultempl/ppc64elf.em b/binutils-2.21/ld/emultempl/ppc64elf.em new file mode 100644 index 0000000..cb8e784 --- /dev/null +++ b/binutils-2.21/ld/emultempl/ppc64elf.em @@ -0,0 +1,791 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# 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. +# + +# This file is sourced from elf32.em, and defines extra powerpc64-elf +# specific routines. +# +fragment <<EOF + +#include "ldctor.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf64-ppc.h" + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; +static int stub_added = 0; + +/* Whether we need to call ppc_layout_sections_again. */ +static int need_laying_out = 0; + +/* Maximum size of a group of input sections that can be handled by + one stub section. A value of +/-1 indicates the bfd back-end + should use a suitable default size. */ +static bfd_signed_vma group_size = 1; + +/* Whether to add ".foo" entries for each "foo" in a version script. */ +static int dotsyms = 1; + +/* Whether to run tls optimization. */ +static int no_tls_opt = 0; +static int no_tls_get_addr_opt = 0; + +/* Whether to run opd optimization. */ +static int no_opd_opt = 0; + +/* Whether to run toc optimization. */ +static int no_toc_opt = 0; + +/* Whether to allow multiple toc sections. */ +static int no_multi_toc = 0; + +/* Whether to sort input toc and got sections. */ +static int no_toc_sort = 0; + +/* Whether to emit symbols for stubs. */ +static int emit_stub_syms = -1; + +static asection *toc_section = 0; + +/* Whether to canonicalize .opd so that there are no overlapping + .opd entries. */ +static int non_overlapping_opd = 0; + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub sections. */ + +static void +ppc_create_output_section_statements (void) +{ + if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && elf_object_id (link_info.output_bfd) == PPC64_ELF_DATA)) + return; + + link_info.wrap_char = '.'; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || !bfd_set_arch_mach (stub_file->the_bfd, + bfd_get_arch (link_info.output_bfd), + bfd_get_mach (link_info.output_bfd))) + { + einfo ("%F%P: can not create BFD %E\n"); + return; + } + + stub_file->the_bfd->flags |= BFD_LINKER_CREATED; + ldlang_add_file (stub_file); + ppc64_elf_init_stub_bfd (stub_file->the_bfd, &link_info); +} + +/* Move the input section statement at *U which happens to be on LIST + to be just before *TO. */ + +static void +move_input_section (lang_statement_list_type *list, + lang_statement_union_type **u, + lang_statement_union_type **to) +{ + lang_statement_union_type *s = *u; + asection *i = s->input_section.section; + asection *p, *n; + + /* Snip the input section from the statement list. If it was the + last statement, fix the list tail pointer. */ + *u = s->header.next; + if (*u == NULL) + list->tail = u; + /* Add it back in the new position. */ + s->header.next = *to; + *to = s; + if (list->tail == to) + list->tail = &s->header.next; + + /* Trim I off the bfd map_head/map_tail doubly linked lists. */ + n = i->map_head.s; + p = i->map_tail.s; + (p != NULL ? p : i->output_section)->map_head.s = n; + (n != NULL ? n : i->output_section)->map_tail.s = p; + + /* Add I back on in its new position. */ + if (s->header.next->header.type == lang_input_section_enum) + { + n = s->header.next->input_section.section; + p = n->map_tail.s; + } + else + { + /* If the next statement is not an input section statement then + TO must point at the previous input section statement + header.next field. */ + lang_input_section_type *prev = (lang_input_section_type *) + ((char *) to - offsetof (lang_statement_union_type, header.next)); + + ASSERT (prev->header.type == lang_input_section_enum); + p = prev->section; + n = p->map_head.s; + } + i->map_head.s = n; + i->map_tail.s = p; + (p != NULL ? p : i->output_section)->map_head.s = i; + (n != NULL ? n : i->output_section)->map_tail.s = i; +} + +/* Sort input section statements in the linker script tree rooted at + LIST so that those whose owning bfd happens to have a section + called .init or .fini are placed first. Place any TOC sections + referenced by small TOC relocs next, with TOC sections referenced + only by bigtoc relocs last. */ + +static void +sort_toc_sections (lang_statement_list_type *list, + lang_statement_union_type **ini, + lang_statement_union_type **small) +{ + lang_statement_union_type *s, **u; + asection *i; + + u = &list->head; + while ((s = *u) != NULL) + { + switch (s->header.type) + { + case lang_wild_statement_enum: + sort_toc_sections (&s->wild_statement.children, ini, small); + break; + + case lang_group_statement_enum: + sort_toc_sections (&s->group_statement.children, ini, small); + break; + + case lang_input_section_enum: + i = s->input_section.section; + /* Leave the stub_file .got where it is. We put the .got + header there. */ + if (i->owner == stub_file->the_bfd) + break; + if (bfd_get_section_by_name (i->owner, ".init") != NULL + || bfd_get_section_by_name (i->owner, ".fini") != NULL) + { + if (ini != NULL && *ini != s) + { + move_input_section (list, u, ini); + if (small == ini) + small = &s->header.next; + ini = &s->header.next; + continue; + } + if (small == ini) + small = &s->header.next; + ini = &s->header.next; + break; + } + else if (ini == NULL) + ini = u; + + if (ppc64_elf_has_small_toc_reloc (i)) + { + if (small != NULL && *small != s) + { + move_input_section (list, u, small); + small = &s->header.next; + continue; + } + small = &s->header.next; + } + else if (small == NULL) + small = u; + break; + + default: + break; + } + u = &s->header.next; + } +} + +static void +prelim_size_sections (void) +{ + 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); + /* We must not cache anything from the preliminary sizing. */ + lang_reset_memory_regions (); + } +} + +static void +ppc_before_allocation (void) +{ + if (stub_file != NULL) + { + if (!no_opd_opt + && !ppc64_elf_edit_opd (&link_info, non_overlapping_opd)) + einfo ("%X%P: can not edit %s %E\n", "opd"); + + if (ppc64_elf_tls_setup (&link_info, no_tls_get_addr_opt, &no_multi_toc) + && !no_tls_opt) + { + /* Size the sections. This is premature, but we want to know the + TLS segment layout so that certain optimizations can be done. */ + prelim_size_sections (); + + if (!ppc64_elf_tls_optimize (&link_info)) + einfo ("%X%P: TLS problem %E\n"); + } + + if (!no_toc_opt + && !link_info.relocatable) + { + prelim_size_sections (); + + if (!ppc64_elf_edit_toc (&link_info)) + einfo ("%X%P: can not edit %s %E\n", "toc"); + } + + if (!no_toc_sort) + { + lang_output_section_statement_type *toc_os; + + toc_os = lang_output_section_find (".got"); + if (toc_os != NULL) + sort_toc_sections (&toc_os->children, NULL, NULL); + } + } + + gld${EMULATION_NAME}_before_allocation (); +} + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + before its associated input section. */ + *lp = info->add.head; + *(info->add.tail) = l; + return TRUE; + } + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + + +/* Call-back for ppc64_elf_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately before INPUT_SECTION. */ + +static asection * +ppc_add_stub_section (const char *stub_sec_name, asection *input_section) +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP); + stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + stub_sec_name, flags); + if (stub_sec == NULL) + goto err_ret; + + output_section = input_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + info.input_section = input_section; + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, os); + + if (info.add.head == NULL) + goto err_ret; + + stub_added = 1; + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + + +/* Another call-back for ppc64_elf_size_stubs. */ + +static void +ppc_layout_sections_again (void) +{ + /* If we have changed sizes of the stub sections, then we need + to recalculate all the section offsets. This may mean we need to + add even more stubs. */ + gld${EMULATION_NAME}_map_segments (TRUE); + + if (!link_info.relocatable) + _bfd_set_gp_value (link_info.output_bfd, + ppc64_elf_toc (link_info.output_bfd)); + + need_laying_out = -1; +} + + +static void +build_toc_list (lang_statement_union_type *statement) +{ + if (statement->header.type == lang_input_section_enum) + { + asection *i = statement->input_section.section; + + if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag + && (i->flags & SEC_EXCLUDE) == 0 + && i->output_section == toc_section) + { + if (!ppc64_elf_next_toc_section (&link_info, i)) + einfo ("%X%P: linker script separates .got and .toc\n"); + } + } +} + + +static void +build_section_lists (lang_statement_union_type *statement) +{ + if (statement->header.type == lang_input_section_enum) + { + asection *i = statement->input_section.section; + + if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag + && (i->flags & SEC_EXCLUDE) == 0 + && i->output_section != NULL + && i->output_section->owner == link_info.output_bfd) + { + if (!ppc64_elf_next_input_section (&link_info, i)) + einfo ("%X%P: can not size stub section: %E\n"); + } + } +} + + +/* Call the back-end function to set TOC base after we have placed all + the sections. */ +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + /* bfd_elf_discard_info just plays with data and debugging sections, + ie. doesn't affect code size, so we can delay resizing the + sections. It's likely we'll resize everything in the process of + adding stubs. */ + if (bfd_elf_discard_info (link_info.output_bfd, &link_info)) + need_laying_out = 1; + + /* If generating a relocatable output file, then we don't have any + stubs. */ + if (stub_file != NULL && !link_info.relocatable) + { + int ret = ppc64_elf_setup_section_lists (&link_info, + &ppc_add_stub_section, + &ppc_layout_sections_again); + if (ret < 0) + einfo ("%X%P: can not size stub section: %E\n"); + else if (ret > 0) + { + ppc64_elf_start_multitoc_partition (&link_info); + + if (!no_multi_toc) + { + toc_section = bfd_get_section_by_name (link_info.output_bfd, + ".got"); + if (toc_section != NULL) + lang_for_each_statement (build_toc_list); + } + + if (ppc64_elf_layout_multitoc (&link_info) + && !no_multi_toc + && toc_section != NULL) + lang_for_each_statement (build_toc_list); + + ppc64_elf_finish_multitoc_partition (&link_info); + + lang_for_each_statement (build_section_lists); + + if (!ppc64_elf_check_init_fini (&link_info)) + einfo ("%P: .init/.fini fragments use differing TOC pointers\n"); + + /* Call into the BFD backend to do the real work. */ + if (!ppc64_elf_size_stubs (&link_info, group_size)) + einfo ("%X%P: can not size stub section: %E\n"); + } + } + + if (need_laying_out != -1) + { + gld${EMULATION_NAME}_map_segments (need_laying_out); + + if (!link_info.relocatable) + _bfd_set_gp_value (link_info.output_bfd, + ppc64_elf_toc (link_info.output_bfd)); + } +} + + +/* Final emulation specific call. */ + +static void +gld${EMULATION_NAME}_finish (void) +{ + /* e_entry on PowerPC64 points to the function descriptor for + _start. If _start is missing, default to the first function + descriptor in the .opd section. */ + entry_section = ".opd"; + + if (link_info.relocatable) + { + asection *toc = bfd_get_section_by_name (link_info.output_bfd, ".toc"); + if (toc != NULL + && bfd_section_size (link_info.output_bfd, toc) > 0x10000) + einfo ("%X%P: TOC section size exceeds 64k\n"); + } + + if (stub_added) + { + char *msg = NULL; + char *line, *endline; + + if (emit_stub_syms < 0) + emit_stub_syms = 1; + if (!ppc64_elf_build_stubs (emit_stub_syms, &link_info, + config.stats ? &msg : NULL)) + einfo ("%X%P: can not build stubs: %E\n"); + + for (line = msg; line != NULL; line = endline) + { + endline = strchr (line, '\n'); + if (endline != NULL) + *endline++ = '\0'; + fprintf (stderr, "%s: %s\n", program_name, line); + } + if (msg != NULL) + free (msg); + } + + ppc64_elf_restore_symbols (&link_info); + finish_default (); +} + + +/* Add a pattern matching ".foo" for every "foo" in a version script. + + The reason for doing this is that many shared library version + scripts export a selected set of functions or data symbols, forcing + others local. eg. + + . VERS_1 { + . global: + . this; that; some; thing; + . local: + . *; + . }; + + To make the above work for PowerPC64, we need to export ".this", + ".that" and so on, otherwise only the function descriptor syms are + exported. Lack of an exported function code sym may cause a + definition to be pulled in from a static library. */ + +static struct bfd_elf_version_expr * +gld${EMULATION_NAME}_new_vers_pattern (struct bfd_elf_version_expr *entry) +{ + struct bfd_elf_version_expr *dot_entry; + unsigned int len; + char *dot_pat; + + if (!dotsyms + || entry->pattern[0] == '.' + || (!entry->literal && entry->pattern[0] == '*')) + return entry; + + dot_entry = xmalloc (sizeof *dot_entry); + *dot_entry = *entry; + dot_entry->next = entry; + len = strlen (entry->pattern) + 2; + dot_pat = xmalloc (len); + dot_pat[0] = '.'; + memcpy (dot_pat + 1, entry->pattern, len - 1); + dot_entry->pattern = dot_pat; + dot_entry->script = 1; + return dot_entry; +} + + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void ppc_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +ppc_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&ppc_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file ppc_lang_for_each_input_file + +EOF + +if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then + fragment <<EOF +/* Special handling for embedded SPU executables. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); +static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); + +static bfd_boolean +ppc64_recognized_file (lang_input_statement_type *entry) +{ + if (embedded_spu_file (entry, "-m64")) + return TRUE; + + return gld${EMULATION_NAME}_load_symbols (entry); +} +EOF +LDEMUL_RECOGNIZED_FILE=ppc64_recognized_file +fi + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_STUBGROUP_SIZE 301 +#define OPTION_STUBSYMS (OPTION_STUBGROUP_SIZE + 1) +#define OPTION_NO_STUBSYMS (OPTION_STUBSYMS + 1) +#define OPTION_DOTSYMS (OPTION_NO_STUBSYMS + 1) +#define OPTION_NO_DOTSYMS (OPTION_DOTSYMS + 1) +#define OPTION_NO_TLS_OPT (OPTION_NO_DOTSYMS + 1) +#define OPTION_NO_TLS_GET_ADDR_OPT (OPTION_NO_TLS_OPT + 1) +#define OPTION_NO_OPD_OPT (OPTION_NO_TLS_GET_ADDR_OPT + 1) +#define OPTION_NO_TOC_OPT (OPTION_NO_OPD_OPT + 1) +#define OPTION_NO_MULTI_TOC (OPTION_NO_TOC_OPT + 1) +#define OPTION_NO_TOC_SORT (OPTION_NO_MULTI_TOC + 1) +#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_TOC_SORT + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE }, + { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS }, + { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS }, + { "dotsyms", no_argument, NULL, OPTION_DOTSYMS }, + { "no-dotsyms", no_argument, NULL, OPTION_NO_DOTSYMS }, + { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, + { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT }, + { "no-opd-optimize", no_argument, NULL, OPTION_NO_OPD_OPT }, + { "no-toc-optimize", no_argument, NULL, OPTION_NO_TOC_OPT }, + { "no-multi-toc", no_argument, NULL, OPTION_NO_MULTI_TOC }, + { "no-toc-sort", no_argument, NULL, OPTION_NO_TOC_SORT }, + { "non-overlapping-opd", no_argument, NULL, OPTION_NON_OVERLAPPING_OPD }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --stub-group-size=N Maximum size of a group of input sections that\n\ + can be handled by one stub section. A negative\n\ + value locates all stubs before their branches\n\ + (with a group size of -N), while a positive\n\ + value allows two groups of input sections, one\n\ + before, and one after each stub section.\n\ + Values of +/-1 indicate the linker should\n\ + choose suitable defaults.\n" + )); + fprintf (file, _("\ + --emit-stub-syms Label linker stubs with a symbol.\n" + )); + fprintf (file, _("\ + --no-emit-stub-syms Don'\''t label linker stubs with a symbol.\n" + )); + fprintf (file, _("\ + --dotsyms For every version pattern \"foo\" in a version\n\ + script, add \".foo\" so that function code\n\ + symbols are treated the same as function\n\ + descriptor symbols. Defaults to on.\n" + )); + fprintf (file, _("\ + --no-dotsyms Don'\''t do anything special in version scripts.\n" + )); + fprintf (file, _("\ + --no-tls-optimize Don'\''t try to optimize TLS accesses.\n" + )); + fprintf (file, _("\ + --no-tls-get-addr-optimize Don'\''t use a special __tls_get_addr call.\n" + )); + fprintf (file, _("\ + --no-opd-optimize Don'\''t optimize the OPD section.\n" + )); + fprintf (file, _("\ + --no-toc-optimize Don'\''t optimize the TOC section.\n" + )); + fprintf (file, _("\ + --no-multi-toc Disallow automatic multiple toc sections.\n" + )); + fprintf (file, _("\ + --no-toc-sort Don'\''t sort TOC and GOT sections.\n" + )); + fprintf (file, _("\ + --non-overlapping-opd Canonicalize .opd, so that there are no\n\ + overlapping .opd entries.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_STUBGROUP_SIZE: + { + const char *end; + group_size = bfd_scan_vma (optarg, &end, 0); + if (*end) + einfo (_("%P%F: invalid number `%s'\''\n"), optarg); + } + break; + + case OPTION_STUBSYMS: + emit_stub_syms = 1; + break; + + case OPTION_NO_STUBSYMS: + emit_stub_syms = 0; + break; + + case OPTION_DOTSYMS: + dotsyms = 1; + break; + + case OPTION_NO_DOTSYMS: + dotsyms = 0; + break; + + case OPTION_NO_TLS_OPT: + no_tls_opt = 1; + break; + + case OPTION_NO_TLS_GET_ADDR_OPT: + no_tls_get_addr_opt = 1; + break; + + case OPTION_NO_OPD_OPT: + no_opd_opt = 1; + break; + + case OPTION_NO_TOC_OPT: + no_toc_opt = 1; + break; + + case OPTION_NO_MULTI_TOC: + no_multi_toc = 1; + break; + + case OPTION_NO_TOC_SORT: + no_toc_sort = 1; + break; + + case OPTION_NON_OVERLAPPING_OPD: + non_overlapping_opd = 1; + break; +' + +# Put these extra ppc64elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation +LDEMUL_FINISH=gld${EMULATION_NAME}_finish +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=ppc_create_output_section_statements +LDEMUL_NEW_VERS_PATTERN=gld${EMULATION_NAME}_new_vers_pattern diff --git a/binutils-2.21/ld/emultempl/rxelf.em b/binutils-2.21/ld/emultempl/rxelf.em new file mode 100644 index 0000000..c4a2dac --- /dev/null +++ b/binutils-2.21/ld/emultempl/rxelf.em @@ -0,0 +1,64 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. +# + +# This file is sourced from elf32.em, and defines extra rx-elf +# specific routines. +# +test -z "$TARGET2_TYPE" && TARGET2_TYPE="rel" +fragment <<EOF + +static bfd_boolean no_flag_mismatch_warnings = FALSE; + +/* This is a convenient point to tell BFD about target specific flags. + After the output has been created, but before inputs are read. */ +static void +rx_elf_create_output_section_statements (void) +{ + extern void bfd_elf32_rx_set_target_flags (bfd_boolean); + + bfd_elf32_rx_set_target_flags (no_flag_mismatch_warnings); +} + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_NO_FLAG_MISMATCH_WARNINGS 301 +' + +PARSE_AND_LIST_LONGOPTS=' + { "no-flag-mismatch-warnings", no_argument, NULL, OPTION_NO_FLAG_MISMATCH_WARNINGS}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --no-flag-mismatch-warnings Don'\''t warn about objects with incompatible" + " endian or dsp settings\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_NO_FLAG_MISMATCH_WARNINGS: + no_flag_mismatch_warnings = TRUE; + break; +' + +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=rx_elf_create_output_section_statements diff --git a/binutils-2.21/ld/emultempl/scoreelf.em b/binutils-2.21/ld/emultempl/scoreelf.em new file mode 100644 index 0000000..897147e --- /dev/null +++ b/binutils-2.21/ld/emultempl/scoreelf.em @@ -0,0 +1,77 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Contributed by: +# Brain.lin (brain.lin@sunplusct.com) +# Mei Ligang (ligang@sunnorth.com.cn) +# Pei-Lin Tsai (pltsai@sunplus.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 is sourced from elf32.em, and defines extra score-elf +# specific routines. +# +fragment <<EOF + +#include "elf32-score.h" + +static void +gld${EMULATION_NAME}_before_parse () +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ + config.dynamic_link = ${DYNAMIC_LINK-TRUE}; + config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; +} + +static void +score_elf_after_open (void) +{ + if (strstr (bfd_get_target (link_info.output_bfd), "score") == NULL) + { + /* The score backend needs special fields in the output hash structure. + These will only be created if the output format is an score 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 S+core binaries\n"); + return; + } + + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_open (); +} + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE='' +PARSE_AND_LIST_SHORTOPTS= +PARSE_AND_LIST_LONGOPTS='' +PARSE_AND_LIST_OPTIONS='' +PARSE_AND_LIST_ARGS_CASES='' + +# We have our own after_open and before_allocation functions, but they call +# the standard routines, so give them a different name. +LDEMUL_AFTER_OPEN=score_elf_after_open + +# Replace the elf before_parse function with our own. +LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse + diff --git a/binutils-2.21/ld/emultempl/sh64elf.em b/binutils-2.21/ld/emultempl/sh64elf.em new file mode 100644 index 0000000..17f9dde --- /dev/null +++ b/binutils-2.21/ld/emultempl/sh64elf.em @@ -0,0 +1,561 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2000, 2001, 2002, 2003, 2004, 2005, 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. +# + +# This file is sourced from elf32.em, and defines extra sh64 +# specific routines. +# + +LDEMUL_AFTER_ALLOCATION=sh64_elf_${EMULATION_NAME}_after_allocation +LDEMUL_BEFORE_ALLOCATION=sh64_elf_${EMULATION_NAME}_before_allocation + +fragment <<EOF + +#include "libiberty.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/sh.h" +#include "elf32-sh64.h" + +/* Check if we need a .cranges section and create it if it's not in any + input file. It might seem better to always create it and if unneeded, + discard it, but I don't find a simple way to discard it totally from + the output. + + Putting it here instead of as a elf_backend_always_size_sections hook + in elf32-sh64.c, means that we have access to linker command line + options here, and we can access input sections in the order in which + they will be linked. */ + +static void +sh64_elf_${EMULATION_NAME}_before_allocation (void) +{ + asection *cranges; + asection *osec; + + /* Call main function; we're just extending it. */ + gld${EMULATION_NAME}_before_allocation (); + + cranges = bfd_get_section_by_name (link_info.output_bfd, + SH64_CRANGES_SECTION_NAME); + + if (cranges != NULL) + { + if (RELAXATION_ENABLED) + { + /* FIXME: Look through incoming sections with .cranges + descriptors, build up some kind of descriptors that the + relaxing function will pick up and adjust, or perhaps make it + find and adjust an associated .cranges descriptor. We could + also look through incoming relocs and kill the ones marking + relaxation areas, but that wouldn't be TRT. */ + einfo + (_("%P: Sorry, turning off relaxing: .cranges section in input.\n")); + einfo (_(" A .cranges section is present in:\n")); + + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *input_cranges + = bfd_get_section_by_name (f->the_bfd, + SH64_CRANGES_SECTION_NAME); + if (input_cranges != NULL) + einfo (" %I\n", f); + } + } + + DISABLE_RELAXATION; + } + + /* We wouldn't need to do anything when there's already a .cranges + section (and have a return here), except that we need to set the + section flags right for output sections that *don't* need a + .cranges section. */ + } + + if (RELAXATION_ENABLED) + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + if (bfd_get_flavour (f->the_bfd) == bfd_target_elf_flavour) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) + { + einfo (_("%P: Sorry, turning off relaxing: SHmedia sections present.\n")); + einfo (" %I\n", f); + DISABLE_RELAXATION; + goto done_scanning_shmedia_sections; + } + } + } + } + } + done_scanning_shmedia_sections: + + /* For each non-empty input section in each output section, check if it + has the same SH64-specific flags. If some input section differs, we + need a .cranges section. */ + for (osec = link_info.output_bfd->sections; + osec != NULL; + osec = osec->next) + { + struct sh64_section_data *sh64_sec_data; + bfd_vma oflags_isa = 0; + bfd_vma iflags_isa = 0; + + if (bfd_get_flavour (link_info.output_bfd) != bfd_target_elf_flavour) + einfo (_("%FError: non-ELF output formats are not supported by this target's linker.\n")); + + sh64_sec_data = sh64_elf_section_data (osec)->sh64_info; + + /* Omit excluded or garbage-collected sections. */ + if (bfd_get_section_flags (link_info.output_bfd, osec) & SEC_EXCLUDE) + continue; + + /* Make sure we have the target section data initialized. */ + if (sh64_sec_data == NULL) + { + sh64_sec_data = xcalloc (1, sizeof (struct sh64_section_data)); + sh64_elf_section_data (osec)->sh64_info = sh64_sec_data; + } + + /* First find an input section so we have flags to compare with; the + flags in the output section are not valid. */ + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0) + { + oflags_isa + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + goto break_1; + } + } + } + } + + break_1: + + /* Check that all input sections have the same contents-type flags + as the first input section. */ + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0) + { + iflags_isa + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + + /* If flags don't agree, we need a .cranges section. + Create it here if it did not exist through input + sections. */ + if (iflags_isa != oflags_isa) + { + if (cranges == NULL) + { + /* This section will be *appended* to + sections, so the outer iteration will reach + it in due time and set + sh64_elf_section_data; no need to set it + specifically here. */ + cranges + = bfd_make_section_with_flags (link_info.output_bfd, + SH64_CRANGES_SECTION_NAME, + SEC_LINKER_CREATED + | SEC_KEEP + | SEC_HAS_CONTENTS + | SEC_DEBUGGING); + if (cranges == NULL) + einfo + (_("%P%E%F: Can't make .cranges section\n")); + } + + /* We don't need to look at more input sections, + and we know this section will have mixed + contents. */ + goto break_2; + } + } + } + } + } + + /* If we got here, then all input sections in this output section + have the same contents flag. Put that where we expect to see + contents flags. We don't need to do this for sections that will + need additional, linker-generated .cranges entries. */ + sh64_sec_data->contents_flags = iflags_isa; + + break_2: + ; + } +} + +/* Size up and extend the .cranges section, merging generated entries. */ + +static void +sh64_elf_${EMULATION_NAME}_after_allocation (void) +{ + bfd_vma new_cranges = 0; + bfd_vma cranges_growth = 0; + asection *osec; + bfd_byte *crangesp; + asection *cranges; + + gld${EMULATION_NAME}_after_allocation (); + + cranges = bfd_get_section_by_name (link_info.output_bfd, + SH64_CRANGES_SECTION_NAME); + + /* If there is no .cranges section, it is because it was seen earlier on + that none was needed. Otherwise it must have been created then, or + be present in input. */ + if (cranges == NULL) + return; + + /* First, we set the ISA flags for each output section according to the + first non-discarded section. For each input section in osec, we + check if it has the same flags. If it does not, we set flags to mark + a mixed section (and exit the loop early). */ + for (osec = link_info.output_bfd->sections; + osec != NULL; + osec = osec->next) + { + bfd_vma oflags_isa = 0; + bfd_boolean need_check_cranges = FALSE; + + /* Omit excluded or garbage-collected sections. */ + if (bfd_get_section_flags (link_info.output_bfd, osec) & SEC_EXCLUDE) + continue; + + /* First find an input section so we have flags to compare with; the + flags in the output section are not valid. */ + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0) + { + oflags_isa + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + goto break_1; + } + } + } + } + + break_1: + + /* Check that all input sections have the same contents-type flags + as the first input section. */ + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0) + { + bfd_vma iflags_isa + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + + /* If flags don't agree, set the target-specific data + of the section to mark that this section needs to + be have .cranges section entries added. Don't + bother setting ELF section flags in output section; + they will be cleared later and will have to be + re-initialized before the linked file is written. */ + if (iflags_isa != oflags_isa) + { + oflags_isa = SHF_SH5_ISA32_MIXED; + + BFD_ASSERT (sh64_elf_section_data (osec)->sh64_info); + + sh64_elf_section_data (osec)->sh64_info->contents_flags + = SHF_SH5_ISA32_MIXED; + need_check_cranges = TRUE; + goto break_2; + } + } + } + } + } + + break_2: + + /* If there were no new ranges for this output section, we don't + need to iterate over the input sections to check how many are + needed. */ + if (! need_check_cranges) + continue; + + /* If we found a section with differing contents type, we need more + ranges to mark the sections that are not mixed (and already have + .cranges descriptors). Calculate the maximum number of new + entries here. We may merge some of them, so that number is not + final; it can shrink. */ + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0 + && ((elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) + != SHF_SH5_ISA32_MIXED)) + new_cranges++; + } + } + } + } + + if (cranges->contents != NULL) + free (cranges->contents); + + BFD_ASSERT (sh64_elf_section_data (cranges)->sh64_info != NULL); + + /* Make sure we have .cranges in memory even if there were only + assembler-generated .cranges. */ + cranges_growth = new_cranges * SH64_CRANGE_SIZE; + cranges->contents = xcalloc (cranges->size + cranges_growth, 1); + bfd_set_section_flags (cranges->owner, cranges, + bfd_get_section_flags (cranges->owner, cranges) + | SEC_IN_MEMORY); + + /* If we don't need to grow the .cranges section beyond what was in the + input sections, we have nothing more to do here. We then only got + here because there was a .cranges section coming from input. Zero + out the number of generated .cranges. */ + if (new_cranges == 0) + { + sh64_elf_section_data (cranges)->sh64_info->cranges_growth = 0; + return; + } + + crangesp = cranges->contents + cranges->size; + + /* Now pass over the sections again, and make reloc orders for the new + .cranges entries. Constants are set as we go. */ + for (osec = link_info.output_bfd->sections; + osec != NULL; + osec = osec->next) + { + struct bfd_link_order *cr_addr_order = NULL; + enum sh64_elf_cr_type last_cr_type = CRT_NONE; + bfd_vma last_cr_size = 0; + bfd_vma continuation_vma = 0; + + /* Omit excluded or garbage-collected sections, and output sections + which were not marked as needing further processing. */ + if ((bfd_get_section_flags (link_info.output_bfd, osec) & SEC_EXCLUDE) != 0 + || (sh64_elf_section_data (osec)->sh64_info->contents_flags + != SHF_SH5_ISA32_MIXED)) + continue; + + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *isec; + + for (isec = f->the_bfd->sections; + isec != NULL; + isec = isec->next) + { + /* Allow only sections that have (at least initially) a + non-zero size, and are not excluded, and are not marked + as containing mixed data, thus already having .cranges + entries. */ + if (isec->output_section == osec + && isec->size != 0 + && (bfd_get_section_flags (isec->owner, isec) + & SEC_EXCLUDE) == 0 + && ((elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) + != SHF_SH5_ISA32_MIXED)) + { + enum sh64_elf_cr_type cr_type; + bfd_vma cr_size; + bfd_vma isa_flags + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + + if (isa_flags == SHF_SH5_ISA32) + cr_type = CRT_SH5_ISA32; + else if ((bfd_get_section_flags (isec->owner, isec) + & SEC_CODE) == 0) + cr_type = CRT_DATA; + else + cr_type = CRT_SH5_ISA16; + + cr_size = isec->size; + + /* Sections can be empty, like .text in a file that + only contains other sections. Ranges shouldn't be + emitted for them. This can presumably happen after + relaxing and is not be caught at the "raw size" + test above. */ + if (cr_size == 0) + continue; + + /* See if this is a continuation of the previous range + for the same output section. If so, just change + the size of the last range and continue. */ + if (cr_type == last_cr_type + && (continuation_vma + == osec->vma + isec->output_offset)) + { + last_cr_size += cr_size; + bfd_put_32 (link_info.output_bfd, last_cr_size, + crangesp - SH64_CRANGE_SIZE + + SH64_CRANGE_CR_SIZE_OFFSET); + + continuation_vma += cr_size; + continue; + } + + /* If we emit relocatable contents, we need a + relocation for the start address. */ + if (link_info.relocatable || link_info.emitrelocations) + { + /* FIXME: We could perhaps use lang_add_reloc and + friends here, but I'm not really sure that + would leave us free to do some optimizations + later. */ + cr_addr_order + = bfd_new_link_order (link_info.output_bfd, cranges); + + if (cr_addr_order == NULL) + { + einfo (_("%P%F: bfd_new_link_order failed\n")); + return; + } + + cr_addr_order->type = bfd_section_reloc_link_order; + cr_addr_order->offset + = (cranges->output_offset + + crangesp + SH64_CRANGE_CR_ADDR_OFFSET + - cranges->contents); + cr_addr_order->size = 4; + cr_addr_order->u.reloc.p + = xmalloc (sizeof (struct bfd_link_order_reloc)); + + cr_addr_order->u.reloc.p->reloc = BFD_RELOC_32; + cr_addr_order->u.reloc.p->u.section = osec; + + /* Since SH, unlike normal RELA-targets, uses a + "partial inplace" REL-like relocation for this, + we put the addend in the contents and specify 0 + for the reloc. */ + bfd_put_32 (link_info.output_bfd, isec->output_offset, + crangesp + SH64_CRANGE_CR_ADDR_OFFSET); + cr_addr_order->u.reloc.p->addend = 0; + } + else + bfd_put_32 (link_info.output_bfd, + osec->vma + isec->output_offset, + crangesp + SH64_CRANGE_CR_ADDR_OFFSET); + + /* If we could make a reloc for cr_size we would do + it, but we would have to have a symbol for the size + of the _input_ section and there's no way to + generate that. */ + bfd_put_32 (link_info.output_bfd, cr_size, + crangesp + SH64_CRANGE_CR_SIZE_OFFSET); + + bfd_put_16 (link_info.output_bfd, cr_type, + crangesp + SH64_CRANGE_CR_TYPE_OFFSET); + + last_cr_type = cr_type; + last_cr_size = cr_size; + continuation_vma + = osec->vma + isec->output_offset + cr_size; + crangesp += SH64_CRANGE_SIZE; + } + } + } + } + } + + /* The .cranges section will have this size, no larger or smaller. + Since relocs (if relocatable linking) will be emitted into the + "extended" size, we must set the raw size to the total. We have to + keep track of the number of new .cranges entries. + + Sorting before writing is done by sh64_elf_final_write_processing. */ + + sh64_elf_section_data (cranges)->sh64_info->cranges_growth + = crangesp - cranges->contents - cranges->size; + cranges->size = crangesp - cranges->contents; + cranges->rawsize = cranges->size; +} +EOF + + diff --git a/binutils-2.21/ld/emultempl/solaris2.em b/binutils-2.21/ld/emultempl/solaris2.em new file mode 100644 index 0000000..0b77375 --- /dev/null +++ b/binutils-2.21/ld/emultempl/solaris2.em @@ -0,0 +1,154 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is generated by a shell script. DO NOT EDIT! */ + +/* Solaris 2 emulation code for ${EMULATION_NAME} + Copyright 2010 Free Software Foundation, Inc. + Written by Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +/* The Solaris 2 ABI requires some global symbols to be present in the + .dynsym table of executables and shared objects. If generating a + versioned shared object, they must always be bound to the base version. + + Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output + File, p.63. */ +static void +elf_solaris2_before_allocation (void) +{ + /* Global symbols required by the Solaris 2 ABI. */ + static const char *global_syms[] = { + "_DYNAMIC", + "_GLOBAL_OFFSET_TABLE_", + "_PROCEDURE_LINKAGE_TABLE_", + "_edata", + "_end", + "_etext", + NULL + }; + const char **sym; + + /* Do this for both executables and shared objects. */ + if (!link_info.relocatable) + { + for (sym = global_syms; *sym != NULL; sym++) + { + struct elf_link_hash_entry *h; + + /* Lookup symbol. */ + h = elf_link_hash_lookup (elf_hash_table (&link_info), *sym, + FALSE, FALSE, FALSE); + if (h == NULL) + continue; + + /* Undo the hiding done by _bfd_elf_define_linkage_sym. */ + h->forced_local = 0; + h->other &= ~STV_HIDDEN; + + /* Emit it into the .dynamic section, too. */ + bfd_elf_link_record_dynamic_symbol (&link_info, h); + } + } + + /* Only do this if emitting a shared object and versioning is in place. */ + if (link_info.shared + && (lang_elf_version_info != NULL || link_info.create_default_symver)) + { + struct bfd_elf_version_expr *globals = NULL, *locals = NULL; + struct bfd_elf_version_tree *basever; + const char *soname; + + for (sym = global_syms; *sym != NULL; sym++) + { + /* Create a version pattern for this symbol. Some of them start + off as local, others as global, so try both. */ + globals = lang_new_vers_pattern (globals, *sym, NULL, TRUE); + locals = lang_new_vers_pattern (locals, *sym, NULL, TRUE); + } + + /* New version node for those symbols. */ + basever = lang_new_vers_node (globals, locals); + + /* The version name matches what bfd_elf_size_dynamic_sections uses + for the base version. */ + soname = bfd_elf_get_dt_soname (link_info.output_bfd); + if (soname == NULL) + soname = lbasename (bfd_get_filename (link_info.output_bfd)); + + /* Register the node. */ + lang_register_vers_node (soname, basever, NULL); + /* Enforce base version. The encoded vd_ndx is vernum + 1. */ + basever->vernum = 0; + } + + gld${EMULATION_NAME}_before_allocation (); +} + +/* The Solaris 2 ABI requires two local symbols to be emitted for every + executable and shared object. + + Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output + File, p.63. */ +static void +elf_solaris2_after_allocation (void) +{ + /* Local symbols required by the Solaris 2 ABI. Already emitted by + emulparams/solaris2.sh. */ + static const char *local_syms[] = { + "_START_", + "_END_", + NULL + }; + const char **sym; + + /* Do this for both executables and shared objects. */ + if (!link_info.relocatable) + { + for (sym = local_syms; *sym != NULL; sym++) + { + struct elf_link_hash_entry *h; + + /* Lookup symbol. */ + h = elf_link_hash_lookup (elf_hash_table (&link_info), *sym, + FALSE, FALSE, FALSE); + if (h == NULL) + continue; + + /* Turn it local. */ + h->forced_local = 1; + /* Type should be STT_OBJECT, not STT_NOTYPE. */ + h->type = STT_OBJECT; + } + } + + gld${EMULATION_NAME}_after_allocation (); +} + +EOF + +LDEMUL_BEFORE_ALLOCATION=elf_solaris2_before_allocation +LDEMUL_AFTER_ALLOCATION=elf_solaris2_after_allocation diff --git a/binutils-2.21/ld/emultempl/spu_icache.S b/binutils-2.21/ld/emultempl/spu_icache.S new file mode 100644 index 0000000..12eb7f1 --- /dev/null +++ b/binutils-2.21/ld/emultempl/spu_icache.S @@ -0,0 +1,7 @@ + .text + .global __icache_br_handler +__icache_br_handler: + stop + .global __icache_call_handler +__icache_call_handler: + stop diff --git a/binutils-2.21/ld/emultempl/spu_icache.o_c b/binutils-2.21/ld/emultempl/spu_icache.o_c new file mode 100644 index 0000000..2006fe2 --- /dev/null +++ b/binutils-2.21/ld/emultempl/spu_icache.o_c @@ -0,0 +1,33 @@ +0x7f,0x45,0x4c,0x46,0x01,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x28, +0x00,0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x73,0x79, +0x6d,0x74,0x61,0x62,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x73,0x68, +0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x2e,0x64,0x61, +0x74,0x61,0x00,0x2e,0x62,0x73,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x2c, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04, +0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe0,0x00,0x00,0x00,0x2b, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x02, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x03, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x01, +0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x01, +0x00,0x5f,0x5f,0x69,0x63,0x61,0x63,0x68,0x65,0x5f,0x62,0x72,0x5f,0x68,0x61,0x6e, +0x64,0x6c,0x65,0x72,0x00,0x5f,0x5f,0x69,0x63,0x61,0x63,0x68,0x65,0x5f,0x63,0x61, +0x6c,0x6c,0x5f,0x68,0x61,0x6e,0x64,0x6c,0x65,0x72,0x00, diff --git a/binutils-2.21/ld/emultempl/spu_ovl.S b/binutils-2.21/ld/emultempl/spu_ovl.S new file mode 100644 index 0000000..509397a --- /dev/null +++ b/binutils-2.21/ld/emultempl/spu_ovl.S @@ -0,0 +1,471 @@ +/* Overlay manager for SPU. + + Copyright 2006, 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. */ + +/* MFC DMA defn's. */ +#define MFC_GET_CMD 0x40 +#define MFC_MAX_DMA_SIZE 0x4000 +#define MFC_TAG_UPDATE_ALL 2 +#define MFC_TAG_ID 0 + +/* Register usage. */ +#define reserved1 $75 +#define parm $75 +#define tab1 reserved1 +#define tab2 reserved1 +#define vma reserved1 +#define oldvma reserved1 +#define newmask reserved1 +#define map reserved1 + +#define reserved2 $76 +#define off1 reserved2 +#define off2 reserved2 +#define present1 reserved2 +#define present2 reserved2 +#define sz reserved2 +#define cmp reserved2 +#define add64 reserved2 +#define cgbits reserved2 +#define off3 reserved2 +#define off4 reserved2 +#define addr4 reserved2 +#define off5 reserved2 +#define tagstat reserved2 + +#define reserved3 $77 +#define size1 reserved3 +#define size2 reserved3 +#define rv3 reserved3 +#define ealo reserved3 +#define cmd reserved3 +#define off64 reserved3 +#define tab3 reserved3 +#define tab4 reserved3 +#define tab5 reserved3 + +#define reserved4 $78 +#define ovl reserved4 +#define rv2 reserved4 +#define rv5 reserved4 +#define cgshuf reserved4 +#define newovl reserved4 +#define irqtmp1 reserved4 +#define irqtmp2 reserved4 + +#define reserved5 $79 +#define target reserved5 + +#define save1 $74 +#define rv4 save1 +#define rv7 save1 +#define tagid save1 +#define maxsize save1 +#define pbyte save1 +#define pbit save1 + +#define save2 $73 +#define cur save2 +#define rv6 save2 +#define osize save2 +#define zovl save2 +#define oldovl save2 +#define newvma save2 + +#define save3 $72 +#define rv1 save3 +#define ea64 save3 +#define buf3 save3 +#define genwi save3 +#define newmap save3 +#define oldmask save3 + +#define save4 $71 +#define irq_stat save4 + + .text + .align 4 + .type __rv_pattern, @object + .size __rv_pattern, 16 +__rv_pattern: + .word 0x00010203, 0x10111213, 0x80808080, 0x80808080 + + .type __cg_pattern, @object + .size __cg_pattern, 16 +__cg_pattern: + .word 0x04050607, 0x80808080, 0x80808080, 0x80808080 + + .type __ovly_current, @object + .size __ovly_current, 16 +__ovly_current: + .space 16 + +/* + * __ovly_return - stub for returning from overlay functions. + * + * On entry the four slots of $lr are: + * __ovly_return, prev ovl index, caller return addr, undefined. + * + * Load the previous overlay and jump to the caller return address. + * Updates __ovly_current. + */ + .align 4 + .global __ovly_return + .type __ovly_return, @function +__ovly_return: + ila tab1, _ovly_table - 16 # 0,2 0 + shlqbyi ovl, $lr, 4 # 1,4 0 +#nop + shlqbyi target, $lr, 8 # 1,4 1 +#nop; lnop +#nop; lnop + shli off1, ovl, 4 # 0,4 4 +#lnop +#nop + hbr ovly_ret9, target # 1,15 5 +#nop; lnop +#nop; lnop +#nop + lqx vma, tab1, off1 # 1,6 8 +#ifdef OVLY_IRQ_SAVE + nop + stqd save4, -64($sp) # 1,6 9 +#else +#nop; lnop +#endif +#nop; lnop +#nop; lnop +#nop; lnop +#nop; lnop +#nop + rotqbyi size1, vma, 4 # 1,4 14 +#nop + stqd save3, -48($sp) # 1,6 15 +#nop + stqd save2, -32($sp) # 1,6 16 +#nop + stqd save1, -16($sp) # 1,6 17 + andi present1, size1, 1 # 0,2 18 + stqr ovl, __ovly_current # 1,6 18 +#nop; lnop +#nop + brz present1, do_load # 1,4 20 +ovly_ret9: +#nop + bi target # 1,4 21 + +/* + * __ovly_load - copy an overlay partion to local store. + * + * On entry $75 points to a word consisting of the overlay index in + * the top 14 bits, and the target address in the bottom 18 bits. + * + * Sets up $lr to return via __ovly_return. If $lr is already set + * to return via __ovly_return, don't change it. In that case we + * have a tail call from one overlay function to another. + * Updates __ovly_current. + */ + .align 3 + .global __ovly_load + .type __ovly_load, @function +__ovly_load: +#if OVL_STUB_SIZE == 8 +######## +#nop + lqd target, 0(parm) # 1,6 -11 +#nop; lnop +#nop; lnop +#nop; lnop +#nop; lnop +#nop; lnop +#nop + rotqby target, target, parm # 1,4 -5 + ila tab2, _ovly_table - 16 # 0,2 -4 + stqd save3, -48($sp) # 1,6 -4 +#nop + stqd save2, -32($sp) # 1,6 -3 +#nop + stqd save1, -16($sp) # 1,6 -2 + rotmi ovl, target, -18 # 0,4 -1 + hbr ovly_load9, target # 1,15 -1 + ila rv1, __ovly_return # 0,2 0 +#lnop +#nop; lnop +#nop + lqr cur, __ovly_current # 1,6 2 + shli off2, ovl, 4 # 0,4 3 + stqr ovl, __ovly_current # 1,6 3 + ceq rv2, $lr, rv1 # 0,2 4 + lqr rv3, __rv_pattern # 1,6 4 +#nop; lnop +#nop; lnop +#nop + lqx vma, tab2, off2 # 1,6 7 +######## +#else /* OVL_STUB_SIZE == 16 */ +######## + ila tab2, _ovly_table - 16 # 0,2 0 + stqd save3, -48($sp) # 1,6 0 + ila rv1, __ovly_return # 0,2 1 + stqd save2, -32($sp) # 1,6 1 + shli off2, ovl, 4 # 0,4 2 + lqr cur, __ovly_current # 1,6 2 + nop + stqr ovl, __ovly_current # 1,6 3 + ceq rv2, $lr, rv1 # 0,2 4 + lqr rv3, __rv_pattern # 1,6 4 +#nop + hbr ovly_load9, target # 1,15 5 +#nop + lqx vma, tab2, off2 # 1,6 6 +#nop + stqd save1, -16($sp) # 1,6 7 +######## +#endif + +#nop; lnop +#nop; lnop +#nop + shufb rv4, rv1, cur, rv3 # 1,4 10 +#nop + fsmb rv5, rv2 # 1,4 11 +#nop + rotqmbyi rv6, $lr, -8 # 1,4 12 +#nop + rotqbyi size2, vma, 4 # 1,4 13 +#nop + lqd save3, -48($sp) # 1,6 14 +#nop; lnop + or rv7, rv4, rv6 # 0,2 16 + lqd save2, -32($sp) # 1,6 16 + andi present2, size2, 1 # 0,2 17 +#ifdef OVLY_IRQ_SAVE + stqd save4, -64($sp) # 1,6 17 +#else + lnop # 1,0 17 +#endif + selb $lr, rv7, $lr, rv5 # 0,2 18 + lqd save1, -16($sp) # 1,6 18 +#nop + brz present2, do_load # 1,4 19 +ovly_load9: +#nop + bi target # 1,4 20 + +/* If we get here, we are about to load a new overlay. + * "vma" contains the relevant entry from _ovly_table[]. + * extern struct { + * u32 vma; + * u32 size; + * u32 file_offset; + * u32 buf; + * } _ovly_table[]; + */ + .align 3 + .global __ovly_load_event + .type __ovly_load_event, @function +__ovly_load_event: +do_load: +#ifdef OVLY_IRQ_SAVE + ila irqtmp1, do_load10 # 0,2 -5 + rotqbyi sz, vma, 8 # 1,4 -5 +#nop + rdch irq_stat, $SPU_RdMachStat # 1,6 -4 +#nop + bid irqtmp1 # 1,4 -3 +do_load10: + nop +#else +#nop + rotqbyi sz, vma, 8 # 1,4 0 +#endif + rotqbyi osize, vma, 4 # 1,4 1 +#nop + lqa ea64, _EAR_ # 1,6 2 +#nop + lqr cgshuf, __cg_pattern # 1,6 3 + +/* We could predict the branch at the end of this loop by adding a few + instructions, and there are plenty of free cycles to do so without + impacting loop execution time. However, it doesn't make a great + deal of sense since we need to wait for the dma to complete anyway. */ +__ovly_xfer_loop: +#nop + rotqmbyi off64, sz, -4 # 1,4 4 +#nop; lnop +#nop; lnop +#nop; lnop + cg cgbits, ea64, off64 # 0,2 8 +#lnop +#nop; lnop +#nop + shufb add64, cgbits, cgbits, cgshuf # 1,4 10 +#nop; lnop +#nop; lnop +#nop; lnop + addx add64, ea64, off64 # 0,2 14 +#lnop + ila maxsize, MFC_MAX_DMA_SIZE # 0,2 15 + lnop + ori ea64, add64, 0 # 0,2 16 + rotqbyi ealo, add64, 4 # 1,4 16 + cgt cmp, osize, maxsize # 0,2 17 + wrch $MFC_LSA, vma # 1,6 17 +#nop; lnop + selb sz, osize, maxsize, cmp # 0,2 19 + wrch $MFC_EAH, ea64 # 1,6 19 + ila tagid, MFC_TAG_ID # 0,2 20 + wrch $MFC_EAL, ealo # 1,6 20 + ila cmd, MFC_GET_CMD # 0,2 21 + wrch $MFC_Size, sz # 1,6 21 + sf osize, sz, osize # 0,2 22 + wrch $MFC_TagId, tagid # 1,6 22 + a vma, vma, sz # 0,2 23 + wrch $MFC_Cmd, cmd # 1,6 23 +#nop + brnz osize, __ovly_xfer_loop # 1,4 24 + +/* Now update our data structions while waiting for DMA to complete. + Low bit of .size needs to be cleared on the _ovly_table entry + corresponding to the evicted overlay, and set on the entry for the + newly loaded overlay. Note that no overlay may in fact be evicted + as _ovly_buf_table[] starts with all zeros. Don't zap .size entry + for zero index! Also of course update the _ovly_buf_table entry. */ +#nop + lqr newovl, __ovly_current # 1,6 25 +#nop; lnop +#nop; lnop +#nop; lnop +#nop; lnop +#nop; lnop + shli off3, newovl, 4 # 0,4 31 +#lnop + ila tab3, _ovly_table - 16 # 0,2 32 +#lnop +#nop + fsmbi pbyte, 0x100 # 1,4 33 +#nop; lnop +#nop + lqx vma, tab3, off3 # 1,6 35 +#nop; lnop + andi pbit, pbyte, 1 # 0,2 37 + lnop +#nop; lnop +#nop; lnop +#nop; lnop + or newvma, vma, pbit # 0,2 41 + rotqbyi buf3, vma, 12 # 1,4 41 +#nop; lnop +#nop + stqx newvma, tab3, off3 # 1,6 43 +#nop; lnop + shli off4, buf3, 2 # 1,4 45 +#lnop + ila tab4, _ovly_buf_table - 4 # 0,2 46 +#lnop +#nop; lnop +#nop; lnop +#nop + lqx map, tab4, off4 # 1,6 49 +#nop + cwx genwi, tab4, off4 # 1,4 50 + a addr4, tab4, off4 # 0,2 51 +#lnop +#nop; lnop +#nop; lnop +#nop; lnop +#nop + rotqby oldovl, map, addr4 # 1,4 55 +#nop + shufb newmap, newovl, map, genwi # 0,4 56 +#if MFC_TAG_ID < 16 + ila newmask, 1 << MFC_TAG_ID # 0,2 57 +#else + ilhu newmask, 1 << (MFC_TAG_ID - 16) # 0,2 57 +#endif +#lnop +#nop; lnop +#nop; lnop + stqd newmap, 0(addr4) # 1,6 60 + +/* Save app's tagmask, wait for DMA complete, restore mask. */ + ila tagstat, MFC_TAG_UPDATE_ALL # 0,2 61 + rdch oldmask, $MFC_RdTagMask # 1,6 61 +#nop + wrch $MFC_WrTagMask, newmask # 1,6 62 +#nop + wrch $MFC_WrTagUpdate, tagstat # 1,6 63 +#nop + rdch tagstat, $MFC_RdTagStat # 1,6 64 +#nop + sync # 1,4 65 +/* Any hint prior to the sync is lost. A hint here allows the branch + to complete 15 cycles after the hint. With no hint the branch will + take 18 or 19 cycles. */ + ila tab5, _ovly_table - 16 # 0,2 66 + hbr do_load99, target # 1,15 66 + shli off5, oldovl, 4 # 0,4 67 + wrch $MFC_WrTagMask, oldmask # 1,6 67 + ceqi zovl, oldovl, 0 # 0,2 68 +#lnop +#nop; lnop +#nop + fsm zovl, zovl # 1,4 70 +#nop + lqx oldvma, tab5, off5 # 1,6 71 +#nop + lqd save3, -48($sp) # 1,6 72 +#nop; lnop + andc pbit, pbit, zovl # 0,2 74 + lqd save2, -32($sp) # 1,6 74 +#ifdef OVLY_IRQ_SAVE + ila irqtmp2, do_load90 # 0,2 75 +#lnop + andi irq_stat, irq_stat, 1 # 0,2 76 +#lnop +#else +#nop; lnop +#nop; lnop +#endif + andc oldvma, oldvma, pbit # 0,2 77 + lqd save1, -16($sp) # 1,6 77 + nop # 0,0 78 +#lnop +#nop + stqx oldvma, tab5, off5 # 1,6 79 +#nop +#ifdef OVLY_IRQ_SAVE + binze irq_stat, irqtmp2 # 1,4 80 +do_load90: +#nop + lqd save4, -64($sp) # 1,6 84 +#else +#nop; lnop +#endif + + .global _ovly_debug_event + .type _ovly_debug_event, @function +_ovly_debug_event: + nop +/* Branch to target address. */ +do_load99: + bi target # 1,4 81/85 + + .size __ovly_load, . - __ovly_load diff --git a/binutils-2.21/ld/emultempl/spu_ovl.o_c b/binutils-2.21/ld/emultempl/spu_ovl.o_c new file mode 100644 index 0000000..c9eff93 --- /dev/null +++ b/binutils-2.21/ld/emultempl/spu_ovl.o_c @@ -0,0 +1,101 @@ +0x7f,0x45,0x4c,0x46,0x01,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x02,0x74,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x28, +0x00,0x08,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x02,0x03,0x10,0x11,0x12,0x13,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x04,0x05,0x06,0x07,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x42,0x00,0x00,0x4b,0x3f,0xe1,0x00,0x4e,0x3f,0xe2,0x00,0x4f,0x0f,0x61,0x27,0x4c, +0x35,0x80,0x27,0x8b,0x38,0x93,0x25,0xcb,0x40,0x20,0x00,0x00,0x24,0xff,0x00,0xc7, +0x3f,0x81,0x25,0xcd,0x24,0xff,0x40,0xc8,0x24,0xff,0x80,0xc9,0x24,0xff,0xc0,0xca, +0x14,0x00,0x66,0xcc,0x23,0xff,0xf7,0xce,0x20,0x00,0x0e,0x4c,0x35,0x00,0x27,0x80, +0x42,0x00,0x00,0x4b,0x24,0xff,0x40,0xc8,0x42,0x00,0x00,0x48,0x24,0xff,0x80,0xc9, +0x0f,0x61,0x27,0x4c,0x33,0xff,0xf3,0xc9,0x40,0x20,0x00,0x00,0x23,0xff,0xf2,0xce, +0x78,0x12,0x00,0x4e,0x33,0xff,0xed,0xcd,0x35,0x80,0x27,0x8f,0x38,0x93,0x25,0xcb, +0x24,0xff,0xc0,0xca,0xb9,0x52,0x64,0x4d,0x36,0xc0,0x27,0x4e,0x3f,0xbe,0x00,0x49, +0x3f,0x81,0x25,0xcd,0x34,0xff,0x40,0xc8,0x08,0x32,0x65,0x4a,0x34,0xff,0x80,0xc9, +0x14,0x00,0x66,0xcc,0x24,0xff,0x00,0xc7,0x80,0x00,0x25,0x4e,0x34,0xff,0xc0,0xca, +0x20,0x00,0x01,0x4c,0x35,0x00,0x27,0x80,0x42,0x00,0x00,0x4e,0x3f,0x82,0x25,0xcc, +0x01,0xa0,0x06,0xc7,0x35,0x08,0x27,0x00,0x40,0x20,0x00,0x00,0x3f,0x81,0x25,0xc9, +0x30,0x80,0x00,0x48,0x33,0xff,0xe3,0xce,0x3f,0xbf,0x26,0x4d,0x18,0x53,0x64,0x4c, +0xb9,0x93,0x26,0x4e,0x68,0x13,0x64,0x4c,0x42,0x20,0x00,0x4a,0x00,0x20,0x00,0x00, +0x04,0x00,0x26,0x48,0x3f,0x81,0x26,0x4d,0x48,0x12,0xa4,0xcc,0x21,0xa0,0x08,0x4b, +0x89,0x92,0xa4,0xcc,0x21,0xa0,0x08,0xc8,0x42,0x00,0x00,0x4a,0x21,0xa0,0x09,0x4d, +0x42,0x00,0x20,0x4d,0x21,0xa0,0x09,0xcc,0x08,0x12,0x66,0x49,0x21,0xa0,0x0a,0x4a, +0x18,0x13,0x25,0xcb,0x21,0xa0,0x0a,0xcd,0x21,0x7f,0xf6,0x49,0x33,0xff,0xda,0xce, +0x0f,0x61,0x27,0x4c,0x42,0x00,0x00,0x4d,0x32,0x80,0x80,0x4a,0x38,0x93,0x26,0xcb, +0x14,0x00,0x65,0x4a,0x00,0x20,0x00,0x00,0x08,0x32,0xa5,0xc9,0x3f,0x83,0x25,0xc8, +0x28,0x93,0x26,0xc9,0x0f,0x60,0xa4,0x4c,0x42,0x00,0x00,0x4d,0x38,0x93,0x26,0xcb, +0x3a,0xd3,0x26,0xc8,0x18,0x13,0x26,0xcc,0x3b,0x93,0x25,0xc9,0xb9,0x12,0xe7,0x48, +0x42,0x00,0x00,0xcb,0x24,0x00,0x26,0x48,0x42,0x00,0x01,0x4c,0x01,0xa0,0x06,0x48, +0x21,0xa0,0x0b,0x4b,0x21,0xa0,0x0b,0xcc,0x01,0xa0,0x0c,0x4c,0x00,0x40,0x00,0x00, +0x42,0x00,0x00,0x4d,0x35,0x80,0x27,0x92,0x0f,0x61,0x24,0xcc,0x21,0xa0,0x0b,0x48, +0x7c,0x00,0x24,0xc9,0x36,0x80,0x24,0xc9,0x38,0x93,0x26,0xcb,0x34,0xff,0x40,0xc8, +0x58,0x32,0x65,0x4a,0x34,0xff,0x80,0xc9,0x42,0x00,0x00,0x4e,0x14,0x00,0x63,0xc7, +0x58,0x32,0xa5,0xcb,0x34,0xff,0xc0,0xca,0x40,0x20,0x00,0x00,0x28,0x93,0x26,0xcb, +0x25,0x24,0x27,0x47,0x34,0xff,0x00,0xc7,0x40,0x20,0x00,0x00,0x35,0x00,0x27,0x80, +0x00,0x2e,0x73,0x79,0x6d,0x74,0x61,0x62,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62, +0x00,0x2e,0x73,0x68,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x72,0x65,0x6c,0x61, +0x2e,0x74,0x65,0x78,0x74,0x00,0x2e,0x64,0x61,0x74,0x61,0x00,0x2e,0x62,0x73,0x73, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40, +0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xdc,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x06, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x26, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x40, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x40, +0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xb4,0x00,0x00,0x01,0x50,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x09, +0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x04, +0x00,0x00,0x00,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x10, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0xd8,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0xd4,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x62,0x00,0x00,0x01,0xfc,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6c,0x00,0x00,0x01,0xf4,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00, +0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0x70,0x00,0x00,0x01,0x90, +0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x9c,0x00,0x00,0x00,0xd8,0x00,0x00,0x00,0x00, +0x12,0x00,0x00,0x01,0x00,0x00,0x00,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xc4,0x00,0x00,0x01,0xf8,0x00,0x00,0x00,0x00, +0x12,0x00,0x00,0x01,0x00,0x5f,0x5f,0x72,0x76,0x5f,0x70,0x61,0x74,0x74,0x65,0x72, +0x6e,0x00,0x5f,0x5f,0x63,0x67,0x5f,0x70,0x61,0x74,0x74,0x65,0x72,0x6e,0x00,0x5f, +0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x63,0x75,0x72,0x72,0x65,0x6e,0x74,0x00,0x6f,0x76, +0x6c,0x79,0x5f,0x72,0x65,0x74,0x39,0x00,0x64,0x6f,0x5f,0x6c,0x6f,0x61,0x64,0x00, +0x6f,0x76,0x6c,0x79,0x5f,0x6c,0x6f,0x61,0x64,0x39,0x00,0x64,0x6f,0x5f,0x6c,0x6f, +0x61,0x64,0x31,0x30,0x00,0x5f,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x78,0x66,0x65,0x72, +0x5f,0x6c,0x6f,0x6f,0x70,0x00,0x64,0x6f,0x5f,0x6c,0x6f,0x61,0x64,0x39,0x39,0x00, +0x64,0x6f,0x5f,0x6c,0x6f,0x61,0x64,0x39,0x30,0x00,0x5f,0x5f,0x6f,0x76,0x6c,0x79, +0x5f,0x72,0x65,0x74,0x75,0x72,0x6e,0x00,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x74,0x61, +0x62,0x6c,0x65,0x00,0x5f,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x6c,0x6f,0x61,0x64,0x00, +0x5f,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x6c,0x6f,0x61,0x64,0x5f,0x65,0x76,0x65,0x6e, +0x74,0x00,0x5f,0x45,0x41,0x52,0x5f,0x00,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x62,0x75, +0x66,0x5f,0x74,0x61,0x62,0x6c,0x65,0x00,0x5f,0x6f,0x76,0x6c,0x79,0x5f,0x64,0x65, +0x62,0x75,0x67,0x5f,0x65,0x76,0x65,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x30, +0x00,0x00,0x0f,0x05,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x70,0x00,0x00,0x0f,0x05, +0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x78,0x00,0x00,0x0e,0x05,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xd8,0x00,0x00,0x01,0x05,0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0xf0, +0x00,0x00,0x12,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x54,0x00,0x00,0x0f,0x05, +0xff,0xff,0xff,0xf0,0x00,0x00,0x01,0x78,0x00,0x00,0x13,0x05,0xff,0xff,0xff,0xfc, +0x00,0x00,0x01,0xb0,0x00,0x00,0x0f,0x05,0xff,0xff,0xff,0xf0,0x00,0x00,0x01,0xd8, +0x00,0x00,0x01,0x05,0x00,0x00,0x01,0xf4, diff --git a/binutils-2.21/ld/emultempl/spuelf.em b/binutils-2.21/ld/emultempl/spuelf.em new file mode 100644 index 0000000..2ea760a --- /dev/null +++ b/binutils-2.21/ld/emultempl/spuelf.em @@ -0,0 +1,824 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 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. +# + +# This file is sourced from elf32.em, and defines extra spu specific +# features. +# +fragment <<EOF +#include "ldctor.h" +#include "elf32-spu.h" + +static void spu_place_special_section (asection *, asection *, const char *); +static bfd_size_type spu_elf_load_ovl_mgr (void); +static FILE *spu_elf_open_overlay_script (void); +static void spu_elf_relink (void); + +static struct spu_elf_params params = +{ + &spu_place_special_section, + &spu_elf_load_ovl_mgr, + &spu_elf_open_overlay_script, + &spu_elf_relink, + 0, ovly_normal, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x3ffff, + 1, 0, 16, 0, 0, 2000 +}; + +static unsigned int no_overlays = 0; +static unsigned int num_lines_set = 0; +static unsigned int line_size_set = 0; +static char *auto_overlay_file = 0; +int my_argc; +char **my_argv; + +static const char ovl_mgr[] = { +EOF + +if ! cat ${srcdir}/emultempl/spu_ovl.o_c >> e${EMULATION_NAME}.c +then + echo >&2 "Missing ${srcdir}/emultempl/spu_ovl.o_c" + echo >&2 "You must build gas/as-new with --target=spu" + exit 1 +fi + +fragment <<EOF +}; + +static const char icache_mgr[] = { +EOF + +if ! cat ${srcdir}/emultempl/spu_icache.o_c >> e${EMULATION_NAME}.c +then + echo >&2 "Missing ${srcdir}/emultempl/spu_icache.o_c" + echo >&2 "You must build gas/as-new with --target=spu" + exit 1 +fi + +fragment <<EOF +}; + +static const struct _ovl_stream ovl_mgr_stream = { + ovl_mgr, + ovl_mgr + sizeof (ovl_mgr) +}; + +static const struct _ovl_stream icache_mgr_stream = { + icache_mgr, + icache_mgr + sizeof (icache_mgr) +}; + + +static int +is_spu_target (void) +{ + extern const bfd_target bfd_elf32_spu_vec; + + return link_info.output_bfd->xvec == &bfd_elf32_spu_vec; +} + +/* Create our note section. */ + +static void +spu_after_open (void) +{ + if (is_spu_target ()) + { + /* Pass params to backend. */ + if ((params.auto_overlay & AUTO_OVERLAY) == 0) + params.auto_overlay = 0; + params.emit_stub_syms |= link_info.emitrelocations; + spu_elf_setup (&link_info, ¶ms); + + if (link_info.relocatable) + lang_add_unique (".text.ia.*"); + + if (!link_info.relocatable + && link_info.input_bfds != NULL + && !spu_elf_create_sections (&link_info)) + einfo ("%X%P: can not create note section: %E\n"); + } + + gld${EMULATION_NAME}_after_open (); +} + +/* If O is NULL, add section S at the end of output section OUTPUT_NAME. + If O is not NULL, add section S at the beginning of output section O, + except for soft-icache which adds to the end. + + Really, we should be duplicating ldlang.c map_input_to_output_sections + logic here, ie. using the linker script to find where the section + goes. That's rather a lot of code, and we don't want to run + map_input_to_output_sections again because most sections are already + mapped. So cheat, and put the section in a fixed place, ignoring any + attempt via a linker script to put .stub, .ovtab, and built-in + overlay manager code somewhere else. */ + +static void +spu_place_special_section (asection *s, asection *o, const char *output_name) +{ + lang_output_section_statement_type *os; + + if (o != NULL) + output_name = o->name; + os = lang_output_section_find (output_name); + if (os == NULL) + { + os = gld${EMULATION_NAME}_place_orphan (s, output_name, 0); + os->addr_tree = NULL; + } + else if (params.ovly_flavour != ovly_soft_icache + && o != NULL && os->children.head != NULL) + { + lang_statement_list_type add; + + lang_list_init (&add); + lang_add_section (&add, s, os); + *add.tail = os->children.head; + os->children.head = add.head; + } + else + { + if (params.ovly_flavour == ovly_soft_icache && o != NULL) + { + /* Pad this stub section so that it finishes at the + end of the icache line. */ + etree_type *e_size; + + push_stat_ptr (&os->children); + e_size = exp_intop (params.line_size - s->size); + lang_add_assignment (exp_assop ('=', ".", e_size)); + pop_stat_ptr (); + } + lang_add_section (&os->children, s, os); + } + + s->output_section->size += s->size; +} + +/* Load built-in overlay manager. */ + +static bfd_size_type +spu_elf_load_ovl_mgr (void) +{ + struct elf_link_hash_entry *h; + const char *ovly_mgr_entry; + const struct _ovl_stream *mgr_stream; + bfd_size_type total = 0; + + ovly_mgr_entry = "__ovly_load"; + mgr_stream = &ovl_mgr_stream; + if (params.ovly_flavour == ovly_soft_icache) + { + ovly_mgr_entry = "__icache_br_handler"; + mgr_stream = &icache_mgr_stream; + } + h = elf_link_hash_lookup (elf_hash_table (&link_info), + ovly_mgr_entry, FALSE, FALSE, FALSE); + + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->def_regular) + { + /* User supplied __ovly_load. */ + } + else if (mgr_stream->start == mgr_stream->end) + einfo ("%F%P: no built-in overlay manager\n"); + else + { + lang_input_statement_type *ovl_is; + + ovl_is = lang_add_input_file ("builtin ovl_mgr", + lang_input_file_is_file_enum, + NULL); + + if (!spu_elf_open_builtin_lib (&ovl_is->the_bfd, mgr_stream)) + einfo ("%X%P: can not open built-in overlay manager: %E\n"); + else + { + asection *in; + + if (!load_symbols (ovl_is, NULL)) + einfo ("%X%P: can not load built-in overlay manager: %E\n"); + + /* Map overlay manager sections to output sections. + First try for a matching output section name, if that + fails then try mapping .abc.xyz to .abc, otherwise map + to .text. */ + for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next) + if ((in->flags & (SEC_ALLOC | SEC_LOAD)) + == (SEC_ALLOC | SEC_LOAD)) + { + const char *oname = in->name; + if (strncmp (in->name, ".ovl.init", 9) != 0) + { + total += in->size; + if (!lang_output_section_find (oname)) + { + lang_output_section_statement_type *os = NULL; + char *p = strchr (oname + 1, '.'); + if (p != NULL) + { + size_t len = p - oname; + p = memcpy (xmalloc (len + 1), oname, len); + p[len] = '\0'; + os = lang_output_section_find (p); + free (p); + } + if (os != NULL) + oname = os->name; + else + oname = ".text"; + } + } + + spu_place_special_section (in, NULL, oname); + } + } + } + return total; +} + +/* Go find if we need to do anything special for overlays. */ + +static void +spu_before_allocation (void) +{ + if (is_spu_target () + && !link_info.relocatable + && !no_overlays) + { + int ret; + + /* Size the sections. This is premature, but we need to know the + rough layout so that overlays can be found. */ + expld.phase = lang_mark_phase_enum; + expld.dataseg.phase = exp_dataseg_none; + one_lang_size_sections_pass (NULL, TRUE); + + /* Find overlays by inspecting section vmas. */ + ret = spu_elf_find_overlays (&link_info); + if (ret == 0) + einfo ("%X%P: can not find overlays: %E\n"); + else if (ret == 2) + { + lang_output_section_statement_type *os; + + if (params.auto_overlay != 0) + { + einfo ("%P: --auto-overlay ignored with user overlay script\n"); + params.auto_overlay = 0; + } + + /* Ensure alignment of overlay sections is sufficient. */ + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + if (os->bfd_section != NULL + && spu_elf_section_data (os->bfd_section) != NULL + && spu_elf_section_data (os->bfd_section)->u.o.ovl_index != 0) + { + if (os->bfd_section->alignment_power < 4) + os->bfd_section->alignment_power = 4; + + /* Also ensure size rounds up. */ + os->block_value = 16; + } + + ret = spu_elf_size_stubs (&link_info); + if (ret == 0) + einfo ("%X%P: can not size overlay stubs: %E\n"); + else if (ret == 2) + spu_elf_load_ovl_mgr (); + + spu_elf_place_overlay_data (&link_info); + } + + /* We must not cache anything from the preliminary sizing. */ + lang_reset_memory_regions (); + } + + if (is_spu_target () + && !link_info.relocatable) + spu_elf_size_sections (link_info.output_bfd, &link_info); + + gld${EMULATION_NAME}_before_allocation (); +} + +struct tflist { + struct tflist *next; + char name[9]; +}; + +static struct tflist *tmp_file_list; + +static void clean_tmp (void) +{ + for (; tmp_file_list != NULL; tmp_file_list = tmp_file_list->next) + unlink (tmp_file_list->name); +} + +static int +new_tmp_file (char **fname) +{ + struct tflist *tf; + int fd; + + if (tmp_file_list == NULL) + atexit (clean_tmp); + tf = xmalloc (sizeof (*tf)); + tf->next = tmp_file_list; + tmp_file_list = tf; + memcpy (tf->name, "ldXXXXXX", sizeof (tf->name)); + *fname = tf->name; +#ifdef HAVE_MKSTEMP + fd = mkstemp (*fname); +#else + *fname = mktemp (*fname); + if (*fname == NULL) + return -1; + fd = open (fname, O_RDWR | O_CREAT | O_EXCL, 0600); +#endif + return fd; +} + +static FILE * +spu_elf_open_overlay_script (void) +{ + FILE *script = NULL; + + if (auto_overlay_file == NULL) + { + int fd = new_tmp_file (&auto_overlay_file); + if (fd == -1) + goto file_err; + script = fdopen (fd, "w"); + } + else + script = fopen (auto_overlay_file, "w"); + + if (script == NULL) + { + file_err: + einfo ("%F%P: can not open script: %E\n"); + } + return script; +} + +static void +spu_elf_relink (void) +{ + char **argv = xmalloc ((my_argc + 4) * sizeof (*argv)); + + memcpy (argv, my_argv, my_argc * sizeof (*argv)); + argv[my_argc++] = "--no-auto-overlay"; + if (tmp_file_list->name == auto_overlay_file) + argv[my_argc - 1] = concat (argv[my_argc - 1], "=", + auto_overlay_file, (const char *) NULL); + argv[my_argc++] = "-T"; + argv[my_argc++] = auto_overlay_file; + argv[my_argc] = 0; + execvp (argv[0], (char *const *) argv); + perror (argv[0]); + _exit (127); +} + +/* Final emulation specific call. */ + +static void +gld${EMULATION_NAME}_finish (void) +{ + if (is_spu_target ()) + { + if (params.local_store_lo < params.local_store_hi) + { + asection *s; + + s = spu_elf_check_vma (&link_info); + if (s != NULL && !params.auto_overlay) + einfo ("%X%P: %A exceeds local store range\n", s); + } + else if (params.auto_overlay) + einfo ("%P: --auto-overlay ignored with zero local store range\n"); + } + + finish_default (); +} + +static char * +gld${EMULATION_NAME}_choose_target (int argc, char *argv[]) +{ + my_argc = argc; + my_argv = argv; + return ldemul_default_target (argc, argv); +} + +EOF + +if grep -q 'ld_elf.*ppc.*_emulation' ldemul-list.h; then + fragment <<EOF +#include <errno.h> +#include "filenames.h" +#include "libiberty.h" + +static const char * +base_name (const char *path) +{ + const char *file = strrchr (path, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + char *bslash = strrchr (path, '\\\\'); + + if (file == NULL || (bslash != NULL && bslash > file)) + file = bslash; + if (file == NULL + && path[0] != '\0' + && path[1] == ':') + file = path + 1; + } +#endif + if (file == NULL) + file = path; + else + ++file; + return file; +} + +/* This function is called when building a ppc32 or ppc64 executable + to handle embedded spu images. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); + +bfd_boolean +embedded_spu_file (lang_input_statement_type *entry, const char *flags) +{ + const char *cmd[6]; + const char *pex_return; + const char *sym; + char *handle, *p; + char *oname; + int fd; + int status; + union lang_statement_union **old_stat_tail; + union lang_statement_union **old_file_tail; + union lang_statement_union *new_ent; + lang_input_statement_type *search; + + if (entry->the_bfd->format != bfd_object + || strcmp (entry->the_bfd->xvec->name, "elf32-spu") != 0 + || (entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_EXEC + && entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_DYN)) + return FALSE; + + /* Use the filename as the symbol marking the program handle struct. */ + sym = base_name (entry->the_bfd->filename); + + handle = xstrdup (sym); + for (p = handle; *p; ++p) + if (!(ISALNUM (*p) || *p == '$' || *p == '.')) + *p = '_'; + + fd = new_tmp_file (&oname); + if (fd == -1) + return FALSE; + close (fd); + + for (search = (lang_input_statement_type *) input_file_chain.head; + search != NULL; + search = (lang_input_statement_type *) search->next_real_file) + if (search->filename != NULL) + { + const char *infile = base_name (search->filename); + + if (strncmp (infile, "crtbegin", 8) == 0) + { + if (infile[8] == 'S') + flags = concat (flags, " -fPIC", (const char *) NULL); + else if (infile[8] == 'T') + flags = concat (flags, " -fpie", (const char *) NULL); + break; + } + } + + cmd[0] = EMBEDSPU; + cmd[1] = flags; + cmd[2] = handle; + cmd[3] = entry->the_bfd->filename; + cmd[4] = oname; + cmd[5] = NULL; + if (trace_file_tries) + { + info_msg (_("running: %s \"%s\" \"%s\" \"%s\" \"%s\"\n"), + cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + fflush (stdout); + } + + pex_return = pex_one (PEX_SEARCH | PEX_LAST, cmd[0], (char *const *) cmd, + cmd[0], NULL, NULL, &status, &errno); + if (NULL != pex_return) { + if (strcmp ("embedspu", EMBEDSPU) != 0) + { + cmd[0] = "embedspu"; + pex_return = pex_one (PEX_SEARCH | PEX_LAST, cmd[0], (char *const *) cmd, + cmd[0], NULL, NULL, &status, &errno); + } + if (NULL != pex_return) { + perror (pex_return); + _exit (127); + } + } + if (status) + return FALSE; + + + old_stat_tail = stat_ptr->tail; + old_file_tail = input_file_chain.tail; + if (lang_add_input_file (oname, lang_input_file_is_file_enum, NULL) == NULL) + return FALSE; + + /* lang_add_input_file puts the new list entry at the end of the statement + and input file lists. Move it to just after the current entry. */ + new_ent = *old_stat_tail; + *old_stat_tail = NULL; + stat_ptr->tail = old_stat_tail; + *old_file_tail = NULL; + input_file_chain.tail = old_file_tail; + new_ent->header.next = entry->header.next; + entry->header.next = new_ent; + new_ent->input_statement.next_real_file = entry->next_real_file; + entry->next_real_file = new_ent; + + /* Ensure bfd sections are excluded from the output. */ + bfd_section_list_clear (entry->the_bfd); + entry->loaded = TRUE; + return TRUE; +} + +EOF +fi + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_SPU_PLUGIN 301 +#define OPTION_SPU_NO_OVERLAYS (OPTION_SPU_PLUGIN + 1) +#define OPTION_SPU_COMPACT_STUBS (OPTION_SPU_NO_OVERLAYS + 1) +#define OPTION_SPU_STUB_SYMS (OPTION_SPU_COMPACT_STUBS + 1) +#define OPTION_SPU_NON_OVERLAY_STUBS (OPTION_SPU_STUB_SYMS + 1) +#define OPTION_SPU_LOCAL_STORE (OPTION_SPU_NON_OVERLAY_STUBS + 1) +#define OPTION_SPU_STACK_ANALYSIS (OPTION_SPU_LOCAL_STORE + 1) +#define OPTION_SPU_STACK_SYMS (OPTION_SPU_STACK_ANALYSIS + 1) +#define OPTION_SPU_AUTO_OVERLAY (OPTION_SPU_STACK_SYMS + 1) +#define OPTION_SPU_AUTO_RELINK (OPTION_SPU_AUTO_OVERLAY + 1) +#define OPTION_SPU_OVERLAY_RODATA (OPTION_SPU_AUTO_RELINK + 1) +#define OPTION_SPU_SOFT_ICACHE (OPTION_SPU_OVERLAY_RODATA + 1) +#define OPTION_SPU_LINE_SIZE (OPTION_SPU_SOFT_ICACHE + 1) +#define OPTION_SPU_NUM_LINES (OPTION_SPU_LINE_SIZE + 1) +#define OPTION_SPU_LRLIVE (OPTION_SPU_NUM_LINES + 1) +#define OPTION_SPU_NON_IA_TEXT (OPTION_SPU_LRLIVE + 1) +#define OPTION_SPU_FIXED_SPACE (OPTION_SPU_NON_IA_TEXT + 1) +#define OPTION_SPU_RESERVED_SPACE (OPTION_SPU_FIXED_SPACE + 1) +#define OPTION_SPU_EXTRA_STACK (OPTION_SPU_RESERVED_SPACE + 1) +#define OPTION_SPU_NO_AUTO_OVERLAY (OPTION_SPU_EXTRA_STACK + 1) +#define OPTION_SPU_EMIT_FIXUPS (OPTION_SPU_NO_AUTO_OVERLAY + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "plugin", no_argument, NULL, OPTION_SPU_PLUGIN }, + { "soft-icache", no_argument, NULL, OPTION_SPU_SOFT_ICACHE }, + { "lrlive-analysis", no_argument, NULL, OPTION_SPU_LRLIVE }, + { "num-lines", required_argument, NULL, OPTION_SPU_NUM_LINES }, + { "line-size", required_argument, NULL, OPTION_SPU_LINE_SIZE }, + { "non-ia-text", no_argument, NULL, OPTION_SPU_NON_IA_TEXT }, + { "no-overlays", no_argument, NULL, OPTION_SPU_NO_OVERLAYS }, + { "compact-stubs", no_argument, NULL, OPTION_SPU_COMPACT_STUBS }, + { "emit-stub-syms", no_argument, NULL, OPTION_SPU_STUB_SYMS }, + { "extra-overlay-stubs", no_argument, NULL, OPTION_SPU_NON_OVERLAY_STUBS }, + { "local-store", required_argument, NULL, OPTION_SPU_LOCAL_STORE }, + { "stack-analysis", no_argument, NULL, OPTION_SPU_STACK_ANALYSIS }, + { "emit-stack-syms", no_argument, NULL, OPTION_SPU_STACK_SYMS }, + { "auto-overlay", optional_argument, NULL, OPTION_SPU_AUTO_OVERLAY }, + { "auto-relink", no_argument, NULL, OPTION_SPU_AUTO_RELINK }, + { "overlay-rodata", no_argument, NULL, OPTION_SPU_OVERLAY_RODATA }, + { "num-regions", required_argument, NULL, OPTION_SPU_NUM_LINES }, + { "region-size", required_argument, NULL, OPTION_SPU_LINE_SIZE }, + { "fixed-space", required_argument, NULL, OPTION_SPU_FIXED_SPACE }, + { "reserved-space", required_argument, NULL, OPTION_SPU_RESERVED_SPACE }, + { "extra-stack-space", required_argument, NULL, OPTION_SPU_EXTRA_STACK }, + { "no-auto-overlay", optional_argument, NULL, OPTION_SPU_NO_AUTO_OVERLAY }, + { "emit-fixups", optional_argument, NULL, OPTION_SPU_EMIT_FIXUPS }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --plugin Make SPU plugin.\n\ + --no-overlays No overlay handling.\n\ + --compact-stubs Use smaller and possibly slower call stubs.\n\ + --emit-stub-syms Add symbols on overlay call stubs.\n\ + --extra-overlay-stubs Add stubs on all calls out of overlay regions.\n\ + --local-store=lo:hi Valid address range.\n\ + --stack-analysis Estimate maximum stack requirement.\n\ + --emit-stack-syms Add sym giving stack needed for each func.\n\ + --auto-overlay [=filename] Create an overlay script in filename if\n\ + executable does not fit in local store.\n\ + --auto-relink Rerun linker using auto-overlay script.\n\ + --overlay-rodata Place read-only data with associated function\n\ + code in overlays.\n\ + --num-regions Number of overlay buffers (default 1).\n\ + --region-size Size of overlay buffers (default 0, auto).\n\ + --fixed-space=bytes Local store for non-overlay code and data.\n\ + --reserved-space=bytes Local store for stack and heap. If not specified\n\ + ld will estimate stack size and assume no heap.\n\ + --extra-stack-space=bytes Space for negative sp access (default 2000) if\n\ + --reserved-space not given.\n\ + --soft-icache Generate software icache overlays.\n\ + --num-lines Number of soft-icache lines (default 32).\n\ + --line-size Size of soft-icache lines (default 1k).\n\ + --non-ia-text Allow non-icache code in icache lines.\n\ + --lrlive-analysis Scan function prologue for lr liveness.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_SPU_PLUGIN: + spu_elf_plugin (1); + break; + + case OPTION_SPU_NO_OVERLAYS: + no_overlays = 1; + break; + + case OPTION_SPU_COMPACT_STUBS: + params.compact_stub = 1; + break; + + case OPTION_SPU_STUB_SYMS: + params.emit_stub_syms = 1; + break; + + case OPTION_SPU_NON_OVERLAY_STUBS: + params.non_overlay_stubs = 1; + break; + + case OPTION_SPU_LOCAL_STORE: + { + char *end; + params.local_store_lo = strtoul (optarg, &end, 0); + if (*end == '\'':'\'') + { + params.local_store_hi = strtoul (end + 1, &end, 0); + if (*end == 0) + break; + } + einfo (_("%P%F: invalid --local-store address range `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_STACK_ANALYSIS: + params.stack_analysis = 1; + break; + + case OPTION_SPU_STACK_SYMS: + params.emit_stack_syms = 1; + break; + + case OPTION_SPU_AUTO_OVERLAY: + params.auto_overlay |= 1; + if (optarg != NULL) + { + auto_overlay_file = optarg; + break; + } + /* Fall thru */ + + case OPTION_SPU_AUTO_RELINK: + params.auto_overlay |= 2; + break; + + case OPTION_SPU_OVERLAY_RODATA: + params.auto_overlay |= 4; + break; + + case OPTION_SPU_SOFT_ICACHE: + params.ovly_flavour = ovly_soft_icache; + /* Software i-cache stubs are always "compact". */ + params.compact_stub = 1; + if (!num_lines_set) + params.num_lines = 32; + else if ((params.num_lines & -params.num_lines) != params.num_lines) + einfo (_("%P%F: invalid --num-lines/--num-regions `%u'\''\n"), + params.num_lines); + if (!line_size_set) + params.line_size = 1024; + else if ((params.line_size & -params.line_size) != params.line_size) + einfo (_("%P%F: invalid --line-size/--region-size `%u'\''\n"), + params.line_size); + break; + + case OPTION_SPU_LRLIVE: + params.lrlive_analysis = 1; + break; + + case OPTION_SPU_NON_IA_TEXT: + params.non_ia_text = 1; + break; + + case OPTION_SPU_NUM_LINES: + { + char *end; + params.num_lines = strtoul (optarg, &end, 0); + num_lines_set = 1; + if (*end == 0 + && (params.ovly_flavour != ovly_soft_icache + || (params.num_lines & -params.num_lines) == params.num_lines)) + break; + einfo (_("%P%F: invalid --num-lines/--num-regions `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_LINE_SIZE: + { + char *end; + params.line_size = strtoul (optarg, &end, 0); + line_size_set = 1; + if (*end == 0 + && (params.ovly_flavour != ovly_soft_icache + || (params.line_size & -params.line_size) == params.line_size)) + break; + einfo (_("%P%F: invalid --line-size/--region-size `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_FIXED_SPACE: + { + char *end; + params.auto_overlay_fixed = strtoul (optarg, &end, 0); + if (*end != 0) + einfo (_("%P%F: invalid --fixed-space value `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_RESERVED_SPACE: + { + char *end; + params.auto_overlay_reserved = strtoul (optarg, &end, 0); + if (*end != 0) + einfo (_("%P%F: invalid --reserved-space value `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_EXTRA_STACK: + { + char *end; + params.extra_stack_space = strtol (optarg, &end, 0); + if (*end != 0) + einfo (_("%P%F: invalid --extra-stack-space value `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_NO_AUTO_OVERLAY: + params.auto_overlay = 0; + if (optarg != NULL) + { + struct tflist *tf; + size_t len; + + if (tmp_file_list == NULL) + atexit (clean_tmp); + + len = strlen (optarg) + 1; + tf = xmalloc (sizeof (*tf) - sizeof (tf->name) + len); + memcpy (tf->name, optarg, len); + tf->next = tmp_file_list; + tmp_file_list = tf; + break; + } + break; + + case OPTION_SPU_EMIT_FIXUPS: + params.emit_fixups = 1; + break; +' + +LDEMUL_AFTER_OPEN=spu_after_open +LDEMUL_BEFORE_ALLOCATION=spu_before_allocation +LDEMUL_FINISH=gld${EMULATION_NAME}_finish +LDEMUL_CHOOSE_TARGET=gld${EMULATION_NAME}_choose_target diff --git a/binutils-2.21/ld/emultempl/sunos.em b/binutils-2.21/ld/emultempl/sunos.em new file mode 100644 index 0000000..bbd6075 --- /dev/null +++ b/binutils-2.21/ld/emultempl/sunos.em @@ -0,0 +1,1037 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +fragment <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + +/* SunOS emulation code for ${EMULATION_NAME} + Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Written by Steve Chamberlain <sac@cygnus.com> + SunOS shared library support 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. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "libiberty.h" +#include "safe-ctype.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +#ifdef HAVE_DIRENT_H +# include <dirent.h> +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# ifdef HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# ifdef HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +static void gld${EMULATION_NAME}_find_so + (lang_input_statement_type *); +static char *gld${EMULATION_NAME}_search_dir + (const char *, const char *, bfd_boolean *); +static void gld${EMULATION_NAME}_check_needed + (lang_input_statement_type *); +static bfd_boolean gld${EMULATION_NAME}_search_needed + (const char *, const char *); +static bfd_boolean gld${EMULATION_NAME}_try_needed + (const char *, const char *); +static void gld${EMULATION_NAME}_find_assignment + (lang_statement_union_type *); +static void gld${EMULATION_NAME}_find_exp_assignment + (etree_type *); +static void gld${EMULATION_NAME}_count_need + (lang_input_statement_type *); +static void gld${EMULATION_NAME}_set_need + (lang_input_statement_type *); + +static void +gld${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + config.dynamic_link = TRUE; + config.has_shared = TRUE; +} + +/* This is called after the command line arguments have been parsed, + but before the linker script has been read. If this is a native + linker, we add the directories in LD_LIBRARY_PATH to the search + list. */ + +static void +gld${EMULATION_NAME}_set_symbols (void) +{ +EOF +if [ "x${host}" = "x${target}" ] ; then + case " ${EMULATION_LIBPATH} " in + *" ${EMULATION_NAME} "*) +fragment <<EOF + const char *env; + + env = (const char *) getenv ("LD_LIBRARY_PATH"); + if (env != NULL) + { + char *l; + + l = xstrdup (env); + while (1) + { + char *c; + + c = strchr (l, ':'); + if (c != NULL) + *c++ = '\0'; + if (*l != '\0') + ldfile_add_library_path (l, FALSE); + if (c == NULL) + break; + l = c; + } + } +EOF + ;; + esac +fi +fragment <<EOF +} + +/* Despite the name, we use this routine to search for dynamic + libraries. On SunOS this requires a directory search. We need to + find the .so file with the highest version number. The user may + restrict the major version by saying, e.g., -lc.1. Also, if we + find a .so file, we need to look for a the same file after + replacing .so with .sa; if it exists, it will be an archive which + provide some initializations for data symbols, and we need to + search it after including the .so file. */ + +static void +gld${EMULATION_NAME}_create_output_section_statements (void) +{ + lang_for_each_input_file (gld${EMULATION_NAME}_find_so); +} + +/* Search the directory for a .so file for each library search. */ + +static void +gld${EMULATION_NAME}_find_so (lang_input_statement_type *inp) +{ + search_dirs_type *search; + char *found = NULL; + char *alc; + struct stat st; + + if (! inp->search_dirs_flag + || ! inp->is_archive + || ! inp->dynamic) + return; + + ASSERT (CONST_STRNEQ (inp->local_sym_name, "-l")); + + for (search = search_head; search != NULL; search = search->next) + { + bfd_boolean found_static; + + found = gld${EMULATION_NAME}_search_dir (search->name, inp->filename, + &found_static); + if (found != NULL || found_static) + break; + } + + if (found == NULL) + { + /* We did not find a matching .so file. This isn't an error, + since there might still be a matching .a file, which will be + found by the usual search. */ + return; + } + + /* Replace the filename with the one we have found. */ + alc = (char *) xmalloc (strlen (search->name) + strlen (found) + 2); + sprintf (alc, "%s/%s", search->name, found); + inp->filename = alc; + + /* Turn off the search_dirs_flag to prevent ldfile_open_file from + searching for this file again. */ + inp->search_dirs_flag = FALSE; + + free (found); + + /* Now look for the same file name, but with .sa instead of .so. If + found, add it to the list of input files. */ + alc = (char *) xmalloc (strlen (inp->filename) + 1); + strcpy (alc, inp->filename); + strstr (alc + strlen (search->name), ".so")[2] = 'a'; + if (stat (alc, &st) != 0) + free (alc); + else + { + lang_input_statement_type *sa; + + /* Add the .sa file to the statement list just before the .so + file. This is really a hack. */ + sa = ((lang_input_statement_type *) + xmalloc (sizeof (lang_input_statement_type))); + *sa = *inp; + + inp->filename = alc; + inp->local_sym_name = alc; + + inp->header.next = (lang_statement_union_type *) sa; + inp->next_real_file = (lang_statement_union_type *) sa; + } +} + +/* Search a directory for a .so file. */ + +static char * +gld${EMULATION_NAME}_search_dir + (const char *dirname, const char *filename, bfd_boolean *found_static) +{ + int force_maj, force_min; + const char *dot; + unsigned int len; + char *alc; + char *found; + int max_maj, max_min; + DIR *dir; + struct dirent *entry; + unsigned int dirnamelen; + char *full_path; + int statval; + struct stat st; + + *found_static = FALSE; + + force_maj = -1; + force_min = -1; + dot = strchr (filename, '.'); + if (dot == NULL) + { + len = strlen (filename); + alc = NULL; + } + else + { + force_maj = atoi (dot + 1); + + len = dot - filename; + alc = (char *) xmalloc (len + 1); + strncpy (alc, filename, len); + alc[len] = '\0'; + filename = alc; + + dot = strchr (dot + 1, '.'); + if (dot != NULL) + force_min = atoi (dot + 1); + } + + found = NULL; + max_maj = max_min = 0; + + dir = opendir (dirname); + if (dir == NULL) + return NULL; + dirnamelen = strlen (dirname); + + while ((entry = readdir (dir)) != NULL) + { + const char *s; + int found_maj, found_min; + + if (! CONST_STRNEQ (entry->d_name, "lib") + || strncmp (entry->d_name + 3, filename, len) != 0) + continue; + + if (dot == NULL + && strcmp (entry->d_name + 3 + len, ".a") == 0) + { + *found_static = TRUE; + continue; + } + + /* We accept libfoo.so without a version number, even though the + native linker does not. This is more convenient for packages + which just generate .so files for shared libraries, as on ELF + systems. */ + if (! CONST_STRNEQ (entry->d_name + 3 + len, ".so")) + continue; + if (entry->d_name[6 + len] == '\0') + ; + else if (entry->d_name[6 + len] == '.' + && ISDIGIT (entry->d_name[7 + len])) + ; + else + continue; + + for (s = entry->d_name + 6 + len; *s != '\0'; s++) + if (*s != '.' && ! ISDIGIT (*s)) + break; + if (*s != '\0') + continue; + + /* We've found a .so file. Work out the major and minor + version numbers. */ + found_maj = 0; + found_min = 0; + sscanf (entry->d_name + 3 + len, ".so.%d.%d", + &found_maj, &found_min); + + if ((force_maj != -1 && force_maj != found_maj) + || (force_min != -1 && force_min != found_min)) + continue; + + /* Make sure the file really exists (ignore broken symlinks). */ + full_path = xmalloc (dirnamelen + 1 + strlen (entry->d_name) + 1); + sprintf (full_path, "%s/%s", dirname, entry->d_name); + statval = stat (full_path, &st); + free (full_path); + if (statval != 0) + continue; + + /* We've found a match for the name we are searching for. See + if this is the version we should use. If the major and minor + versions match, we use the last entry in alphabetical order; + I don't know if this is how SunOS distinguishes libc.so.1.8 + from libc.so.1.8.1, but it ought to suffice. */ + if (found == NULL + || (found_maj > max_maj) + || (found_maj == max_maj + && (found_min > max_min + || (found_min == max_min + && strcmp (entry->d_name, found) > 0)))) + { + if (found != NULL) + free (found); + found = (char *) xmalloc (strlen (entry->d_name) + 1); + strcpy (found, entry->d_name); + max_maj = found_maj; + max_min = found_min; + } + } + + closedir (dir); + + if (alc != NULL) + free (alc); + + return found; +} + +/* These variables are required to pass information back and forth + between after_open and check_needed. */ + +static struct bfd_link_needed_list *global_needed; +static bfd_boolean global_found; + +/* This is called after all the input files have been opened. */ + +static void +gld${EMULATION_NAME}_after_open (void) +{ + struct bfd_link_needed_list *needed, *l; + + /* We only need to worry about this when doing a final link. */ + if (link_info.relocatable || link_info.shared) + return; + + /* Get the list of files which appear in ld_need entries in dynamic + objects included in the link. For each such file, we want to + track down the corresponding library, and include the symbol + table in the link. This is what the runtime dynamic linker will + do. Tracking the files down here permits one dynamic object to + include another without requiring special action by the person + doing the link. Note that the needed list can actually grow + while we are stepping through this loop. */ + needed = bfd_sunos_get_needed_list (link_info.output_bfd, &link_info); + for (l = needed; l != NULL; l = l->next) + { + struct bfd_link_needed_list *ll; + const char *lname; + search_dirs_type *search; + + lname = l->name; + + /* If we've already seen this file, skip it. */ + for (ll = needed; ll != l; ll = ll->next) + if (strcmp (ll->name, lname) == 0) + break; + if (ll != l) + continue; + + /* See if this file was included in the link explicitly. */ + global_needed = l; + global_found = FALSE; + lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); + if (global_found) + continue; + + if (! CONST_STRNEQ (lname, "-l")) + { + bfd *abfd; + + abfd = bfd_openr (lname, bfd_get_target (link_info.output_bfd)); + if (abfd != NULL) + { + if (! bfd_check_format (abfd, bfd_object)) + { + (void) bfd_close (abfd); + abfd = NULL; + } + } + if (abfd != NULL) + { + if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) + { + (void) bfd_close (abfd); + abfd = NULL; + } + } + if (abfd != NULL) + { + /* We've found the needed dynamic object. */ + if (! bfd_link_add_symbols (abfd, &link_info)) + einfo ("%F%B: could not read symbols: %E\n", abfd); + } + else + { + einfo ("%P: warning: %s, needed by %B, not found\n", + lname, l->by); + } + + continue; + } + + lname += 2; + + /* We want to search for the file in the same way that the + dynamic linker will search. That means that we want to use + rpath_link, rpath or -L, then the environment variable + LD_LIBRARY_PATH (native only), then (if rpath was used) the + linker script LIB_SEARCH_DIRS. */ + if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, + lname)) + continue; + if (command_line.rpath != NULL) + { + if (gld${EMULATION_NAME}_search_needed (command_line.rpath, lname)) + continue; + } + else + { + for (search = search_head; search != NULL; search = search->next) + if (gld${EMULATION_NAME}_try_needed (search->name, lname)) + break; + if (search != NULL) + continue; + } +EOF +if [ "x${host}" = "x${target}" ] ; then + case " ${EMULATION_LIBPATH} " in + *" ${EMULATION_NAME} "*) +fragment <<EOF + { + const char *lib_path; + + lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); + if (gld${EMULATION_NAME}_search_needed (lib_path, lname)) + continue; + } +EOF + ;; + esac +fi +fragment <<EOF + if (command_line.rpath != NULL) + { + for (search = search_head; search != NULL; search = search->next) + { + if (search->cmdline) + continue; + if (gld${EMULATION_NAME}_try_needed (search->name, lname)) + break; + } + if (search != NULL) + continue; + } + + einfo ("%P: warning: %s, needed by %B, not found\n", + l->name, l->by); + } +} + +/* Search for a needed file in a path. */ + +static bfd_boolean +gld${EMULATION_NAME}_search_needed (const char *path, const char *name) +{ + const char *s; + + if (path == NULL || *path == '\0') + return FALSE; + while (1) + { + const char *dir; + char *dircopy; + + s = strchr (path, ':'); + if (s == NULL) + { + dircopy = NULL; + dir = path; + } + else + { + dircopy = (char *) xmalloc (s - path + 1); + memcpy (dircopy, path, s - path); + dircopy[s - path] = '\0'; + dir = dircopy; + } + + if (gld${EMULATION_NAME}_try_needed (dir, name)) + return TRUE; + + if (dircopy != NULL) + free (dircopy); + + if (s == NULL) + break; + path = s + 1; + } + + return FALSE; +} + +/* This function is called for each possible directory for a needed + dynamic object. */ + +static bfd_boolean +gld${EMULATION_NAME}_try_needed (const char *dir, const char *name) +{ + char *file; + char *alc; + bfd_boolean ignore; + bfd *abfd; + + file = gld${EMULATION_NAME}_search_dir (dir, name, &ignore); + if (file == NULL) + return FALSE; + + alc = (char *) xmalloc (strlen (dir) + strlen (file) + 2); + sprintf (alc, "%s/%s", dir, file); + free (file); + abfd = bfd_openr (alc, bfd_get_target (link_info.output_bfd)); + if (abfd == NULL) + return FALSE; + if (! bfd_check_format (abfd, bfd_object)) + { + (void) bfd_close (abfd); + return FALSE; + } + if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) + { + (void) bfd_close (abfd); + return FALSE; + } + + /* We've found the needed dynamic object. */ + + /* Add this file into the symbol table. */ + if (! bfd_link_add_symbols (abfd, &link_info)) + einfo ("%F%B: could not read symbols: %E\n", abfd); + + return TRUE; +} + +/* See if we have already included a needed object in the link. This + does not have to be precise, as it does no harm to include a + dynamic object more than once. */ + +static void +gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) +{ + if (s->filename == NULL) + return; + if (! CONST_STRNEQ (global_needed->name, "-l")) + { + if (strcmp (s->filename, global_needed->name) == 0) + global_found = TRUE; + } + else + { + const char *sname, *lname; + const char *sdot, *ldot; + int lmaj, lmin, smaj, smin; + + lname = global_needed->name + 2; + + sname = strrchr (s->filename, '/'); + if (sname == NULL) + sname = s->filename; + else + ++sname; + + if (! CONST_STRNEQ (sname, "lib")) + return; + sname += 3; + + ldot = strchr (lname, '.'); + if (ldot == NULL) + ldot = lname + strlen (lname); + + sdot = strstr (sname, ".so."); + if (sdot == NULL) + return; + + if (sdot - sname != ldot - lname + || strncmp (lname, sname, sdot - sname) != 0) + return; + + lmaj = lmin = -1; + sscanf (ldot, ".%d.%d", &lmaj, &lmin); + smaj = smin = -1; + sscanf (sdot, ".so.%d.%d", &smaj, &smin); + if ((smaj != lmaj && smaj != -1 && lmaj != -1) + || (smin != lmin && smin != -1 && lmin != -1)) + return; + + global_found = TRUE; + } +} + +/* We need to use static variables to pass information around the call + to lang_for_each_statement. Ick. */ + +static const char *find_assign; +static bfd_boolean found_assign; + +/* We need to use static variables to pass information around the call + to lang_for_each_input_file. Ick. */ + +static bfd_size_type need_size; +static bfd_size_type need_entries; +static bfd_byte *need_contents; +static bfd_byte *need_pinfo; +static bfd_byte *need_pnames; + +/* The size of one entry in the .need section, not including the file + name. */ + +#define NEED_ENTRY_SIZE (16) + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + struct bfd_link_hash_entry *hdyn = NULL; + asection *sneed; + asection *srules; + asection *sdyn; + + /* The SunOS native linker creates a shared library whenever there + are any undefined symbols in a link, unless -e is used. This is + pretty weird, but we are compatible. */ + if (! link_info.shared && ! link_info.relocatable && ! entry_from_cmdline) + { + struct bfd_link_hash_entry *h; + + for (h = link_info.hash->undefs; h != NULL; h = h->u.undef.next) + { + if (h->type == bfd_link_hash_undefined + && h->u.undef.abfd != NULL + && (h->u.undef.abfd->flags & DYNAMIC) == 0 + && strcmp (h->root.string, "__DYNAMIC") != 0 + && strcmp (h->root.string, "__GLOBAL_OFFSET_TABLE_") != 0) + { + find_assign = h->root.string; + found_assign = FALSE; + lang_for_each_statement (gld${EMULATION_NAME}_find_assignment); + if (! found_assign) + { + link_info.shared = TRUE; + break; + } + } + } + } + + if (link_info.shared) + { + lang_output_section_statement_type *os; + + /* Set the .text section to start at 0x20, not 0x2020. FIXME: + This is too magical. */ + os = lang_output_section_statement_lookup (".text", 0, TRUE); + if (os->addr_tree == NULL) + os->addr_tree = exp_intop (0x20); + } + + /* We need to create a __DYNAMIC symbol. We don't do this in the + linker script because we want to set the value to the start of + the dynamic section if there is one, or to zero if there isn't + one. We need to create the symbol before calling + size_dynamic_sections, although we can't set the value until + afterward. */ + if (! link_info.relocatable) + { + hdyn = bfd_link_hash_lookup (link_info.hash, "__DYNAMIC", TRUE, FALSE, + FALSE); + if (hdyn == NULL) + einfo ("%P%F: bfd_link_hash_lookup: %E\n"); + if (! bfd_sunos_record_link_assignment (link_info.output_bfd, &link_info, + "__DYNAMIC")) + einfo ("%P%F: failed to record assignment to __DYNAMIC: %E\n"); + } + + /* If we are going to make any variable assignments, we need to let + the backend linker know about them in case the variables are + referred to by dynamic objects. */ + lang_for_each_statement (gld${EMULATION_NAME}_find_assignment); + + /* Let the backend linker work out the sizes of any sections + required by dynamic linking. */ + if (! bfd_sunos_size_dynamic_sections (link_info.output_bfd, &link_info, + &sdyn, &sneed, &srules)) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); + + if (sneed != NULL) + { + /* Set up the .need section. See the description of the ld_need + field in include/aout/sun4.h. */ + + need_entries = 0; + need_size = 0; + + lang_for_each_input_file (gld${EMULATION_NAME}_count_need); + + /* We should only have a .need section if we have at least one + dynamic object. */ + ASSERT (need_entries != 0); + + sneed->size = need_size; + sneed->contents = (bfd_byte *) xmalloc (need_size); + + need_contents = sneed->contents; + need_pinfo = sneed->contents; + need_pnames = sneed->contents + need_entries * 16; + + lang_for_each_input_file (gld${EMULATION_NAME}_set_need); + + ASSERT ((bfd_size_type) (need_pnames - sneed->contents) == need_size); + } + + if (srules != NULL) + { + /* Set up the .rules section. This is just a PATH like string + of the -L arguments given on the command line. We permit the + user to specify the directories using the -rpath command line + option. */ + if (command_line.rpath) + { + srules->size = strlen (command_line.rpath); + srules->contents = (bfd_byte *) command_line.rpath; + } + else + { + unsigned int size; + search_dirs_type *search; + + size = 0; + for (search = search_head; search != NULL; search = search->next) + if (search->cmdline) + size += strlen (search->name) + 1; + srules->size = size; + if (size > 0) + { + char *p; + + srules->contents = (bfd_byte *) xmalloc (size); + p = (char *) srules->contents; + *p = '\0'; + for (search = search_head; search != NULL; search = search->next) + { + if (search->cmdline) + { + if (p != (char *) srules->contents) + *p++ = ':'; + strcpy (p, search->name); + p += strlen (p); + } + } + } + } + } + + /* We must assign a value to __DYNAMIC. It should be zero if we are + not doing a dynamic link, or the start of the .dynamic section if + we are doing one. */ + if (! link_info.relocatable) + { + hdyn->type = bfd_link_hash_defined; + hdyn->u.def.value = 0; + if (sdyn != NULL) + hdyn->u.def.section = sdyn; + else + hdyn->u.def.section = bfd_abs_section_ptr; + } + + before_allocation_default (); +} + +/* This is called by the before_allocation routine via + lang_for_each_statement. It does one of two things: if the + variable find_assign is set, it sets found_assign if it finds an + assignment to that variable; otherwise it tells the backend linker + about all assignment statements, in case they are assignments to + symbols which are referred to by dynamic objects. */ + +static void +gld${EMULATION_NAME}_find_assignment (lang_statement_union_type *s) +{ + if (s->header.type == lang_assignment_statement_enum + && (find_assign == NULL || ! found_assign)) + gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); +} + +/* Look through an expression for an assignment statement. */ + +static void +gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) +{ + switch (exp->type.node_class) + { + case etree_assign: + if (find_assign != NULL) + { + if (strcmp (find_assign, exp->assign.dst) == 0) + found_assign = TRUE; + return; + } + + if (strcmp (exp->assign.dst, ".") != 0) + { + if (! bfd_sunos_record_link_assignment (link_info.output_bfd, + &link_info, + exp->assign.dst)) + einfo ("%P%F: failed to record assignment to %s: %E\n", + exp->assign.dst); + } + gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); + break; + + case etree_binary: + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); + break; + + case etree_trinary: + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); + break; + + case etree_unary: + gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); + break; + + default: + break; + } +} + +/* Work out the size of the .need section, and the number of entries. + The backend will set the ld_need field of the dynamic linking + information to point to the .need section. See include/aout/sun4.h + for more information. */ + +static void +gld${EMULATION_NAME}_count_need (lang_input_statement_type *inp) +{ + if (inp->the_bfd != NULL + && (inp->the_bfd->flags & DYNAMIC) != 0) + { + ++need_entries; + need_size += NEED_ENTRY_SIZE; + if (! inp->is_archive) + need_size += strlen (inp->filename) + 1; + else + { + ASSERT (inp->local_sym_name[0] == '-' + && inp->local_sym_name[1] == 'l'); + need_size += strlen (inp->local_sym_name + 2) + 1; + } + } +} + +/* Fill in the contents of the .need section. */ + +static void +gld${EMULATION_NAME}_set_need (lang_input_statement_type *inp) +{ + if (inp->the_bfd != NULL + && (inp->the_bfd->flags & DYNAMIC) != 0) + { + bfd_size_type c; + + /* To really fill in the .need section contents, we need to know + the final file position of the section, but we don't. + Instead, we use offsets, and rely on the BFD backend to + finish the section up correctly. FIXME: Talk about lack of + referential locality. */ + bfd_put_32 (link_info.output_bfd, need_pnames - need_contents, + need_pinfo); + if (! inp->is_archive) + { + bfd_put_32 (link_info.output_bfd, (bfd_vma) 0, need_pinfo + 4); + bfd_put_16 (link_info.output_bfd, (bfd_vma) 0, need_pinfo + 8); + bfd_put_16 (link_info.output_bfd, (bfd_vma) 0, need_pinfo + 10); + strcpy ((char *) need_pnames, inp->filename); + } + else + { + char *verstr; + int maj, min; + + bfd_put_32 (link_info.output_bfd, (bfd_vma) 0x80000000, + need_pinfo + 4); + maj = 0; + min = 0; + verstr = strstr (inp->filename, ".so."); + if (verstr != NULL) + sscanf (verstr, ".so.%d.%d", &maj, &min); + bfd_put_16 (link_info.output_bfd, (bfd_vma) maj, need_pinfo + 8); + bfd_put_16 (link_info.output_bfd, (bfd_vma) min, need_pinfo + 10); + strcpy ((char *) need_pnames, inp->local_sym_name + 2); + } + + c = (need_pinfo - need_contents) / NEED_ENTRY_SIZE; + if (c + 1 >= need_entries) + bfd_put_32 (link_info.output_bfd, (bfd_vma) 0, need_pinfo + 12); + else + bfd_put_32 (link_info.output_bfd, (bfd_vma) (c + 1) * NEED_ENTRY_SIZE, + need_pinfo + 12); + + need_pinfo += NEED_ENTRY_SIZE; + need_pnames += strlen ((char *) need_pnames) + 1; + } +} + +static char * +gld${EMULATION_NAME}_get_script (int *isfile) +EOF + +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +fragment <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + gld${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld${EMULATION_NAME}_before_allocation, + gld${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + gld${EMULATION_NAME}_create_output_section_statements, + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + gld${EMULATION_NAME}_set_symbols, + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/ticoff.em b/binutils-2.21/ld/emultempl/ticoff.em new file mode 100644 index 0000000..dff1d70 --- /dev/null +++ b/binutils-2.21/ld/emultempl/ticoff.em @@ -0,0 +1,186 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +(echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) +fragment <<EOF +/* This file is part of GLD, the Gnu Linker. + Copyright 1999, 2000, 2002, 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. */ + +/* For TI COFF */ +/* Need to determine load and run pages for output sections */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +static int coff_version; + +/* TI COFF extra command line options */ +#define OPTION_COFF_FORMAT (300 + 1) + +static void +gld${EMULATION_NAME}_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[] = { + /* TI COFF options */ + {"format", required_argument, NULL, OPTION_COFF_FORMAT }, + {NULL, no_argument, NULL, 0} + }; + + *longopts = (struct option *) + xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +static void +gld_${EMULATION_NAME}_list_options (FILE * file) +{ + fprintf (file, _(" --format 0|1|2 Specify which COFF version to use\n")); +} + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + switch (optc) + { + default: + return FALSE; + + case OPTION_COFF_FORMAT: + if ((*optarg == '0' || *optarg == '1' || *optarg == '2') + && optarg[1] == '\0') + { + static char buf[] = "coffX-${OUTPUT_FORMAT_TEMPLATE}"; + coff_version = *optarg - '0'; + buf[4] = *optarg; + lang_add_output_format (buf, NULL, NULL, 0); + } + else + { + einfo (_("%P%F: invalid COFF format version %s\n"), optarg); + } + break; + } + return FALSE; +} + +static void +gld_${EMULATION_NAME}_before_parse(void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +if test -n "$COMPILE_IN" +then +# Scripts compiled in. + +# sed commands to quote an ld script as a C string. +sc='s/["\\]/\\&/g +s/$/\\n\\/ +1s/^/"/ +$s/$/n"/ +' +fragment <<EOF +{ + *isfile = 0; + if (link_info.relocatable && config.build_constructors) + return `sed "$sc" ldscripts/${EMULATION_NAME}.xu`; + else if (link_info.relocatable) + return `sed "$sc" ldscripts/${EMULATION_NAME}.xr`; + else if (!config.text_read_only) + return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`; + else if (!config.magic_demand_paged) + return `sed "$sc" ldscripts/${EMULATION_NAME}.xn`; + else + return `sed "$sc" ldscripts/${EMULATION_NAME}.x`; +} +EOF + +else +# Scripts read from the filesystem. + +fragment <<EOF +{ + *isfile = 1; + + if (link_info.relocatable && config.build_constructors) + return "ldscripts/${EMULATION_NAME}.xu"; + else if (link_info.relocatable) + return "ldscripts/${EMULATION_NAME}.xr"; + else if (!config.text_read_only) + return "ldscripts/${EMULATION_NAME}.xbn"; + else if (!config.magic_demand_paged) + return "ldscripts/${EMULATION_NAME}.xn"; + else + return "ldscripts/${EMULATION_NAME}.x"; +} +EOF + +fi + +fragment <<EOF +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + after_parse_default, + after_open_default, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + before_allocation_default, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set_symbols */ + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + NULL, /* unrecognized_file */ + gld_${EMULATION_NAME}_list_options, + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/vanilla.em b/binutils-2.21/ld/emultempl/vanilla.em new file mode 100644 index 0000000..4a83dfd --- /dev/null +++ b/binutils-2.21/ld/emultempl/vanilla.em @@ -0,0 +1,87 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +fragment <<EOF +/* A vanilla emulation with no defaults + Copyright 1991, 1992, 1994, 2000, 2001, 2002, 2003, 2005, 2007, 2008 + 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 "bfdlink.h" + +#include "ld.h" +#include "ldmisc.h" +#include "ldmain.h" + +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" + +static void vanilla_before_parse (void) +{ +} + +static void +vanilla_set_output_arch (void) +{ + /* Set the output architecture and machine if possible */ + unsigned long machine = 0; + bfd_set_arch_mach (link_info.output_bfd, + ldfile_output_architecture, machine); +} + +static char * +vanilla_get_script (int *isfile) +{ + *isfile = 0; + return ""; +} + +struct ld_emulation_xfer_struct ld_vanilla_emulation = +{ + vanilla_before_parse, + syslib_default, + hll_default, + after_parse_default, + after_open_default, + after_allocation_default, + vanilla_set_output_arch, + ldemul_default_target, + before_allocation_default, + vanilla_get_script, + "vanilla", + "a.out-sunos-big", + finish_default, + NULL, /* create output section statements */ + NULL, /* open dynamic archive */ + NULL, /* place orphan */ + NULL, /* set symbols */ + NULL, /* parse args */ + NULL, /* add_options */ + NULL, /* handle_option */ + NULL, /* unrecognized file */ + NULL, /* list options */ + NULL, /* recognized file */ + NULL, /* find_potential_libraries */ + NULL /* new_vers_pattern */ +}; +EOF diff --git a/binutils-2.21/ld/emultempl/vms.em b/binutils-2.21/ld/emultempl/vms.em new file mode 100644 index 0000000..f21796b --- /dev/null +++ b/binutils-2.21/ld/emultempl/vms.em @@ -0,0 +1,126 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2010 +# 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. +# + +# This file is sourced from generic.em. + +fragment <<EOF +static void +gld${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + config.dynamic_link = TRUE; + config.has_shared = FALSE; /* Not yet. */ +} + +/* This is called before the input files are opened. We add the + standard library. */ + +static void +gld${EMULATION_NAME}_create_output_section_statements (void) +{ + lang_add_input_file ("imagelib", lang_input_file_is_l_enum, NULL); + lang_add_input_file ("starlet", lang_input_file_is_l_enum, NULL); + lang_add_input_file ("sys\$public_vectors", lang_input_file_is_l_enum, NULL); +} + +/* Try to open a dynamic archive. This is where we know that VMS + shared images (dynamic libraries) have an extension of .exe. */ + +static bfd_boolean +gld${EMULATION_NAME}_open_dynamic_archive (const char *arch ATTRIBUTE_UNUSED, + search_dirs_type *search, + lang_input_statement_type *entry) +{ + char *string; + + if (! entry->is_archive) + return FALSE; + + string = (char *) xmalloc (strlen (search->name) + + strlen (entry->filename) + + sizeof "/.exe"); + + sprintf (string, "%s/%s.exe", search->name, entry->filename); + + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + + entry->filename = string; + + return TRUE; +} + +static int +gld${EMULATION_NAME}_find_potential_libraries + (char *name, lang_input_statement_type *entry) +{ + return ldfile_open_file_search (name, entry, "", ".olb"); +} + +/* Place an orphan section. We use this to put random OVR sections. + Much borrowed from elf32.em. */ + +static lang_output_section_statement_type * +vms_place_orphan (asection *s, + const char *secname ATTRIBUTE_UNUSED, + int constraint ATTRIBUTE_UNUSED) +{ + static struct orphan_save hold_data = + { + "\$DATA\$", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 + }; + + /* We have nothing to say for anything other than a final link or an excluded + section. */ + if (link_info.relocatable + || (s->flags & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD) + return NULL; + + /* FIXME: we should place sections by VMS program section flags. */ + + /* Only handle data sections. */ + if ((s->flags & SEC_DATA) == 0) + return NULL; + + if (hold_data.os == NULL) + hold_data.os = lang_output_section_find (hold_data.name); + + if (hold_data.os != NULL) + { + lang_add_section (&hold_data.os->children, s, hold_data.os); + return hold_data.os; + } + else + return NULL; +} +EOF + +LDEMUL_PLACE_ORPHAN=vms_place_orphan +LDEMUL_BEFORE_PARSE=gld"$EMULATION_NAME"_before_parse +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=gld"$EMULATION_NAME"_create_output_section_statements +LDEMUL_FIND_POTENTIAL_LIBRARIES=gld"$EMULATION_NAME"_find_potential_libraries +LDEMUL_OPEN_DYNAMIC_ARCHIVE=gld"$EMULATION_NAME"_open_dynamic_archive diff --git a/binutils-2.21/ld/emultempl/vxworks.em b/binutils-2.21/ld/emultempl/vxworks.em new file mode 100644 index 0000000..7a21ac3 --- /dev/null +++ b/binutils-2.21/ld/emultempl/vxworks.em @@ -0,0 +1,102 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006, 2007, 2008, 2010 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. +# + +if test -n "$VXWORKS_BASE_EM_FILE" ; then + source_em "${srcdir}/emultempl/${VXWORKS_BASE_EM_FILE}.em" +fi + +fragment <<EOF + +static int force_dynamic; + +static void +vxworks_before_parse (void) +{ + ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse} (); + config.rpath_separator = ';'; +} + +static void +vxworks_after_open (void) +{ + ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open} (); + + if (force_dynamic + && link_info.input_bfds + && bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && !_bfd_elf_link_create_dynamic_sections (link_info.input_bfds, + &link_info)) + einfo ("%X%P: Cannot create dynamic sections %E\n"); + + if (!force_dynamic + && !link_info.shared + && bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && elf_hash_table (&link_info)->dynamic_sections_created) + einfo ("%X%P: Dynamic sections created in non-dynamic link\n"); +} + +EOF + +PARSE_AND_LIST_PROLOGUE=$PARSE_AND_LIST_PROLOGUE' +enum { + OPTION_FORCE_DYNAMIC = 501 +}; +' + +PARSE_AND_LIST_LONGOPTS=$PARSE_AND_LIST_LONGOPTS' + {"force-dynamic", no_argument, NULL, OPTION_FORCE_DYNAMIC}, +' + +PARSE_AND_LIST_OPTIONS=$PARSE_AND_LIST_OPTIONS' + fprintf (file, _("\ + --force-dynamic Always create dynamic sections\n")); +' + +PARSE_AND_LIST_ARGS_CASES=$PARSE_AND_LIST_ARGS_CASES' + case OPTION_FORCE_DYNAMIC: + force_dynamic = 1; + break; +' + +# Hook in our routines above. There are three possibilities: +# +# (1) VXWORKS_BASE_EM_FILE did not set the hook's LDEMUL_FOO variable. +# We want to define LDEMUL_FOO to vxworks_foo in that case, +# +# (2) VXWORKS_BASE_EM_FILE set the hook's LDEMUL_FOO variable to +# gld${EMULATION_NAME}_foo. This means that the file has +# replaced elf32.em's default definition, so we simply #define +# the current value of LDEMUL_FOO to vxworks_foo. +# +# (3) VXWORKS_BASE_EM_FILE set the hook's LDEMUL_FOO variable to +# something other than gld${EMULATION_NAME}_foo. We handle +# this case in the same way as (1). +for override in before_parse after_open; do + var="LDEMUL_`echo ${override} | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`" + eval value=\$${var} + if test "${value}" = "gld${EMULATION_NAME}_${override}"; then + fragment <<EOF +#define ${value} vxworks_${override} +EOF + else + eval $var=vxworks_${override} + fi +done diff --git a/binutils-2.21/ld/emultempl/xtensaelf.em b/binutils-2.21/ld/emultempl/xtensaelf.em new file mode 100644 index 0000000..b7da721 --- /dev/null +++ b/binutils-2.21/ld/emultempl/xtensaelf.em @@ -0,0 +1,1960 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# 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. +# + +# This file is sourced from elf32.em, and defines extra xtensa-elf +# specific routines. +# +fragment <<EOF + +#include <xtensa-config.h> +#include "../bfd/elf-bfd.h" +#include "../bfd/libbfd.h" +#include "elf/xtensa.h" +#include "bfd.h" + +/* Provide default values for new configuration settings. */ +#ifndef XSHAL_ABI +#define XSHAL_ABI 0 +#endif + +static void xtensa_wild_group_interleave (lang_statement_union_type *); +static void xtensa_colocate_output_literals (lang_statement_union_type *); +static void xtensa_strip_inconsistent_linkonce_sections + (lang_statement_list_type *); + + +/* This number is irrelevant until we turn on use_literal_pages */ +static bfd_vma xtensa_page_power = 12; /* 4K pages. */ + +/* To force a page break between literals and text, change + xtensa_use_literal_pages to "TRUE". */ +static bfd_boolean xtensa_use_literal_pages = FALSE; + +#define EXTRA_VALIDATION 0 + + +static char * +elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED, + char **argv ATTRIBUTE_UNUSED) +{ + if (XCHAL_HAVE_BE) + return "${BIG_OUTPUT_FORMAT}"; + else + return "${LITTLE_OUTPUT_FORMAT}"; +} + + +static void +elf_xtensa_before_parse (void) +{ + /* Just call the default hook.... Tensilica's version of this function + does some other work that isn't relevant here. */ + gld${EMULATION_NAME}_before_parse (); +} + + +static void +remove_section (bfd *abfd, asection *os) +{ + asection **spp; + for (spp = &abfd->sections; *spp; spp = &(*spp)->next) + if (*spp == os) + { + *spp = os->next; + os->owner->section_count--; + break; + } +} + + +static bfd_boolean +replace_insn_sec_with_prop_sec (bfd *abfd, + const char *insn_sec_name, + const char *prop_sec_name, + char **error_message) +{ + asection *insn_sec; + asection *prop_sec; + bfd_byte *prop_contents = NULL; + bfd_byte *insn_contents = NULL; + unsigned entry_count; + unsigned entry; + Elf_Internal_Shdr *rel_hdr; + Elf_Internal_Rela *internal_relocs = NULL; + unsigned reloc_count; + + *error_message = ""; + insn_sec = bfd_get_section_by_name (abfd, insn_sec_name); + if (insn_sec == NULL) + return TRUE; + entry_count = insn_sec->size / 8; + + prop_sec = bfd_get_section_by_name (abfd, prop_sec_name); + if (prop_sec != NULL && insn_sec != NULL) + { + *error_message = _("file already has property tables"); + return FALSE; + } + + if (insn_sec->size != 0) + { + insn_contents = (bfd_byte *) bfd_malloc (insn_sec->size); + if (insn_contents == NULL) + { + *error_message = _("out of memory"); + goto cleanup; + } + if (! bfd_get_section_contents (abfd, insn_sec, insn_contents, + (file_ptr) 0, insn_sec->size)) + { + *error_message = _("failed to read section contents"); + goto cleanup; + } + } + + /* Create a property table section for it. */ + prop_sec_name = strdup (prop_sec_name); + prop_sec = bfd_make_section_with_flags + (abfd, prop_sec_name, bfd_get_section_flags (abfd, insn_sec)); + if (prop_sec == NULL + || ! bfd_set_section_alignment (abfd, prop_sec, 2)) + { + *error_message = _("could not create new section"); + goto cleanup; + } + + prop_sec->size = entry_count * 12; + prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size); + elf_section_data (prop_sec)->this_hdr.contents = prop_contents; + + /* The entry size and size must be set to allow the linker to compute + the number of relocations since it does not use reloc_count. */ + rel_hdr = _bfd_elf_single_rel_hdr (prop_sec); + rel_hdr->sh_entsize = sizeof (Elf32_External_Rela); + rel_hdr->sh_size = _bfd_elf_single_rel_hdr (insn_sec)->sh_size; + + if (prop_contents == NULL && prop_sec->size != 0) + { + *error_message = _("could not allocate section contents"); + goto cleanup; + } + + /* Read the relocations. */ + reloc_count = insn_sec->reloc_count; + if (reloc_count != 0) + { + /* If there is already an internal_reloc, then save it so that the + read_relocs function freshly allocates a copy. */ + Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs; + + elf_section_data (insn_sec)->relocs = NULL; + internal_relocs = + _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE); + elf_section_data (insn_sec)->relocs = saved_relocs; + + if (internal_relocs == NULL) + { + *error_message = _("out of memory"); + goto cleanup; + } + } + + /* Create a relocation section for the property section. */ + if (internal_relocs != NULL) + { + elf_section_data (prop_sec)->relocs = internal_relocs; + prop_sec->reloc_count = reloc_count; + } + + /* Now copy each insn table entry to the prop table entry with + appropriate flags. */ + for (entry = 0; entry < entry_count; ++entry) + { + unsigned value; + unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM + | XTENSA_PROP_INSN_NO_REORDER); + value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0); + bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0); + value = bfd_get_32 (abfd, insn_contents + entry * 8 + 4); + bfd_put_32 (abfd, value, prop_contents + entry * 12 + 4); + bfd_put_32 (abfd, flags, prop_contents + entry * 12 + 8); + } + + /* Now copy all of the relocations. Change offsets for the + instruction table section to offsets in the property table + section. */ + if (internal_relocs) + { + unsigned i; + + for (i = 0; i < reloc_count; i++) + { + Elf_Internal_Rela *rela; + unsigned r_offset; + + rela = &internal_relocs[i]; + + /* If this relocation is to the .xt.insn section, + change the section number and the offset. */ + r_offset = rela->r_offset; + r_offset += 4 * (r_offset / 8); + rela->r_offset = r_offset; + } + } + + remove_section (abfd, insn_sec); + + if (insn_contents) + free (insn_contents); + + return TRUE; + + cleanup: + if (prop_sec && prop_sec->owner) + remove_section (abfd, prop_sec); + if (insn_contents) + free (insn_contents); + if (internal_relocs) + free (internal_relocs); + + return FALSE; +} + + +#define PROP_SEC_BASE_NAME ".xt.prop" +#define INSN_SEC_BASE_NAME ".xt.insn" +#define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x." + + +static void +replace_instruction_table_sections (bfd *abfd, asection *sec) +{ + char *message = ""; + const char *insn_sec_name = NULL; + char *prop_sec_name = NULL; + char *owned_prop_sec_name = NULL; + const char *sec_name; + + sec_name = bfd_get_section_name (abfd, sec); + if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0) + { + insn_sec_name = INSN_SEC_BASE_NAME; + prop_sec_name = PROP_SEC_BASE_NAME; + } + else if (CONST_STRNEQ (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME)) + { + insn_sec_name = sec_name; + owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20); + prop_sec_name = owned_prop_sec_name; + strcpy (prop_sec_name, ".gnu.linkonce.prop.t."); + strcat (prop_sec_name, + sec_name + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)); + } + if (insn_sec_name != NULL) + { + if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, + &message)) + { + einfo (_("%P: warning: failed to convert %s table in %B (%s); subsequent disassembly may be incomplete\n"), + insn_sec_name, abfd, message); + } + } + if (owned_prop_sec_name) + free (owned_prop_sec_name); +} + + +/* This is called after all input sections have been opened to convert + instruction tables (.xt.insn, gnu.linkonce.x.*) tables into property + tables (.xt.prop) before any section placement. */ + +static void +elf_xtensa_after_open (void) +{ + /* First call the ELF version. */ + gld${EMULATION_NAME}_after_open (); + + /* Now search the input files looking for instruction table sections. */ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *sec = f->the_bfd->sections; + asection *next_sec; + + /* Do not use bfd_map_over_sections here since we are removing + sections as we iterate. */ + while (sec != NULL) + { + next_sec = sec->next; + replace_instruction_table_sections (f->the_bfd, sec); + sec = next_sec; + } + } +} + + +static bfd_boolean +xt_config_info_unpack_and_check (char *data, + bfd_boolean *pmismatch, + char **pmsg) +{ + char *d, *key; + unsigned num; + + *pmismatch = FALSE; + + d = data; + while (*d) + { + key = d; + d = strchr (d, '='); + if (! d) + goto error; + + /* Overwrite the equal sign. */ + *d++ = 0; + + /* Check if this is a quoted string or a number. */ + if (*d == '"') + { + /* No string values are currently checked by LD; + just skip over the quotes. */ + d++; + d = strchr (d, '"'); + if (! d) + goto error; + /* Overwrite the trailing quote. */ + *d++ = 0; + } + else + { + if (*d == 0) + goto error; + num = strtoul (d, &d, 0); + + if (! strcmp (key, "ABI")) + { + if (num != XSHAL_ABI) + { + *pmismatch = TRUE; + *pmsg = "ABI does not match"; + } + } + else if (! strcmp (key, "USE_ABSOLUTE_LITERALS")) + { + if (num != XSHAL_USE_ABSOLUTE_LITERALS) + { + *pmismatch = TRUE; + *pmsg = "incompatible use of the Extended L32R option"; + } + } + } + + if (*d++ != '\n') + goto error; + } + + return TRUE; + + error: + return FALSE; +} + + +#define XTINFO_NAME "Xtensa_Info" +#define XTINFO_NAMESZ 12 +#define XTINFO_TYPE 1 + +static void +check_xtensa_info (bfd *abfd, asection *info_sec) +{ + char *data, *errmsg = ""; + bfd_boolean mismatch; + + data = xmalloc (info_sec->size); + if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size)) + einfo (_("%F%P:%B: cannot read contents of section %A\n"), abfd, info_sec); + + if (info_sec->size > 24 + && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4) + && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ + && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE + && strcmp (data + 12, XTINFO_NAME) == 0 + && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ, + &mismatch, &errmsg)) + { + if (mismatch) + einfo (_("%P:%B: warning: incompatible Xtensa configuration (%s)\n"), + abfd, errmsg); + } + else + einfo (_("%P:%B: warning: cannot parse .xtensa.info section\n"), abfd); + + free (data); +} + + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +elf_xtensa_before_allocation (void) +{ + asection *info_sec, *first_info_sec; + bfd *first_bfd; + bfd_boolean is_big_endian = XCHAL_HAVE_BE; + + /* Check that the output endianness matches the Xtensa + configuration. The BFD library always includes both big and + little endian target vectors for Xtensa, but it only supports the + detailed instruction encode/decode operations (such as are + required to process relocations) for the selected Xtensa + configuration. */ + + if (is_big_endian + && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + { + einfo (_("%F%P: little endian output does not match " + "Xtensa configuration\n")); + } + if (!is_big_endian + && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_BIG) + { + einfo (_("%F%P: big endian output does not match " + "Xtensa configuration\n")); + } + + /* Keep track of the first input .xtensa.info section, and as a fallback, + the first input bfd where a .xtensa.info section could be created. + After the input .xtensa.info has been checked, the contents of the + first one will be replaced with the output .xtensa.info table. */ + first_info_sec = 0; + first_bfd = 0; + + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + /* Check that the endianness for each input file matches the output. + The merge_private_bfd_data hook has already reported any mismatches + as errors, but those errors are not fatal. At this point, we + cannot go any further if there are any mismatches. */ + if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG)) + einfo (_("%F%P: cross-endian linking for %B not supported\n"), + f->the_bfd); + + if (! first_bfd) + first_bfd = f->the_bfd; + + info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info"); + if (! info_sec) + continue; + + if (! first_info_sec) + first_info_sec = info_sec; + + /* Unpack the .xtensa.info section and check it against the current + Xtensa configuration. */ + check_xtensa_info (f->the_bfd, info_sec); + + /* Do not include this copy of .xtensa.info in the output. */ + info_sec->size = 0; + info_sec->flags |= SEC_EXCLUDE; + } + + /* Reuse the first .xtensa.info input section to hold the output + .xtensa.info; or, if none were found, create a new section in the + first input bfd (assuming there is one). */ + info_sec = first_info_sec; + if (! info_sec && first_bfd) + { + info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info", + SEC_HAS_CONTENTS | SEC_READONLY); + if (! info_sec) + einfo (_("%F%P: failed to create .xtensa.info section\n")); + } + if (info_sec) + { + int xtensa_info_size; + char *data; + + info_sec->flags &= ~SEC_EXCLUDE; + info_sec->flags |= SEC_IN_MEMORY; + + data = xmalloc (100); + sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n", + XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI); + xtensa_info_size = strlen (data) + 1; + + /* Add enough null terminators to pad to a word boundary. */ + do + data[xtensa_info_size++] = 0; + while ((xtensa_info_size & 3) != 0); + + info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size; + info_sec->contents = xmalloc (info_sec->size); + bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0); + bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4); + bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8); + memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ); + memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size); + free (data); + } + + /* Enable relaxation by default if the "--no-relax" option was not + specified. This is done here instead of in the before_parse hook + because there is a check in main() to prohibit use of --relax and + -r together and that combination should be allowed for Xtensa. */ + if (RELAXATION_DISABLED_BY_DEFAULT) + ENABLE_RELAXATION; + + xtensa_strip_inconsistent_linkonce_sections (stat_ptr); + + gld${EMULATION_NAME}_before_allocation (); + + xtensa_wild_group_interleave (stat_ptr->head); + + if (RELAXATION_ENABLED) + xtensa_colocate_output_literals (stat_ptr->head); + + /* TBD: We need to force the page alignments to here and only do + them as needed for the entire output section. Finally, if this + is a relocatable link then we need to add alignment notes so + that the literals can be separated later. */ +} + + +typedef struct wildcard_list section_name_list; + +typedef struct reloc_deps_e_t reloc_deps_e; +typedef struct reloc_deps_section_t reloc_deps_section; +typedef struct reloc_deps_graph_t reloc_deps_graph; + + +struct reloc_deps_e_t +{ + asection *src; /* Contains l32rs. */ + asection *tgt; /* Contains literals. */ + reloc_deps_e *next; +}; + +/* Place these in the userdata field. */ +struct reloc_deps_section_t +{ + reloc_deps_e *preds; + reloc_deps_e *succs; + bfd_boolean is_only_literal; +}; + + +struct reloc_deps_graph_t +{ + size_t count; + size_t size; + asection **sections; +}; + +static void xtensa_layout_wild + (const reloc_deps_graph *, lang_wild_statement_type *); + +typedef void (*deps_callback_t) (asection *, /* src_sec */ + bfd_vma, /* src_offset */ + asection *, /* target_sec */ + bfd_vma, /* target_offset */ + void *); /* closure */ + +extern bfd_boolean xtensa_callback_required_dependence + (bfd *, asection *, struct bfd_link_info *, deps_callback_t, void *); +static void xtensa_ldlang_clear_addresses (lang_statement_union_type *); +static bfd_boolean ld_local_file_relocations_fit + (lang_statement_union_type *, const reloc_deps_graph *); +static bfd_vma ld_assign_relative_paged_dot + (bfd_vma, lang_statement_union_type *, const reloc_deps_graph *, + bfd_boolean); +static bfd_vma ld_xtensa_insert_page_offsets + (bfd_vma, lang_statement_union_type *, reloc_deps_graph *, bfd_boolean); +#if EXTRA_VALIDATION +static size_t ld_count_children (lang_statement_union_type *); +#endif + +extern lang_statement_list_type constructor_list; + +static reloc_deps_section * +xtensa_get_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + asection *sec) +{ + /* We have a separate function for this so that + we could in the future keep a completely independent + structure that maps a section to its dependence edges. + For now, we place these in the sec->userdata field. */ + reloc_deps_section *sec_deps = sec->userdata; + return sec_deps; +} + +static void +xtensa_set_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + asection *sec, + reloc_deps_section *deps_section) +{ + sec->userdata = deps_section; +} + + +/* This is used to keep a list of all of the sections participating in + the graph so we can clean them up quickly. */ + +static void +xtensa_append_section_deps (reloc_deps_graph *deps, asection *sec) +{ + if (deps->size <= deps->count) + { + asection **new_sections; + size_t i; + size_t new_size; + + new_size = deps->size * 2; + if (new_size == 0) + new_size = 20; + + new_sections = xmalloc (sizeof (asection *) * new_size); + memset (new_sections, 0, sizeof (asection *) * new_size); + for (i = 0; i < deps->count; i++) + { + new_sections[i] = deps->sections[i]; + } + if (deps->sections != NULL) + free (deps->sections); + deps->sections = new_sections; + deps->size = new_size; + } + deps->sections[deps->count] = sec; + deps->count++; +} + + +static void +free_reloc_deps_graph (reloc_deps_graph *deps) +{ + size_t i; + for (i = 0; i < deps->count; i++) + { + asection *sec = deps->sections[i]; + reloc_deps_section *sec_deps; + sec_deps = xtensa_get_section_deps (deps, sec); + if (sec_deps) + { + reloc_deps_e *next; + while (sec_deps->succs != NULL) + { + next = sec_deps->succs->next; + free (sec_deps->succs); + sec_deps->succs = next; + } + + while (sec_deps->preds != NULL) + { + next = sec_deps->preds->next; + free (sec_deps->preds); + sec_deps->preds = next; + } + free (sec_deps); + } + xtensa_set_section_deps (deps, sec, NULL); + } + if (deps->sections) + free (deps->sections); + + free (deps); +} + + +static bfd_boolean +section_is_source (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + lang_statement_union_type *s) +{ + asection *sec; + const reloc_deps_section *sec_deps; + + if (s->header.type != lang_input_section_enum) + return FALSE; + sec = s->input_section.section; + + sec_deps = xtensa_get_section_deps (deps, sec); + return sec_deps && sec_deps->succs != NULL; +} + + +static bfd_boolean +section_is_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + lang_statement_union_type *s) +{ + asection *sec; + const reloc_deps_section *sec_deps; + + if (s->header.type != lang_input_section_enum) + return FALSE; + sec = s->input_section.section; + + sec_deps = xtensa_get_section_deps (deps, sec); + return sec_deps && sec_deps->preds != NULL; +} + + +static bfd_boolean +section_is_source_or_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + lang_statement_union_type *s) +{ + return (section_is_source (deps, s) + || section_is_target (deps, s)); +} + + +typedef struct xtensa_ld_iter_stack_t xtensa_ld_iter_stack; +typedef struct xtensa_ld_iter_t xtensa_ld_iter; + +struct xtensa_ld_iter_t +{ + lang_statement_union_type *parent; /* Parent of the list. */ + lang_statement_list_type *l; /* List that holds it. */ + lang_statement_union_type **loc; /* Place in the list. */ +}; + +struct xtensa_ld_iter_stack_t +{ + xtensa_ld_iter iterloc; /* List that hold it. */ + + xtensa_ld_iter_stack *next; /* Next in the stack. */ + xtensa_ld_iter_stack *prev; /* Back pointer for stack. */ +}; + + +static void +ld_xtensa_move_section_after (xtensa_ld_iter *to, xtensa_ld_iter *current) +{ + lang_statement_union_type *to_next; + lang_statement_union_type *current_next; + lang_statement_union_type **e; + +#if EXTRA_VALIDATION + size_t old_to_count, new_to_count; + size_t old_current_count, new_current_count; +#endif + + if (to == current) + return; + +#if EXTRA_VALIDATION + old_to_count = ld_count_children (to->parent); + old_current_count = ld_count_children (current->parent); +#endif + + to_next = *(to->loc); + current_next = (*current->loc)->header.next; + + *(to->loc) = *(current->loc); + + *(current->loc) = current_next; + (*(to->loc))->header.next = to_next; + + /* reset "to" list tail */ + for (e = &to->l->head; *e != NULL; e = &(*e)->header.next) + ; + to->l->tail = e; + + /* reset "current" list tail */ + for (e = ¤t->l->head; *e != NULL; e = &(*e)->header.next) + ; + current->l->tail = e; + +#if EXTRA_VALIDATION + new_to_count = ld_count_children (to->parent); + new_current_count = ld_count_children (current->parent); + + ASSERT ((old_to_count + old_current_count) + == (new_to_count + new_current_count)); +#endif +} + + +/* Can only be called with lang_statements that have lists. Returns + FALSE if the list is empty. */ + +static bfd_boolean +iter_stack_empty (xtensa_ld_iter_stack **stack_p) +{ + return *stack_p == NULL; +} + + +static bfd_boolean +iter_stack_push (xtensa_ld_iter_stack **stack_p, + lang_statement_union_type *parent) +{ + xtensa_ld_iter_stack *stack; + lang_statement_list_type *l = NULL; + + switch (parent->header.type) + { + case lang_output_section_statement_enum: + l = &parent->output_section_statement.children; + break; + case lang_wild_statement_enum: + l = &parent->wild_statement.children; + break; + case lang_group_statement_enum: + l = &parent->group_statement.children; + break; + default: + ASSERT (0); + return FALSE; + } + + /* Empty. do not push. */ + if (l->tail == &l->head) + return FALSE; + + stack = xmalloc (sizeof (xtensa_ld_iter_stack)); + memset (stack, 0, sizeof (xtensa_ld_iter_stack)); + stack->iterloc.parent = parent; + stack->iterloc.l = l; + stack->iterloc.loc = &l->head; + + stack->next = *stack_p; + stack->prev = NULL; + if (*stack_p != NULL) + (*stack_p)->prev = stack; + *stack_p = stack; + return TRUE; +} + + +static void +iter_stack_pop (xtensa_ld_iter_stack **stack_p) +{ + xtensa_ld_iter_stack *stack; + + stack = *stack_p; + + if (stack == NULL) + { + ASSERT (stack != NULL); + return; + } + + if (stack->next != NULL) + stack->next->prev = NULL; + + *stack_p = stack->next; + free (stack); +} + + +/* This MUST be called if, during iteration, the user changes the + underlying structure. It will check for a NULL current and advance + accordingly. */ + +static void +iter_stack_update (xtensa_ld_iter_stack **stack_p) +{ + if (!iter_stack_empty (stack_p) + && (*(*stack_p)->iterloc.loc) == NULL) + { + iter_stack_pop (stack_p); + + while (!iter_stack_empty (stack_p) + && ((*(*stack_p)->iterloc.loc)->header.next == NULL)) + { + iter_stack_pop (stack_p); + } + if (!iter_stack_empty (stack_p)) + (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next; + } +} + + +static void +iter_stack_next (xtensa_ld_iter_stack **stack_p) +{ + xtensa_ld_iter_stack *stack; + lang_statement_union_type *current; + stack = *stack_p; + + current = *stack->iterloc.loc; + /* If we are on the first element. */ + if (current != NULL) + { + switch (current->header.type) + { + case lang_output_section_statement_enum: + case lang_wild_statement_enum: + case lang_group_statement_enum: + /* If the list if not empty, we are done. */ + if (iter_stack_push (stack_p, *stack->iterloc.loc)) + return; + /* Otherwise increment the pointer as normal. */ + break; + default: + break; + } + } + + while (!iter_stack_empty (stack_p) + && ((*(*stack_p)->iterloc.loc)->header.next == NULL)) + { + iter_stack_pop (stack_p); + } + if (!iter_stack_empty (stack_p)) + (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next; +} + + +static lang_statement_union_type * +iter_stack_current (xtensa_ld_iter_stack **stack_p) +{ + return *((*stack_p)->iterloc.loc); +} + + +/* The iter stack is a preorder. */ + +static void +iter_stack_create (xtensa_ld_iter_stack **stack_p, + lang_statement_union_type *parent) +{ + iter_stack_push (stack_p, parent); +} + + +static void +iter_stack_copy_current (xtensa_ld_iter_stack **stack_p, xtensa_ld_iter *front) +{ + *front = (*stack_p)->iterloc; +} + + +static void +xtensa_colocate_literals (reloc_deps_graph *deps, + lang_statement_union_type *statement) +{ + /* Keep a stack of pointers to control iteration through the contours. */ + xtensa_ld_iter_stack *stack = NULL; + xtensa_ld_iter_stack **stack_p = &stack; + + xtensa_ld_iter front; /* Location where new insertion should occur. */ + xtensa_ld_iter *front_p = NULL; + + xtensa_ld_iter current; /* Location we are checking. */ + xtensa_ld_iter *current_p = NULL; + bfd_boolean in_literals = FALSE; + + if (deps->count == 0) + return; + + iter_stack_create (stack_p, statement); + + while (!iter_stack_empty (stack_p)) + { + bfd_boolean skip_increment = FALSE; + lang_statement_union_type *l = iter_stack_current (stack_p); + + switch (l->header.type) + { + case lang_assignment_statement_enum: + /* Any assignment statement should block reordering across it. */ + front_p = NULL; + in_literals = FALSE; + break; + + case lang_input_section_enum: + if (front_p == NULL) + { + in_literals = (section_is_target (deps, l) + && !section_is_source (deps, l)); + if (in_literals) + { + front_p = &front; + iter_stack_copy_current (stack_p, front_p); + } + } + else + { + bfd_boolean is_target; + current_p = ¤t; + iter_stack_copy_current (stack_p, current_p); + is_target = (section_is_target (deps, l) + && !section_is_source (deps, l)); + + if (in_literals) + { + iter_stack_copy_current (stack_p, front_p); + if (!is_target) + in_literals = FALSE; + } + else + { + if (is_target) + { + /* Try to insert in place. */ + ld_xtensa_move_section_after (front_p, current_p); + ld_assign_relative_paged_dot (0x100000, + statement, + deps, + xtensa_use_literal_pages); + + /* We use this code because it's already written. */ + if (!ld_local_file_relocations_fit (statement, deps)) + { + /* Move it back. */ + ld_xtensa_move_section_after (current_p, front_p); + /* Reset the literal placement. */ + iter_stack_copy_current (stack_p, front_p); + } + else + { + /* Move front pointer up by one. */ + front_p->loc = &(*front_p->loc)->header.next; + + /* Do not increment the current pointer. */ + skip_increment = TRUE; + } + } + } + } + break; + default: + break; + } + + if (!skip_increment) + iter_stack_next (stack_p); + else + /* Be careful to update the stack_p if it now is a null. */ + iter_stack_update (stack_p); + } + + lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, statement); +} + + +static void +xtensa_move_dependencies_to_front (reloc_deps_graph *deps, + lang_wild_statement_type *w) +{ + /* Keep a front pointer and a current pointer. */ + lang_statement_union_type **front; + lang_statement_union_type **current; + + /* Walk to the end of the targets. */ + for (front = &w->children.head; + (*front != NULL) && section_is_source_or_target (deps, *front); + front = &(*front)->header.next) + ; + + if (*front == NULL) + return; + + current = &(*front)->header.next; + while (*current != NULL) + { + if (section_is_source_or_target (deps, *current)) + { + /* Insert in place. */ + xtensa_ld_iter front_iter; + xtensa_ld_iter current_iter; + + front_iter.parent = (lang_statement_union_type *) w; + front_iter.l = &w->children; + front_iter.loc = front; + + current_iter.parent = (lang_statement_union_type *) w; + current_iter.l = &w->children; + current_iter.loc = current; + + ld_xtensa_move_section_after (&front_iter, ¤t_iter); + front = &(*front)->header.next; + } + else + { + current = &(*current)->header.next; + } + } +} + + +static bfd_boolean +deps_has_sec_edge (const reloc_deps_graph *deps, asection *src, asection *tgt) +{ + const reloc_deps_section *sec_deps; + const reloc_deps_e *sec_deps_e; + + sec_deps = xtensa_get_section_deps (deps, src); + if (sec_deps == NULL) + return FALSE; + + for (sec_deps_e = sec_deps->succs; + sec_deps_e != NULL; + sec_deps_e = sec_deps_e->next) + { + ASSERT (sec_deps_e->src == src); + if (sec_deps_e->tgt == tgt) + return TRUE; + } + return FALSE; +} + + +static bfd_boolean +deps_has_edge (const reloc_deps_graph *deps, + lang_statement_union_type *src, + lang_statement_union_type *tgt) +{ + if (!section_is_source (deps, src)) + return FALSE; + if (!section_is_target (deps, tgt)) + return FALSE; + + if (src->header.type != lang_input_section_enum) + return FALSE; + if (tgt->header.type != lang_input_section_enum) + return FALSE; + + return deps_has_sec_edge (deps, src->input_section.section, + tgt->input_section.section); +} + + +static void +add_deps_edge (reloc_deps_graph *deps, asection *src_sec, asection *tgt_sec) +{ + reloc_deps_section *src_sec_deps; + reloc_deps_section *tgt_sec_deps; + + reloc_deps_e *src_edge; + reloc_deps_e *tgt_edge; + + if (deps_has_sec_edge (deps, src_sec, tgt_sec)) + return; + + src_sec_deps = xtensa_get_section_deps (deps, src_sec); + if (src_sec_deps == NULL) + { + /* Add a section. */ + src_sec_deps = xmalloc (sizeof (reloc_deps_section)); + memset (src_sec_deps, 0, sizeof (reloc_deps_section)); + src_sec_deps->is_only_literal = 0; + src_sec_deps->preds = NULL; + src_sec_deps->succs = NULL; + xtensa_set_section_deps (deps, src_sec, src_sec_deps); + xtensa_append_section_deps (deps, src_sec); + } + + tgt_sec_deps = xtensa_get_section_deps (deps, tgt_sec); + if (tgt_sec_deps == NULL) + { + /* Add a section. */ + tgt_sec_deps = xmalloc (sizeof (reloc_deps_section)); + memset (tgt_sec_deps, 0, sizeof (reloc_deps_section)); + tgt_sec_deps->is_only_literal = 0; + tgt_sec_deps->preds = NULL; + tgt_sec_deps->succs = NULL; + xtensa_set_section_deps (deps, tgt_sec, tgt_sec_deps); + xtensa_append_section_deps (deps, tgt_sec); + } + + /* Add the edges. */ + src_edge = xmalloc (sizeof (reloc_deps_e)); + memset (src_edge, 0, sizeof (reloc_deps_e)); + src_edge->src = src_sec; + src_edge->tgt = tgt_sec; + src_edge->next = src_sec_deps->succs; + src_sec_deps->succs = src_edge; + + tgt_edge = xmalloc (sizeof (reloc_deps_e)); + memset (tgt_edge, 0, sizeof (reloc_deps_e)); + tgt_edge->src = src_sec; + tgt_edge->tgt = tgt_sec; + tgt_edge->next = tgt_sec_deps->preds; + tgt_sec_deps->preds = tgt_edge; +} + + +static void +build_deps_graph_callback (asection *src_sec, + bfd_vma src_offset ATTRIBUTE_UNUSED, + asection *target_sec, + bfd_vma target_offset ATTRIBUTE_UNUSED, + void *closure) +{ + reloc_deps_graph *deps = closure; + + /* If the target is defined. */ + if (target_sec != NULL) + add_deps_edge (deps, src_sec, target_sec); +} + + +static reloc_deps_graph * +ld_build_required_section_dependence (lang_statement_union_type *s) +{ + reloc_deps_graph *deps; + xtensa_ld_iter_stack *stack = NULL; + + deps = xmalloc (sizeof (reloc_deps_graph)); + deps->sections = NULL; + deps->count = 0; + deps->size = 0; + + for (iter_stack_create (&stack, s); + !iter_stack_empty (&stack); + iter_stack_next (&stack)) + { + lang_statement_union_type *l = iter_stack_current (&stack); + + if (l->header.type == lang_input_section_enum) + { + lang_input_section_type *input; + input = &l->input_section; + xtensa_callback_required_dependence (input->section->owner, + input->section, + &link_info, + /* Use the same closure. */ + build_deps_graph_callback, + deps); + } + } + return deps; +} + + +#if EXTRA_VALIDATION +static size_t +ld_count_children (lang_statement_union_type *s) +{ + size_t count = 0; + xtensa_ld_iter_stack *stack = NULL; + for (iter_stack_create (&stack, s); + !iter_stack_empty (&stack); + iter_stack_next (&stack)) + { + lang_statement_union_type *l = iter_stack_current (&stack); + ASSERT (l != NULL); + count++; + } + return count; +} +#endif /* EXTRA_VALIDATION */ + + +/* Check if a particular section is included in the link. This will only + be true for one instance of a particular linkonce section. */ + +static bfd_boolean input_section_found = FALSE; +static asection *input_section_target = NULL; + +static void +input_section_linked_worker (lang_statement_union_type *statement) +{ + if ((statement->header.type == lang_input_section_enum + && (statement->input_section.section == input_section_target))) + input_section_found = TRUE; +} + +static bfd_boolean +input_section_linked (asection *sec) +{ + input_section_found = FALSE; + input_section_target = sec; + lang_for_each_statement_worker (input_section_linked_worker, stat_ptr->head); + return input_section_found; +} + + +/* Strip out any linkonce property tables or XCC exception tables where the + associated linkonce text is from a different object file. Normally, + a matching set of linkonce sections is taken from the same object file, + but sometimes the files are compiled differently so that some of the + linkonce sections are not present in all files. Stripping the + inconsistent sections like this is not completely robust -- a much + better solution is to use comdat groups. */ + +static int linkonce_len = sizeof (".gnu.linkonce.") - 1; + +static bfd_boolean +is_inconsistent_linkonce_section (asection *sec) +{ + bfd *abfd = sec->owner; + const char *sec_name = bfd_get_section_name (abfd, sec); + const char *name; + + if ((bfd_get_section_flags (abfd, sec) & SEC_LINK_ONCE) == 0 + || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0) + return FALSE; + + /* Check if this is an Xtensa property section or an exception table + for Tensilica's XCC compiler. */ + name = sec_name + linkonce_len; + if (CONST_STRNEQ (name, "prop.")) + name = strchr (name + 5, '.') + 1; + else if (name[1] == '.' + && (name[0] == 'p' || name[0] == 'e' || name[0] == 'h')) + name += 2; + else + name = 0; + + if (name) + { + char *dep_sec_name = xmalloc (strlen (sec_name) + 1); + asection *dep_sec; + + /* Get the associated linkonce text section and check if it is + included in the link. If not, this section is inconsistent + and should be stripped. */ + strcpy (dep_sec_name, ".gnu.linkonce.t."); + strcat (dep_sec_name, name); + dep_sec = bfd_get_section_by_name (abfd, dep_sec_name); + if (dep_sec == NULL || ! input_section_linked (dep_sec)) + { + free (dep_sec_name); + return TRUE; + } + free (dep_sec_name); + } + + return FALSE; +} + + +static void +xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist) +{ + lang_statement_union_type **s_p = &slist->head; + while (*s_p) + { + lang_statement_union_type *s = *s_p; + lang_statement_union_type *s_next = (*s_p)->header.next; + + switch (s->header.type) + { + case lang_input_section_enum: + if (is_inconsistent_linkonce_section (s->input_section.section)) + { + s->input_section.section->output_section = bfd_abs_section_ptr; + *s_p = s_next; + continue; + } + break; + + case lang_constructors_statement_enum: + xtensa_strip_inconsistent_linkonce_sections (&constructor_list); + break; + + case lang_output_section_statement_enum: + if (s->output_section_statement.children.head) + xtensa_strip_inconsistent_linkonce_sections + (&s->output_section_statement.children); + break; + + case lang_wild_statement_enum: + xtensa_strip_inconsistent_linkonce_sections + (&s->wild_statement.children); + break; + + case lang_group_statement_enum: + xtensa_strip_inconsistent_linkonce_sections + (&s->group_statement.children); + 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_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + + s_p = &(*s_p)->header.next; + } + + /* Reset the tail of the list, in case the last entry was removed. */ + if (s_p != slist->tail) + slist->tail = s_p; +} + + +static void +xtensa_wild_group_interleave_callback (lang_statement_union_type *statement) +{ + lang_wild_statement_type *w; + reloc_deps_graph *deps; + if (statement->header.type == lang_wild_statement_enum) + { +#if EXTRA_VALIDATION + size_t old_child_count; + size_t new_child_count; +#endif + bfd_boolean no_reorder; + + w = &statement->wild_statement; + + no_reorder = FALSE; + + /* If it has 0 or 1 section bound, then do not reorder. */ + if (w->children.head == NULL + || (w->children.head->header.type == lang_input_section_enum + && w->children.head->header.next == NULL)) + no_reorder = TRUE; + + if (w->filenames_sorted) + no_reorder = TRUE; + + /* Check for sorting in a section list wildcard spec as well. */ + if (!no_reorder) + { + struct wildcard_list *l; + for (l = w->section_list; l != NULL; l = l->next) + { + if (l->spec.sorted == TRUE) + { + no_reorder = TRUE; + break; + } + } + } + + /* Special case until the NOREORDER linker directive is supported: + *(.init) output sections and *(.fini) specs may NOT be reordered. */ + + /* Check for sorting in a section list wildcard spec as well. */ + if (!no_reorder) + { + struct wildcard_list *l; + for (l = w->section_list; l != NULL; l = l->next) + { + if (l->spec.name + && ((strcmp (".init", l->spec.name) == 0) + || (strcmp (".fini", l->spec.name) == 0))) + { + no_reorder = TRUE; + break; + } + } + } + +#if EXTRA_VALIDATION + old_child_count = ld_count_children (statement); +#endif + + /* It is now officially a target. Build the graph of source + section -> target section (kept as a list of edges). */ + deps = ld_build_required_section_dependence (statement); + + /* If this wildcard does not reorder.... */ + if (!no_reorder && deps->count != 0) + { + /* First check for reverse dependences. Fix if possible. */ + xtensa_layout_wild (deps, w); + + xtensa_move_dependencies_to_front (deps, w); +#if EXTRA_VALIDATION + new_child_count = ld_count_children (statement); + ASSERT (new_child_count == old_child_count); +#endif + + xtensa_colocate_literals (deps, statement); + +#if EXTRA_VALIDATION + new_child_count = ld_count_children (statement); + ASSERT (new_child_count == old_child_count); +#endif + } + + /* Clean up. */ + free_reloc_deps_graph (deps); + } +} + + +static void +xtensa_wild_group_interleave (lang_statement_union_type *s) +{ + lang_for_each_statement_worker (xtensa_wild_group_interleave_callback, s); +} + + +static void +xtensa_layout_wild (const reloc_deps_graph *deps, lang_wild_statement_type *w) +{ + /* If it does not fit initially, we need to do this step. Move all + of the wild literal sections to a new list, then move each of + them back in just before the first section they depend on. */ + lang_statement_union_type **s_p; +#if EXTRA_VALIDATION + size_t old_count, new_count; + size_t ct1, ct2; +#endif + + lang_wild_statement_type literal_wild; + literal_wild.header.next = NULL; + literal_wild.header.type = lang_wild_statement_enum; + literal_wild.filename = NULL; + literal_wild.filenames_sorted = FALSE; + literal_wild.section_list = NULL; + literal_wild.keep_sections = FALSE; + literal_wild.children.head = NULL; + literal_wild.children.tail = &literal_wild.children.head; + +#if EXTRA_VALIDATION + old_count = ld_count_children ((lang_statement_union_type*) w); +#endif + + s_p = &w->children.head; + while (*s_p != NULL) + { + lang_statement_union_type *l = *s_p; + if (l->header.type == lang_input_section_enum) + { + if (section_is_target (deps, l) + && ! section_is_source (deps, l)) + { + /* Detach. */ + *s_p = l->header.next; + if (*s_p == NULL) + w->children.tail = s_p; + l->header.next = NULL; + + /* Append. */ + *literal_wild.children.tail = l; + literal_wild.children.tail = &l->header.next; + continue; + } + } + s_p = &(*s_p)->header.next; + } + +#if EXTRA_VALIDATION + ct1 = ld_count_children ((lang_statement_union_type*) w); + ct2 = ld_count_children ((lang_statement_union_type*) &literal_wild); + + ASSERT (old_count == (ct1 + ct2)); +#endif + + /* Now place them back in front of their dependent sections. */ + + while (literal_wild.children.head != NULL) + { + lang_statement_union_type *lit = literal_wild.children.head; + bfd_boolean placed = FALSE; + +#if EXTRA_VALIDATION + ASSERT (ct2 > 0); + ct2--; +#endif + + /* Detach. */ + literal_wild.children.head = lit->header.next; + if (literal_wild.children.head == NULL) + literal_wild.children.tail = &literal_wild.children.head; + lit->header.next = NULL; + + /* Find a spot to place it. */ + for (s_p = &w->children.head; *s_p != NULL; s_p = &(*s_p)->header.next) + { + lang_statement_union_type *src = *s_p; + if (deps_has_edge (deps, src, lit)) + { + /* Place it here. */ + lit->header.next = *s_p; + *s_p = lit; + placed = TRUE; + break; + } + } + + if (!placed) + { + /* Put it at the end. */ + *w->children.tail = lit; + w->children.tail = &lit->header.next; + } + } + +#if EXTRA_VALIDATION + new_count = ld_count_children ((lang_statement_union_type*) w); + ASSERT (new_count == old_count); +#endif +} + + +static void +xtensa_colocate_output_literals_callback (lang_statement_union_type *statement) +{ + reloc_deps_graph *deps; + if (statement->header.type == lang_output_section_statement_enum) + { + /* Now, we walk over the contours of the output section statement. + + First we build the literal section dependences as before. + + At the first uniquely_literal section, we mark it as a good + spot to place other literals. Continue walking (and counting + sizes) until we find the next literal section. If this + section can be moved to the first one, then we move it. If + we every find a modification of ".", start over. If we find + a labeling of the current location, start over. Finally, at + the end, if we require page alignment, add page alignments. */ + +#if EXTRA_VALIDATION + size_t old_child_count; + size_t new_child_count; +#endif + bfd_boolean no_reorder = FALSE; + +#if EXTRA_VALIDATION + old_child_count = ld_count_children (statement); +#endif + + /* It is now officially a target. Build the graph of source + section -> target section (kept as a list of edges). */ + + deps = ld_build_required_section_dependence (statement); + + /* If this wildcard does not reorder.... */ + if (!no_reorder) + { + /* First check for reverse dependences. Fix if possible. */ + xtensa_colocate_literals (deps, statement); + +#if EXTRA_VALIDATION + new_child_count = ld_count_children (statement); + ASSERT (new_child_count == old_child_count); +#endif + } + + /* Insert align/offset assignment statement. */ + if (xtensa_use_literal_pages) + { + ld_xtensa_insert_page_offsets (0, statement, deps, + xtensa_use_literal_pages); + lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, + statement); + } + + /* Clean up. */ + free_reloc_deps_graph (deps); + } +} + + +static void +xtensa_colocate_output_literals (lang_statement_union_type *s) +{ + lang_for_each_statement_worker (xtensa_colocate_output_literals_callback, s); +} + + +static void +xtensa_ldlang_clear_addresses (lang_statement_union_type *statement) +{ + switch (statement->header.type) + { + case lang_input_section_enum: + { + asection *bfd_section = statement->input_section.section; + bfd_section->output_offset = 0; + } + break; + default: + break; + } +} + + +static bfd_vma +ld_assign_relative_paged_dot (bfd_vma dot, + lang_statement_union_type *s, + const reloc_deps_graph *deps ATTRIBUTE_UNUSED, + bfd_boolean lit_align) +{ + /* Walk through all of the input statements in this wild statement + assign dot to all of them. */ + + xtensa_ld_iter_stack *stack = NULL; + xtensa_ld_iter_stack **stack_p = &stack; + + bfd_boolean first_section = FALSE; + bfd_boolean in_literals = FALSE; + + for (iter_stack_create (stack_p, s); + !iter_stack_empty (stack_p); + iter_stack_next (stack_p)) + { + lang_statement_union_type *l = iter_stack_current (stack_p); + + switch (l->header.type) + { + case lang_input_section_enum: + { + asection *section = l->input_section.section; + size_t align_pow = section->alignment_power; + bfd_boolean do_xtensa_alignment = FALSE; + + if (lit_align) + { + bfd_boolean sec_is_target = section_is_target (deps, l); + bfd_boolean sec_is_source = section_is_source (deps, l); + + if (section->size != 0 + && (first_section + || (in_literals && !sec_is_target) + || (!in_literals && sec_is_target))) + { + do_xtensa_alignment = TRUE; + } + first_section = FALSE; + if (section->size != 0) + in_literals = (sec_is_target && !sec_is_source); + } + + if (do_xtensa_alignment && xtensa_page_power != 0) + dot += (1 << xtensa_page_power); + + dot = align_power (dot, align_pow); + section->output_offset = dot; + dot += section->size; + } + break; + case lang_fill_statement_enum: + dot += l->fill_statement.size; + break; + case lang_padding_statement_enum: + dot += l->padding_statement.size; + break; + default: + break; + } + } + return dot; +} + + +static bfd_boolean +ld_local_file_relocations_fit (lang_statement_union_type *statement, + const reloc_deps_graph *deps ATTRIBUTE_UNUSED) +{ + /* Walk over all of the dependencies that we identified and make + sure that IF the source and target are here (addr != 0): + 1) target addr < source addr + 2) (roundup(source + source_size, 4) - rounddown(target, 4)) + < (256K - (1 << bad align)) + Need a worst-case proof.... */ + + xtensa_ld_iter_stack *stack = NULL; + xtensa_ld_iter_stack **stack_p = &stack; + size_t max_align_power = 0; + size_t align_penalty = 256; + reloc_deps_e *e; + size_t i; + + /* Find the worst-case alignment requirement for this set of statements. */ + for (iter_stack_create (stack_p, statement); + !iter_stack_empty (stack_p); + iter_stack_next (stack_p)) + { + lang_statement_union_type *l = iter_stack_current (stack_p); + if (l->header.type == lang_input_section_enum) + { + lang_input_section_type *input = &l->input_section; + asection *section = input->section; + if (section->alignment_power > max_align_power) + max_align_power = section->alignment_power; + } + } + + /* Now check that everything fits. */ + for (i = 0; i < deps->count; i++) + { + asection *sec = deps->sections[i]; + const reloc_deps_section *deps_section = + xtensa_get_section_deps (deps, sec); + if (deps_section) + { + /* We choose to walk through the successors. */ + for (e = deps_section->succs; e != NULL; e = e->next) + { + if (e->src != e->tgt + && e->src->output_section == e->tgt->output_section + && e->src->output_offset != 0 + && e->tgt->output_offset != 0) + { + bfd_vma l32r_addr = + align_power (e->src->output_offset + e->src->size, 2); + bfd_vma target_addr = e->tgt->output_offset & ~3; + if (l32r_addr < target_addr) + { + fprintf (stderr, "Warning: " + "l32r target section before l32r\n"); + return FALSE; + } + + if (l32r_addr - target_addr > 256 * 1024 - align_penalty) + return FALSE; + } + } + } + } + + return TRUE; +} + + +static bfd_vma +ld_xtensa_insert_page_offsets (bfd_vma dot, + lang_statement_union_type *s, + reloc_deps_graph *deps, + bfd_boolean lit_align) +{ + xtensa_ld_iter_stack *stack = NULL; + xtensa_ld_iter_stack **stack_p = &stack; + + bfd_boolean first_section = FALSE; + bfd_boolean in_literals = FALSE; + + if (!lit_align) + return FALSE; + + for (iter_stack_create (stack_p, s); + !iter_stack_empty (stack_p); + iter_stack_next (stack_p)) + { + lang_statement_union_type *l = iter_stack_current (stack_p); + + switch (l->header.type) + { + case lang_input_section_enum: + { + asection *section = l->input_section.section; + bfd_boolean do_xtensa_alignment = FALSE; + + if (lit_align) + { + if (section->size != 0 + && (first_section + || (in_literals && !section_is_target (deps, l)) + || (!in_literals && section_is_target (deps, l)))) + { + do_xtensa_alignment = TRUE; + } + first_section = FALSE; + if (section->size != 0) + { + in_literals = (section_is_target (deps, l) + && !section_is_source (deps, l)); + } + } + + if (do_xtensa_alignment && xtensa_page_power != 0) + { + /* Create an expression that increments the current address, + i.e., "dot", by (1 << xtensa_align_power). */ + etree_type *name_op = exp_nameop (NAME, "."); + etree_type *addend_op = exp_intop (1 << xtensa_page_power); + etree_type *add_op = exp_binop ('+', name_op, addend_op); + etree_type *assign_op = exp_assop ('=', ".", add_op); + + lang_assignment_statement_type *assign_stmt; + lang_statement_union_type *assign_union; + lang_statement_list_type tmplist; + + /* There is hidden state in "lang_add_assignment". It + appends the new assignment statement to the stat_ptr + list. Thus, we swap it before and after the call. */ + + lang_list_init (&tmplist); + push_stat_ptr (&tmplist); + /* Warning: side effect; statement appended to stat_ptr. */ + assign_stmt = lang_add_assignment (assign_op); + assign_union = (lang_statement_union_type *) assign_stmt; + pop_stat_ptr (); + + assign_union->header.next = l; + *(*stack_p)->iterloc.loc = assign_union; + iter_stack_next (stack_p); + } + } + break; + default: + break; + } + } + return dot; +} + +EOF + +# Define some shell vars to insert bits of code into the standard ELF +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_OPT_SIZEOPT (300) +#define OPTION_LITERAL_MOVEMENT (OPTION_OPT_SIZEOPT + 1) +#define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1) +extern int elf32xtensa_size_opt; +extern int elf32xtensa_no_literal_movement; +' + +PARSE_AND_LIST_LONGOPTS=' + { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT}, + { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT}, + { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --size-opt When relaxing longcalls, prefer size\n\ + optimization over branch target alignment\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_OPT_SIZEOPT: + elf32xtensa_size_opt = 1; + break; + case OPTION_LITERAL_MOVEMENT: + elf32xtensa_no_literal_movement = 0; + break; + case OPTION_NO_LITERAL_MOVEMENT: + elf32xtensa_no_literal_movement = 1; + break; +' + +# Replace some of the standard ELF functions with our own versions. +# +LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse +LDEMUL_AFTER_OPEN=elf_xtensa_after_open +LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target +LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation diff --git a/binutils-2.21/ld/emultempl/z80.em b/binutils-2.21/ld/emultempl/z80.em new file mode 100644 index 0000000..100ebd0 --- /dev/null +++ b/binutils-2.21/ld/emultempl/z80.em @@ -0,0 +1,102 @@ +# This shell script emits C code -*- C -*- +# to keep track of the machine type of Z80 object files +# It does some substitutions. +# Copyright 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. + +LDEMUL_BEFORE_PARSE=gldz80_before_parse +LDEMUL_RECOGNIZED_FILE=gldz80_recognized_file +LDEMUL_AFTER_OPEN=gldz80_after_open + +fragment <<EOF +/* --- \begin{z80.em} */ +/* Codes for machine types, bitwise or gives the code to use for the + output. */ +#define M_Z80STRICT 1 +#define M_Z80 3 +#define M_Z80FULL 7 +#define M_R800 11 +#define M_Z80ANY 15 + +/* Bitwise or of the machine types seen so far. */ +static int result_mach_type; + +static void +${LDEMUL_BEFORE_PARSE} (void) +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); +#endif /* not TARGET_ */ + result_mach_type = M_Z80STRICT; +} + + +/* Update result_mach_type. */ +static bfd_boolean +${LDEMUL_RECOGNIZED_FILE} (lang_input_statement_type *entry) +{ + unsigned long mach_type; + + mach_type = bfd_get_mach (entry->the_bfd); + switch (mach_type) + { + case bfd_mach_z80strict: + result_mach_type |= M_Z80STRICT; + break; + case bfd_mach_z80: + result_mach_type |= M_Z80; + break; + case bfd_mach_z80full: + result_mach_type |= M_Z80FULL; + break; + case bfd_mach_r800: + result_mach_type |= M_R800; + break; + default: + result_mach_type |= M_Z80ANY; + } + return FALSE; +} + +/* Set the machine type of the output file based on result_mach_type. */ +static void +gldz80_after_open (void) +{ + unsigned long mach_type; + + switch (result_mach_type) + { + case M_Z80STRICT: + mach_type = bfd_mach_z80strict; + break; + case M_Z80: + mach_type = bfd_mach_z80; + break; + case M_Z80FULL: + mach_type = bfd_mach_z80full; + break; + case M_R800: + mach_type = bfd_mach_r800; + break; + default: + mach_type = 0; + } + bfd_set_arch_mach (link_info.output_bfd, bfd_arch_z80, mach_type); +} +/* --- \end{z80.em} */ +EOF |