diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2004-05-17 20:42:59 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2004-05-17 20:42:59 +0000 |
commit | dabfd0a2b923dc8dd2fab68d1669102a0aa4352c (patch) | |
tree | d015d45f09daaa846ca3dc8ca58b731e65c28eea /gnu/usr.bin/binutils/ld/emultempl | |
parent | b92d90de71fbbb34bdcd7269aa7b30856e0b4f06 (diff) |
import binutils 2.14 (excluding testsuites, .info files, and .po files)
Diffstat (limited to 'gnu/usr.bin/binutils/ld/emultempl')
18 files changed, 4304 insertions, 289 deletions
diff --git a/gnu/usr.bin/binutils/ld/emultempl/alphaelf.em b/gnu/usr.bin/binutils/ld/emultempl/alphaelf.em new file mode 100644 index 00000000000..4ff83cb76f2 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/alphaelf.em @@ -0,0 +1,83 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em, and defines extra alpha +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include "elf/internal.h" +#include "elf/alpha.h" +#include "elf-bfd.h" + +static void alpha_after_parse PARAMS ((void)); +static void alpha_finish PARAMS ((void)); + +static int elf64alpha_32bit = 0; + +/* Set the start address as in the Tru64 ld. */ +#define ALPHA_TEXT_START_32BIT 0x12000000 + +static void +alpha_after_parse () +{ + if (elf64alpha_32bit && !link_info.shared && !link_info.relocateable) + lang_section_start (".interp", + exp_binop ('+', + exp_intop (ALPHA_TEXT_START_32BIT), + exp_nameop (SIZEOF_HEADERS, NULL))); +} + +static void +alpha_finish () +{ + if (elf64alpha_32bit) + elf_elfheader (output_bfd)->e_flags |= EF_ALPHA_32BIT; + + gld${EMULATION_NAME}_finish (); +} +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 +' + +PARSE_AND_LIST_LONGOPTS=' + {"taso", no_argument, NULL, OPTION_TASO}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" -taso\t\t\tLoad executable in the lower 31-bit addressable\n")); + fprintf (file, _("\t\t\t virtual address range\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_TASO: + elf64alpha_32bit = 1; + break; +' + +# Put these extra alpha routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_PARSE=alpha_after_parse +LDEMUL_FINISH=alpha_finish diff --git a/gnu/usr.bin/binutils/ld/emultempl/armcoff.em b/gnu/usr.bin/binutils/ld/emultempl/armcoff.em index ab7084351cb..11566581e03 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/armcoff.em +++ b/gnu/usr.bin/binutils/ld/emultempl/armcoff.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c <<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 + Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com @@ -43,11 +43,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); -static int gld${EMULATION_NAME}_parse_args PARAMS((int, char **)); +static void gld${EMULATION_NAME}_add_options + PARAMS ((int, char **, int, struct option **, int, struct option **)); static void gld${EMULATION_NAME}_list_options PARAMS ((FILE *)); +static bfd_boolean gld${EMULATION_NAME}_handle_option PARAMS ((int)); static void gld${EMULATION_NAME}_finish PARAMS ((void)); +static void gld${EMULATION_NAME}_after_open PARAMS ((void)); -/* If true, then interworking stubs which support calls to old, non-interworking +/* If TRUE, then interworking stubs which support calls to old, non-interworking aware ARM code should be generated. */ static int support_old_code = 0; @@ -56,12 +59,25 @@ static char * thumb_entry_symbol = NULL; #define OPTION_SUPPORT_OLD_CODE 300 #define OPTION_THUMB_ENTRY 301 -static struct option longopts[] = +static void +gld${EMULATION_NAME}_add_options (ns, shortopts, nl, longopts, nrl, really_longopts) + int ns ATTRIBUTE_UNUSED; + char **shortopts ATTRIBUTE_UNUSED; + int nl; + struct option **longopts; + int nrl ATTRIBUTE_UNUSED; + struct option **really_longopts ATTRIBUTE_UNUSED; { - {"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, - {"thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY}, - {NULL, no_argument, NULL, 0} -}; + 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 = (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) @@ -71,34 +87,14 @@ gld${EMULATION_NAME}_list_options (file) fprintf (file, _(" --thumb-entry=<sym> Set the entry point to be Thumb symbol <sym>\n")); } -static int -gld${EMULATION_NAME}_parse_args (argc, argv) - int argc; - char ** argv; +static bfd_boolean +gld${EMULATION_NAME}_handle_option (optc) + int optc; { - int longind; - int optc; - int prevoptind = optind; - int prevopterr = opterr; - int wanterror; - static int lastoptind = -1; - - if (lastoptind != optind) - opterr = 0; - - wanterror = opterr; - lastoptind = optind; - - optc = getopt_long_only (argc, argv, "-", longopts, & longind); - opterr = prevopterr; - switch (optc) { default: - if (wanterror) - xexit (1); - optind = prevoptind; - return 0; + return FALSE; case OPTION_SUPPORT_OLD_CODE: support_old_code = 1; @@ -109,7 +105,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; } - return 1; + return TRUE; } static void @@ -176,7 +172,8 @@ gld${EMULATION_NAME}_finish PARAMS((void)) if (thumb_entry_symbol == NULL) return; - h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, false, false, true); + 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 @@ -202,10 +199,10 @@ gld${EMULATION_NAME}_finish PARAMS((void)) sprintf_vma (buffer + 2, val); - if (entry_symbol != NULL && entry_from_cmdline) + if (entry_symbol.name != NULL && entry_from_cmdline) einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), - thumb_entry_symbol, entry_symbol); - entry_symbol = buffer; + thumb_entry_symbol, entry_symbol.name); + entry_symbol.name = buffer; } else einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); @@ -227,19 +224,19 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 0; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return EOF -sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c -echo ' ; else if (link_info.relocateable == true) 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 +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable) 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. @@ -248,9 +245,9 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 1; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return "ldscripts/${EMULATION_NAME}.xu"; - else if (link_info.relocateable == true) + else if (link_info.relocateable) return "ldscripts/${EMULATION_NAME}.xr"; else if (!config.text_read_only) return "ldscripts/${EMULATION_NAME}.xbn"; @@ -284,10 +281,13 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = NULL, /* open dynamic archive */ NULL, /* place orphan */ NULL, /* set symbols */ - gld${EMULATION_NAME}_parse_args, + 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, /* find_potential_libraries */ + NULL /* new_vers_pattern */ }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/armelf.em b/gnu/usr.bin/binutils/ld/emultempl/armelf.em index 0d1b8ed9b15..b125c579eff 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/armelf.em +++ b/gnu/usr.bin/binutils/ld/emultempl/armelf.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000 +# Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2002, 2003 # Free Software Foundation, Inc. # # This file is part of GLD, the Gnu Linker. @@ -26,6 +26,7 @@ cat >>e${EMULATION_NAME}.c <<EOF static int no_pipeline_knowledge = 0; static char *thumb_entry_symbol = NULL; +static bfd *bfd_for_interwork; static void @@ -34,12 +35,11 @@ gld${EMULATION_NAME}_before_parse () #ifndef TARGET_ /* I.e., if not generic. */ ldfile_set_output_arch ("`echo ${ARCH}`"); #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`; + 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_after_open PARAMS((void)); +static void arm_elf_after_open PARAMS ((void)); static void arm_elf_after_open () @@ -57,9 +57,7 @@ arm_elf_after_open () { LANG_FOR_EACH_INPUT_STATEMENT (is) { - /* The interworking bfd must be the last one to be processed */ - if (!is->next) - bfd_elf32_arm_get_bfd_for_interworking (is->the_bfd, & link_info); + bfd_elf32_arm_add_glue_sections_to_bfd (is->the_bfd, & link_info); } } @@ -67,19 +65,63 @@ arm_elf_after_open () gld${EMULATION_NAME}_after_open (); } +static void arm_elf_set_bfd_for_interworking + PARAMS ((lang_statement_union_type *)); + +static void +arm_elf_set_bfd_for_interworking (statement) + lang_statement_union_type *statement; +{ + if (statement->header.type == lang_input_section_enum + && !statement->input_section.ifile->just_syms_flag) + { + asection *i = statement->input_section.section; + asection *output_section = i->output_section; + + ASSERT (output_section->owner == output_bfd); + + if ((output_section->flags & SEC_HAS_CONTENTS) != 0 + && (i->flags & SEC_NEVER_LOAD) == 0 + && ! i->owner->output_has_begun) + { + bfd_for_interwork = i->owner; + bfd_for_interwork->output_has_begun = TRUE; + } + } +} static void arm_elf_before_allocation PARAMS ((void)); static void arm_elf_before_allocation () { + bfd *tem; + /* Call the standard elf routine. */ gld${EMULATION_NAME}_before_allocation (); - /* We should be able to set the size of the interworking stub section */ + if (link_info.input_bfds != NULL) + { + /* The interworking bfd must be the last one in the link. */ + bfd_for_interwork = NULL; + for (tem = link_info.input_bfds; tem != NULL; tem = tem->link_next) + tem->output_has_begun = FALSE; + + lang_for_each_statement (arm_elf_set_bfd_for_interworking); + for (tem = link_info.input_bfds; tem != NULL; tem = tem->link_next) + tem->output_has_begun = FALSE; + + /* If bfd_for_interwork is NULL, then there are no loadable sections + with real contents to be linked, so we are not going to have to + create any interworking stubs, so it is OK not to call + bfd_elf32_arm_get_bfd_for_interworking. */ + if (bfd_for_interwork != NULL) + bfd_elf32_arm_get_bfd_for_interworking (bfd_for_interwork, &link_info); + } + /* 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 */ + /* 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) { @@ -92,23 +134,25 @@ arm_elf_before_allocation () } } - /* We have seen it all. Allocate it, and carry on */ + /* We have seen it all. Allocate it, and carry on. */ bfd_elf32_arm_allocate_interworking_sections (& link_info); } - -static void gld${EMULATION_NAME}_finish PARAMS ((void)); +static void arm_elf_finish PARAMS ((void)); static void -gld${EMULATION_NAME}_finish PARAMS((void)) +arm_elf_finish () { struct bfd_link_hash_entry * h; + /* Call the elf32.em routine. */ + gld${EMULATION_NAME}_finish (); + if (thumb_entry_symbol == NULL) return; h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, - false, false, true); + FALSE, FALSE, TRUE); if (h != (struct bfd_link_hash_entry *) NULL && (h->type == bfd_link_hash_defined @@ -134,10 +178,10 @@ gld${EMULATION_NAME}_finish PARAMS((void)) sprintf_vma (buffer + 2, val); - if (entry_symbol != NULL && entry_from_cmdline) + if (entry_symbol.name != NULL && entry_from_cmdline) einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), - thumb_entry_symbol, entry_symbol); - entry_symbol = buffer; + thumb_entry_symbol, entry_symbol.name); + entry_symbol.name = buffer; } else einfo (_("%P: warning: connot find thumb start symbol %s\n"), @@ -184,4 +228,4 @@ LDEMUL_BEFORE_ALLOCATION=arm_elf_before_allocation LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse # Call the extra arm-elf function -LDEMUL_FINISH=gld${EMULATION_NAME}_finish +LDEMUL_FINISH=arm_elf_finish diff --git a/gnu/usr.bin/binutils/ld/emultempl/armelf_oabi.em b/gnu/usr.bin/binutils/ld/emultempl/armelf_oabi.em index 1f2deb385d6..555b947e383 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/armelf_oabi.em +++ b/gnu/usr.bin/binutils/ld/emultempl/armelf_oabi.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c <<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 + Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com @@ -50,6 +50,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); +static void gld${EMULATION_NAME}_after_open PARAMS ((void)); static void gld${EMULATION_NAME}_before_parse () @@ -112,19 +113,19 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 0; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return EOF -sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c -echo ' ; else if (link_info.relocateable == true) 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 +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable) 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. @@ -133,9 +134,9 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 1; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return "ldscripts/${EMULATION_NAME}.xu"; - else if (link_info.relocateable == true) + else if (link_info.relocateable) return "ldscripts/${EMULATION_NAME}.xr"; else if (!config.text_read_only) return "ldscripts/${EMULATION_NAME}.xbn"; @@ -170,9 +171,12 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = 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, /* find_potential_libraries */ + NULL /* new_vers_pattern */ }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/beos.em b/gnu/usr.bin/binutils/ld/emultempl/beos.em index 3c9e3edc9b2..3b84280f971 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/beos.em +++ b/gnu/usr.bin/binutils/ld/emultempl/beos.em @@ -1,8 +1,14 @@ # 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 cat >e${EMULATION_NAME}.c <<EOF /* This file is part of GLD, the Gnu Linker. - Copyright 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc. + Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,8 +29,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 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. */ - + the correct entry point by default. */ + #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" @@ -32,11 +38,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "libiberty.h" #include "ld.h" #include "ldmain.h" -#include "ldgram.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" @@ -49,20 +55,22 @@ static void gld_${EMULATION_NAME}_set_symbols PARAMS ((void)); static void gld_${EMULATION_NAME}_after_open PARAMS ((void)); static void gld_${EMULATION_NAME}_before_parse PARAMS ((void)); static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void)); -static boolean gld${EMULATION_NAME}_place_orphan +static bfd_boolean gld${EMULATION_NAME}_place_orphan PARAMS ((lang_input_statement_type *, asection *)); static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *)); -static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **)); -#if 0 /* argument to qsort so don't prototype */ -static int sort_by_file_name PARAMS ((void *, void *)); -static int sort_by_section_name PARAMS ((void *, void *)); -#endif +static int sort_by_file_name PARAMS ((const PTR, const PTR)); +static int sort_by_section_name PARAMS ((const PTR, const PTR)); static lang_statement_union_type **sort_sections_1 PARAMS ((lang_statement_union_type **, lang_statement_union_type *, int, - int (*)())); + int (*) PARAMS((const PTR, const PTR)))); static void sort_sections PARAMS ((lang_statement_union_type *)); +static void set_pe_name PARAMS ((char *, long int)); +static void set_pe_subsystem PARAMS ((void)); +static void set_pe_value PARAMS ((char *)); +static void set_pe_stack_heap PARAMS ((char *, char *)); + static struct internal_extra_pe_aouthdr pe; static int dll; @@ -71,8 +79,16 @@ extern const char *output_filename; static void gld_${EMULATION_NAME}_before_parse() { + const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}"); + if (arch) + { + ldfile_output_architecture = arch->arch; + ldfile_output_machine = arch->mach; + ldfile_output_machine_name = arch->printable_name; + } + else + ldfile_output_architecture = bfd_arch_${ARCH}; output_filename = "a.exe"; - ldfile_output_architecture = bfd_arch_${ARCH}; } /* PE format extra command line options. */ @@ -93,13 +109,25 @@ gld_${EMULATION_NAME}_before_parse() #define OPTION_SUBSYSTEM (OPTION_STACK + 1) #define OPTION_HEAP (OPTION_SUBSYSTEM + 1) -static struct option longopts[] = { - /* PE options */ +static void gld${EMULATION_NAME}_add_options + PARAMS ((int, char **, int, struct option **, int, struct option **)); + +static void +gld${EMULATION_NAME}_add_options (ns, shortopts, nl, longopts, nrl, really_longopts) + 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}, + {"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}, @@ -109,9 +137,14 @@ static struct option longopts[] = { {"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} + {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 */ @@ -132,7 +165,7 @@ static definfo init[] = #define IMAGEBASEOFF 0 D(ImageBase,"__image_base__", BEOS_EXE_IMAGE_BASE), #define DLLOFF 1 - {&dll, sizeof(dll), 0, "__dll__"}, + {&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), @@ -177,7 +210,7 @@ set_pe_subsystem () const char *sver; int len; int i; - static const struct + static const struct { const char *name; const int value; @@ -252,7 +285,7 @@ set_pe_subsystem () static void set_pe_value (name) char *name; - + { char *end; set_pe_name (name, strtoul (optarg, &end, 0)); @@ -282,35 +315,17 @@ set_pe_stack_heap (resname, comname) } +static bfd_boolean gld${EMULATION_NAME}_handle_option + PARAMS ((int)); -static int -gld_${EMULATION_NAME}_parse_args(argc, argv) - int argc; - char **argv; +static bfd_boolean +gld${EMULATION_NAME}_handle_option (optc) + int optc; { - int longind; - int optc; - int prevoptind = optind; - int prevopterr = opterr; - int wanterror; - static int lastoptind = -1; - - if (lastoptind != optind) - opterr = 0; - wanterror = opterr; - - lastoptind = optind; - - optc = getopt_long_only (argc, argv, "-", longopts, &longind); - opterr = prevopterr; - switch (optc) { default: - if (wanterror) - xexit (1); - optind = prevoptind; - return 0; + return FALSE; case OPTION_BASE_FILE: link_info.base_file = (PTR) fopen (optarg, FOPEN_WB); @@ -323,10 +338,10 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) break; /* PE options */ - case OPTION_HEAP: + case OPTION_HEAP: set_pe_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); break; - case OPTION_STACK: + case OPTION_STACK: set_pe_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); break; case OPTION_SUBSYSTEM: @@ -363,7 +378,7 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) set_pe_value ("__image_base__"); break; } - return 1; + return TRUE; } /* Assign values to the special symbols before the linker script is @@ -399,7 +414,7 @@ gld_${EMULATION_NAME}_set_symbols() for (j = 0; init[j].ptr; j++) { long val = init[j].value; - lang_add_assignment (exp_assop ('=' ,init[j].symbol, exp_intop (val))); + 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)) @@ -413,7 +428,7 @@ gld_${EMULATION_NAME}_set_symbols() } /* Restore the pointer. */ stat_ptr = save; - + if (pe.FileAlignment > pe.SectionAlignment) { @@ -441,11 +456,11 @@ gld_${EMULATION_NAME}_after_open() static int sort_by_file_name (a, b) - void *a; - void *b; + const PTR a; + const PTR b; { - lang_statement_union_type **ra = a; - lang_statement_union_type **rb = 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.ifile->the_bfd->my_archive->filename, @@ -458,19 +473,19 @@ sort_by_file_name (a, b) 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, + 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 > + 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 > + return (((*ra)->input_section.section->reloc_count > (*rb)->input_section.section->reloc_count) ? 0 : 1); } else @@ -478,12 +493,12 @@ sort_by_file_name (a, b) 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.ifile->the_bfd, + if (! bfd_get_section_contents ((*ra)->input_section.ifile->the_bfd, (*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.ifile->the_bfd); - if (! bfd_get_section_contents ((*rb)->input_section.ifile->the_bfd, + if (! bfd_get_section_contents ((*rb)->input_section.ifile->the_bfd, (*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.ifile->the_bfd); @@ -498,11 +513,11 @@ return 0; static int sort_by_section_name (a, b) - void *a; - void *b; + const PTR a; + const PTR b; { - lang_statement_union_type **ra = a; - lang_statement_union_type **rb = 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); @@ -527,7 +542,7 @@ static lang_statement_union_type ** sort_sections_1 (startptr, next_after, count, sort_func) lang_statement_union_type **startptr,*next_after; int count; - int (*sort_func) (); + int (*sort_func) PARAMS ((const PTR, const PTR)); { lang_statement_union_type **vec; lang_statement_union_type *p; @@ -540,7 +555,7 @@ sort_sections_1 (startptr, next_after, count, sort_func) vec = ((lang_statement_union_type **) xmalloc (count * sizeof (lang_statement_union_type *))); - for (p = *startptr, i = 0; i < count; i++, p = p->next) + for (p = *startptr, i = 0; i < count; i++, p = p->header.next) vec[i] = p; qsort (vec, count, sizeof (vec[0]), sort_func); @@ -573,7 +588,7 @@ static void sort_sections (s) lang_statement_union_type *s; { - for (; s ; s = s->next) + for (; s ; s = s->header.next) switch (s->header.type) { case lang_output_section_statement_enum: @@ -582,66 +597,73 @@ sort_sections (s) case lang_wild_statement_enum: { lang_statement_union_type **p = &s->wild_statement.children.head; + struct wildcard_list *sec; - /* Is this the .idata section? */ - if (s->wild_statement.section_name != NULL - && strncmp (s->wild_statement.section_name, ".idata", 6) == 0) + for (sec = s->wild_statement.section_list; sec; sec = sec->next) { - /* 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) + /* Is this the .idata section? */ + if (sec->spec.name != NULL + && strncmp (sec->spec.name, ".idata", 6) == 0) { - lang_statement_union_type *start = *p; - if (start->header.type != lang_input_section_enum - || !start->input_section.ifile->the_bfd->my_archive) - p = &(start->header.next); - else + /* 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 *end; - int count; - - for (end = start, count = 0; - end && end->header.type == lang_input_section_enum; - end = end->next) - count++; - - p = sort_sections_1 (p, end, count, sort_by_file_name); + lang_statement_union_type *start = *p; + if (start->header.type != lang_input_section_enum + || !start->input_section.ifile->the_bfd->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; } - 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 (s->wild_statement.section_name != NULL) - { - char *q = strchr (s->wild_statement.section_name, '\$'); - - if (q != NULL - && (q[1] == '\0' - || (q[1] == '*' && q[2] == '\0'))) + /* 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) { - lang_statement_union_type *end; - int count; + char *q = strchr (sec->spec.name, '\$'); - for (end = *p, count = 0; end; end = end->next) + if (q != NULL + && (q[1] == '\0' + || (q[1] == '*' && q[2] == '\0'))) { - if (end->header.type != lang_input_section_enum) - abort (); - count++; + 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); } - (void) sort_sections_1 (p, end, count, sort_by_section_name); + break; } - break; } } break; @@ -650,7 +672,7 @@ sort_sections (s) } } -static void +static void gld_${EMULATION_NAME}_before_allocation() { extern lang_statement_list_type *stat_ptr; @@ -707,7 +729,7 @@ gld_${EMULATION_NAME}_before_allocation() which are not mentioned in the linker script. */ /*ARGSUSED*/ -static boolean +static bfd_boolean gld${EMULATION_NAME}_place_orphan (file, s) lang_input_statement_type *file; asection *s; @@ -718,14 +740,14 @@ gld${EMULATION_NAME}_place_orphan (file, s) lang_statement_union_type *l; if ((s->flags & SEC_ALLOC) == 0) - return false; + return FALSE; /* 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.relocateable) - return false; + return FALSE; secname = bfd_get_section_name (s->owner, s); @@ -734,7 +756,7 @@ gld${EMULATION_NAME}_place_orphan (file, s) if (*secname == '\$') einfo ("%P%F: section %s has '\$' as first character\n", secname); if (strchr (secname + 1, '\$') == NULL) - return false; + return FALSE; /* Look up the output section. The Microsoft specs say sections names in image files never contain a '\$'. Fortunately, lang_..._lookup creates @@ -751,12 +773,17 @@ gld${EMULATION_NAME}_place_orphan (file, s) ps[0] = '\$'; ps[1] = 0; - for (l = os->children.head; l; l = l->next) - { - if (l->header.type == lang_wild_statement_enum - && strcmp (l->wild_statement.section_name, output_secname) == 0) - break; - } + 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) #if 1 @@ -765,11 +792,20 @@ gld${EMULATION_NAME}_place_orphan (file, s) should one decide to not require *(.foo\$) to appear in the linker script. */ { - lang_wild_statement_type *new = new_stat (lang_wild_statement, - &os->children); - new->section_name = xmalloc (strlen (output_secname) + 2); - sprintf (new->section_name, "%s\$", output_secname); + lang_wild_statement_type *new; + struct wildcard_list *tmp; + + tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); + tmp->next = NULL; + tmp->spec.name = xmalloc (strlen (output_secname) + 2); + sprintf (tmp->spec.name, "%s\$", output_secname); + tmp->spec.exclude_name_list = NULL; + tmp->sorted = FALSE; + new = new_stat (lang_wild_statement, &os->children); new->filename = NULL; + new->filenames_sorted = FALSE; + new->section_list = tmp; + new->keep_sections = FALSE; lang_list_init (&new->children); l = new; } @@ -779,9 +815,9 @@ gld${EMULATION_NAME}_place_orphan (file, s) 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. */ - wild_doit (&l->wild_statement.children, s, os, file); + lang_add_section (&l->wild_statement.children, s, os, file); - return true; + return TRUE; } static char * @@ -793,27 +829,27 @@ EOF sc="-f stringify.sed" cat >>e${EMULATION_NAME}.c <<EOF -{ +{ *isfile = 0; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return EOF -sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c -echo ' ; else if (link_info.relocateable == true) 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 +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable) 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 cat >>e${EMULATION_NAME}.c <<EOF -struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { gld_${EMULATION_NAME}_before_parse, syslib_default, @@ -832,10 +868,13 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = NULL, /* open dynamic archive */ gld${EMULATION_NAME}_place_orphan, gld_${EMULATION_NAME}_set_symbols, - gld_${EMULATION_NAME}_parse_args, + 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, /* find_potential_libraries */ + NULL /* new_vers_pattern */ }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/m68hc1xelf.em b/gnu/usr.bin/binutils/ld/emultempl/m68hc1xelf.em new file mode 100644 index 00000000000..5e5dc102434 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/m68hc1xelf.em @@ -0,0 +1,391 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 1991, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include "ldctor.h" +#include "elf32-m68hc1x.h" + +static void m68hc11elf_create_output_section_statements PARAMS ((void)); +static asection *m68hc11elf_add_stub_section + PARAMS ((const char *, asection *)); +static void gld${EMULATION_NAME}_finish PARAMS ((void)); +static void m68hc11_elf_${EMULATION_NAME}_before_allocation PARAMS ((void)); + + +/* 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 () +{ + 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.relocateable) + return; + + ret = elf32_m68hc11_setup_section_lists (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 (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); + + /* 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 () +{ + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", output_bfd); + if (stub_file->the_bfd == NULL + || !bfd_set_arch_mach (stub_file->the_bfd, + bfd_get_arch (output_bfd), + bfd_get_mach (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 + PARAMS ((struct hook_stub_info *, lang_statement_union_type **)); + +static bfd_boolean +hook_in_stub (info, lp) + 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 (stub_sec_name, tramp_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; + + stub_sec = bfd_make_section_anyway (stub_file->the_bfd, stub_sec_name); + if (stub_sec == NULL) + goto err_ret; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + if (!bfd_set_section_flags (stub_file->the_bfd, stub_sec, flags)) + 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, stub_file); + + 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; +} + +/* Final emulation specific call. For the 68HC12 we use this opportunity + to build linker stubs. */ + +static void +gld${EMULATION_NAME}_finish () +{ + /* 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 (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 (output_bfd, &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 m68hc11_for_each_input_file_wrapper + PARAMS ((lang_input_statement_type *)); +static void m68hc11_lang_for_each_input_file + PARAMS ((void (*) (lang_input_statement_type *))); + +static void (*real_func) PARAMS ((lang_input_statement_type *)); + +static void m68hc11_for_each_input_file_wrapper (l) + lang_input_statement_type *l; +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +m68hc11_lang_for_each_input_file (func) + void (*func) PARAMS ((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_FINISH=gld${EMULATION_NAME}_finish +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=m68hc11elf_create_output_section_statements diff --git a/gnu/usr.bin/binutils/ld/emultempl/m68kcoff.em b/gnu/usr.bin/binutils/ld/emultempl/m68kcoff.em index 078324fcc58..765447a258b 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/m68kcoff.em +++ b/gnu/usr.bin/binutils/ld/emultempl/m68kcoff.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* This file is is generated by a shell script. DO NOT EDIT! */ /* Handle embedded relocs for m68k. - Copyright 2000 Free Software Foundation, Inc. + Copyright 2000, 2002, 2003 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>. @@ -179,19 +179,19 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 0; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return EOF -sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c -echo ' ; else if (link_info.relocateable == true) 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 +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable) 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. @@ -200,9 +200,9 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 1; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return "ldscripts/${EMULATION_NAME}.xu"; - else if (link_info.relocateable == true) + else if (link_info.relocateable) return "ldscripts/${EMULATION_NAME}.xr"; else if (!config.text_read_only) return "ldscripts/${EMULATION_NAME}.xbn"; @@ -237,9 +237,12 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = 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, /* find_potential_libraries */ + NULL /* new_vers_pattern */ }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/mipself.em b/gnu/usr.bin/binutils/ld/emultempl/mipself.em new file mode 100644 index 00000000000..62a53e0a57f --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/mipself.em @@ -0,0 +1,183 @@ +# Copyright 2002 Free Software Foundation, Inc. +# Written by Mitch Lichtenberg <mpl@broadcom.com> and +# Chris Demetriou <cgd@broadcom.com> based on m68kelf.em and mipsecoff.em. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# This shell script emits a C file. -*- C -*- + + +# 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 + mips*-*-elf) + echo "#define SUPPORT_EMBEDDED_RELOCS" >>e${EMULATION_NAME}.c + ;; +esac + +cat >>e${EMULATION_NAME}.c <<EOF + +static void mips_elf${ELFSIZE}_after_open PARAMS ((void)); +#ifdef SUPPORT_EMBEDDED_RELOCS +static void mips_elf${ELFSIZE}_check_sections PARAMS ((bfd *, asection *, + PTR)); +#endif +static void mips_elf${ELFSIZE}_after_allocation PARAMS ((void)); + +/* This function is run after all the input files have been opened. */ + +static void +mips_elf${ELFSIZE}_after_open() +{ + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_open (); + +#ifdef SUPPORT_EMBEDDED_RELOCS + if (command_line.embedded_relocs && (! link_info.relocateable)) + { + bfd *abfd; + + /* In the embedded relocs mode we create a .rel.sdata section for + each input file with a .sdata section which has has + relocations. 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 + ELF. We need to call a special BFD backend function to + generate the embedded relocs, and we have that function + only for ELF */ + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + einfo ("%F%B: all input objects must be ELF for --embedded-relocs\n"); + + if (bfd_get_arch_size (abfd) != ${ELFSIZE}) + einfo ("%F%B: all input objects must be ${ELFSIZE}-bit ELF for --embedded-relocs\n"); + + datasec = bfd_get_section_by_name (abfd, ".sdata"); + + /* 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, ".rel.sdata"); + 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, + (${ELFSIZE} == 32) ? 2 : 3) + || ! bfd_set_section_size (abfd, relsec, + datasec->reloc_count + * ((${ELFSIZE} / 8) + 8))) + einfo ("%F%B: cannot create .rel.sdata section: %E\n"); + } + + /* Double check that all other data sections have no relocs, + as is required for embedded PIC code. */ + bfd_map_over_sections (abfd, mips_elf${ELFSIZE}_check_sections, + (PTR) datasec); + } + } +#endif /* SUPPORT_EMBEDDED_RELOCS */ +} + +#ifdef SUPPORT_EMBEDDED_RELOCS +/* Check that of the data sections, only the .sdata section has + relocs. This is called via bfd_map_over_sections. */ + +static void +mips_elf${ELFSIZE}_check_sections (abfd, sec, sdatasec) + bfd *abfd; + asection *sec; + PTR sdatasec; +{ + if ((bfd_get_section_flags (abfd, sec) & SEC_DATA) + && sec != (asection *) sdatasec + && sec->reloc_count != 0) + einfo ("%B%X: section %s has relocs; cannot 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. If we are generating embedded relocs, it calls a special + BFD backend routine to do the work. */ + +static void +mips_elf${ELFSIZE}_after_allocation () +{ + /* Call the standard elf routine. */ + after_allocation_default (); + +#ifdef SUPPORT_EMBEDDED_RELOCS + if (command_line.embedded_relocs && (! link_info.relocateable)) + { + bfd *abfd; + + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link_next) + { + asection *datasec, *relsec; + char *errmsg; + + datasec = bfd_get_section_by_name (abfd, ".sdata"); + + if (datasec == NULL || datasec->reloc_count == 0) + continue; + + relsec = bfd_get_section_by_name (abfd, ".rel.sdata"); + ASSERT (relsec != NULL); + + if (! bfd_mips_elf${ELFSIZE}_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); + } + } + } +#endif /* SUPPORT_EMBEDDED_RELOCS */ +} + +EOF + +# 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=mips_elf${ELFSIZE}_after_open +LDEMUL_AFTER_ALLOCATION=mips_elf${ELFSIZE}_after_allocation diff --git a/gnu/usr.bin/binutils/ld/emultempl/mmix-elfnmmo.em b/gnu/usr.bin/binutils/ld/emultempl/mmix-elfnmmo.em new file mode 100644 index 00000000000..8ec604f6e36 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/mmix-elfnmmo.em @@ -0,0 +1,124 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em and mmo.em, used to define +# MMIX-specific things common to ELF and MMO. + +cat >>e${EMULATION_NAME}.c <<EOF +#include "elf/mmix.h" + +static void mmix_before_allocation PARAMS ((void)); +static void mmix_after_allocation PARAMS ((void)); + +/* Set up handling of linker-allocated global registers. */ + +static void +mmix_before_allocation () +{ + /* 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 if not doing a relocatable link. */ + if (! link_info.relocateable) + command_line.relax = TRUE; + + if (!_bfd_mmix_prepare_linker_allocated_gregs (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 () +{ + asection *sec + = bfd_get_section_by_name (output_bfd, MMIX_REG_CONTENTS_SECTION_NAME); + bfd_signed_vma regvma; + + /* 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. */ + if (sec == NULL) + sec + = bfd_get_section_by_name (output_bfd, + MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); + if (sec == NULL) + return; + + regvma = 256 * 8 - sec->_raw_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->_raw_size / 8); + regvma = 32 * 8; + } + + /* Set vma to correspond to first such register number * 8. */ + bfd_set_section_vma (output_bfd, sec, (bfd_vma) regvma); + + /* ??? Why isn't the section size (_cooked_size) set? Doesn't it get + set regardless of presence of relocations? */ + if (sec->_cooked_size == 0 + && ! bfd_set_section_size (output_bfd, sec, sec->_raw_size)) + { + /* This is a fatal error; make the einfo call not return. */ + einfo ("%F%P: Can't set section %s size to %u\n", + MMIX_REG_CONTENTS_SECTION_NAME, (unsigned) sec->_raw_size); + } + + /* 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 (output_bfd, MMIX_REG_SECTION_NAME); + if (sec != NULL) + bfd_set_section_vma (abfd, sec, 0); + + if (!_bfd_mmix_finalize_linker_allocated_gregs (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/gnu/usr.bin/binutils/ld/emultempl/mmixelf.em b/gnu/usr.bin/binutils/ld/emultempl/mmixelf.em new file mode 100644 index 00000000000..80d2d94830c --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/mmixelf.em @@ -0,0 +1,46 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. + +. ${srcdir}/emultempl/mmix-elfnmmo.em + +cat >>e${EMULATION_NAME}.c <<EOF +#line 29 "${srcdir}/emultempl/elfmmix.em" + +static void elfmmix_before_parse PARAMS ((void)); + +static void +elfmmix_before_parse () +{ + 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/gnu/usr.bin/binutils/ld/emultempl/mmo.em b/gnu/usr.bin/binutils/ld/emultempl/mmo.em new file mode 100644 index 00000000000..e65e89bc5d9 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/mmo.em @@ -0,0 +1,276 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em and mmo.em, used to define +# linker MMIX-specifics common to ELF and MMO. + +cat >>e${EMULATION_NAME}.c <<EOF +/* Need to have this define before mmix-elfnmmo, which includes + needrelax.em which uses this name for the before_allocation function, + normally defined in elf32.em. */ +#define gldmmo_before_allocation before_allocation_default +EOF + +. ${srcdir}/emultempl/mmix-elfnmmo.em + +cat >>e${EMULATION_NAME}.c <<EOF + +static bfd_boolean mmo_place_orphan + PARAMS ((lang_input_statement_type *, asection *)); +static asection *output_prev_sec_find + PARAMS ((lang_output_section_statement_type *)); +static void mmo_finish PARAMS ((void)); +static void mmo_wipe_sec_reloc_flag PARAMS ((bfd *, asection *, PTR)); +static void mmo_after_open PARAMS ((void)); + +/* Find the last output section before given output statement. + Used by place_orphan. */ + +static asection * +output_prev_sec_find (os) + lang_output_section_statement_type *os; +{ + asection *s = (asection *) NULL; + lang_statement_union_type *u; + lang_output_section_statement_type *lookup; + + for (u = lang_output_section_statement.head; + u != (lang_statement_union_type *) NULL; + u = lookup->next) + { + lookup = &u->output_section_statement; + if (lookup == os) + break; + if (lookup->bfd_section != NULL + && lookup->bfd_section != bfd_abs_section_ptr + && lookup->bfd_section != bfd_com_section_ptr + && lookup->bfd_section != bfd_und_section_ptr) + s = lookup->bfd_section; + } + + if (u == NULL) + return NULL; + + return s; +} + +struct orphan_save { + lang_output_section_statement_type *os; + asection **section; + lang_statement_union_type **stmt; +}; + +#define HAVE_SECTION(hold, name) \ +(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) + +/* 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 bfd_boolean +mmo_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + static struct orphan_save hold_text; + struct orphan_save *place; + lang_output_section_statement_type *os; + lang_statement_list_type *old; + lang_statement_list_type add; + asection *snew, **pps, *bfd_section; + + /* We have nothing to say for anything other than a final link. */ + if (link_info.relocateable + || (bfd_get_section_flags (s->owner, s) + & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD) + return FALSE; + + /* Only care for sections we're going to load. */ + os = lang_output_section_find (bfd_get_section_name (s->owner, s)); + + /* 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, file); + return TRUE; + } + + /* 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 ((bfd_get_section_flags (s->owner, s) & (SEC_CODE | SEC_READONLY)) == 0) + return FALSE; + + if (hold_text.os == NULL) + hold_text.os = lang_output_section_find (MMO_TEXT_SECTION_NAME); + + place = &hold_text; + + /* 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. */ + + /* Start building a list of statements for this section. + First save the current statement pointer. */ + old = stat_ptr; + + /* Add the output section statements for this orphan to our own private + list, inserting them later into the global statement list. */ + stat_ptr = &add; + lang_list_init (stat_ptr); + + os = lang_enter_output_section_statement (bfd_get_section_name (s->owner, + s), + NULL, 0, + (bfd_vma) 0, + (etree_type *) NULL, + (etree_type *) NULL, + (etree_type *) NULL); + + lang_add_section (&os->children, s, os, file); + + lang_leave_output_section_statement + ((bfd_vma) 0, "*default*", + (struct lang_output_section_phdr_list *) NULL, NULL); + + /* Restore the global list pointer. */ + stat_ptr = old; + + snew = os->bfd_section; + if (snew == NULL) + /* /DISCARD/ section. */ + return TRUE; + + /* 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) + { + if (os == NULL) + return FALSE; + hold_text.os = os; + } + + bfd_section = place->os->bfd_section; + if (place->section == NULL && bfd_section == NULL) + bfd_section = output_prev_sec_find (place->os); + + if (place->section != NULL + || (bfd_section != NULL + && bfd_section != snew)) + { + /* Shuffle the section to make the output file look neater. This is + really only cosmetic. */ + if (place->section == NULL) + /* Put orphans after the first section on the list. */ + place->section = &bfd_section->next; + + /* Unlink the section. */ + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + ; + bfd_section_list_remove (output_bfd, pps); + + /* Now tack it on to the "place->os" section list. */ + bfd_section_list_insert (output_bfd, place->section, snew); + } + place->section = &snew->next; /* Save the end of this list. */ + + if (add.head != NULL) + { + /* We try to put the output statements in some sort of reasonable + order here, because they determine the final load addresses of + the orphan sections. */ + if (place->stmt == NULL) + { + /* Put the new statement list right at the head. */ + *add.tail = place->os->header.next; + place->os->header.next = add.head; + } + else + { + /* Put it after the last orphan statement we added. */ + *add.tail = *place->stmt; + *place->stmt = add.head; + } + + /* Fix the global list pointer if we happened to tack our new list + at the tail. */ + if (*old->tail == add.head) + old->tail = add.tail; + + /* Save the end of this list. */ + place->stmt = add.tail; + } + + return TRUE; +} + +/* 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 (abfd, sec, ptr) + bfd *abfd; + asection *sec; + PTR 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 +mmo_finish () +{ + bfd_map_over_sections (output_bfd, mmo_wipe_sec_reloc_flag, NULL); +} + +/* 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 () +{ + /* 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 (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_FINISH=mmo_finish +LDEMUL_AFTER_OPEN=mmo_after_open diff --git a/gnu/usr.bin/binutils/ld/emultempl/needrelax.em b/gnu/usr.bin/binutils/ld/emultempl/needrelax.em new file mode 100644 index 00000000000..242b7787435 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/needrelax.em @@ -0,0 +1,40 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2001, 2002 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 + +cat >>e${EMULATION_NAME}.c <<EOF + +static void need_relax_${EMULATION_NAME}_before_allocation PARAMS ((void)); + +static void +need_relax_${EMULATION_NAME}_before_allocation () +{ + /* 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.relocateable) + command_line.relax = TRUE; +} +EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/netbsd.em b/gnu/usr.bin/binutils/ld/emultempl/netbsd.em new file mode 100644 index 00000000000..891a87941fc --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/netbsd.em @@ -0,0 +1,11 @@ +LDEMUL_BEFORE_PARSE=gldnetbsd_before_parse +cat >>e${EMULATION_NAME}.c <<EOF +static void gldnetbsd_before_parse PARAMS ((void)); + +static void +gldnetbsd_before_parse () +{ + gld${EMULATION_NAME}_before_parse (); + link_info.common_skip_ar_aymbols = bfd_link_common_skip_text; +} +EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/ppc32elf.em b/gnu/usr.bin/binutils/ld/emultempl/ppc32elf.em new file mode 100644 index 00000000000..fbe1782aa1d --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/ppc32elf.em @@ -0,0 +1,82 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em, and defines extra powerpc64-elf +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include "libbfd.h" +#include "elf32-ppc.h" + +/* Whether to run tls optimization. */ +static int notlsopt = 0; + +static void ppc_before_allocation PARAMS ((void)); + +static void +ppc_before_allocation () +{ + extern const bfd_target bfd_elf32_powerpc_vec; + extern const bfd_target bfd_elf32_powerpcle_vec; + + if (link_info.hash->creator == &bfd_elf32_powerpc_vec + || link_info.hash->creator == &bfd_elf32_powerpcle_vec) + { + if (ppc_elf_tls_setup (output_bfd, &link_info) && !notlsopt) + { + if (!ppc_elf_tls_optimize (output_bfd, &link_info)) + { + einfo ("%X%P: TLS problem %E\n"); + return; + } + } + } + gld${EMULATION_NAME}_before_allocation (); +} + +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_TLS_OPT 301 +' + +PARSE_AND_LIST_LONGOPTS=' + { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --no-tls-optimize Don'\''t try to optimize TLS accesses.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_NO_TLS_OPT: + notlsopt = 1; + break; +' + +# Put these extra ppc64elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation diff --git a/gnu/usr.bin/binutils/ld/emultempl/ppc64elf.em b/gnu/usr.bin/binutils/ld/emultempl/ppc64elf.em new file mode 100644 index 00000000000..9f688a3d06a --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/ppc64elf.em @@ -0,0 +1,540 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2002, 2003 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em, and defines extra powerpc64-elf +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include "ldctor.h" +#include "libbfd.h" +#include "elf64-ppc.h" + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; + +/* 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 notlsopt = 0; + +static void ppc_create_output_section_statements + PARAMS ((void)); +static void ppc_after_open + PARAMS ((void)); +static void ppc_before_allocation + PARAMS ((void)); +static asection *ppc_add_stub_section + PARAMS ((const char *, asection *)); +static void ppc_layout_sections_again + PARAMS ((void)); +static void gld${EMULATION_NAME}_after_allocation + PARAMS ((void)); +static void build_section_lists + PARAMS ((lang_statement_union_type *)); +static struct bfd_elf_version_expr *gld${EMULATION_NAME}_new_vers_pattern + PARAMS ((struct bfd_elf_version_expr *)); + +/* 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 () +{ + extern const bfd_target bfd_elf64_powerpc_vec; + extern const bfd_target bfd_elf64_powerpcle_vec; + + if (link_info.hash->creator != &bfd_elf64_powerpc_vec + && link_info.hash->creator != &bfd_elf64_powerpcle_vec) + return; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", output_bfd); + if (stub_file->the_bfd == NULL + || !bfd_set_arch_mach (stub_file->the_bfd, + bfd_get_arch (output_bfd), + bfd_get_mach (output_bfd))) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + ldlang_add_file (stub_file); +} + +static void +ppc_after_open () +{ + if (!ppc64_elf_mark_entry_syms (&link_info)) + { + einfo ("%X%P: can not mark entry symbols %E\n"); + return; + } + + gld${EMULATION_NAME}_after_open (); +} + +static void +ppc_before_allocation () +{ + if (stub_file != NULL) + { + if (!ppc64_elf_edit_opd (output_bfd, &link_info)) + { + einfo ("%X%P: can not edit opd %E\n"); + return; + } + + if (ppc64_elf_tls_setup (output_bfd, &link_info) && !notlsopt) + { + /* Size the sections. This is premature, but we want to know the + TLS segment layout so that certain optimizations can be done. */ + lang_size_sections (stat_ptr->head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + + if (!ppc64_elf_tls_optimize (output_bfd, &link_info)) + { + einfo ("%X%P: TLS problem %E\n"); + return; + } + + lang_reset_memory_regions (); + } + } + + 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 + PARAMS ((struct hook_stub_info *, lang_statement_union_type **)); + +static bfd_boolean +hook_in_stub (info, lp) + 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 (stub_sec_name, input_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; + + stub_sec = bfd_make_section_anyway (stub_file->the_bfd, stub_sec_name); + if (stub_sec == NULL) + goto err_ret; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + if (!bfd_set_section_flags (stub_file->the_bfd, stub_sec, flags)) + 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, stub_file); + + 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 ppc64_elf_size_stubs. */ + +static void +ppc_layout_sections_again () +{ + /* 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. */ + need_laying_out = 0; + + lang_reset_memory_regions (); + + /* Resize the sections. */ + lang_size_sections (stat_ptr->head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + + /* Recalculate TOC base. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (stat_ptr->head, abs_output_section, + (fill_type *) 0, (bfd_vma) 0); +} + + +/* Call the back-end function to set TOC base after we have placed all + the sections. */ +static void +gld${EMULATION_NAME}_after_allocation () +{ + if (!link_info.relocateable) + _bfd_set_gp_value (output_bfd, ppc64_elf_toc (output_bfd)); +} + + +static void +build_section_lists (statement) + lang_statement_union_type *statement; +{ + if (statement->header.type == lang_input_section_enum + && !statement->input_section.ifile->just_syms_flag + && statement->input_section.section->output_section != NULL + && statement->input_section.section->output_section->owner == output_bfd) + { + ppc64_elf_next_input_section (&link_info, + statement->input_section.section); + } +} + + +/* Final emulation specific call. */ + +static void +gld${EMULATION_NAME}_finish () +{ + /* 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"; + + /* bfd_elf64_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${ELFSIZE}_discard_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.relocateable) + { + int ret = ppc64_elf_setup_section_lists (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 (!ppc64_elf_size_stubs (output_bfd, + stub_file->the_bfd, + &link_info, + group_size, + &ppc_add_stub_section, + &ppc_layout_sections_again)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + } + } + + if (need_laying_out) + ppc_layout_sections_again (); + + if (stub_file != NULL && stub_file->the_bfd->sections != NULL) + { + if (!ppc64_elf_build_stubs (&link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } +} + + +/* 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. */ + +struct bfd_elf_version_expr * +gld${EMULATION_NAME}_new_vers_pattern (entry) + struct bfd_elf_version_expr *entry; +{ + struct bfd_elf_version_expr *dot_entry; + struct bfd_elf_version_expr *next; + unsigned int len; + char *dot_pat; + + if (!dotsyms || entry->pattern[0] == '*') + return entry; + + /* Is the script adding ".foo" explicitly? */ + if (entry->pattern[0] == '.') + { + /* We may have added this pattern automatically. Don't add it + again. Quadratic behaviour here is acceptable as the list + may be traversed for each input bfd symbol. */ + for (next = entry->next; next != NULL; next = next->next) + { + if (strcmp (next->pattern, entry->pattern) == 0 + && next->match == entry->match) + { + next = entry->next; + free ((char *) entry->pattern); + free (entry); + return next; + } + } + return entry; + } + + /* Don't add ".foo" if the script has already done so. */ + for (next = entry->next; next != NULL; next = next->next) + { + if (next->pattern[0] == '.' + && strcmp (next->pattern + 1, entry->pattern) == 0 + && next->match == entry->match) + return entry; + } + + dot_entry = (struct bfd_elf_version_expr *) xmalloc (sizeof *dot_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->match = entry->match; + return dot_entry; +} + + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void ppc_for_each_input_file_wrapper + PARAMS ((lang_input_statement_type *)); +static void ppc_lang_for_each_input_file + PARAMS ((void (*) (lang_input_statement_type *))); + +static void (*real_func) PARAMS ((lang_input_statement_type *)); + +static void ppc_for_each_input_file_wrapper (l) + lang_input_statement_type *l; +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +ppc_lang_for_each_input_file (func) + void (*func) PARAMS ((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 + +# 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_DOTSYMS (OPTION_STUBGROUP_SIZE + 1) +#define OPTION_NO_DOTSYMS (OPTION_DOTSYMS + 1) +#define OPTION_NO_TLS_OPT (OPTION_NO_DOTSYMS + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE }, + { "dotsyms", no_argument, NULL, OPTION_DOTSYMS }, + { "no-dotsyms", no_argument, NULL, OPTION_NO_DOTSYMS }, + { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, +' + +PARSE_AND_LIST_OPTIONS=' + 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 before 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, _("\ + --dotsyms For every version pattern \"foo\" in a version script,\n\ + add \".foo\" so that function code symbols are\n\ + treated the same as function descriptor symbols.\n\ + 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" + )); +' + +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_DOTSYMS: + dotsyms = 1; + break; + + case OPTION_NO_DOTSYMS: + dotsyms = 0; + break; + + case OPTION_NO_TLS_OPT: + notlsopt = 1; + break; +' + +# Put these extra ppc64elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=ppc_after_open +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/gnu/usr.bin/binutils/ld/emultempl/sh64elf.em b/gnu/usr.bin/binutils/ld/emultempl/sh64elf.em new file mode 100644 index 00000000000..066cab86d8b --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/sh64elf.em @@ -0,0 +1,568 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 + +cat >>e${EMULATION_NAME}.c <<EOF + +#include "libiberty.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/sh.h" +#include "elf32-sh64.h" + +static void sh64_elf_${EMULATION_NAME}_before_allocation PARAMS ((void)); +static void sh64_elf_${EMULATION_NAME}_after_allocation PARAMS ((void)); + +/* 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 () +{ + asection *cranges; + asection *osec; + + /* Call main function; we're just extending it. */ + gld${EMULATION_NAME}_before_allocation (); + + cranges = bfd_get_section_by_name (output_bfd, SH64_CRANGES_SECTION_NAME); + + if (cranges != NULL) + { + if (command_line.relax) + { + /* 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); + } + } + + command_line.relax = FALSE; + } + + /* 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 (command_line.relax) + { + 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); + command_line.relax = FALSE; + 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 = 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 (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 (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->_raw_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->_raw_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 (output_bfd, + SH64_CRANGES_SECTION_NAME); + if (cranges == NULL + || !bfd_set_section_flags (output_bfd, + cranges, + SEC_LINKER_CREATED + | SEC_KEEP + | SEC_HAS_CONTENTS + | SEC_DEBUGGING)) + 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 () +{ + bfd_vma new_cranges = 0; + bfd_vma cranges_growth = 0; + asection *osec; + bfd_byte *crangesp; + + asection *cranges + = bfd_get_section_by_name (output_bfd, SH64_CRANGES_SECTION_NAME); + + /* If this ever starts doing something, we will pick it up. */ + after_allocation_default (); + + /* 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 = 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 (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->_raw_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->_raw_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->_raw_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++; + } + } + } + } + + BFD_ASSERT (cranges->contents == NULL); + 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 + = (bfd_byte *) xcalloc (cranges->_raw_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->_raw_size; + + /* Now pass over the sections again, and make reloc orders for the new + .cranges entries. Constants are set as we go. */ + for (osec = 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 (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->_raw_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->_cooked_size + ? isec->_cooked_size : isec->_raw_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 (output_bfd, last_cr_size, + crangesp - SH64_CRANGE_SIZE + + SH64_CRANGE_CR_SIZE_OFFSET); + + continuation_vma += cr_size; + continue; + } + + /* If we emit relocateable contents, we need a + relocation for the start address. */ + if (link_info.relocateable || 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 (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 + = ((struct bfd_link_order_reloc *) + 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 (output_bfd, isec->output_offset, + crangesp + SH64_CRANGE_CR_ADDR_OFFSET); + cr_addr_order->u.reloc.p->addend = 0; + + /* We must update the number of relocations here, + since the elf linker does not take link orders + into account when setting header sizes. The + actual relocation orders are however executed + correctly. */ + elf_section_data(cranges)->rel_count++; + } + else + bfd_put_32 (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 (output_bfd, cr_size, + crangesp + SH64_CRANGE_CR_SIZE_OFFSET); + + bfd_put_16 (output_bfd, (bfd_vma) 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 relocateable 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. */ + + cranges->_cooked_size = crangesp - cranges->contents; + sh64_elf_section_data (cranges)->sh64_info->cranges_growth + = cranges->_cooked_size - cranges->_raw_size; + cranges->_raw_size = cranges->_cooked_size; +} diff --git a/gnu/usr.bin/binutils/ld/emultempl/ticoff.em b/gnu/usr.bin/binutils/ld/emultempl/ticoff.em index a2ab4dbfbc2..90c940e4976 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/ticoff.em +++ b/gnu/usr.bin/binutils/ld/emultempl/ticoff.em @@ -3,7 +3,7 @@ (echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) cat >>e${EMULATION_NAME}.c <<EOF /* This file is part of GLD, the Gnu Linker. - Copyright 1999, 2000 Free Software Foundation, Inc. + Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,34 +27,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.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" -#include "getopt.h" - static int coff_version; static void gld_${EMULATION_NAME}_before_parse PARAMS ((void)); static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *)); -static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **)); +static void gld${EMULATION_NAME}_add_options + PARAMS ((int, char **, int, struct option **, int, struct option **)); +static bfd_boolean gld${EMULATION_NAME}_handle_option PARAMS ((int)); static void gld_${EMULATION_NAME}_list_options PARAMS ((FILE *)); /* TI COFF extra command line options */ #define OPTION_COFF_FORMAT (300 + 1) -static struct option longopts[] = +static void +gld${EMULATION_NAME}_add_options (ns, shortopts, nl, longopts, nrl, really_longopts) + int ns ATTRIBUTE_UNUSED; + char **shortopts ATTRIBUTE_UNUSED; + int nl; + struct option **longopts; + int nrl ATTRIBUTE_UNUSED; + struct option **really_longopts ATTRIBUTE_UNUSED; { - /* TI COFF options */ - {"format", required_argument, NULL, OPTION_COFF_FORMAT }, - {NULL, no_argument, NULL, 0} -}; + 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) @@ -63,34 +76,14 @@ gld_${EMULATION_NAME}_list_options (file) fprintf (file, _(" --format 0|1|2 Specify which COFF version to use")); } -static int -gld_${EMULATION_NAME}_parse_args(argc, argv) - int argc; - char **argv; +static bfd_boolean +gld${EMULATION_NAME}_handle_option (optc) + int optc; { - int longind; - int optc; - int prevoptind = optind; - int prevopterr = opterr; - int wanterror; - static int lastoptind = -1; - - if (lastoptind != optind) - opterr = 0; - wanterror = opterr; - - lastoptind = optind; - - optc = getopt_long_only (argc, argv, "-", longopts, &longind); - opterr = prevopterr; - switch (optc) { default: - if (wanterror) - xexit (1); - optind = prevoptind; - return 0; + return FALSE; case OPTION_COFF_FORMAT: if ((*optarg == '0' || *optarg == '1' || *optarg == '2') @@ -106,11 +99,10 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) else { einfo (_("%P%F: invalid COFF format version %s\n"), optarg); - } break; } - return 1; + return FALSE; } static void @@ -138,9 +130,9 @@ $s/$/n"/ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 0; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return `sed "$sc" ldscripts/${EMULATION_NAME}.xu`; - else if (link_info.relocateable == true) + else if (link_info.relocateable) return `sed "$sc" ldscripts/${EMULATION_NAME}.xr`; else if (!config.text_read_only) return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`; @@ -158,9 +150,9 @@ cat >>e${EMULATION_NAME}.c <<EOF { *isfile = 1; - if (link_info.relocateable == true && config.build_constructors == true) + if (link_info.relocateable && config.build_constructors) return "ldscripts/${EMULATION_NAME}.xu"; - else if (link_info.relocateable == true) + else if (link_info.relocateable) return "ldscripts/${EMULATION_NAME}.xr"; else if (!config.text_read_only) return "ldscripts/${EMULATION_NAME}.xbn"; @@ -193,10 +185,13 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = NULL, /* open dynamic archive */ NULL, /* place orphan */ NULL, /* set_symbols */ - gld_${EMULATION_NAME}_parse_args, + 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, /* find_potential_libraries */ + NULL /* new_vers_pattern */ }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/xtensaelf.em b/gnu/usr.bin/binutils/ld/emultempl/xtensaelf.em new file mode 100644 index 00000000000..b0700758f69 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emultempl/xtensaelf.em @@ -0,0 +1,1586 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2003 +# Free Software Foundation, Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This file is sourced from elf32.em, and defines extra xtensa-elf +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include <xtensa-config.h> + +static char *elf_xtensa_choose_target + PARAMS ((int, char **)); +static bfd_boolean elf_xtensa_place_orphan + PARAMS ((lang_input_statement_type *, asection *)); +static void elf_xtensa_before_parse + PARAMS ((void)); +static void elf_xtensa_before_allocation + PARAMS ((void)); +static void xtensa_wild_group_interleave + PARAMS ((lang_statement_union_type *)); +static void xtensa_wild_group_interleave_callback + PARAMS ((lang_statement_union_type *)); +static void xtensa_colocate_output_literals + PARAMS ((lang_statement_union_type *)); +static void xtensa_colocate_output_literals_callback + PARAMS ((lang_statement_union_type *)); + + +/* Flag for the emulation-specific "--no-relax" option. */ +static bfd_boolean disable_relaxation = FALSE; + +/* 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 (argc, argv) + int argc ATTRIBUTE_UNUSED; + char **argv ATTRIBUTE_UNUSED; +{ + if (XCHAL_HAVE_BE) + return "${BIG_OUTPUT_FORMAT}"; + else + return "${LITTLE_OUTPUT_FORMAT}"; +} + + +static bfd_boolean +elf_xtensa_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + /* Early exit for relocatable links. */ + if (link_info.relocateable) + return FALSE; + + return gld${EMULATION_NAME}_place_orphan (file, s); +} + + +static void +elf_xtensa_before_parse () +{ + /* 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 (); +} + + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +void +elf_xtensa_before_allocation () +{ + bfd *in_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 && output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + { + einfo (_("%F%P: little endian output does not match " + "Xtensa configuration\n")); + } + if (!is_big_endian && output_bfd->xvec->byteorder == BFD_ENDIAN_BIG) + { + einfo (_("%F%P: big endian output does not match " + "Xtensa configuration\n")); + } + + /* 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. */ + + for (in_bfd = link_info.input_bfds; + in_bfd != NULL; + in_bfd = in_bfd->link_next) + { + if ((is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + || (!is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_BIG)) + einfo (_("%F%P: cross-endian linking not supported\n")); + } + + /* 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 (!disable_relaxation) + command_line.relax = TRUE; + + gld${EMULATION_NAME}_before_allocation (); + + xtensa_wild_group_interleave (stat_ptr->head); + if (command_line.relax) + 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 relocateable 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 + PARAMS ((const reloc_deps_graph *, lang_wild_statement_type *)); + +typedef void (*deps_callback_t) + PARAMS ((asection *, /* src_sec */ + bfd_vma, /* src_offset */ + asection *, /* target_sec */ + bfd_vma, /* target_offset */ + PTR)); /* closure */ + +static void build_deps_graph_callback + PARAMS ((asection *, bfd_vma, asection *, bfd_vma, PTR)); +extern bfd_boolean xtensa_callback_required_dependence + PARAMS ((bfd *, asection *, struct bfd_link_info *, + deps_callback_t, PTR)); +static void xtensa_ldlang_clear_addresses + PARAMS ((lang_statement_union_type *)); +static bfd_boolean ld_local_file_relocations_fit + PARAMS ((lang_statement_union_type *, const reloc_deps_graph *)); +static bfd_vma ld_assign_relative_paged_dot + PARAMS ((bfd_vma, lang_statement_union_type *, + const reloc_deps_graph *, bfd_boolean)); +static bfd_vma ld_xtensa_insert_page_offsets + PARAMS ((bfd_vma, lang_statement_union_type *, reloc_deps_graph *, + bfd_boolean)); +static void lang_for_each_statement_worker + PARAMS ((void (*) (lang_statement_union_type *), + lang_statement_union_type *)); +static void xtensa_move_dependencies_to_front + PARAMS ((reloc_deps_graph *, lang_wild_statement_type *)); +static reloc_deps_graph *ld_build_required_section_dependence + PARAMS ((lang_statement_union_type *)); +static bfd_boolean section_is_source + PARAMS ((const reloc_deps_graph *, lang_statement_union_type *)); +static bfd_boolean section_is_target + PARAMS ((const reloc_deps_graph *, lang_statement_union_type *)); +static bfd_boolean section_is_source_or_target + PARAMS ((const reloc_deps_graph *, lang_statement_union_type *)); +static bfd_boolean deps_has_sec_edge + PARAMS ((const reloc_deps_graph *, asection *, asection *)); +static bfd_boolean deps_has_edge + PARAMS ((const reloc_deps_graph *, lang_statement_union_type *, + lang_statement_union_type *)); +static void add_deps_edge + PARAMS ((reloc_deps_graph *, asection *, asection *)); +#if EXTRA_VALIDATION +static size_t ld_count_children + PARAMS ((lang_statement_union_type *)); +#endif +static void free_reloc_deps_graph + PARAMS ((reloc_deps_graph *)); +static void xtensa_colocate_literals + PARAMS ((reloc_deps_graph *, lang_statement_union_type *)); +static reloc_deps_section *xtensa_get_section_deps + PARAMS ((const reloc_deps_graph *, asection *)); +static void xtensa_set_section_deps + PARAMS ((const reloc_deps_graph *, asection *, reloc_deps_section *)); +static void xtensa_append_section_deps + PARAMS ((reloc_deps_graph *, asection *)); + +extern lang_statement_list_type constructor_list; + +/* Begin verbatim code from ldlang.c: + the following are copied from ldlang.c because they are defined + there statically. */ + +static void +lang_for_each_statement_worker (func, s) + void (*func) PARAMS ((lang_statement_union_type *)); + lang_statement_union_type *s; +{ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + func (s); + + switch (s->header.type) + { + case lang_constructors_statement_enum: + lang_for_each_statement_worker (func, constructor_list.head); + break; + case lang_output_section_statement_enum: + lang_for_each_statement_worker + (func, + s->output_section_statement.children.head); + break; + case lang_wild_statement_enum: + lang_for_each_statement_worker + (func, + s->wild_statement.children.head); + break; + case lang_group_statement_enum: + lang_for_each_statement_worker (func, + s->group_statement.children.head); + break; + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + case lang_input_section_enum: + case lang_input_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + default: + FAIL (); + break; + } + } +} + +/* End of verbatim code from ldlang.c. */ + + +reloc_deps_section * +xtensa_get_section_deps (deps, sec) + 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 = (reloc_deps_section *) sec->userdata; + return sec_deps; +} + +void +xtensa_set_section_deps (deps, sec, deps_section) + const reloc_deps_graph *deps ATTRIBUTE_UNUSED; + asection *sec; + reloc_deps_section *deps_section; +{ + sec->userdata = (void *) 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 (deps, sec) + 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 = (asection**) 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 (deps) + 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); +} + + +bfd_boolean +section_is_source (deps, s) + 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); +} + + +bfd_boolean +section_is_target (deps, s) + 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); +} + +bfd_boolean +section_is_source_or_target (deps, s) + 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 + PARAMS ((xtensa_ld_iter *, xtensa_ld_iter *)); + + +void +ld_xtensa_move_section_after (to, current) + 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 + PARAMS ((xtensa_ld_iter_stack **)); +static bfd_boolean iter_stack_push + PARAMS ((xtensa_ld_iter_stack **, lang_statement_union_type *)); +static void iter_stack_pop + PARAMS ((xtensa_ld_iter_stack **)); +static void iter_stack_update + PARAMS ((xtensa_ld_iter_stack **)); +static void iter_stack_next + PARAMS ((xtensa_ld_iter_stack **)); +static lang_statement_union_type *iter_stack_current + PARAMS ((xtensa_ld_iter_stack **)); +static void iter_stack_create + PARAMS ((xtensa_ld_iter_stack **, lang_statement_union_type *)); +static void iter_stack_copy_current + PARAMS ((xtensa_ld_iter_stack **, xtensa_ld_iter *)); + + +static bfd_boolean +iter_stack_empty (stack_p) + xtensa_ld_iter_stack **stack_p; +{ + return (*stack_p == NULL); +} + + +static bfd_boolean +iter_stack_push (stack_p, parent) + 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 = (xtensa_ld_iter_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 (stack_p) + 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 (stack_p) + 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 (stack_p) + 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 (stack_p) + xtensa_ld_iter_stack **stack_p; +{ + return *((*stack_p)->iterloc.loc); +} + + +/* The iter stack is a preorder. */ + +static void +iter_stack_create (stack_p, parent) + xtensa_ld_iter_stack **stack_p; + lang_statement_union_type *parent; +{ + iter_stack_push (stack_p, parent); +} + + +static void +iter_stack_copy_current (stack_p, front) + xtensa_ld_iter_stack **stack_p; + xtensa_ld_iter *front; +{ + *front = (*stack_p)->iterloc; +} + + +void +xtensa_colocate_literals (deps, statement) + 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; + +#if 0 + ld_assign_relative_paged_dot (0x100000, statement, deps, + xtensa_use_literal_pages); + + if (!ld_local_file_relocations_fit (statement, deps)) + fprintf (stderr, "initial relocation placement does not fit\n"); + + lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, statement); +#endif + + 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); +} + + +void +xtensa_move_dependencies_to_front (deps, w) + 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 (deps, src, tgt) + 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 (deps, src, tgt) + 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 (deps, src_sec, tgt_sec) + 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 = (reloc_deps_section *) + 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 = (reloc_deps_section *) + 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 = (reloc_deps_e *) 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 = (reloc_deps_e *) 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; +} + + +void +build_deps_graph_callback (src_sec, src_offset, + target_sec, target_offset, closure) + asection *src_sec; + bfd_vma src_offset ATTRIBUTE_UNUSED; + asection *target_sec; + bfd_vma target_offset ATTRIBUTE_UNUSED; + PTR closure; +{ + reloc_deps_graph *deps; + deps = (reloc_deps_graph*) closure; + + /* If the target is defined. */ + if (target_sec != NULL) + add_deps_edge (deps, src_sec, target_sec); +} + + +reloc_deps_graph * +ld_build_required_section_dependence (s) + lang_statement_union_type *s; +{ + reloc_deps_graph *deps; + xtensa_ld_iter_stack *stack = NULL; + + deps = (reloc_deps_graph*) 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->ifile->the_bfd, + input->section, + &link_info, + /* Use the same closure. */ + build_deps_graph_callback, + (PTR) deps); + } + } + return deps; +} + + +#if EXTRA_VALIDATION +size_t +ld_count_children (s) + 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 */ + + +void +xtensa_wild_group_interleave_callback (statement) + 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); + } +} + + +void +xtensa_wild_group_interleave (s) + lang_statement_union_type *s; +{ + lang_for_each_statement_worker (xtensa_wild_group_interleave_callback, s); +} + + +void +xtensa_layout_wild (deps, w) + 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 +} + + +void +xtensa_colocate_output_literals_callback (statement) + lang_statement_union_type * statement; +{ + lang_output_section_statement_type *os; + 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; + + os = &statement->output_section_statement; + +#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 ((bfd_vma) 0, statement, deps, + xtensa_use_literal_pages); + lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, + statement); + } + + /* Clean up. */ + free_reloc_deps_graph (deps); + } +} + + +void +xtensa_colocate_output_literals (s) + lang_statement_union_type *s; +{ + lang_for_each_statement_worker (xtensa_colocate_output_literals_callback, s); +} + + +void +xtensa_ldlang_clear_addresses (statement) + 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; + } +} + + +bfd_vma +ld_assign_relative_paged_dot (dot, s, deps, lit_align) + 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->_raw_size != 0 + && (first_section + || (in_literals && !sec_is_target) + || (!in_literals && sec_is_target))) + { + do_xtensa_alignment = TRUE; + } + first_section = FALSE; + if (section->_raw_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->_raw_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; +} + + +bfd_boolean +ld_local_file_relocations_fit (statement, deps) + 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->_raw_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; +} + + +bfd_vma +ld_xtensa_insert_page_offsets (dot, s, deps, lit_align) + 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->_raw_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->_raw_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; + lang_statement_list_type *old_stat_ptr = stat_ptr; + + /* 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. */ + + tmplist.head = NULL; + tmplist.tail = &tmplist.head; + + 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; + stat_ptr = old_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_NO_RELAX 301 +' + +PARSE_AND_LIST_LONGOPTS=' + { "no-relax", no_argument, NULL, OPTION_NO_RELAX}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --no-relax\t\tDo not relax branches or coalesce literals\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_NO_RELAX: + disable_relaxation = TRUE; + break; +' + +# Replace some of the standard ELF functions with our own versions. +# +LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse +LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target +LDEMUL_PLACE_ORPHAN=elf_xtensa_place_orphan +LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation + |