diff options
Diffstat (limited to 'ld/emultempl')
33 files changed, 3975 insertions, 355 deletions
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em index d525edd890455..c2617f2ce4125 100644 --- a/ld/emultempl/aix.em +++ b/ld/emultempl/aix.em @@ -10,7 +10,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* AIX emulation code for ${EMULATION_NAME} Copyright 1991, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005 + 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> AIX support by Ian Lance Taylor <ian@cygnus.com> @@ -34,8 +34,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "safe-ctype.h" #include "getopt.h" @@ -268,7 +268,7 @@ gld${EMULATION_NAME}_parse_args (int argc, char **argv) if (indx == 0) indx = 1; - if (indx < argc && strncmp (argv[indx], "-b", 2) == 0) + if (indx < argc && CONST_STRNEQ (argv[indx], "-b")) { char *s; @@ -651,18 +651,52 @@ gld${EMULATION_NAME}_before_allocation (void) size_t len; search_dirs_type *search; - len = strlen (search_head->name); - libpath = xmalloc (len + 1); - strcpy (libpath, search_head->name); - for (search = search_head->next; search != NULL; search = search->next) + /* PR ld/4023: Strip sysroot prefix from any paths + being inserted into the output binary's DT_RPATH. */ + if (ld_sysroot != NULL + && * ld_sysroot != 0) { - size_t nlen; + const char * name = search_head->name; + size_t ld_sysroot_len = strlen (ld_sysroot); + + if (strncmp (name, ld_sysroot, ld_sysroot_len) == 0) + name += ld_sysroot_len; + + len = strlen (name); + libpath = xmalloc (len + 1); + strcpy (libpath, name); - nlen = strlen (search->name); - libpath = xrealloc (libpath, len + nlen + 2); - libpath[len] = ':'; - strcpy (libpath + len + 1, search->name); - len += nlen + 1; + for (search = search_head->next; search != NULL; search = search->next) + { + size_t nlen; + + name = search->name; + if (strncmp (name, ld_sysroot, ld_sysroot_len) == 0) + name += ld_sysroot_len; + + nlen = strlen (name); + libpath = xrealloc (libpath, len + nlen + 2); + libpath[len] = ':'; + strcpy (libpath + len + 1, name); + len += nlen + 1; + } + } + else + { + len = strlen (search_head->name); + libpath = xmalloc (len + 1); + strcpy (libpath, search_head->name); + + for (search = search_head->next; search != NULL; search = search->next) + { + size_t nlen; + + nlen = strlen (search->name); + libpath = xrealloc (libpath, len + nlen + 2); + libpath[len] = ':'; + strcpy (libpath + len + 1, search->name); + len += nlen + 1; + } } } diff --git a/ld/emultempl/armcoff.em b/ld/emultempl/armcoff.em index d5fd67d8ce2e8..a2e2c6c2d07a9 100644 --- a/ld/emultempl/armcoff.em +++ b/ld/emultempl/armcoff.em @@ -5,7 +5,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* emulate the original gld for the given ${EMULATION_NAME} Copyright 1991, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005 Free Software Foundation, Inc. + 2004, 2005, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com This file is part of GLD, the Gnu Linker. @@ -26,8 +26,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "getopt.h" @@ -154,45 +154,46 @@ gld${EMULATION_NAME}_after_open (void) static void gld${EMULATION_NAME}_finish (void) { - struct bfd_link_hash_entry * h; - - if (thumb_entry_symbol == NULL) - return; - - h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, - FALSE, FALSE, TRUE); - - if (h != (struct bfd_link_hash_entry *) NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak) - && h->u.def.section->output_section != NULL) + if (thumb_entry_symbol != NULL) { - static char buffer[32]; - bfd_vma val; - - /* Special procesing is required for a Thumb entry symbol. The - bottom bit of its address must be set. */ - val = (h->u.def.value - + bfd_get_section_vma (output_bfd, - h->u.def.section->output_section) - + h->u.def.section->output_offset); - - val |= 1; - - /* Now convert this value into a string and store it in entry_symbol - where the lang_finish() function will pick it up. */ - buffer[0] = '0'; - buffer[1] = 'x'; - - sprintf_vma (buffer + 2, val); - - if (entry_symbol.name != NULL && entry_from_cmdline) - einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), - thumb_entry_symbol, entry_symbol.name); - entry_symbol.name = buffer; + struct bfd_link_hash_entry * h; + + h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, + FALSE, FALSE, TRUE); + + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + && h->u.def.section->output_section != NULL) + { + static char buffer[32]; + bfd_vma val; + + /* Special procesing is required for a Thumb entry symbol. The + bottom bit of its address must be set. */ + val = (h->u.def.value + + bfd_get_section_vma (output_bfd, + h->u.def.section->output_section) + + h->u.def.section->output_offset); + + val |= 1; + + /* Now convert this value into a string and store it in entry_symbol + where the lang_finish() function will pick it up. */ + buffer[0] = '0'; + buffer[1] = 'x'; + + sprintf_vma (buffer + 2, val); + + if (entry_symbol.name != NULL && entry_from_cmdline) + einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), + thumb_entry_symbol, entry_symbol.name); + entry_symbol.name = buffer; + } + else + einfo (_("%P: warning: connot find thumb start symbol %s\n"), + thumb_entry_symbol); } - else - einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); finish_default (); } diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index bd74ab5705bff..e9f663f494a5c 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -35,6 +35,9 @@ static int target1_is_rel = 0${TARGET1_IS_REL}; static char *target2_type = "${TARGET2_TYPE}"; static int fix_v4bx = 0; static int use_blx = 0; +static bfd_arm_vfp11_fix vfp11_denorm_fix = BFD_ARM_VFP11_FIX_DEFAULT; +static int no_enum_size_warning = 0; +static int pic_veneer = 0; static void gld${EMULATION_NAME}_before_parse (void) @@ -103,9 +106,6 @@ arm_elf_before_allocation (void) { bfd *tem; - /* Call the standard elf routine. */ - gld${EMULATION_NAME}_before_allocation (); - if (link_info.input_bfds != NULL) { /* The interworking bfd must be the last one in the link. */ @@ -124,27 +124,55 @@ arm_elf_before_allocation (void) 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 */ - { - LANG_FOR_EACH_INPUT_STATEMENT (is) - { - if (!bfd_elf32_arm_process_before_allocation (is->the_bfd, & link_info, - byteswap_code)) - { + bfd_elf32_arm_set_byteswap_code (&link_info, byteswap_code); + + /* Choose type of VFP11 erratum fix, or warn if specified fix is unnecessary + due to architecture version. */ + bfd_elf32_arm_set_vfp11_fix (output_bfd, &link_info); + + /* We should be able to set the size of the interworking stub section. We + can't do it until later if we have dynamic sections, though. */ + if (! elf_hash_table (&link_info)->dynamic_sections_created) + { + /* Here we rummage through the found bfds to collect glue information. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + /* Initialise mapping tables for code/data. */ + bfd_elf32_arm_init_maps (is->the_bfd); + + if (!bfd_elf32_arm_process_before_allocation (is->the_bfd, + &link_info) + || !bfd_elf32_arm_vfp11_erratum_scan (is->the_bfd, &link_info)) /* xgettext:c-format */ einfo (_("Errors encountered processing file %s"), is->filename); - } - } - } + } + } + + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_before_allocation (); /* We have seen it all. Allocate it, and carry on. */ bfd_elf32_arm_allocate_interworking_sections (& link_info); } static void +arm_elf_after_allocation (void) +{ + /* Call the standard elf routine. */ + after_allocation_default (); + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + /* Figure out where VFP11 erratum veneers (and the labels returning + from same) have been placed. */ + bfd_elf32_arm_vfp11_fix_veneer_locations (is->the_bfd, &link_info); + } + } +} + +static void arm_elf_finish (void) { struct bfd_link_hash_entry * h; @@ -207,13 +235,15 @@ arm_elf_finish (void) thumb_entry_symbol); } -/* This is a convenitent point to tell BFD about target specific flags. +/* This is a convenient point to tell BFD about target specific flags. After the output has been created, but before inputs are read. */ static void arm_elf_create_output_section_statements (void) { - bfd_elf32_arm_set_target_relocs (&link_info, target1_is_rel, target2_type, - fix_v4bx, use_blx); + bfd_elf32_arm_set_target_relocs (output_bfd, &link_info, target1_is_rel, + target2_type, fix_v4bx, use_blx, + vfp11_denorm_fix, no_enum_size_warning, + pic_veneer); } EOF @@ -229,6 +259,9 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_TARGET2 305 #define OPTION_FIX_V4BX 306 #define OPTION_USE_BLX 307 +#define OPTION_VFP11_DENORM_FIX 308 +#define OPTION_NO_ENUM_SIZE_WARNING 309 +#define OPTION_PIC_VENEER 310 ' PARSE_AND_LIST_SHORTOPTS=p @@ -242,6 +275,9 @@ PARSE_AND_LIST_LONGOPTS=' { "target2", required_argument, NULL, OPTION_TARGET2}, { "fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX}, { "use-blx", no_argument, NULL, OPTION_USE_BLX}, + { "vfp11-denorm-fix", required_argument, NULL, OPTION_VFP11_DENORM_FIX}, + { "no-enum-size-warning", no_argument, NULL, OPTION_NO_ENUM_SIZE_WARNING}, + { "pic-veneer", no_argument, NULL, OPTION_PIC_VENEER}, ' PARSE_AND_LIST_OPTIONS=' @@ -252,6 +288,9 @@ PARSE_AND_LIST_OPTIONS=' fprintf (file, _(" --target2=<type> Specify definition of R_ARM_TARGET2\n")); fprintf (file, _(" --fix-v4bx Rewrite BX rn as MOV pc, rn for ARMv4\n")); fprintf (file, _(" --use-blx Enable use of BLX instructions\n")); + fprintf (file, _(" --vfp11-denorm-fix Specify how to fix VFP11 denorm erratum\n")); + fprintf (file, _(" --no-enum-size-warning Don'\''t warn about objects with incompatible enum sizes\n")); + fprintf (file, _(" --pic-veneer Always generate PIC interworking veneers\n")); ' PARSE_AND_LIST_ARGS_CASES=' @@ -286,12 +325,32 @@ PARSE_AND_LIST_ARGS_CASES=' case OPTION_USE_BLX: use_blx = 1; break; + + case OPTION_VFP11_DENORM_FIX: + if (strcmp (optarg, "none") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_NONE; + else if (strcmp (optarg, "scalar") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_SCALAR; + else if (strcmp (optarg, "vector") == 0) + vfp11_denorm_fix = BFD_ARM_VFP11_FIX_VECTOR; + else + einfo (_("Unrecognized VFP11 fix type '\''%s'\''.\n"), optarg); + break; + + case OPTION_NO_ENUM_SIZE_WARNING: + no_enum_size_warning = 1; + break; + + case OPTION_PIC_VENEER: + pic_veneer = 1; + break; ' # We have our own after_open and before_allocation functions, but they call # the standard routines, so give them a different name. LDEMUL_AFTER_OPEN=arm_elf_after_open LDEMUL_BEFORE_ALLOCATION=arm_elf_before_allocation +LDEMUL_AFTER_ALLOCATION=arm_elf_after_allocation LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=arm_elf_create_output_section_statements # Replace the elf before_parse function with our own. diff --git a/ld/emultempl/avrelf.em b/ld/emultempl/avrelf.em new file mode 100644 index 0000000000000..1f5ab5cf507fa --- /dev/null +++ b/ld/emultempl/avrelf.em @@ -0,0 +1,269 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006 +# 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., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301 USA. + +# This file is sourced from elf32.em, and defines extra avr-elf +# specific routines. It is used to generate the trampolines for the avr6 +# family devices where one needs to address the issue that it is not possible +# to reach the whole program memory by using 16 bit pointers. + +cat >>e${EMULATION_NAME}.c <<EOF + +#include "elf32-avr.h" +#include "ldctor.h" + +/* The fake file and it's corresponding section meant to hold + the linker stubs if needed. */ + +static lang_input_statement_type *stub_file; +static asection *avr_stub_section; + +/* Variables set by the command-line parameters and transfered + to the bfd without use of global shared variables. */ + +static bfd_boolean avr_no_stubs = FALSE; +static bfd_boolean avr_debug_relax = FALSE; +static bfd_boolean avr_debug_stubs = FALSE; +static bfd_boolean avr_replace_call_ret_sequences = TRUE; +static bfd_vma avr_pc_wrap_around = 0x10000000; + +/* Transfers information to the bfd frontend. */ + +static void +avr_elf_set_global_bfd_parameters (void) +{ + elf32_avr_setup_params (& link_info, + stub_file->the_bfd, + avr_stub_section, + avr_no_stubs, + avr_debug_stubs, + avr_debug_relax, + avr_pc_wrap_around, + avr_replace_call_ret_sequences); +} + + +/* Makes a conservative estimate of the trampoline section size that could + be corrected later on. */ + +static void +avr_elf_${EMULATION_NAME}_before_allocation (void) +{ + int ret; + + gld${EMULATION_NAME}_before_allocation (); + + /* We only need stubs for the avr6 family. */ + if (strcmp ("${EMULATION_NAME}","avr6")) + avr_no_stubs = TRUE; + + avr_elf_set_global_bfd_parameters (); + + /* If generating a relocatable output file, then + we don't have to generate the trampolines. */ + if (link_info.relocatable) + avr_no_stubs = TRUE; + + if (avr_no_stubs) + return; + + ret = elf32_avr_setup_section_lists (output_bfd, &link_info); + + if (ret < 0) + einfo ("%X%P: can not setup the input section list: %E\n"); + + if (ret <= 0) + return; + + /* Call into the BFD backend to do the real "stub"-work. */ + if (! elf32_avr_size_stubs (output_bfd, &link_info, TRUE)) + einfo ("%X%P: can not size stub section: %E\n"); +} + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub section and generate the section itself. */ + +static void +avr_elf_create_output_section_statements (void) +{ + flagword flags; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + + stub_file->the_bfd = bfd_create ("linker stubs", 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 stub BFD %E\n"); + return; + } + + /* Now we add the stub section. */ + + avr_stub_section = bfd_make_section_anyway (stub_file->the_bfd, + ".trampolines"); + if (avr_stub_section == 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, avr_stub_section, flags)) + goto err_ret; + + avr_stub_section->alignment_power = 1; + + ldlang_add_file (stub_file); + + return; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return; +} + +/* Re-calculates the size of the stubs so that we won't waste space. */ + +static void +avr_elf_finish (void) +{ + if (!avr_no_stubs) + { + /* 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_avr_size_stubs (output_bfd, &link_info, FALSE)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + + if (!elf32_avr_build_stubs (&link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } + } + + gld${EMULATION_NAME}_finish (); +} + + +EOF + + +PARSE_AND_LIST_PROLOGUE=' + +#define OPTION_NO_CALL_RET_REPLACEMENT 301 +#define OPTION_PMEM_WRAP_AROUND 302 +#define OPTION_NO_STUBS 303 +#define OPTION_DEBUG_STUBS 304 +#define OPTION_DEBUG_RELAX 305 +' + +PARSE_AND_LIST_LONGOPTS=' + { "no-call-ret-replacement", no_argument, + NULL, OPTION_NO_CALL_RET_REPLACEMENT}, + { "pmem-wrap-around", required_argument, + NULL, OPTION_PMEM_WRAP_AROUND}, + { "no-stubs", no_argument, + NULL, OPTION_NO_STUBS}, + { "debug-stubs", no_argument, + NULL, OPTION_DEBUG_STUBS}, + { "debug-relax", no_argument, + NULL, OPTION_DEBUG_RELAX}, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _(" --pmem-wrap-around=<val> " + "Make the linker relaxation machine assume that a\n" + " " + "program counter wrap-around occures at address\n" + " " + "<val>. Supported values are 8k, 16k, 32k and 64k.\n")); + fprintf (file, _(" --no-call-ret-replacement " + "The relaxation machine normally will\n" + " " + "substitute two immediately following call/ret\n" + " " + "instructions by a single jump instruction.\n" + " " + "This option disables this optimization.\n")); + fprintf (file, _(" --no-stubs " + "If the linker detects to attempt to access\n" + " " + "an instruction beyond 128k by a reloc that\n" + " " + "is limited to 128k max, it inserts a jump\n" + " " + "stub. You can de-active this with this switch.\n")); + fprintf (file, _(" --debug-stubs Used for debugging avr-ld.\n")); + fprintf (file, _(" --debug-relax Used for debugging avr-ld.\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + + case OPTION_PMEM_WRAP_AROUND: + { + /* This variable is defined in the bfd library. */ + if ((!strcmp (optarg,"32k")) || (!strcmp (optarg,"32K"))) + avr_pc_wrap_around = 32768; + else if ((!strcmp (optarg,"8k")) || (!strcmp (optarg,"8K"))) + avr_pc_wrap_around = 8192; + else if ((!strcmp (optarg,"16k")) || (!strcmp (optarg,"16K"))) + avr_pc_wrap_around = 16384; + else if ((!strcmp (optarg,"64k")) || (!strcmp (optarg,"64K"))) + avr_pc_wrap_around = 0x10000; + else + return FALSE; + } + break; + + case OPTION_DEBUG_STUBS: + avr_debug_stubs = TRUE; + break; + + case OPTION_DEBUG_RELAX: + avr_debug_relax = TRUE; + break; + + case OPTION_NO_STUBS: + avr_no_stubs = TRUE; + break; + + case OPTION_NO_CALL_RET_REPLACEMENT: + { + /* This variable is defined in the bfd library. */ + avr_replace_call_ret_sequences = FALSE; + } + break; +' + +# +# Put these extra avr-elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_BEFORE_ALLOCATION=avr_elf_${EMULATION_NAME}_before_allocation +LDEMUL_FINISH=avr_elf_finish +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=avr_elf_create_output_section_statements diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em index 220ba5900a3f1..9f42a4f181576 100644 --- a/ld/emultempl/beos.em +++ b/ld/emultempl/beos.em @@ -8,7 +8,7 @@ fi cat >e${EMULATION_NAME}.c <<EOF /* This file is part of GLD, the Gnu Linker. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 Free Software Foundation, Inc. + 2005, 2006, 2007 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 @@ -31,8 +31,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. only determine if the subsystem is console or windows in order to select the correct entry point by default. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "getopt.h" #include "libiberty.h" @@ -452,16 +452,15 @@ sort_by_section_name (const void *a, const void *b) const lang_statement_union_type *const *rb = b; int i; i = strcmp ((*ra)->input_section.section->name, - (*rb)->input_section.section->name); -/* this is a hack to make .stab and .stabstr last, so we don't have - to fix strip/objcopy for .reloc sections. - FIXME stripping images with a .rsrc section still needs to be fixed */ - if ( i != 0) + (*rb)->input_section.section->name); + /* This is a hack to make .stab and .stabstr last, so we don't have + to fix strip/objcopy for .reloc sections. + FIXME stripping images with a .rsrc section still needs to be fixed. */ + if (i != 0) { - if ((strncmp ((*ra)->input_section.section->name, ".stab", 5) == 0) - && (strncmp ((*rb)->input_section.section->name, ".stab", 5) != 0)) + if ((CONST_STRNEQ ((*ra)->input_section.section->name, ".stab")) + && (! CONST_STRNEQ ((*rb)->input_section.section->name, ".stab"))) return 1; - return i; } return i; } @@ -534,7 +533,7 @@ sort_sections (lang_statement_union_type *s) { /* Is this the .idata section? */ if (sec->spec.name != NULL - && strncmp (sec->spec.name, ".idata", 6) == 0) + && CONST_STRNEQ (sec->spec.name, ".idata")) { /* Sort the children. We want to sort any objects in the same archive. In order to handle the case of diff --git a/ld/emultempl/cr16elf.em b/ld/emultempl/cr16elf.em new file mode 100644 index 0000000000000..0881634bb0183 --- /dev/null +++ b/ld/emultempl/cr16elf.em @@ -0,0 +1,92 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2007 Free Software Foundation, Inc. +# Contributed by M R Swami Reddy <MR.Swami.Reddy@nsc.com> +# +# 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +# + +# This file is sourced from elf32.em, and defines extra cr16-elf +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +#include "ldctor.h" + +/* Flag for the emulation-specific "--no-relax" option. */ +static bfd_boolean disable_relaxation = FALSE; + +static void +cr16elf_after_parse (void) +{ + /* Always behave as if called with --sort-common command line + option. + This is to emulate the CRTools' method of keeping variables + of different alignment in separate sections. */ + config.sort_common = TRUE; + + /* Don't create a demand-paged executable, since this feature isn't + meaninful in CR16 embedded systems. Moreover, when magic_demand_paged + is true the link sometimes fails. */ + config.magic_demand_paged = FALSE; +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +cr16elf_before_allocation (void) +{ + /* Call the default first. */ + gld${EMULATION_NAME}_before_allocation (); + + /* Enable relaxation by default if the "--no-relax" option was not + specified. This is done here instead of in the before_parse hook + because there is a check in main() to prohibit use of --relax and + -r together. */ + + if (!disable_relaxation) + command_line.relax = TRUE; +} + +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 Do not relax branches\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_NO_RELAX: + disable_relaxation = TRUE; + break; +' + +# Put these extra cr16-elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_PARSE=cr16elf_after_parse +LDEMUL_BEFORE_ALLOCATION=cr16elf_before_allocation + diff --git a/ld/emultempl/elf-generic.em b/ld/emultempl/elf-generic.em new file mode 100644 index 0000000000000..7edee8b68e20a --- /dev/null +++ b/ld/emultempl/elf-generic.em @@ -0,0 +1,81 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006 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., +# 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +# + +# This file is sourced from elf32.em and from ELF targets that use +# generic.em. +# +cat >>e${EMULATION_NAME}.c <<EOF + +static void +gld${EMULATION_NAME}_map_segments (bfd_boolean need_layout) +{ + int tries = 10; + + do + { + if (need_layout) + { + lang_reset_memory_regions (); + + /* Resize the sections. */ + lang_size_sections (NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (); + + need_layout = FALSE; + } + + if (output_bfd->xvec->flavour == bfd_target_elf_flavour + && !link_info.relocatable) + { + bfd_size_type phdr_size; + + phdr_size = elf_tdata (output_bfd)->program_header_size; + /* If we don't have user supplied phdrs, throw away any + previous linker generated program headers. */ + if (lang_phdr_list == NULL) + elf_tdata (output_bfd)->segment_map = NULL; + if (!_bfd_elf_map_sections_to_segments (output_bfd, &link_info)) + einfo ("%F%P: map sections to segments failed: %E\n"); + + if (phdr_size != elf_tdata (output_bfd)->program_header_size) + { + if (tries > 6) + /* The first few times we allow any change to + phdr_size . */ + need_layout = TRUE; + else if (phdr_size < elf_tdata (output_bfd)->program_header_size) + /* After that we only allow the size to grow. */ + need_layout = TRUE; + else + elf_tdata (output_bfd)->program_header_size = phdr_size; + } + } + } + while (need_layout && --tries); + + if (tries == 0) + einfo (_("%P%F: looping in map_segments")); +} +EOF diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 1925979605399..d9f6fbb8e6561 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -13,7 +13,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> ELF support by Ian Lance Taylor <ian@cygnus.com> @@ -35,9 +35,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "config.h" -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "safe-ctype.h" #include "getopt.h" @@ -60,8 +59,7 @@ static void gld${EMULATION_NAME}_before_parse (void); static void gld${EMULATION_NAME}_after_open (void); static void gld${EMULATION_NAME}_before_allocation (void); static bfd_boolean gld${EMULATION_NAME}_place_orphan (asection *s); -static void gld${EMULATION_NAME}_layout_sections_again (void); -static void gld${EMULATION_NAME}_finish (void) ATTRIBUTE_UNUSED; +static void gld${EMULATION_NAME}_finish (void); EOF @@ -79,6 +77,7 @@ fi # Import any needed special functions and/or overrides. # +. ${srcdir}/emultempl/elf-generic.em if test -n "$EXTRA_EM_FILE" ; then . ${srcdir}/emultempl/${EXTRA_EM_FILE}.em fi @@ -365,7 +364,7 @@ case ${target} in struct bfd_link_needed_list *l; for (l = needed; l != NULL; l = l->next) - if (strncmp (l->name, "libc.so", 7) == 0) + if (CONST_STRNEQ (l->name, "libc.so")) break; if (l == NULL) { @@ -459,7 +458,7 @@ gld${EMULATION_NAME}_search_needed (const char *path, { char *filename, *sset; - s = strchr (path, ':'); + s = strchr (path, config.rpath_separator); if (s == NULL) s = path + strlen (path); @@ -492,7 +491,8 @@ EOF if [ "x${USE_LIBPATH}" = xyes ] ; then cat >>e${EMULATION_NAME}.c <<EOF -/* Add the sysroot to every entry in a colon-separated path. */ +/* Add the sysroot to every entry in a path separated by + config.rpath_separator. */ static char * gld${EMULATION_NAME}_add_sysroot (const char *path) @@ -504,7 +504,7 @@ gld${EMULATION_NAME}_add_sysroot (const char *path) colons = 0; i = 0; while (path[i]) - if (path[i++] == ':') + if (path[i++] == config.rpath_separator) colons++; if (path[i]) @@ -516,7 +516,7 @@ gld${EMULATION_NAME}_add_sysroot (const char *path) p = ret + strlen (ret); i = 0; while (path[i]) - if (path[i] == ':') + if (path[i] == config.rpath_separator) { *p++ = path[i++]; strcpy (p, ld_sysroot); @@ -698,7 +698,7 @@ gld${EMULATION_NAME}_parse_ld_so_conf if (p[0] == '\0') continue; - if (!strncmp (p, "include", 7) && (p[7] == ' ' || p[7] == '\t')) + if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t')) { char *dir, c; p += 8; @@ -745,7 +745,7 @@ gld${EMULATION_NAME}_parse_ld_so_conf info->alloc += p - dir + 256; info->path = xrealloc (info->path, info->alloc); } - info->path[info->len++] = ':'; + info->path[info->len++] = config.rpath_separator; } memcpy (info->path + info->len, dir, p - dir); info->len += p - dir; @@ -865,6 +865,42 @@ gld${EMULATION_NAME}_after_open (void) { struct bfd_link_needed_list *needed, *l; + if (link_info.eh_frame_hdr + && ! link_info.traditional_format + && ! link_info.relocatable) + { + struct elf_link_hash_table *htab; + + htab = elf_hash_table (&link_info); + if (is_elf_hash_table (htab)) + { + bfd *abfd; + asection *s; + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) + { + s = bfd_get_section_by_name (abfd, ".eh_frame"); + if (s && s->size > 8 && !bfd_is_abs_section (s->output_section)) + break; + } + if (abfd) + { + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (abfd); + s = bfd_make_section_with_flags (abfd, ".eh_frame_hdr", + bed->dynamic_sec_flags + | SEC_READONLY); + if (s != NULL + && bfd_set_section_alignment (abfd, s, 2)) + htab->eh_info.hdr_sec = s; + else + einfo ("%P: warning: Cannot create .eh_frame_hdr section," + " --eh-frame-hdr ignored.\n"); + } + } + } + /* We only need to worry about this when doing a final link. */ if (link_info.relocatable || !link_info.executable) return; @@ -1180,10 +1216,8 @@ ${ELF_INTERPRETER_SET_DEFAULT} { asection *s; bfd_size_type sz; - bfd_size_type prefix_len; char *msg; bfd_boolean ret; - const char * gnu_warning_prefix = _("warning: "); if (is->just_syms_flag) continue; @@ -1193,14 +1227,12 @@ ${ELF_INTERPRETER_SET_DEFAULT} continue; sz = s->size; - prefix_len = strlen (gnu_warning_prefix); - msg = xmalloc ((size_t) (prefix_len + sz + 1)); - strcpy (msg, gnu_warning_prefix); - if (! bfd_get_section_contents (is->the_bfd, s, msg + prefix_len, + msg = xmalloc ((size_t) (sz + 1)); + if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz)) einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", is->the_bfd); - msg[prefix_len + sz] = '\0'; + msg[sz] = '\0'; ret = link_info.callbacks->warning (&link_info, msg, (const char *) NULL, is->the_bfd, (asection *) NULL, @@ -1208,13 +1240,20 @@ ${ELF_INTERPRETER_SET_DEFAULT} ASSERT (ret); free (msg); - /* Clobber the section size, so that we don't waste copying the - warning into the output file. */ + /* Clobber the section size, so that we don't waste space + copying the warning into the output file. If we've already + sized the output section, adjust its size. The adjustment + is on rawsize because targets that size sections early will + have called lang_reset_memory_regions after sizing. */ + if (s->output_section != NULL + && s->output_section->rawsize >= s->size) + s->output_section->rawsize -= s->size; + s->size = 0; - /* Also set SEC_EXCLUDE, so that symbols defined in the warning - section don't get copied to the output. */ - s->flags |= SEC_EXCLUDE; + /* Also set SEC_EXCLUDE, so that local symbols defined in the + warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE | SEC_KEEP; } } @@ -1326,7 +1365,7 @@ output_rel_find (asection *sec, int isdyn) lookup = lookup->next) { if (lookup->constraint != -1 - && strncmp (".rel", lookup->name, 4) == 0) + && CONST_STRNEQ (lookup->name, ".rel")) { int lookrela = lookup->name[4] == 'a'; @@ -1435,7 +1474,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s) default: break; } - else if (strncmp (secname, ".rel", 4) == 0) + else if (CONST_STRNEQ (secname, ".rel")) { secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; isdyn = 1; @@ -1483,7 +1522,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s) sections into the .text section to get them out of the way. */ if (link_info.executable && ! link_info.relocatable - && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 + && CONST_STRNEQ (secname, ".gnu.warning.") && hold[orphan_text].os != NULL) { lang_add_section (&hold[orphan_text].os->children, s, @@ -1502,7 +1541,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s) ; else if ((s->flags & SEC_LOAD) != 0 && ((iself && sh_type == SHT_NOTE) - || (!iself && strncmp (secname, ".note", 5) == 0))) + || (!iself && CONST_STRNEQ (secname, ".note")))) place = &hold[orphan_interp]; else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) place = &hold[orphan_bss]; @@ -1511,7 +1550,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s) else if ((s->flags & SEC_READONLY) == 0) place = &hold[orphan_data]; else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL)) - || (!iself && strncmp (secname, ".rel", 4) == 0)) + || (!iself && CONST_STRNEQ (secname, ".rel"))) && (s->flags & SEC_LOAD) != 0) place = &hold[orphan_rel]; else if ((s->flags & SEC_CODE) == 0) @@ -1560,26 +1599,11 @@ if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then cat >>e${EMULATION_NAME}.c <<EOF static void -gld${EMULATION_NAME}_layout_sections_again (void) -{ - lang_reset_memory_regions (); - - /* Resize the sections. */ - lang_size_sections (NULL, TRUE); - - /* Redo special stuff. */ - ldemul_after_allocation (); - - /* Do the assignments again. */ - lang_do_assignments (); -} - -static void gld${EMULATION_NAME}_finish (void) { - if (bfd_elf_discard_info (output_bfd, &link_info)) - gld${EMULATION_NAME}_layout_sections_again (); + bfd_boolean need_layout = bfd_elf_discard_info (output_bfd, &link_info); + gld${EMULATION_NAME}_map_segments (need_layout); finish_default (); } EOF @@ -1734,6 +1758,7 @@ cat >>e${EMULATION_NAME}.c <<EOF #define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1) #define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1) #define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1) +#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1) static void gld${EMULATION_NAME}_add_options @@ -1750,6 +1775,7 @@ cat >>e${EMULATION_NAME}.c <<EOF {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR}, {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, + {"hash-style", required_argument, NULL, OPTION_HASH_STYLE}, {"Bgroup", no_argument, NULL, OPTION_GROUP}, EOF fi @@ -1806,6 +1832,22 @@ cat >>e${EMULATION_NAME}.c <<EOF add_excluded_libs (optarg); break; + case OPTION_HASH_STYLE: + link_info.emit_hash = FALSE; + link_info.emit_gnu_hash = FALSE; + if (strcmp (optarg, "sysv") == 0) + link_info.emit_hash = TRUE; + else if (strcmp (optarg, "gnu") == 0) + link_info.emit_gnu_hash = TRUE; + else if (strcmp (optarg, "both") == 0) + { + link_info.emit_hash = TRUE; + link_info.emit_gnu_hash = TRUE; + } + else + einfo (_("%P%F: invalid hash style \`%s'\n"), optarg); + break; + case 'z': if (strcmp (optarg, "initfirst") == 0) link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST; @@ -1826,6 +1868,11 @@ cat >>e${EMULATION_NAME}.c <<EOF link_info.flags |= (bfd_vma) DF_BIND_NOW; link_info.flags_1 |= (bfd_vma) DF_1_NOW; } + else if (strcmp (optarg, "lazy") == 0) + { + link_info.flags &= ~(bfd_vma) DF_BIND_NOW; + link_info.flags_1 &= ~(bfd_vma) DF_1_NOW; + } else if (strcmp (optarg, "origin") == 0) { link_info.flags |= (bfd_vma) DF_ORIGIN; @@ -1851,10 +1898,41 @@ cat >>e${EMULATION_NAME}.c <<EOF link_info.noexecstack = TRUE; link_info.execstack = FALSE; } +EOF + + if test -n "$COMMONPAGESIZE"; then +cat >>e${EMULATION_NAME}.c <<EOF else if (strcmp (optarg, "relro") == 0) link_info.relro = TRUE; else if (strcmp (optarg, "norelro") == 0) link_info.relro = FALSE; +EOF + fi + +cat >>e${EMULATION_NAME}.c <<EOF + else if (CONST_STRNEQ (optarg, "max-page-size=")) + { + char *end; + + config.maxpagesize = strtoul (optarg + 14, &end, 0); + if (*end || (config.maxpagesize & (config.maxpagesize - 1)) != 0) + einfo (_("%P%F: invalid maxium page size \`%s'\n"), + optarg + 14); + ASSERT (default_target != NULL); + bfd_emul_set_maxpagesize (default_target, config.maxpagesize); + } + else if (CONST_STRNEQ (optarg, "common-page-size=")) + { + char *end; + config.commonpagesize = strtoul (optarg + 17, &end, 0); + if (*end + || (config.commonpagesize & (config.commonpagesize - 1)) != 0) + einfo (_("%P%F: invalid common page size \`%s'\n"), + optarg + 17); + ASSERT (default_target != NULL); + bfd_emul_set_commonpagesize (default_target, + config.commonpagesize); + } /* What about the other Solaris -z options? FIXME. */ break; EOF @@ -1888,11 +1966,13 @@ cat >>e${EMULATION_NAME}.c <<EOF fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n")); fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n")); fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n")); + fprintf (file, _(" --hash-style=STYLE\tSet hash style to sysv, gnu or both\n")); fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n")); fprintf (file, _(" -z defs\t\tReport unresolved symbols in object files.\n")); fprintf (file, _(" -z execstack\t\tMark executable as requiring executable stack\n")); fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n")); fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but executable\n")); + fprintf (file, _(" -z lazy\t\tMark object lazy runtime binding (default)\n")); fprintf (file, _(" -z loadfltr\t\tMark object requiring immediate process\n")); fprintf (file, _(" -z muldefs\t\tAllow multiple definitions\n")); fprintf (file, _(" -z nocombreloc\tDon't merge dynamic relocs into one section\n")); @@ -1902,10 +1982,28 @@ cat >>e${EMULATION_NAME}.c <<EOF fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n")); fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n")); fprintf (file, _(" -z noexecstack\tMark executable as not requiring executable stack\n")); +EOF + + if test -n "$COMMONPAGESIZE"; then +cat >>e${EMULATION_NAME}.c <<EOF fprintf (file, _(" -z norelro\t\tDon't create RELRO program header\n")); +EOF + fi + +cat >>e${EMULATION_NAME}.c <<EOF fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n")); fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t at runtime\n")); +EOF + + if test -n "$COMMONPAGESIZE"; then +cat >>e${EMULATION_NAME}.c <<EOF fprintf (file, _(" -z relro\t\tCreate RELRO program header\n")); +EOF + fi + +cat >>e${EMULATION_NAME}.c <<EOF + fprintf (file, _(" -z max-page-size=SIZE\tSet maximum page size to SIZE\n")); + fprintf (file, _(" -z common-page-size=SIZE\n\t\t\tSet common page size to SIZE\n")); fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n")); EOF fi diff --git a/ld/emultempl/genelf.em b/ld/emultempl/genelf.em new file mode 100644 index 0000000000000..dae75a16ebe79 --- /dev/null +++ b/ld/emultempl/genelf.em @@ -0,0 +1,39 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +# + +# This file is sourced from generic.em +# +cat >>e${EMULATION_NAME}.c <<EOF +#include "elf-bfd.h" + +EOF +. ${srcdir}/emultempl/elf-generic.em +cat >>e${EMULATION_NAME}.c <<EOF + +static void +gld${EMULATION_NAME}_finish (void) +{ + gld${EMULATION_NAME}_map_segments (FALSE); + finish_default (); +} +EOF +# Put these extra routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_FINISH=gld${EMULATION_NAME}_finish diff --git a/ld/emultempl/generic.em b/ld/emultempl/generic.em index 985cdf8e24f4a..9ea6d02ed7e0e 100644 --- a/ld/emultempl/generic.em +++ b/ld/emultempl/generic.em @@ -4,8 +4,8 @@ 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, 1992, 1994, 1996, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. + Copyright 1991, 1992, 1994, 1996, 1999, 2000, 2001, 2002, 2003, 2004, + 2007 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com This file is part of GLD, the Gnu Linker. @@ -26,8 +26,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "ld.h" diff --git a/ld/emultempl/gld960.em b/ld/emultempl/gld960.em index 63b5bb341a3f8..11ea43478e75f 100644 --- a/ld/emultempl/gld960.em +++ b/ld/emultempl/gld960.em @@ -1,7 +1,7 @@ # This shell script emits a C file. -*- C -*- # It does some substitutions. cat >e${EMULATION_NAME}.c <<EOF -/* Copyright 1991, 1992, 1994, 1999, 2000, 2001, 2002, 2003, 2005 +/* Copyright 1991, 1992, 1994, 1999, 2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -25,8 +25,8 @@ the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110 */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "bfdlink.h" diff --git a/ld/emultempl/gld960c.em b/ld/emultempl/gld960c.em index 6973a06d40359..68f513a62e74a 100644 --- a/ld/emultempl/gld960c.em +++ b/ld/emultempl/gld960c.em @@ -2,7 +2,7 @@ # It does some substitutions. cat >e${EMULATION_NAME}.c <<EOF /* Copyright 1991, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 Free Software Foundation, Inc. + 2005, 2007 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -26,8 +26,8 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "safe-ctype.h" #include "bfdlink.h" diff --git a/ld/emultempl/hppaelf.em b/ld/emultempl/hppaelf.em index 82f37b69168dc..61e53cbee4634 100644 --- a/ld/emultempl/hppaelf.em +++ b/ld/emultempl/hppaelf.em @@ -220,9 +220,8 @@ hppaelf_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - need_laying_out = 0; - - gld${EMULATION_NAME}_layout_sections_again (); + gld${EMULATION_NAME}_map_segments (TRUE); + need_laying_out = -1; } @@ -248,7 +247,7 @@ build_section_lists (lang_statement_union_type *statement) to build linker stubs. */ static void -hppaelf_finish (void) +gld${EMULATION_NAME}_finish (void) { /* bfd_elf_discard_info just plays with debugging sections, ie. doesn't affect any code, so we can delay resizing the @@ -288,8 +287,8 @@ hppaelf_finish (void) } } - if (need_laying_out) - hppaelf_layout_sections_again (); + if (need_laying_out != -1) + gld${EMULATION_NAME}_map_segments (need_laying_out); if (! link_info.relocatable) { @@ -381,5 +380,5 @@ PARSE_AND_LIST_ARGS_CASES=' # Put these extra hppaelf routines in ld_${EMULATION_NAME}_emulation # LDEMUL_AFTER_PARSE=hppaelf_after_parse -LDEMUL_FINISH=hppaelf_finish +LDEMUL_FINISH=gld${EMULATION_NAME}_finish LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=hppaelf_create_output_section_statements diff --git a/ld/emultempl/irix.em b/ld/emultempl/irix.em index 5dfc2a44c5a4e..0fd9be9974a8a 100644 --- a/ld/emultempl/irix.em +++ b/ld/emultempl/irix.em @@ -39,3 +39,4 @@ irix_after_open (void) EOF LDEMUL_AFTER_OPEN=irix_after_open +. "${srcdir}/emultempl/mipself.em" diff --git a/ld/emultempl/linux.em b/ld/emultempl/linux.em index 996a7ea110049..48ac046884d3c 100644 --- a/ld/emultempl/linux.em +++ b/ld/emultempl/linux.em @@ -10,7 +10,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* Linux a.out emulation code for ${EMULATION_NAME} Copyright 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005 Free Software Foundation, Inc. + 2003, 2004, 2005, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> Linux support by Eric Youngdale <ericy@cais.cais.com> @@ -32,8 +32,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "ld.h" diff --git a/ld/emultempl/lnk960.em b/ld/emultempl/lnk960.em index 95384d42d5a2e..a868b539729fe 100644 --- a/ld/emultempl/lnk960.em +++ b/ld/emultempl/lnk960.em @@ -2,8 +2,8 @@ # It does some substitutions. cat >e${EMULATION_NAME}.c <<EOF /* intel coff loader emulation specific stuff - Copyright 1991, 1992, 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2005 - Free Software Foundation, Inc. + Copyright 1991, 1992, 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, + 2005, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com This file is part of GLD, the Gnu Linker. @@ -22,9 +22,9 @@ You should have received a copy of the GNU General Public License along with GLD; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "sysdep.h" #include "libiberty.h" #include "bfd.h" -#include "sysdep.h" #include "bfdlink.h" /*#include "archures.h"*/ diff --git a/ld/emultempl/m68kcoff.em b/ld/emultempl/m68kcoff.em index 4bf3994b67b30..287dff4cdcf3b 100644 --- a/ld/emultempl/m68kcoff.em +++ b/ld/emultempl/m68kcoff.em @@ -4,7 +4,8 @@ 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, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright 2000, 2002, 2003, 2004, 2005, 2007 + 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>. @@ -27,8 +28,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "ld.h" diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em new file mode 100644 index 0000000000000..846cdc51dbb01 --- /dev/null +++ b/ld/emultempl/mipself.em @@ -0,0 +1,37 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +cat >>e${EMULATION_NAME}.c <<EOF +static void +mips_after_parse (void) +{ + /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different + ways. .gnu.hash needs symbols to be grouped by hash code whereas the + MIPS ABI requires a mapping between the GOT and the symbol table. */ + if (link_info.emit_gnu_hash) + { + einfo ("%X%P: .gnu.hash is incompatible with the MIPS ABI\n"); + link_info.emit_hash = TRUE; + link_info.emit_gnu_hash = FALSE; + } + after_parse_default (); +} +EOF + +LDEMUL_AFTER_PARSE=mips_after_parse diff --git a/ld/emultempl/mmixelf.em b/ld/emultempl/mmixelf.em index 9954343f475a6..be8d907908476 100644 --- a/ld/emultempl/mmixelf.em +++ b/ld/emultempl/mmixelf.em @@ -24,7 +24,6 @@ . ${srcdir}/emultempl/mmix-elfnmmo.em cat >>e${EMULATION_NAME}.c <<EOF -#line 29 "${srcdir}/emultempl/elfmmix.em" static void elfmmix_before_parse (void) diff --git a/ld/emultempl/mmo.em b/ld/emultempl/mmo.em index 0a7d648bf1b84..11475751da28b 100644 --- a/ld/emultempl/mmo.em +++ b/ld/emultempl/mmo.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. +# Copyright 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. # # This file is part of GLD, the Gnu Linker. # @@ -18,16 +18,24 @@ # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. # -# This file is sourced from elf32.em and mmo.em, used to define -# linker MMIX-specifics common to ELF and MMO. +# This file is sourced from generic.em. 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. */ +/* Need to have this macro defined before mmix-elfnmmo, which uses the + name for the before_allocation function, defined in ldemul.c (for + the mmo "emulation") or in elf32.em (for the elf64mmix + "emulation"). */ #define gldmmo_before_allocation before_allocation_default + +/* We include this header *not* because we expect to handle ELF here + but because we re-use the map_segments function in elf-generic.em, + a file which is rightly somewhat ELF-centric. But this is only to + get a weird testcase right; ld-mmix/bpo-22, forcing ELF to be + output from the mmo emulation: -m mmo --oformat elf64-mmix! */ +#include "elf-bfd.h" EOF +. ${srcdir}/emultempl/elf-generic.em . ${srcdir}/emultempl/mmix-elfnmmo.em cat >>e${EMULATION_NAME}.c <<EOF @@ -112,6 +120,7 @@ static void mmo_finish (void) { bfd_map_over_sections (output_bfd, mmo_wipe_sec_reloc_flag, NULL); + gld${EMULATION_NAME}_map_segments (FALSE); finish_default (); } diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 5afa8da00fef8..a540669f7aa3f 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -11,7 +11,7 @@ rm -f e${EMULATION_NAME}.c cat >>e${EMULATION_NAME}.c <<EOF /* This file is part of GLD, the Gnu Linker. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 Free Software Foundation, Inc. + 2005, 2006, 2007 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 @@ -37,17 +37,20 @@ cat >>e${EMULATION_NAME}.c <<EOF #define TARGET_IS_${EMULATION_NAME} /* Do this before including bfd.h, so we prototype the right functions. */ -#ifdef TARGET_IS_arm_epoc_pe -#define bfd_arm_pe_allocate_interworking_sections \ - bfd_arm_epoc_pe_allocate_interworking_sections -#define bfd_arm_pe_get_bfd_for_interworking \ - bfd_arm_epoc_pe_get_bfd_for_interworking -#define bfd_arm_pe_process_before_allocation \ - bfd_arm_epoc_pe_process_before_allocation -#endif -#include "bfd.h" +#if defined(TARGET_IS_armpe) \ + || defined(TARGET_IS_arm_epoc_pe) \ + || defined(TARGET_IS_arm_wince_pe) +#define bfd_arm_allocate_interworking_sections \ + bfd_${EMULATION_NAME}_allocate_interworking_sections +#define bfd_arm_get_bfd_for_interworking \ + bfd_${EMULATION_NAME}_get_bfd_for_interworking +#define bfd_arm_process_before_allocation \ + bfd_${EMULATION_NAME}_process_before_allocation +#endif + #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "getopt.h" #include "libiberty.h" @@ -85,10 +88,12 @@ cat >>e${EMULATION_NAME}.c <<EOF #define PE_DEF_SECTION_ALIGNMENT ${OVERRIDE_SECTION_ALIGNMENT} #endif -#if defined(TARGET_IS_i386pe) -#define DLL_SUPPORT -#endif -#if defined(TARGET_IS_shpe) || defined(TARGET_IS_mipspe) || defined(TARGET_IS_armpe) +#if defined(TARGET_IS_i386pe) \ + || defined(TARGET_IS_shpe) \ + || defined(TARGET_IS_mipspe) \ + || defined(TARGET_IS_armpe) \ + || defined(TARGET_IS_arm_epoc_pe) \ + || defined(TARGET_IS_arm_wince_pe) #define DLL_SUPPORT #endif @@ -99,7 +104,8 @@ cat >>e${EMULATION_NAME}.c <<EOF #undef PE_DEF_SECTION_ALIGNMENT #undef PE_DEF_FILE_ALIGNMENT #define NT_EXE_IMAGE_BASE 0x00010000 -#ifdef TARGET_IS_armpe + +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_wince_pe) #define PE_DEF_SECTION_ALIGNMENT 0x00001000 #define PE_DEF_SUBSYSTEM 9 #else @@ -109,6 +115,7 @@ cat >>e${EMULATION_NAME}.c <<EOF #define PE_DEF_FILE_ALIGNMENT 0x00000200 #endif +#define U(S) ${INITIAL_SYMBOL_CHAR} S static struct internal_extra_pe_aouthdr pe; static int dll; @@ -139,7 +146,7 @@ gld_${EMULATION_NAME}_before_parse (void) link_info.pei386_runtime_pseudo_reloc = -1; #if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2) -#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe +#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe || defined TARGET_IS_arm_wince_pe lang_default_entry ("WinMainCRTStartup"); #else lang_default_entry ("_WinMainCRTStartup"); @@ -282,8 +289,8 @@ static definfo init[] = D(MinorOperatingSystemVersion,"__minor_os_version__", 0), D(MajorImageVersion,"__major_image_version__", 1), D(MinorImageVersion,"__minor_image_version__", 0), -#ifdef TARGET_IS_armpe - D(MajorSubsystemVersion,"__major_subsystem_version__", 2), +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_wince_pe) + D(MajorSubsystemVersion,"__major_subsystem_version__", 3), #else D(MajorSubsystemVersion,"__major_subsystem_version__", 4), #endif @@ -394,7 +401,7 @@ set_pe_subsystem (void) { "windows", 2, "WinMainCRTStartup" }, { "console", 3, "mainCRTStartup" }, { "posix", 7, "__PosixProcessStartup"}, - { "wince", 9, "_WinMainCRTStartup" }, + { "wince", 9, "WinMainCRTStartup" }, { "xbox", 14, "mainCRTStartup" }, { NULL, 0, NULL } }; @@ -919,15 +926,14 @@ pe_find_data_imports (void) for (i = 0; i < nsyms; i++) { - if (memcmp (symbols[i]->name, "__head_", - sizeof ("__head_") - 1)) + if (! CONST_STRNEQ (symbols[i]->name, U ("_head_"))) continue; if (pe_dll_extra_pe_debug) printf ("->%s\n", symbols[i]->name); pe_data_import_dll = (char*) (symbols[i]->name + - sizeof ("__head_") - 1); + sizeof (U ("_head_")) - 1); break; } @@ -983,7 +989,7 @@ gld_${EMULATION_NAME}_after_open (void) including an internal BFD header. */ if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == 0) - einfo (_("%F%P: PE operations on non PE file.\n")); + einfo (_("%F%P: cannot perform PE operations on non PE output file '%B'.\n"), output_bfd); pe_data (output_bfd)->pe_opthdr = pe; pe_data (output_bfd)->dll = init[DLLOFF].value; @@ -997,22 +1003,21 @@ gld_${EMULATION_NAME}_after_open (void) pe_find_data_imports (); -#if ! (defined (TARGET_IS_i386pe) || defined (TARGET_IS_armpe)) - if (link_info.shared) -#else +#if defined (TARGET_IS_i386pe) \ + || defined (TARGET_IS_armpe) \ + || defined (TARGET_IS_arm_epoc_pe) \ + || defined (TARGET_IS_arm_wince_pe) if (!link_info.relocatable) -#endif pe_dll_build_sections (output_bfd, &link_info); - -#ifndef TARGET_IS_i386pe -#ifndef TARGET_IS_armpe else pe_exe_build_sections (output_bfd, &link_info); +#else + if (link_info.shared) + pe_dll_build_sections (output_bfd, &link_info); #endif -#endif -#endif +#endif /* DLL_SUPPORT */ -#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) if (strstr (bfd_get_target (output_bfd), "arm") == NULL) { /* The arm backend needs special fields in the output hash structure. @@ -1026,7 +1031,7 @@ gld_${EMULATION_NAME}_after_open (void) /* Find a BFD that can hold the interworking stubs. */ LANG_FOR_EACH_INPUT_STATEMENT (is) { - if (bfd_arm_pe_get_bfd_for_interworking (is->the_bfd, & link_info)) + if (bfd_arm_get_bfd_for_interworking (is->the_bfd, & link_info)) break; } } @@ -1055,7 +1060,7 @@ gld_${EMULATION_NAME}_after_open (void) { if (strcmp (sec->name, ".idata\$2") == 0) idata2 = 1; - if (strncmp (sec->name, ".idata\$", 7) == 0) + if (CONST_STRNEQ (sec->name, ".idata\$")) is_imp = 1; reloc_count += sec->reloc_count; } @@ -1245,6 +1250,74 @@ gld_${EMULATION_NAME}_after_open (void) } } } + + { + /* The following chunk of code tries to identify jump stubs in + import libraries which are dead code and eliminates them + from the final link. For each exported symbol <sym>, there + is a object file in the import library with a .text section + and several .idata$* sections. The .text section contains the + symbol definition for <sym> which is a jump stub of the form + jmp *__imp_<sym>. The .idata$5 contains the symbol definition + for __imp_<sym> which is the address of the slot for <sym> in + the import address table. When a symbol is imported explicitly + using __declspec(dllimport) declaration, the compiler generates + a reference to __imp_<sym> which directly resolves to the + symbol in .idata$5, in which case the jump stub code is not + needed. The following code tries to identify jump stub sections + in import libraries which are not referred to by anyone and + marks them for exclusion from the final link. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + int is_imp = 0; + asection *sec, *stub_sec = NULL; + + /* See if this is an import library thunk. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strncmp (sec->name, ".idata\$", 7) == 0) + is_imp = 1; + /* The section containing the jmp stub has code + and has a reloc. */ + if ((sec->flags & SEC_CODE) && sec->reloc_count) + stub_sec = sec; + } + + if (is_imp && stub_sec) + { + long symsize; + asymbol **symbols; + long src_count; + struct bfd_link_hash_entry * blhe; + + symsize = bfd_get_symtab_upper_bound (is->the_bfd); + symbols = xmalloc (symsize); + symsize = bfd_canonicalize_symtab (is->the_bfd, symbols); + + for (src_count = 0; src_count < symsize; src_count++) + { + if (symbols[src_count]->section->id == stub_sec->id) + { + /* This symbol belongs to the section containing + the stub. */ + blhe = bfd_link_hash_lookup (link_info.hash, + symbols[src_count]->name, + FALSE, FALSE, TRUE); + /* If the symbol in the stub section has no other + undefined references, exclude the stub section + from the final link. */ + if (blhe && (blhe->type == bfd_link_hash_defined) + && (blhe->u.undef.next == NULL)) + stub_sec->flags |= SEC_EXCLUDE; + } + } + free (symbols); + } + } + } + } } static void @@ -1267,7 +1340,7 @@ gld_${EMULATION_NAME}_before_allocation (void) ppc_allocate_toc_section (&link_info); #endif /* TARGET_IS_ppcpe */ -#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) /* FIXME: we should be able to set the size of the interworking stub section. @@ -1277,7 +1350,7 @@ gld_${EMULATION_NAME}_before_allocation (void) { LANG_FOR_EACH_INPUT_STATEMENT (is) { - if (! bfd_arm_pe_process_before_allocation + if (! bfd_arm_process_before_allocation (is->the_bfd, & link_info, support_old_code)) { /* xgettext:c-format */ @@ -1288,8 +1361,8 @@ gld_${EMULATION_NAME}_before_allocation (void) } /* We have seen it all. Allocate it, and carry on. */ - bfd_arm_pe_allocate_interworking_sections (& link_info); -#endif /* TARGET_IS_armpe */ + bfd_arm_allocate_interworking_sections (& link_info); +#endif /* TARGET_IS_armpe || TARGET_IS_arm_epoc_pe || TARGET_IS_arm_wince_pe */ before_allocation_default (); } @@ -1338,7 +1411,7 @@ gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIB { struct bfd_link_hash_entry *h; - sprintf (buf, "_%s", pe_def_file->exports[i].internal_name); + sprintf (buf, "%s%s", U (""), pe_def_file->exports[i].internal_name); h = bfd_link_hash_lookup (link_info.hash, buf, TRUE, TRUE, TRUE); if (h == (struct bfd_link_hash_entry *) NULL) @@ -1404,19 +1477,14 @@ gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUT #ifdef TARGET_IS_armpe pe_dll_id_target ("pei-arm-little"); #endif - if (bfd_get_format (entry->the_bfd) == bfd_object) - { - char fbuf[LD_PATHMAX + 1]; - const char *ext; - - if (REALPATH (entry->filename, fbuf) == NULL) - strncpy (fbuf, entry->filename, sizeof (fbuf)); - - ext = fbuf + strlen (fbuf) - 4; - - if (strcmp (ext, ".dll") == 0 || strcmp (ext, ".DLL") == 0) - return pe_implied_import_dll (fbuf); - } +#ifdef TARGET_IS_arm_epoc_pe + pe_dll_id_target ("epoc-pei-arm-little"); +#endif +#ifdef TARGET_IS_arm_wince_pe + pe_dll_id_target ("pei-arm-wince-little"); +#endif + if (pe_bfd_is_dll (entry->the_bfd)) + return pe_implied_import_dll (entry->filename); #endif return FALSE; } @@ -1424,7 +1492,7 @@ gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUT static void gld_${EMULATION_NAME}_finish (void) { -#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) struct bfd_link_hash_entry * h; if (thumb_entry_symbol != NULL) @@ -1464,7 +1532,7 @@ gld_${EMULATION_NAME}_finish (void) else einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); } -#endif /* defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) */ +#endif /* defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) */ finish_default (); @@ -1694,87 +1762,100 @@ gld_${EMULATION_NAME}_open_dynamic_archive (const char *arch ATTRIBUTE_UNUSED, search_dirs_type *search, lang_input_statement_type *entry) { + static const struct + { + const char * format; + bfd_boolean use_prefix; + } + libname_fmt [] = + { + /* Preferred explicit import library for dll's. */ + { "lib%s.dll.a", FALSE }, + /* Alternate explicit import library for dll's. */ + { "%s.dll.a", FALSE }, + /* "libfoo.a" could be either an import lib or a static lib. + For backwards compatibility, libfoo.a needs to precede + libfoo.dll and foo.dll in the search. */ + { "lib%s.a", FALSE }, + /* The 'native' spelling of an import lib name is "foo.lib". */ + { "%s.lib", FALSE }, +#ifdef DLL_SUPPORT + /* Try "<prefix>foo.dll" (preferred dll name, if specified). */ + { "%s%s.dll", TRUE }, +#endif + /* Try "libfoo.dll" (default preferred dll name). */ + { "lib%s.dll", FALSE }, + /* Finally try 'native' dll name "foo.dll". */ + { "%s.dll", FALSE }, + /* Note: If adding more formats to this table, make sure to check to + see if their length is longer than libname_fmt[0].format, and if + so, update the call to xmalloc() below. */ + { NULL, FALSE } + }; + static unsigned int format_max_len = 0; const char * filename; - char * string; + char * full_string; + char * base_string; + unsigned int i; + if (! entry->is_archive) return FALSE; filename = entry->filename; - string = (char *) xmalloc (strlen (search->name) - + strlen (filename) - + sizeof "/lib.a.dll" + if (format_max_len == 0) + /* We need to allow space in the memory that we are going to allocate + for the characters in the format string. Since the format array is + static we only need to calculate this information once. In theory + this value could also be computed statically, but this introduces + the possibility for a discrepancy and hence a possible memory + corruption. The lengths we compute here will be too long because + they will include any formating characters (%s) in the strings, but + this will not matter. */ + for (i = 0; libname_fmt[i].format; i++) + if (format_max_len < strlen (libname_fmt[i].format)) + format_max_len = strlen (libname_fmt[i].format); + + full_string = xmalloc (strlen (search->name) + + strlen (filename) + + format_max_len #ifdef DLL_SUPPORT - + (pe_dll_search_prefix ? strlen (pe_dll_search_prefix) : 0) + + (pe_dll_search_prefix + ? strlen (pe_dll_search_prefix) : 0) #endif - + 1); + /* Allow for the terminating NUL and for the path + separator character that is inserted between + search->name and the start of the format string. */ + + 2); - /* Try "libfoo.dll.a" first (preferred explicit import library for dll's. */ - sprintf (string, "%s/lib%s.dll.a", search->name, filename); + sprintf (full_string, "%s/", search->name); + base_string = full_string + strlen (full_string); - if (! ldfile_try_open_bfd (string, entry)) + for (i = 0; libname_fmt[i].format; i++) { - /* Try "foo.dll.a" next (alternate explicit import library for dll's. */ - sprintf (string, "%s/%s.dll.a", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) +#ifdef DLL_SUPPORT + if (libname_fmt[i].use_prefix) { - /* Try libfoo.a next. Normally, this would be interpreted as a static - library, but it *could* be an import library. For backwards compatibility, - libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search, - or sometimes errors occur when building legacy packages. - - Putting libfoo.a here means that in a failure case (i.e. the library - -lfoo is not found) we will search for libfoo.a twice before - giving up -- once here, and once when searching for a "static" lib. - for a "static" lib. */ - /* Try "libfoo.a" (import lib, or static lib, but must - take precedence over dll's). */ - sprintf (string, "%s/lib%s.a", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) - { -#ifdef DLL_SUPPORT - if (pe_dll_search_prefix) - { - /* Try "<prefix>foo.dll" (preferred dll name, if specified). */ - sprintf (string, "%s/%s%s.dll", search->name, pe_dll_search_prefix, filename); - if (! ldfile_try_open_bfd (string, entry)) - { - /* Try "libfoo.dll" (default preferred dll name). */ - sprintf (string, "%s/lib%s.dll", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) - { - /* Finally, try "foo.dll" (alternate dll name). */ - sprintf (string, "%s/%s.dll", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) - { - free (string); - return FALSE; - } - } - } - } - else /* pe_dll_search_prefix not specified. */ -#endif - { - /* Try "libfoo.dll" (preferred dll name). */ - sprintf (string, "%s/lib%s.dll", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) - { - /* Finally, try "foo.dll" (alternate dll name). */ - sprintf (string, "%s/%s.dll", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) - { - free (string); - return FALSE; - } - } - } - } + if (!pe_dll_search_prefix) + continue; + sprintf (base_string, libname_fmt[i].format, pe_dll_search_prefix, filename); } + else +#endif + sprintf (base_string, libname_fmt[i].format, filename); + + if (ldfile_try_open_bfd (full_string, entry)) + break; + } + + if (!libname_fmt[i].format) + { + free (full_string); + return FALSE; } - entry->filename = string; + entry->filename = full_string; return TRUE; } diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em new file mode 100644 index 0000000000000..f44471b6a2879 --- /dev/null +++ b/ld/emultempl/pep.em @@ -0,0 +1,1706 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +test -z "${ENTRY}" && ENTRY="_mainCRTStartup" +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +rm -f e${EMULATION_NAME}.c +(echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) +cat >>e${EMULATION_NAME}.c <<EOF +/* This file is part of GLD, the Gnu Linker. + Copyright 2006, 2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. */ + +/* For WINDOWS_XP64 and higher */ +/* Based on pe.em, but modified for 64 bit support. */ + +#define TARGET_IS_${EMULATION_NAME} + +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "getopt.h" +#include "libiberty.h" +#include "ld.h" +#include "ldmain.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include <ldgram.h> +#include "ldlex.h" +#include "ldmisc.h" +#include "ldctor.h" +#include "coff/internal.h" + +/* FIXME: See bfd/peXXigen.c for why we include an architecture specific + header in generic PE code. */ +#include "coff/x86_64.h" +#include "coff/pe.h" + +/* FIXME: This is a BFD internal header file, and we should not be + using it here. */ +#include "../bfd/libcoff.h" + +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +#include "deffile.h" +#include "pep-dll.h" +#include "safe-ctype.h" + +/* Permit the emulation parameters to override the default section + alignment by setting OVERRIDE_SECTION_ALIGNMENT. FIXME: This makes + it seem that include/coff/internal.h should not define + PE_DEF_SECTION_ALIGNMENT. */ +#if PE_DEF_SECTION_ALIGNMENT != ${OVERRIDE_SECTION_ALIGNMENT:-PE_DEF_SECTION_ALIGNMENT} +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SECTION_ALIGNMENT ${OVERRIDE_SECTION_ALIGNMENT} +#endif + +#ifdef TARGET_IS_i386pep +#define DLL_SUPPORT +#endif + +#if defined(TARGET_IS_i386pep) || ! defined(DLL_SUPPORT) +#define PE_DEF_SUBSYSTEM 3 +#else +#undef NT_EXE_IMAGE_BASE +#define NT_EXE_IMAGE_BASE 0x00010000 +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SUBSYSTEM 2 +#undef PE_DEF_FILE_ALIGNMENT +#define PE_DEF_FILE_ALIGNMENT 0x00000200 +#define PE_DEF_SECTION_ALIGNMENT 0x00000400 +#endif + + +static struct internal_extra_pe_aouthdr pep; +static int dll; +static flagword real_flags = IMAGE_FILE_LARGE_ADDRESS_AWARE; +static int support_old_code = 0; +static lang_assignment_statement_type *image_base_statement = 0; + +#ifdef DLL_SUPPORT +static int pep_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */ +static char * pep_out_def_filename = NULL; +static char * pep_implib_filename = NULL; +static int pep_enable_auto_image_base = 0; +static char * pep_dll_search_prefix = NULL; +#endif + +extern const char *output_filename; + +static void +gld_${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + output_filename = "${EXECUTABLE_NAME:-a.exe}"; +#ifdef DLL_SUPPORT + config.dynamic_link = TRUE; + config.has_shared = 1; + link_info.pei386_auto_import = -1; + link_info.pei386_runtime_pseudo_reloc = -1; + +#if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2) + lang_default_entry ("_WinMainCRTStartup"); +#else + lang_default_entry ("${ENTRY}"); +#endif +#endif +} + +/* PE format extra command line options. */ + +/* Used for setting flags in the PE header. */ +enum options +{ + OPTION_BASE_FILE = 300 + 1, + OPTION_DLL, + OPTION_FILE_ALIGNMENT, + OPTION_IMAGE_BASE, + OPTION_MAJOR_IMAGE_VERSION, + OPTION_MAJOR_OS_VERSION, + OPTION_MAJOR_SUBSYSTEM_VERSION, + OPTION_MINOR_IMAGE_VERSION, + OPTION_MINOR_OS_VERSION, + OPTION_MINOR_SUBSYSTEM_VERSION, + OPTION_SECTION_ALIGNMENT, + OPTION_STACK, + OPTION_SUBSYSTEM, + OPTION_HEAP, + OPTION_SUPPORT_OLD_CODE, + OPTION_OUT_DEF, + OPTION_EXPORT_ALL, + OPTION_EXCLUDE_SYMBOLS, + OPTION_KILL_ATS, + OPTION_STDCALL_ALIASES, + OPTION_ENABLE_STDCALL_FIXUP, + OPTION_DISABLE_STDCALL_FIXUP, + OPTION_IMPLIB_FILENAME, + OPTION_WARN_DUPLICATE_EXPORTS, + OPTION_IMP_COMPAT, + OPTION_ENABLE_AUTO_IMAGE_BASE, + OPTION_DISABLE_AUTO_IMAGE_BASE, + OPTION_DLL_SEARCH_PREFIX, + OPTION_NO_DEFAULT_EXCLUDES, + OPTION_DLL_ENABLE_AUTO_IMPORT, + OPTION_DLL_DISABLE_AUTO_IMPORT, + OPTION_ENABLE_EXTRA_PE_DEBUG, + OPTION_EXCLUDE_LIBS, + OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC, + OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC +}; + +static void +gld${EMULATION_NAME}_add_options + (int ns ATTRIBUTE_UNUSED, + char **shortopts ATTRIBUTE_UNUSED, + int nl, + struct option **longopts, + int nrl ATTRIBUTE_UNUSED, + struct option **really_longopts ATTRIBUTE_UNUSED) +{ + static const struct option xtra_long[] = + { + /* PE options */ + {"base-file", required_argument, NULL, OPTION_BASE_FILE}, + {"dll", no_argument, NULL, OPTION_DLL}, + {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT}, + {"heap", required_argument, NULL, OPTION_HEAP}, + {"image-base", required_argument, NULL, OPTION_IMAGE_BASE}, + {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION}, + {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION}, + {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION}, + {"minor-image-version", required_argument, NULL, OPTION_MINOR_IMAGE_VERSION}, + {"minor-os-version", required_argument, NULL, OPTION_MINOR_OS_VERSION}, + {"minor-subsystem-version", required_argument, NULL, OPTION_MINOR_SUBSYSTEM_VERSION}, + {"section-alignment", required_argument, NULL, OPTION_SECTION_ALIGNMENT}, + {"stack", required_argument, NULL, OPTION_STACK}, + {"subsystem", required_argument, NULL, OPTION_SUBSYSTEM}, + {"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, +#ifdef DLL_SUPPORT + /* getopt allows abbreviations, so we do this to stop it + from treating -o as an abbreviation for this option. */ + {"output-def", required_argument, NULL, OPTION_OUT_DEF}, + {"output-def", required_argument, NULL, OPTION_OUT_DEF}, + {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL}, + {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMBOLS}, + {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, + {"kill-at", no_argument, NULL, OPTION_KILL_ATS}, + {"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES}, + {"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP}, + {"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP}, + {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME}, + {"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS}, + /* getopt() allows abbreviations, so we do this to stop it from + treating -c as an abbreviation for these --compat-implib. */ + {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, + {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, + {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, + {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE}, + {"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX}, + {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES}, + {"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT}, + {"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT}, + {"enable-extra-pep-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG}, + {"enable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC}, + {"disable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC}, +#endif + {NULL, no_argument, NULL, 0} + }; + + *longopts = xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +/* PE/WIN32; added routines to get the subsystem type, heap and/or stack + parameters which may be input from the command line. */ + +typedef struct +{ + void *ptr; + int size; + int value; + char *symbol; + int inited; +} definfo; + +#define D(field,symbol,def) {&pep.field,sizeof(pep.field), def, symbol,0} + +static definfo init[] = +{ + /* imagebase must be first */ +#define IMAGEBASEOFF 0 + D(ImageBase,"__image_base__", NT_EXE_IMAGE_BASE), +#define DLLOFF 1 + {&dll, sizeof(dll), 0, "__dll__", 0}, +#define MSIMAGEBASEOFF 2 + D(ImageBase,"__ImageBase", NT_EXE_IMAGE_BASE), + D(SectionAlignment,"__section_alignment__", PE_DEF_SECTION_ALIGNMENT), + D(FileAlignment,"__file_alignment__", PE_DEF_FILE_ALIGNMENT), + D(MajorOperatingSystemVersion,"__major_os_version__", 4), + D(MinorOperatingSystemVersion,"__minor_os_version__", 0), + D(MajorImageVersion,"__major_image_version__", 0), + D(MinorImageVersion,"__minor_image_version__", 0), + D(MajorSubsystemVersion,"__major_subsystem_version__", 5), + D(MinorSubsystemVersion,"__minor_subsystem_version__", 2), + D(Subsystem,"__subsystem__", ${SUBSYSTEM}), + D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x200000), + D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000), + D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000), + D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000), + D(LoaderFlags,"__loader_flags__", 0x0), + { NULL, 0, 0, NULL, 0 } +}; + + +static void +gld_${EMULATION_NAME}_list_options (FILE *file) +{ + fprintf (file, _(" --base_file <basefile> Generate a base file for relocatable DLLs\n")); + fprintf (file, _(" --dll Set image base to the default for DLLs\n")); + fprintf (file, _(" --file-alignment <size> Set file alignment\n")); + fprintf (file, _(" --heap <size> Set initial size of the heap\n")); + fprintf (file, _(" --image-base <address> Set start address of the executable\n")); + fprintf (file, _(" --major-image-version <number> Set version number of the executable\n")); + fprintf (file, _(" --major-os-version <number> Set minimum required OS version\n")); + fprintf (file, _(" --major-subsystem-version <number> Set minimum required OS subsystem version\n")); + fprintf (file, _(" --minor-image-version <number> Set revision number of the executable\n")); + fprintf (file, _(" --minor-os-version <number> Set minimum required OS revision\n")); + fprintf (file, _(" --minor-subsystem-version <number> Set minimum required OS subsystem revision\n")); + fprintf (file, _(" --section-alignment <size> Set section alignment\n")); + fprintf (file, _(" --stack <size> Set size of the initial stack\n")); + fprintf (file, _(" --subsystem <name>[:<version>] Set required OS subsystem [& version]\n")); + fprintf (file, _(" --support-old-code Support interworking with old code\n")); +#ifdef DLL_SUPPORT + fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n")); + fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n")); + fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n")); + fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n")); + fprintf (file, _(" --exclude-libs lib,lib,... Exclude libraries from automatic export\n")); + fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n")); + fprintf (file, _(" --kill-at Remove @nn from exported symbols\n")); + fprintf (file, _(" --out-implib <file> Generate import library\n")); + fprintf (file, _(" --output-def <file> Generate a .DEF file for the built DLL\n")); + fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports.\n")); + fprintf (file, _(" --compat-implib Create backward compatible import libs;\n\ + create __imp_<SYMBOL> as well.\n")); + fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n\ + unless user specifies one\n")); + fprintf (file, _(" --disable-auto-image-base Do not auto-choose image base. (default)\n")); + fprintf (file, _(" --dll-search-prefix=<string> When linking dynamically to a dll without\n\ + an importlib, use <string><basename>.dll\n\ + in preference to lib<basename>.dll \n")); + fprintf (file, _(" --enable-auto-import Do sophistcated linking of _sym to\n\ + __imp_sym for DATA references\n")); + fprintf (file, _(" --disable-auto-import Do not auto-import DATA items from DLLs\n")); + fprintf (file, _(" --enable-runtime-pseudo-reloc Work around auto-import limitations by\n\ + adding pseudo-relocations resolved at\n\ + runtime.\n")); + fprintf (file, _(" --disable-runtime-pseudo-reloc Do not add runtime pseudo-relocations for\n\ + auto-imported DATA.\n")); + fprintf (file, _(" --enable-extra-pep-debug Enable verbose debug output when building\n\ + or linking to DLLs (esp. auto-import)\n")); +#endif +} + + +static void +set_pep_name (char *name, long val) +{ + int i; + + /* Find the name and set it. */ + for (i = 0; init[i].ptr; i++) + { + if (strcmp (name, init[i].symbol) == 0) + { + init[i].value = val; + init[i].inited = 1; + if (strcmp (name,"__image_base__") == 0) + set_pep_name ("__ImageBase", val); + return; + } + } + abort (); +} + + +static void +set_pep_subsystem (void) +{ + const char *sver; + const char *entry; + const char *initial_symbol_char; + char *end; + int len; + int i; + int subsystem; + unsigned long temp_subsystem; + static const struct + { + const char *name; + const int value; + const char *entry; + } + v[] = + { + { "native", 1, "NtProcessStartup" }, + { "windows", 2, "WinMainCRTStartup" }, + { "console", 3, "mainCRTStartup" }, + { "posix", 7, "__PosixProcessStartup"}, + { "wince", 9, "_WinMainCRTStartup" }, + { "xbox", 14, "mainCRTStartup" }, + { NULL, 0, NULL } + }; + /* Entry point name for arbitrary subsystem numbers. */ + static const char default_entry[] = "mainCRTStartup"; + + /* Check for the presence of a version number. */ + sver = strchr (optarg, ':'); + if (sver == NULL) + len = strlen (optarg); + else + { + len = sver - optarg; + set_pep_name ("__major_subsystem_version__", + strtoul (sver + 1, &end, 0)); + if (*end == '.') + set_pep_name ("__minor_subsystem_version__", + strtoul (end + 1, &end, 0)); + if (*end != '\0') + einfo (_("%P: warning: bad version number in -subsystem option\n")); + } + + /* Check for numeric subsystem. */ + temp_subsystem = strtoul (optarg, & end, 0); + if ((*end == ':' || *end == '\0') && (temp_subsystem < 65536)) + { + /* Search list for a numeric match to use its entry point. */ + for (i = 0; v[i].name; i++) + if (v[i].value == (int) temp_subsystem) + break; + + /* If no match, use the default. */ + if (v[i].name != NULL) + entry = v[i].entry; + else + entry = default_entry; + + /* Use this subsystem. */ + subsystem = (int) temp_subsystem; + } + else + { + /* Search for subsystem by name. */ + for (i = 0; v[i].name; i++) + if (strncmp (optarg, v[i].name, len) == 0 + && v[i].name[len] == '\0') + break; + + if (v[i].name == NULL) + { + einfo (_("%P%F: invalid subsystem type %s\n"), optarg); + return; + } + + entry = v[i].entry; + subsystem = v[i].value; + } + + set_pep_name ("__subsystem__", subsystem); + + initial_symbol_char = ${INITIAL_SYMBOL_CHAR}; + if (*initial_symbol_char != '\0') + { + char *alc_entry; + + /* lang_default_entry expects its argument to be permanently + allocated, so we don't free this string. */ + alc_entry = xmalloc (strlen (initial_symbol_char) + + strlen (entry) + + 1); + strcpy (alc_entry, initial_symbol_char); + strcat (alc_entry, entry); + entry = alc_entry; + } + + lang_default_entry (entry); + + return; +} + + +static void +set_pep_value (char *name) +{ + char *end; + + set_pep_name (name, strtoul (optarg, &end, 0)); + + if (end == optarg) + einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); + + optarg = end; +} + + +static void +set_pep_stack_heap (char *resname, char *comname) +{ + set_pep_value (resname); + + if (*optarg == ',') + { + optarg++; + set_pep_value (comname); + } + else if (*optarg) + einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); +} + + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + switch (optc) + { + default: + return FALSE; + + case OPTION_BASE_FILE: + link_info.base_file = fopen (optarg, FOPEN_WB); + if (link_info.base_file == NULL) + { + /* xgettext:c-format */ + fprintf (stderr, _("%s: Can't open base file %s\n"), + program_name, optarg); + xexit (1); + } + break; + + /* PE options. */ + case OPTION_HEAP: + set_pep_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); + break; + case OPTION_STACK: + set_pep_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); + break; + case OPTION_SUBSYSTEM: + set_pep_subsystem (); + break; + case OPTION_MAJOR_OS_VERSION: + set_pep_value ("__major_os_version__"); + break; + case OPTION_MINOR_OS_VERSION: + set_pep_value ("__minor_os_version__"); + break; + case OPTION_MAJOR_SUBSYSTEM_VERSION: + set_pep_value ("__major_subsystem_version__"); + break; + case OPTION_MINOR_SUBSYSTEM_VERSION: + set_pep_value ("__minor_subsystem_version__"); + break; + case OPTION_MAJOR_IMAGE_VERSION: + set_pep_value ("__major_image_version__"); + break; + case OPTION_MINOR_IMAGE_VERSION: + set_pep_value ("__minor_image_version__"); + break; + case OPTION_FILE_ALIGNMENT: + set_pep_value ("__file_alignment__"); + break; + case OPTION_SECTION_ALIGNMENT: + set_pep_value ("__section_alignment__"); + break; + case OPTION_DLL: + set_pep_name ("__dll__", 1); + break; + case OPTION_IMAGE_BASE: + set_pep_value ("__image_base__"); + break; + case OPTION_SUPPORT_OLD_CODE: + support_old_code = 1; + break; +#ifdef DLL_SUPPORT + case OPTION_OUT_DEF: + pep_out_def_filename = xstrdup (optarg); + break; + case OPTION_EXPORT_ALL: + pep_dll_export_everything = 1; + break; + case OPTION_EXCLUDE_SYMBOLS: + pep_dll_add_excludes (optarg, 0); + break; + case OPTION_EXCLUDE_LIBS: + pep_dll_add_excludes (optarg, 1); + break; + case OPTION_KILL_ATS: + pep_dll_kill_ats = 1; + break; + case OPTION_STDCALL_ALIASES: + pep_dll_stdcall_aliases = 1; + break; + case OPTION_ENABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 1; + break; + case OPTION_DISABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 0; + break; + case OPTION_IMPLIB_FILENAME: + pep_implib_filename = xstrdup (optarg); + break; + case OPTION_WARN_DUPLICATE_EXPORTS: + pep_dll_warn_dup_exports = 1; + break; + case OPTION_IMP_COMPAT: + pep_dll_compat_implib = 1; + break; + case OPTION_ENABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 1; + break; + case OPTION_DISABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 0; + break; + case OPTION_DLL_SEARCH_PREFIX: + pep_dll_search_prefix = xstrdup (optarg); + break; + case OPTION_NO_DEFAULT_EXCLUDES: + pep_dll_do_default_excludes = 0; + break; + case OPTION_DLL_ENABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 1; + break; + case OPTION_DLL_DISABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 0; + break; + case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = 1; + break; + case OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = 0; + break; + case OPTION_ENABLE_EXTRA_PE_DEBUG: + pep_dll_extra_pe_debug = 1; + break; +#endif + } + return TRUE; +} + + +#ifdef DLL_SUPPORT +static unsigned long +strhash (const char *str) +{ + const unsigned char *s; + unsigned long hash; + unsigned int c; + unsigned int len; + + hash = 0; + len = 0; + s = (const unsigned char *) str; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + return hash; +} + +/* Use the output file to create a image base for relocatable DLLs. */ + +static unsigned long +compute_dll_image_base (const char *ofile) +{ + unsigned long hash = strhash (ofile); + return 0x61300000 + ((hash << 16) & 0x0FFC0000); +} +#endif + +/* Assign values to the special symbols before the linker script is + read. */ + +static void +gld_${EMULATION_NAME}_set_symbols (void) +{ + /* Run through and invent symbols for all the + names and insert the defaults. */ + int j; + lang_statement_list_type *save; + + if (!init[IMAGEBASEOFF].inited) + { + if (link_info.relocatable) + init[IMAGEBASEOFF].value = 0; + else if (init[DLLOFF].value || (link_info.shared && !link_info.pie)) +#ifdef DLL_SUPPORT + init[IMAGEBASEOFF].value = (pep_enable_auto_image_base) ? + compute_dll_image_base (output_filename) : NT_DLL_IMAGE_BASE; +#else + init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE; +#endif + else + init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE; + init[MSIMAGEBASEOFF].value = init[IMAGEBASEOFF].value; + } + + /* Don't do any symbol assignments if this is a relocatable link. */ + if (link_info.relocatable) + return; + + /* Glue the assignments into the abs section. */ + save = stat_ptr; + + stat_ptr = &(abs_output_section->children); + + for (j = 0; init[j].ptr; j++) + { + long val = init[j].value; + lang_assignment_statement_type *rv; + rv = lang_add_assignment (exp_assop ('=', init[j].symbol, + exp_intop (val))); + if (init[j].size == sizeof (short)) + *(short *) init[j].ptr = val; + else if (init[j].size == sizeof (int)) + *(int *) init[j].ptr = val; + else if (init[j].size == sizeof (long)) + *(long *) init[j].ptr = val; + /* This might be a long long or other special type. */ + else if (init[j].size == sizeof (bfd_vma)) + *(bfd_vma *) init[j].ptr = val; + else abort (); + if (j == IMAGEBASEOFF) + image_base_statement = rv; + } + /* Restore the pointer. */ + stat_ptr = save; + + if (pep.FileAlignment > pep.SectionAlignment) + { + einfo (_("%P: warning, file alignment > section alignment.\n")); + } +} + +/* This is called after the linker script and the command line options + have been read. */ + +static void +gld_${EMULATION_NAME}_after_parse (void) +{ + /* The Windows libraries are designed for the linker to treat the + entry point as an undefined symbol. Otherwise, the .obj that + defines mainCRTStartup is brought in because it is the first + encountered in libc.lib and it has other symbols in it which will + be pulled in by the link process. To avoid this, we act as + though the user specified -u with the entry point symbol. + + This function is called after the linker script and command line + options have been read, so at this point we know the right entry + point. This function is called before the input files are + opened, so registering the symbol as undefined will make a + difference. */ + + if (! link_info.relocatable && entry_symbol.name != NULL) + ldlang_add_undef (entry_symbol.name); +} + +/* pep-dll.c directly accesses pep_data_import_dll, + so it must be defined outside of #ifdef DLL_SUPPORT. + Note - this variable is deliberately not initialised. + This allows it to be treated as a common varaible, and only + exist in one incarnation in a multiple target enabled linker. */ +char * pep_data_import_dll; + +#ifdef DLL_SUPPORT +static struct bfd_link_hash_entry *pep_undef_found_sym; + +static bfd_boolean +pep_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf) +{ + int sl; + char *string = inf; + + sl = strlen (string); + if (h->type == bfd_link_hash_defined + && strncmp (h->root.string, string, sl) == 0 + && h->root.string[sl] == '@') + { + pep_undef_found_sym = h; + return FALSE; + } + return TRUE; +} + +static void +pep_fixup_stdcalls (void) +{ + static int gave_warning_message = 0; + struct bfd_link_hash_entry *undef, *sym; + + if (pep_dll_extra_pe_debug) + printf ("%s\n", __FUNCTION__); + + for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) + if (undef->type == bfd_link_hash_undefined) + { + char* at = strchr (undef->root.string, '@'); + int lead_at = (*undef->root.string == '@'); + /* For now, don't try to fixup fastcall symbols. */ + + if (at && !lead_at) + { + /* The symbol is a stdcall symbol, so let's look for a + cdecl symbol with the same name and resolve to that. */ + char *cname = xstrdup (undef->root.string /* + lead_at */); + at = strchr (cname, '@'); + *at = 0; + sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + + if (pep_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, cname); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } + else + { + /* The symbol is a cdecl symbol, so we look for stdcall + symbols - which means scanning the whole symbol table. */ + pep_undef_found_sym = 0; + bfd_link_hash_traverse (link_info.hash, pep_undef_cdecl_match, + (char *) undef->root.string); + sym = pep_undef_found_sym; + if (sym) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + + if (pep_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, sym->root.string); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } + } +} + +static int +make_import_fixup (arelent *rel, asection *s) +{ + struct bfd_symbol *sym = *rel->sym_ptr_ptr; + char addend[4]; + + if (pep_dll_extra_pe_debug) + printf ("arelent: %s@%#lx: add=%li\n", sym->name, + (long) rel->address, (long) rel->addend); + + if (! bfd_get_section_contents (s->owner, s, addend, rel->address, sizeof (addend))) + einfo (_("%C: Cannot get section contents - auto-import exception\n"), + s->owner, s, rel->address); + + pep_create_import_fixup (rel, s, bfd_get_32 (s->owner, addend)); + + return 1; +} + +static void +pep_find_data_imports (void) +{ + struct bfd_link_hash_entry *undef, *sym; + + if (link_info.pei386_auto_import == 0) + return; + + for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) + { + if (undef->type == bfd_link_hash_undefined) + { + /* C++ symbols are *long*. */ + char buf[4096]; + + if (pep_dll_extra_pe_debug) + printf ("%s:%s\n", __FUNCTION__, undef->root.string); + + sprintf (buf, "__imp_%s", undef->root.string); + + sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + bfd *b = sym->u.def.section->owner; + asymbol **symbols; + int nsyms, symsize, i; + + if (link_info.pei386_auto_import == -1) + info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), + undef->root.string, buf); + + symsize = bfd_get_symtab_upper_bound (b); + symbols = xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (i = 0; i < nsyms; i++) + { + if (! CONST_STRNEQ (symbols[i]->name, "__head_")) + continue; + + if (pep_dll_extra_pe_debug) + printf ("->%s\n", symbols[i]->name); + + pep_data_import_dll = (char*) (symbols[i]->name + + sizeof ("__head_") - 1); + break; + } + + pep_walk_relocs_of_symbol (&link_info, undef->root.string, + make_import_fixup); + + /* Let's differentiate it somehow from defined. */ + undef->type = bfd_link_hash_defweak; + /* We replace original name with __imp_ prefixed, this + 1) may trash memory 2) leads to duplicate symbol generation. + Still, IMHO it's better than having name poluted. */ + undef->root.string = sym->root.string; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + } + } + } +} + +static bfd_boolean +pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) +{ + if (pep_dll_extra_pe_debug) + printf ("+%s\n", h->string); + + return TRUE; +} +#endif /* DLL_SUPPORT */ + + +static void +gld_${EMULATION_NAME}_after_open (void) +{ +#ifdef DLL_SUPPORT + if (pep_dll_extra_pe_debug) + { + bfd *a; + struct bfd_link_hash_entry *sym; + + printf ("%s()\n", __FUNCTION__); + + for (sym = link_info.hash->undefs; sym; sym=sym->u.undef.next) + printf ("-%s\n", sym->root.string); + bfd_hash_traverse (&link_info.hash->table, pr_sym, NULL); + + for (a = link_info.input_bfds; a; a = a->link_next) + printf ("*%s\n",a->filename); + } +#endif + + /* Pass the wacky PE command line options into the output bfd. + FIXME: This should be done via a function, rather than by + including an internal BFD header. */ + + if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == 0) + einfo (_("%F%P: cannot perform PE operations on non PE output file '%B'.\n"), output_bfd); + + pe_data (output_bfd)->pe_opthdr = pep; + pe_data (output_bfd)->dll = init[DLLOFF].value; + pe_data (output_bfd)->real_flags |= real_flags; + +#ifdef DLL_SUPPORT + if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */ + pep_fixup_stdcalls (); + + pep_process_import_defs (output_bfd, & link_info); + + pep_find_data_imports (); + +#ifndef TARGET_IS_i386pep + if (link_info.shared) +#else + if (!link_info.relocatable) +#endif + pep_dll_build_sections (output_bfd, &link_info); + +#ifndef TARGET_IS_i386pep + else + pep_exe_build_sections (output_bfd, &link_info); +#endif +#endif /* DLL_SUPPORT */ + + { + /* This next chunk of code tries to detect the case where you have + two import libraries for the same DLL (specifically, + symbolically linking libm.a and libc.a in cygwin to + libcygwin.a). In those cases, it's possible for function + thunks from the second implib to be used but without the + head/tail objects, causing an improper import table. We detect + those cases and rename the "other" import libraries to match + the one the head/tail come from, so that the linker will sort + things nicely and produce a valid import table. */ + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + int idata2 = 0, reloc_count=0, is_imp = 0; + asection *sec; + + /* See if this is an import library thunk. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strcmp (sec->name, ".idata\$2") == 0) + idata2 = 1; + if (CONST_STRNEQ (sec->name, ".idata\$")) + is_imp = 1; + reloc_count += sec->reloc_count; + } + + if (is_imp && !idata2 && reloc_count) + { + /* It is, look for the reference to head and see if it's + from our own library. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + int i; + long symsize; + long relsize; + asymbol **symbols; + arelent **relocs; + int nrelocs; + + symsize = bfd_get_symtab_upper_bound (is->the_bfd); + if (symsize < 1) + break; + relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec); + if (relsize < 1) + break; + + symbols = xmalloc (symsize); + symsize = bfd_canonicalize_symtab (is->the_bfd, symbols); + if (symsize < 0) + { + einfo ("%X%P: unable to process symbols: %E"); + return; + } + + relocs = xmalloc ((size_t) relsize); + nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec, + relocs, symbols); + if (nrelocs < 0) + { + free (relocs); + einfo ("%X%P: unable to process relocs: %E"); + return; + } + + for (i = 0; i < nrelocs; i++) + { + struct bfd_symbol *s; + struct bfd_link_hash_entry * blhe; + char *other_bfd_filename; + char *n; + + s = (relocs[i]->sym_ptr_ptr)[0]; + + if (s->flags & BSF_LOCAL) + continue; + + /* Thunk section with reloc to another bfd. */ + blhe = bfd_link_hash_lookup (link_info.hash, + s->name, + FALSE, FALSE, TRUE); + + if (blhe == NULL + || blhe->type != bfd_link_hash_defined) + continue; + + other_bfd_filename + = blhe->u.def.section->owner->my_archive + ? bfd_get_filename (blhe->u.def.section->owner->my_archive) + : bfd_get_filename (blhe->u.def.section->owner); + + if (strcmp (bfd_get_filename (is->the_bfd->my_archive), + other_bfd_filename) == 0) + continue; + + /* Rename this implib to match the other one. */ + n = xmalloc (strlen (other_bfd_filename) + 1); + strcpy (n, other_bfd_filename); + is->the_bfd->my_archive->filename = n; + } + + free (relocs); + /* Note - we do not free the symbols, + they are now cached in the BFD. */ + } + } + } + } + } + + { + int is_ms_arch = 0; + bfd *cur_arch = 0; + lang_input_statement_type *is2; + lang_input_statement_type *is3; + + /* Careful - this is a shell script. Watch those dollar signs! */ + /* Microsoft import libraries have every member named the same, + and not in the right order for us to link them correctly. We + must detect these and rename the members so that they'll link + correctly. There are three types of objects: the head, the + thunks, and the sentinel(s). The head is easy; it's the one + with idata2. We assume that the sentinels won't have relocs, + and the thunks will. It's easier than checking the symbol + table for external references. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + char *pnt; + bfd *arch = is->the_bfd->my_archive; + + if (cur_arch != arch) + { + cur_arch = arch; + is_ms_arch = 1; + + for (is3 = is; + is3 && is3->the_bfd->my_archive == arch; + is3 = (lang_input_statement_type *) is3->next) + { + /* A MS dynamic import library can also contain static + members, so look for the first element with a .dll + extension, and use that for the remainder of the + comparisons. */ + pnt = strrchr (is3->the_bfd->filename, '.'); + if (pnt != NULL && strcmp (pnt, ".dll") == 0) + break; + } + + if (is3 == NULL) + is_ms_arch = 0; + else + { + /* OK, found one. Now look to see if the remaining + (dynamic import) members use the same name. */ + for (is2 = is; + is2 && is2->the_bfd->my_archive == arch; + is2 = (lang_input_statement_type *) is2->next) + { + /* Skip static members, ie anything with a .obj + extension. */ + pnt = strrchr (is2->the_bfd->filename, '.'); + if (pnt != NULL && strcmp (pnt, ".obj") == 0) + continue; + + if (strcmp (is3->the_bfd->filename, + is2->the_bfd->filename)) + { + is_ms_arch = 0; + break; + } + } + } + } + + /* This fragment might have come from an .obj file in a Microsoft + import, and not an actual import record. If this is the case, + then leave the filename alone. */ + pnt = strrchr (is->the_bfd->filename, '.'); + + if (is_ms_arch && (strcmp (pnt, ".dll") == 0)) + { + int idata2 = 0, reloc_count=0; + asection *sec; + char *new_name, seq; + + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strcmp (sec->name, ".idata\$2") == 0) + idata2 = 1; + reloc_count += sec->reloc_count; + } + + if (idata2) /* .idata2 is the TOC */ + seq = 'a'; + else if (reloc_count > 0) /* thunks */ + seq = 'b'; + else /* sentinel */ + seq = 'c'; + + new_name = xmalloc (strlen (is->the_bfd->filename) + 3); + sprintf (new_name, "%s.%c", is->the_bfd->filename, seq); + is->the_bfd->filename = new_name; + + new_name = xmalloc (strlen (is->filename) + 3); + sprintf (new_name, "%s.%c", is->filename, seq); + is->filename = new_name; + } + } + } + } +} + +static void +gld_${EMULATION_NAME}_before_allocation (void) +{ + before_allocation_default (); +} + +#ifdef DLL_SUPPORT +/* This is called when an input file isn't recognized as a BFD. We + check here for .DEF files and pull them in automatically. */ + +static int +saw_option (char *option) +{ + int i; + + for (i = 0; init[i].ptr; i++) + if (strcmp (init[i].symbol, option) == 0) + return init[i].inited; + return 0; +} +#endif /* DLL_SUPPORT */ + +static bfd_boolean +gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT + const char *ext = entry->filename + strlen (entry->filename) - 4; + + if (strcmp (ext, ".def") == 0 || strcmp (ext, ".DEF") == 0) + { + pep_def_file = def_file_parse (entry->filename, pep_def_file); + + if (pep_def_file) + { + int i, buflen=0, len; + char *buf; + + for (i = 0; i < pep_def_file->num_exports; i++) + { + len = strlen (pep_def_file->exports[i].internal_name); + if (buflen < len + 2) + buflen = len + 2; + } + + buf = xmalloc (buflen); + + for (i = 0; i < pep_def_file->num_exports; i++) + { + struct bfd_link_hash_entry *h; + + sprintf (buf, "_%s", pep_def_file->exports[i].internal_name); + + h = bfd_link_hash_lookup (link_info.hash, buf, TRUE, TRUE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + bfd_link_add_undef (link_info.hash, h); + } + } + free (buf); + + /* def_file_print (stdout, pep_def_file); */ + if (pep_def_file->is_dll == 1) + link_info.shared = 1; + + if (pep_def_file->base_address != (bfd_vma)(-1)) + { + pep.ImageBase = + pe_data (output_bfd)->pe_opthdr.ImageBase = + init[IMAGEBASEOFF].value = pep_def_file->base_address; + init[IMAGEBASEOFF].inited = 1; + if (image_base_statement) + image_base_statement->exp = + exp_assop ('=', "__image_base__", exp_intop (pep.ImageBase)); + } + + if (pep_def_file->stack_reserve != -1 + && ! saw_option ("__size_of_stack_reserve__")) + { + pep.SizeOfStackReserve = pep_def_file->stack_reserve; + if (pep_def_file->stack_commit != -1) + pep.SizeOfStackCommit = pep_def_file->stack_commit; + } + if (pep_def_file->heap_reserve != -1 + && ! saw_option ("__size_of_heap_reserve__")) + { + pep.SizeOfHeapReserve = pep_def_file->heap_reserve; + if (pep_def_file->heap_commit != -1) + pep.SizeOfHeapCommit = pep_def_file->heap_commit; + } + return TRUE; + } + } +#endif + return FALSE; +} + +static bfd_boolean +gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT +#ifdef TARGET_IS_i386pep + pep_dll_id_target ("pei-x86-64"); +#endif + if (bfd_get_format (entry->the_bfd) == bfd_object) + { + char fbuf[LD_PATHMAX + 1]; + const char *ext; + + if (REALPATH (entry->filename, fbuf) == NULL) + strncpy (fbuf, entry->filename, sizeof (fbuf)); + + ext = fbuf + strlen (fbuf) - 4; + + if (strcmp (ext, ".dll") == 0 || strcmp (ext, ".DLL") == 0) + return pep_implied_import_dll (fbuf); + } +#endif + return FALSE; +} + +static void +gld_${EMULATION_NAME}_finish (void) +{ + finish_default (); + +#ifdef DLL_SUPPORT + if (link_info.shared + || (!link_info.relocatable && pep_def_file->num_exports != 0)) + { + pep_dll_fill_sections (output_bfd, &link_info); + if (pep_implib_filename) + pep_dll_generate_implib (pep_def_file, pep_implib_filename); + } + + if (pep_out_def_filename) + pep_dll_generate_def_file (pep_out_def_filename); +#endif /* DLL_SUPPORT */ + + /* I don't know where .idata gets set as code, but it shouldn't be. */ + { + asection *asec = bfd_get_section_by_name (output_bfd, ".idata"); + + if (asec) + { + asec->flags &= ~SEC_CODE; + asec->flags |= SEC_DATA; + } + } +} + + +/* Place an orphan section. + + We use this to put sections in a reasonable place in the file, and + to ensure that they are aligned as required. + + We handle grouped sections here as well. A section named .foo$nn + goes into the output section .foo. All grouped sections are sorted + by name. + + Grouped sections for the default sections are handled by the + default linker script using wildcards, and are sorted by + sort_sections. */ + +static bfd_boolean +gld_${EMULATION_NAME}_place_orphan (asection *s) +{ + const char *secname; + const char *orig_secname; + char *dollar = NULL; + lang_output_section_statement_type *os; + lang_statement_list_type add_child; + + secname = bfd_get_section_name (s->owner, s); + + /* Look through the script to see where to place this section. */ + orig_secname = secname; + if (!link_info.relocatable + && (dollar = strchr (secname, '$')) != NULL) + { + size_t len = dollar - orig_secname; + char *newname = xmalloc (len + 1); + memcpy (newname, orig_secname, len); + newname[len] = '\0'; + secname = newname; + } + + os = lang_output_section_find (secname); + + lang_list_init (&add_child); + + if (os != NULL + && (os->bfd_section == NULL + || os->bfd_section->flags == 0 + || ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0)) + { + /* We already have an output section statement with this + name, and its bfd section, if any, has compatible flags. + If the section already exists but does not have any flags set, + then it has been created by the linker, probably as a result of + a --section-start command line switch. */ + lang_add_section (&add_child, s, os); + } + else + { + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".bss", + SEC_ALLOC, + 0, 0, 0, 0 } + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_data, + orphan_bss + }; + static int orphan_init_done = 0; + struct orphan_save *place; + lang_output_section_statement_type *after; + etree_type *address; + + if (!orphan_init_done) + { + struct orphan_save *ho; + for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) + if (ho->name != NULL) + { + ho->os = lang_output_section_find (ho->name); + if (ho->os != NULL && ho->os->flags == 0) + ho->os->flags = ho->flags; + } + orphan_init_done = 1; + } + + /* Try to put the new output section in a reasonable place based + on the section name and section flags. */ + + place = NULL; + if ((s->flags & SEC_ALLOC) == 0) + ; + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + place = &hold[orphan_bss]; + else if ((s->flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; + else if ((s->flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; + else + place = &hold[orphan_text]; + + after = NULL; + if (place != NULL) + { + if (place->os == NULL) + place->os = lang_output_section_find (place->name); + after = place->os; + if (after == NULL) + after = lang_output_section_find_by_flags (s, &place->os, NULL); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = (&lang_output_section_statement.head + ->output_section_statement); + } + + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocatable characteristics. */ + if (bfd_get_section_by_name (output_bfd, secname) != NULL) + { + static int count = 1; + secname = bfd_get_unique_section_name (output_bfd, secname, &count); + if (secname == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); + } + + /* All sections in an executable must be aligned to a page boundary. */ + address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); + os = lang_insert_orphan (s, secname, after, place, address, &add_child); + } + + { + lang_statement_union_type **pl = &os->children.head; + + if (dollar != NULL) + { + bfd_boolean found_dollar; + + /* The section name has a '$'. Sort it with the other '$' + sections. */ + found_dollar = FALSE; + for ( ; *pl != NULL; pl = &(*pl)->header.next) + { + lang_input_section_type *ls; + const char *lname; + + if ((*pl)->header.type != lang_input_section_enum) + continue; + + ls = &(*pl)->input_section; + + lname = bfd_get_section_name (ls->section->owner, ls->section); + if (strchr (lname, '$') == NULL) + { + if (found_dollar) + break; + } + else + { + found_dollar = TRUE; + if (strcmp (orig_secname, lname) < 0) + break; + } + } + } + + if (add_child.head != NULL) + { + add_child.head->header.next = *pl; + *pl = add_child.head; + } + } + + return TRUE; +} + +static bfd_boolean +gld_${EMULATION_NAME}_open_dynamic_archive + (const char *arch ATTRIBUTE_UNUSED, + search_dirs_type *search, + lang_input_statement_type *entry) +{ + static const struct + { + const char * format; + bfd_boolean use_prefix; + } + libname_fmt [] = + { + /* Preferred explicit import library for dll's. */ + { "lib%s.dll.a", FALSE }, + /* Alternate explicit import library for dll's. */ + { "%s.dll.a", FALSE }, + /* "libfoo.a" could be either an import lib or a static lib. + For backwards compatibility, libfoo.a needs to precede + libfoo.dll and foo.dll in the search. */ + { "lib%s.a", FALSE }, + /* The 'native' spelling of an import lib name is "foo.lib". */ + { "%s.lib", FALSE }, +#ifdef DLL_SUPPORT + /* Try "<prefix>foo.dll" (preferred dll name, if specified). */ + { "%s%s.dll", TRUE }, +#endif + /* Try "libfoo.dll" (default preferred dll name). */ + { "lib%s.dll", FALSE }, + /* Finally try 'native' dll name "foo.dll". */ + { "%s.dll", FALSE }, + /* Note: If adding more formats to this table, make sure to check to + see if their length is longer than libname_fmt[0].format, and if + so, update the call to xmalloc() below. */ + { NULL, FALSE } + }; + static unsigned int format_max_len = 0; + const char * filename; + char * full_string; + char * base_string; + unsigned int i; + + + if (! entry->is_archive) + return FALSE; + + filename = entry->filename; + + if (format_max_len == 0) + /* We need to allow space in the memory that we are going to allocate + for the characters in the format string. Since the format array is + static we only need to calculate this information once. In theory + this value could also be computed statically, but this introduces + the possibility for a discrepancy and hence a possible memory + corruption. The lengths we compute here will be too long because + they will include any formating characters (%s) in the strings, but + this will not matter. */ + for (i = 0; libname_fmt[i].format; i++) + if (format_max_len < strlen (libname_fmt[i].format)) + format_max_len = strlen (libname_fmt[i].format); + + full_string = xmalloc (strlen (search->name) + + strlen (filename) + + format_max_len +#ifdef DLL_SUPPORT + + (pep_dll_search_prefix + ? strlen (pep_dll_search_prefix) : 0) +#endif + /* Allow for the terminating NUL and for the path + separator character that is inserted between + search->name and the start of the format string. */ + + 2); + + sprintf (full_string, "%s/", search->name); + base_string = full_string + strlen (full_string); + + for (i = 0; libname_fmt[i].format; i++) + { +#ifdef DLL_SUPPORT + if (libname_fmt[i].use_prefix) + { + if (!pep_dll_search_prefix) + continue; + sprintf (base_string, libname_fmt[i].format, pep_dll_search_prefix, filename); + } + else +#endif + sprintf (base_string, libname_fmt[i].format, filename); + + if (ldfile_try_open_bfd (full_string, entry)) + break; + } + + if (!libname_fmt[i].format) + { + free (full_string); + return FALSE; + } + + entry->filename = full_string; + + return TRUE; +} + +static int +gld_${EMULATION_NAME}_find_potential_libraries + (char *name, lang_input_statement_type *entry) +{ + return ldfile_open_file_search (name, entry, "", ".lib"); +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +# Scripts compiled in. +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +cat >>e${EMULATION_NAME}.c <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +cat >>e${EMULATION_NAME}.c <<EOF + + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + gld_${EMULATION_NAME}_after_parse, + gld_${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld_${EMULATION_NAME}_before_allocation, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + gld_${EMULATION_NAME}_finish, + NULL, /* Create output section statements. */ + gld_${EMULATION_NAME}_open_dynamic_archive, + gld_${EMULATION_NAME}_place_orphan, + gld_${EMULATION_NAME}_set_symbols, + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + gld_${EMULATION_NAME}_unrecognized_file, + gld_${EMULATION_NAME}_list_options, + gld_${EMULATION_NAME}_recognized_file, + gld_${EMULATION_NAME}_find_potential_libraries, + NULL /* new_vers_pattern. */ +}; +EOF diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em index 10f91074dfecb..b0239e0b76a5e 100644 --- a/ld/emultempl/ppc32elf.em +++ b/ld/emultempl/ppc32elf.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2003, 2005 Free Software Foundation, Inc. +# Copyright 2003, 2005, 2007 Free Software Foundation, Inc. # # This file is part of GLD, the Gnu Linker. # @@ -45,7 +45,7 @@ static int notlsopt = 0; static int emit_stub_syms = 0; /* Chooses the correct place for .plt and .got. */ -static int old_plt = 0; +static enum ppc_elf_plt_type plt_style = PLT_UNSET; static int old_got = 0; static void @@ -62,7 +62,7 @@ ppc_after_open (void) lang_output_section_statement_type *got_os[2]; emit_stub_syms |= link_info.emitrelocations; - new_plt = ppc_elf_select_plt_layout (output_bfd, &link_info, old_plt, + new_plt = ppc_elf_select_plt_layout (output_bfd, &link_info, plt_style, emit_stub_syms); if (new_plt < 0) einfo ("%X%P: select_plt_layout problem %E\n"); @@ -124,19 +124,40 @@ ppc_before_allocation (void) EOF +if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then + cat >>e${EMULATION_NAME}.c <<EOF +/* Special handling for embedded SPU executables. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); +static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); + +static bfd_boolean +ppc_recognized_file (lang_input_statement_type *entry) +{ + if (embedded_spu_file (entry, "-m32")) + return TRUE; + + return gld${EMULATION_NAME}_load_symbols (entry); +} + +EOF +LDEMUL_RECOGNIZED_FILE=ppc_recognized_file +fi + # Define some shell vars to insert bits of code into the standard elf # parse_args and list_options functions. # PARSE_AND_LIST_PROLOGUE=' #define OPTION_NO_TLS_OPT 301 -#define OPTION_OLD_PLT 302 -#define OPTION_OLD_GOT 303 -#define OPTION_STUBSYMS 304 +#define OPTION_NEW_PLT 302 +#define OPTION_OLD_PLT 303 +#define OPTION_OLD_GOT 304 +#define OPTION_STUBSYMS 305 ' PARSE_AND_LIST_LONGOPTS=' { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS }, { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, + { "secure-plt", no_argument, NULL, OPTION_NEW_PLT }, { "bss-plt", no_argument, NULL, OPTION_OLD_PLT }, { "sdata-got", no_argument, NULL, OPTION_OLD_GOT }, ' @@ -145,6 +166,7 @@ PARSE_AND_LIST_OPTIONS=' fprintf (file, _("\ --emit-stub-syms Label linker stubs with a symbol.\n\ --no-tls-optimize Don'\''t try to optimize TLS accesses.\n\ + --secure-plt Use new-style PLT if possible.\n\ --bss-plt Force old-style BSS PLT.\n\ --sdata-got Force GOT location just before .sdata.\n" )); @@ -159,8 +181,12 @@ PARSE_AND_LIST_ARGS_CASES=' notlsopt = 1; break; + case OPTION_NEW_PLT: + plt_style = PLT_NEW; + break; + case OPTION_OLD_PLT: - old_plt = 1; + plt_style = PLT_OLD; break; case OPTION_OLD_GOT: diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em index ea337712ed1c6..9372f88d3d3d9 100644 --- a/ld/emultempl/ppc64elf.em +++ b/ld/emultempl/ppc64elf.em @@ -225,7 +225,7 @@ ppc_add_stub_section (const char *stub_sec_name, asection *input_section) goto err_ret; flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE - | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP); if (!bfd_set_section_flags (stub_file->the_bfd, stub_sec, flags)) goto err_ret; @@ -258,9 +258,8 @@ ppc_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - need_laying_out = 0; - - gld${EMULATION_NAME}_layout_sections_again (); + gld${EMULATION_NAME}_map_segments (TRUE); + need_laying_out = -1; } @@ -311,7 +310,7 @@ build_section_lists (lang_statement_union_type *statement) /* Final emulation specific call. */ static void -ppc_finish (void) +gld${EMULATION_NAME}_finish (void) { /* e_entry on PowerPC64 points to the function descriptor for _start. If _start is missing, default to the first function @@ -353,8 +352,8 @@ ppc_finish (void) } } - if (need_laying_out) - ppc_layout_sections_again (); + if (need_laying_out != -1) + gld${EMULATION_NAME}_map_segments (need_laying_out); if (link_info.relocatable) { @@ -415,17 +414,22 @@ gld${EMULATION_NAME}_new_vers_pattern (struct bfd_elf_version_expr *entry) unsigned int len; char *dot_pat; - if (!dotsyms || entry->pattern[0] == '*' || entry->pattern[0] == '.') + if (!dotsyms + || (entry->pattern != NULL + && (entry->pattern[0] == '*' || entry->pattern[0] == '.'))) return entry; dot_entry = xmalloc (sizeof *dot_entry); *dot_entry = *entry; dot_entry->next = entry; - len = strlen (entry->pattern) + 2; - dot_pat = xmalloc (len); - dot_pat[0] = '.'; - memcpy (dot_pat + 1, entry->pattern, len - 1); - dot_entry->pattern = dot_pat; + if (entry->pattern != NULL) + { + 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; + } if (entry->symbol != NULL) { len = strlen (entry->symbol) + 2; @@ -460,6 +464,24 @@ ppc_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) EOF +if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then + cat >>e${EMULATION_NAME}.c <<EOF +/* Special handling for embedded SPU executables. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); +static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); + +static bfd_boolean +ppc64_recognized_file (lang_input_statement_type *entry) +{ + if (embedded_spu_file (entry, "-m64")) + return TRUE; + + return gld${EMULATION_NAME}_load_symbols (entry); +} +EOF +LDEMUL_RECOGNIZED_FILE=ppc64_recognized_file +fi + # Define some shell vars to insert bits of code into the standard elf # parse_args and list_options functions. # @@ -574,6 +596,6 @@ PARSE_AND_LIST_ARGS_CASES=' # LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation -LDEMUL_FINISH=ppc_finish +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/ld/emultempl/scoreelf.em b/ld/emultempl/scoreelf.em new file mode 100644 index 0000000000000..a529a1b704dd3 --- /dev/null +++ b/ld/emultempl/scoreelf.em @@ -0,0 +1,74 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006 Free Software Foundation, Inc. +# Contributed by: +# Mei Ligang (ligang@sunnorth.com.cn) +# Pei-Lin Tsai (pltsai@sunplus.com) + +# 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# + +# This file is sourced from elf32.em, and defines extra score-elf +# specific routines. +# +cat >>e${EMULATION_NAME}.c <<EOF + +static void +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`; +} + +static void +score_elf_after_open (void) +{ + if (strstr (bfd_get_target (output_bfd), "score") == NULL) + { + /* The score backend needs special fields in the output hash structure. + These will only be created if the output format is an score format, + hence we do not support linking and changing output formats at the + same time. Use a link followed by objcopy to change output formats. */ + einfo ("%F%X%P: error: cannot change output format whilst linking S+core binaries\n"); + return; + } + + /* Call the standard elf routine. */ + gld${EMULATION_NAME}_after_open (); +} + +EOF + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE='' +PARSE_AND_LIST_SHORTOPTS= +PARSE_AND_LIST_LONGOPTS='' +PARSE_AND_LIST_OPTIONS='' +PARSE_AND_LIST_ARGS_CASES='' + +# We have our own after_open and before_allocation functions, but they call +# the standard routines, so give them a different name. +LDEMUL_AFTER_OPEN=score_elf_after_open + +# Replace the elf before_parse function with our own. +LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse + diff --git a/ld/emultempl/spu_ovl.S b/ld/emultempl/spu_ovl.S new file mode 100644 index 0000000000000..adc6ab22a776e --- /dev/null +++ b/ld/emultempl/spu_ovl.S @@ -0,0 +1,294 @@ +/* Overlay manager for SPU. + + Copyright 2006, 2007 Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/** + * MFC DMA defn's. + */ +#define MFC_GET_CMD 0x40 +#define MFC_MAX_DMA_SIZE 0x4000 +#define MFC_TAG_UPDATE_ALL 2 +#define MFC_TAG_ID 0 + + +/** + * Temporary register allocations. + * These are saved/restored here. + */ +#define tab $75 +#define cgbits $75 +#define add64 $75 +#define ealo $75 +#define newmask $75 +#define tagstat $75 +#define bchn $75 +#define rv1 $75 + +#define off $76 +#define off64 $76 +#define maxsize $76 +#define oldmask $76 +#define sz $76 +#define lnkr $76 +#define rv2 $76 + +#define cur $77 +#define cmp $77 +#define buf $77 +#define genwi $77 +#define tagid $77 +#define cmd $77 +#define rv3 $77 + +#define cgshuf $78 + +#define vma $6 + +#define map $7 +#define osize $7 +#define cmp2 $7 + +#define ea64 $8 +#define retval $8 + +#ifdef OVLY_IRQ_SAVE +#define irqtmp $8 +#define irq_stat $9 +#endif + + .extern _ovly_table + .extern _ovly_buf_table + + .text + .align 4 + .type __rv_pattern, @object + .size __rv_pattern, 16 +__rv_pattern: + .word 0x00010203, 0x1c1d1e1f, 0x00010203, 0x10111213 + .type __cg_pattern, @object + .size __cg_pattern, 16 +__cg_pattern: + .word 0x04050607, 0x80808080, 0x80808080, 0x80808080 + +/** + * __ovly_return - stub for returning from overlay functions. + * + * inputs: + * $lr link register + * + * outputs: + * $78 old partition number, to be reloaded + * $79 return address in old partion number + */ + .global __ovly_return + .type __ovly_return, @function + + .word 0 +__ovly_return: + shlqbyi $78, $lr, 4 + shlqbyi $79, $lr, 8 + biz $78, $79 + .size __ovly_return, . - __ovly_return + +/** + * __ovly_load - copy an overlay partion to local store. + * + * inputs: + * $78 partition number to be loaded. + * $79 branch target in new partition. + * $lr link register, containing return addr. + * + * outputs: + * $lr new link register, returning through __ovly_return. + * + * Copy a new overlay partition into local store, or return + * immediately if the partition is already resident. + */ + .global __ovly_load + .type __ovly_load, @function + +__ovly_load: +/* Save temporary registers to stack. */ + stqd $6, -16($sp) + stqd $7, -32($sp) + stqd $8, -48($sp) + +#ifdef OVLY_IRQ_SAVE +/* Save irq state, then disable interrupts. */ + stqd $9, -64($sp) + ila irqtmp, __ovly_irq_save + rdch irq_stat, $SPU_RdMachStat + bid irqtmp +__ovly_irq_save: +#endif + +/* Set branch hint to overlay target. */ + hbr __ovly_load_ret, $79 + +/* Get caller's overlay index by back chaining through stack frames. + * Loop until end of stack (back chain all-zeros) or + * encountered a link register we set here. */ + lqd bchn, 0($sp) + ila retval, __ovly_return + +__ovly_backchain_loop: + lqd lnkr, 16(bchn) + lqd bchn, 0(bchn) + ceq cmp, lnkr, retval + ceqi cmp2, bchn, 0 + or cmp, cmp, cmp2 + brz cmp, __ovly_backchain_loop + +/* If we reached the zero back-chain, then lnkr is bogus. Clear the + * part of lnkr that we use later (slot 3). */ + rotqbyi cmp2, cmp2, 4 + andc lnkr, lnkr, cmp2 + +/* Set lr = {__ovly_return, prev ovl ndx, caller return adr, callee ovl ndx}. */ + lqd rv1, (__rv_pattern-__ovly_return+4)(retval) + shufb rv2, retval, lnkr, rv1 + shufb rv3, $lr, $78, rv1 + fsmbi rv1, 0xff + selb rv2, rv2, rv3, rv1 +/* If we have a tail call from one overlay function to another overlay, + then lr is already set up. Don't change it. */ + ceq rv1, $lr, retval + fsmb rv1, rv1 + selb $lr, rv2, $lr, rv1 + +/* Branch to $79 if non-overlay */ + brz $78, __ovly_load_restore + +/* Load values from _ovly_table[$78]. + * extern struct { + * u32 vma; + * u32 size; + * u32 file_offset; + * u32 buf; + * } _ovly_table[]; + */ + shli off, $78, 4 + ila tab, _ovly_table - 16 + lqx vma, tab, off + rotqbyi buf, vma, 12 + +/* Load values from _ovly_buf_table[buf]. + * extern struct { + * u32 mapped; + * } _ovly_buf_table[]; + */ + ila tab, _ovly_buf_table + ai off, buf, -1 + shli off, off, 2 + lqx map, tab, off + rotqby cur, map, off + +/* Branch to $79 now if overlay is already mapped. */ + ceq cmp, $78, cur + brnz cmp, __ovly_load_restore + +/* Marker for profiling code. If we get here, we are about to load + * a new overlay. + */ + .global __ovly_load_event + .type __ovly_load_event, @function +__ovly_load_event: + +/* Set _ovly_buf_table[buf].mapped = $78. */ + cwx genwi, tab, off + shufb map, $78, map, genwi + stqx map, tab, off + +/* A new partition needs to be loaded. Prepare for DMA loop. + * _EAR_ is the 64b base EA, filled in at run time by the + * loader, and indicating the value for SPU executable image start. + */ + lqd cgshuf, (__cg_pattern-__ovly_return+4)(retval) + rotqbyi osize, vma, 4 + rotqbyi sz, vma, 8 + lqa ea64, _EAR_ + +__ovly_xfer_loop: +/* 64b add to compute next ea64. */ + rotqmbyi off64, sz, -4 + cg cgbits, ea64, off64 + shufb add64, cgbits, cgbits, cgshuf + addx add64, ea64, off64 + ori ea64, add64, 0 + +/* Setup DMA parameters, then issue DMA request. */ + rotqbyi ealo, add64, 4 + ila maxsize, MFC_MAX_DMA_SIZE + cgt cmp, osize, maxsize + selb sz, osize, maxsize, cmp + ila tagid, MFC_TAG_ID + wrch $MFC_LSA, vma + wrch $MFC_EAH, ea64 + wrch $MFC_EAL, ealo + wrch $MFC_Size, sz + wrch $MFC_TagId, tagid + ila cmd, MFC_GET_CMD + wrch $MFC_Cmd, cmd + +/* Increment vma, decrement size, branch back as needed. */ + a vma, vma, sz + sf osize, sz, osize + brnz osize, __ovly_xfer_loop + +/* Save app's tagmask, wait for DMA complete, restore mask. */ + rdch oldmask, $MFC_RdTagMask +#if MFC_TAG_ID < 16 + ilh newmask, 1 << MFC_TAG_ID +#else + ilhu newmask, 1 << (MFC_TAG_ID - 16) +#endif + wrch $MFC_WrTagMask, newmask + ila tagstat, MFC_TAG_UPDATE_ALL + wrch $MFC_WrTagUpdate, tagstat + rdch tagstat, $MFC_RdTagStat + sync + wrch $MFC_WrTagMask, oldmask + + .global _ovly_debug_event + .type _ovly_debug_event, @function +_ovly_debug_event: +/* GDB inserts debugger trap here. */ + nop + +__ovly_load_restore: +#ifdef OVLY_IRQ_SAVE +/* Conditionally re-enable interrupts. */ + andi irq_stat, irq_stat, 1 + ila irqtmp, __ovly_irq_restore + binze irq_stat, irqtmp +__ovly_irq_restore: + lqd $9, -64($sp) +#endif + +/* Restore saved registers. */ + lqd $8, -48($sp) + lqd $7, -32($sp) + lqd $6, -16($sp) + +__ovly_load_ret: +/* Branch to target address. */ + bi $79 + + .size __ovly_load, . - __ovly_load diff --git a/ld/emultempl/spu_ovl.o b/ld/emultempl/spu_ovl.o Binary files differnew file mode 100644 index 0000000000000..a68eea3970aac --- /dev/null +++ b/ld/emultempl/spu_ovl.o diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em new file mode 100644 index 0000000000000..05adeb8582c6b --- /dev/null +++ b/ld/emultempl/spuelf.em @@ -0,0 +1,504 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006, 2007 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., +# 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +# + +# This file is sourced from elf32.em, and defines extra spu specific +# features. +# +cat >>e${EMULATION_NAME}.c <<EOF +#include "ldctor.h" +#include "elf32-spu.h" + +/* Non-zero if no overlay processing should be done. */ +static int no_overlays = 0; + +/* Non-zero if we want stubs on all calls out of overlay regions. */ +static int non_overlay_stubs = 0; + +/* Whether to emit symbols for stubs. */ +static int emit_stub_syms = 0; + +/* Non-zero to perform stack space analysis. */ +static int stack_analysis = 0; + +/* Whether to emit symbols with stack requirements for each function. */ +static int emit_stack_syms = 0; + +/* Range of valid addresses for loadable sections. */ +static bfd_vma local_store_lo = 0; +static bfd_vma local_store_hi = 0x3ffff; + +static const char ovl_mgr[] = { +EOF + +../binutils/bin2c < ${srcdir}/emultempl/spu_ovl.o >> e${EMULATION_NAME}.c + +cat >>e${EMULATION_NAME}.c <<EOF +}; + +static const struct _ovl_stream ovl_mgr_stream = { + ovl_mgr, + ovl_mgr + sizeof (ovl_mgr) +}; + +static asection *toe = NULL; + + +static int +is_spu_target (void) +{ + extern const bfd_target bfd_elf32_spu_vec; + + return link_info.hash->creator == &bfd_elf32_spu_vec; +} + +/* Create our note section. */ + +static void +spu_after_open (void) +{ + if (is_spu_target () + && !link_info.relocatable + && link_info.input_bfds != NULL + && !spu_elf_create_sections (output_bfd, &link_info, + stack_analysis, emit_stack_syms)) + einfo ("%X%P: can not create note section: %E\n"); + + gld${EMULATION_NAME}_after_open (); +} + +/* Add section S at the end of output section OUTPUT_NAME. + + Really, we should be duplicating ldlang.c map_input_to_output_sections + logic here, ie. using the linker script to find where the section + goes. That's rather a lot of code, and we don't want to run + map_input_to_output_sections again because most sections are already + mapped. So cheat, and put the section in a fixed place, ignoring any + attempt via a linker script to put .stub, .ovtab, and built-in + overlay manager code somewhere else. */ + +static void +spu_place_special_section (asection *s, const char *output_name) +{ + lang_output_section_statement_type *os; + + os = lang_output_section_find (output_name); + if (os == NULL) + { + const char *save = s->name; + s->name = output_name; + gld${EMULATION_NAME}_place_orphan (s); + s->name = save; + } + else + lang_add_section (&os->children, s, os); + + s->output_section->size += s->size; +} + +/* Load built-in overlay manager, and tweak overlay section alignment. */ + +static void +spu_elf_load_ovl_mgr (void) +{ + lang_output_section_statement_type *os; + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (elf_hash_table (&link_info), + "__ovly_load", FALSE, FALSE, FALSE); + + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->def_regular) + { + /* User supplied __ovly_load. */ + } + else if (ovl_mgr_stream.start == ovl_mgr_stream.end) + einfo ("%F%P: no built-in overlay manager\n"); + else + { + lang_input_statement_type *ovl_is; + + ovl_is = lang_add_input_file ("builtin ovl_mgr", + lang_input_file_is_file_enum, + NULL); + + if (!spu_elf_open_builtin_lib (&ovl_is->the_bfd, &ovl_mgr_stream)) + einfo ("%X%P: can not open built-in overlay manager: %E\n"); + else + { + asection *in; + + if (!load_symbols (ovl_is, NULL)) + einfo ("%X%P: can not load built-in overlay manager: %E\n"); + + /* Map overlay manager sections to output sections. */ + for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next) + if ((in->flags & (SEC_ALLOC | SEC_LOAD)) + == (SEC_ALLOC | SEC_LOAD)) + spu_place_special_section (in, ".text"); + } + } + + /* Ensure alignment of overlay sections is sufficient. */ + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + if (os->bfd_section != NULL + && spu_elf_section_data (os->bfd_section) != NULL + && spu_elf_section_data (os->bfd_section)->ovl_index != 0) + { + if (os->bfd_section->alignment_power < 4) + os->bfd_section->alignment_power = 4; + + /* Also ensure size rounds up. */ + os->block_value = 16; + } +} + +/* Go find if we need to do anything special for overlays. */ + +static void +spu_before_allocation (void) +{ + if (is_spu_target () + && !link_info.relocatable + && !no_overlays) + { + /* Size the sections. This is premature, but we need to know the + rough layout so that overlays can be found. */ + expld.phase = lang_mark_phase_enum; + expld.dataseg.phase = exp_dataseg_none; + one_lang_size_sections_pass (NULL, TRUE); + + /* Find overlays by inspecting section vmas. */ + if (spu_elf_find_overlays (output_bfd, &link_info)) + { + asection *stub, *ovtab; + + if (!spu_elf_size_stubs (output_bfd, &link_info, non_overlay_stubs, + stack_analysis, &stub, &ovtab, &toe)) + einfo ("%X%P: can not size overlay stubs: %E\n"); + + if (stub != NULL) + { + spu_place_special_section (stub, ".text"); + spu_place_special_section (ovtab, ".data"); + spu_place_special_section (toe, ".toe"); + + spu_elf_load_ovl_mgr (); + } + } + + /* We must not cache anything from the preliminary sizing. */ + lang_reset_memory_regions (); + } + + gld${EMULATION_NAME}_before_allocation (); +} + +/* Final emulation specific call. */ + +static void +gld${EMULATION_NAME}_finish (void) +{ + int need_laying_out; + + need_laying_out = bfd_elf_discard_info (output_bfd, &link_info); + + gld${EMULATION_NAME}_map_segments (need_laying_out); + + if (is_spu_target () && local_store_lo < local_store_hi) + { + asection *s; + + s = spu_elf_check_vma (output_bfd, local_store_lo, local_store_hi); + if (s != NULL) + einfo ("%X%P: %A exceeds local store range\n", s); + } + + if (toe != NULL + && !spu_elf_build_stubs (&link_info, + emit_stub_syms || link_info.emitrelocations, + toe)) + einfo ("%X%P: can not build overlay stubs: %E\n"); + + finish_default (); +} + +EOF + +if grep -q 'ld_elf.*ppc.*_emulation' ldemul-list.h; then + cat >>e${EMULATION_NAME}.c <<EOF +#include "filenames.h" +#include <fcntl.h> +#include <sys/wait.h> + +struct tflist { + struct tflist *next; + char name[9]; +}; + +static struct tflist *tmp_file_list; + +static void clean_tmp (void) +{ + for (; tmp_file_list != NULL; tmp_file_list = tmp_file_list->next) + unlink (tmp_file_list->name); +} + +static const char * +base_name (const char *path) +{ + const char *file = strrchr (path, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + char *bslash = strrchr (path, '\\\\'); + + if (file == NULL || (bslash != NULL && bslash > file)) + file = bslash; + if (file == NULL + && path[0] != '\0' + && path[1] == ':') + file = path + 1; + } +#endif + if (file == NULL) + file = path; + else + ++file; + return file; +} + +/* This function is called when building a ppc32 or ppc64 executable + to handle embedded spu images. */ +extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); + +bfd_boolean +embedded_spu_file (lang_input_statement_type *entry, const char *flags) +{ + const char *cmd[6]; + const char *sym; + char *handle, *p; + struct tflist *tf; + char *oname; + int fd; + pid_t pid; + int status; + union lang_statement_union **old_stat_tail; + union lang_statement_union **old_file_tail; + union lang_statement_union *new_ent; + lang_input_statement_type *search; + + if (entry->the_bfd->format != bfd_object + || strcmp (entry->the_bfd->xvec->name, "elf32-spu") != 0 + || (entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_EXEC + && entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_DYN)) + return FALSE; + + /* Use the filename as the symbol marking the program handle struct. */ + sym = base_name (entry->the_bfd->filename); + + handle = xstrdup (sym); + for (p = handle; *p; ++p) + if (!(ISALNUM (*p) || *p == '$' || *p == '.')) + *p = '_'; + + if (tmp_file_list == NULL) + atexit (clean_tmp); + tf = xmalloc (sizeof (*tf)); + tf->next = tmp_file_list; + tmp_file_list = tf; + oname = tf->name; + memcpy (tf->name, "ldXXXXXX", sizeof (tf->name)); + +#ifdef HAVE_MKSTEMP + fd = mkstemp (oname); +#else + oname = mktemp (oname); + if (oname == NULL) + return FALSE; + fd = open (oname, O_RDWR | O_CREAT | O_EXCL, 0600); +#endif + if (fd == -1) + return FALSE; + close (fd); + + for (search = (lang_input_statement_type *) input_file_chain.head; + search != NULL; + search = (lang_input_statement_type *) search->next_real_file) + { + const char *infile = base_name (search->filename); + + if (infile != NULL + && strncmp (infile, "crtbegin", 8) == 0) + { + if (infile[8] == 'S') + flags = concat (flags, " -fPIC", NULL); + else if (infile[8] == 'T') + flags = concat (flags, " -fpie", NULL); + break; + } + } + + /* Use fork() and exec() rather than system() so that we don't + need to worry about quoting args. */ + cmd[0] = EMBEDSPU; + cmd[1] = flags; + cmd[2] = handle; + cmd[3] = entry->the_bfd->filename; + cmd[4] = oname; + cmd[5] = NULL; + if (trace_file_tries) + { + info_msg (_("running: %s \"%s\" \"%s\" \"%s\" \"%s\"\n"), + cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + fflush (stdout); + } + + pid = fork (); + if (pid == -1) + return FALSE; + if (pid == 0) + { + execvp (cmd[0], (char *const *) cmd); + if (strcmp ("embedspu", EMBEDSPU) != 0) + { + cmd[0] = "embedspu"; + execvp (cmd[0], (char *const *) cmd); + } + perror (cmd[0]); + _exit (127); + } +#ifdef HAVE_WAITPID +#define WAITFOR(PID, STAT) waitpid (PID, STAT, 0) +#else +#define WAITFOR(PID, STAT) wait (STAT) +#endif + if (WAITFOR (pid, &status) != pid + || !WIFEXITED (status) + || WEXITSTATUS (status) != 0) + return FALSE; +#undef WAITFOR + + old_stat_tail = stat_ptr->tail; + old_file_tail = input_file_chain.tail; + if (lang_add_input_file (oname, lang_input_file_is_file_enum, NULL) == NULL) + return FALSE; + + /* lang_add_input_file put the new list entry at the end of the statement + and input file lists. Move it to just after the current entry. */ + new_ent = *old_stat_tail; + *old_stat_tail = NULL; + stat_ptr->tail = old_stat_tail; + *old_file_tail = NULL; + input_file_chain.tail = old_file_tail; + new_ent->header.next = entry->header.next; + entry->header.next = new_ent; + new_ent->input_statement.next_real_file = entry->next_real_file; + entry->next_real_file = new_ent; + + /* Ensure bfd sections are excluded from the output. */ + bfd_section_list_clear (entry->the_bfd); + entry->loaded = TRUE; + return TRUE; +} + +EOF +fi + +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_SPU_PLUGIN 301 +#define OPTION_SPU_NO_OVERLAYS (OPTION_SPU_PLUGIN + 1) +#define OPTION_SPU_STUB_SYMS (OPTION_SPU_NO_OVERLAYS + 1) +#define OPTION_SPU_NON_OVERLAY_STUBS (OPTION_SPU_STUB_SYMS + 1) +#define OPTION_SPU_LOCAL_STORE (OPTION_SPU_NON_OVERLAY_STUBS + 1) +#define OPTION_SPU_STACK_ANALYSIS (OPTION_SPU_LOCAL_STORE + 1) +#define OPTION_SPU_STACK_SYMS (OPTION_SPU_STACK_ANALYSIS + 1) +' + +PARSE_AND_LIST_LONGOPTS=' + { "plugin", no_argument, NULL, OPTION_SPU_PLUGIN }, + { "no-overlays", no_argument, NULL, OPTION_SPU_NO_OVERLAYS }, + { "emit-stub-syms", no_argument, NULL, OPTION_SPU_STUB_SYMS }, + { "extra-overlay-stubs", no_argument, NULL, OPTION_SPU_NON_OVERLAY_STUBS }, + { "local-store", required_argument, NULL, OPTION_SPU_LOCAL_STORE }, + { "stack-analysis", no_argument, NULL, OPTION_SPU_STACK_ANALYSIS }, + { "emit-stack-syms", no_argument, NULL, OPTION_SPU_STACK_SYMS }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --plugin Make SPU plugin.\n\ + --no-overlays No overlay handling.\n\ + --emit-stub-syms Add symbols on overlay call stubs.\n\ + --extra-overlay-stubs Add stubs on all calls out of overlay regions.\n\ + --local-store=lo:hi Valid address range.\n\ + --stack-analysis Estimate maximum stack requirement.\n\ + --emit-stack-syms Add __stack_func giving stack needed for each func.\n" + )); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_SPU_PLUGIN: + spu_elf_plugin (1); + break; + + case OPTION_SPU_NO_OVERLAYS: + no_overlays = 1; + break; + + case OPTION_SPU_STUB_SYMS: + emit_stub_syms = 1; + break; + + case OPTION_SPU_NON_OVERLAY_STUBS: + non_overlay_stubs = 1; + break; + + case OPTION_SPU_LOCAL_STORE: + { + char *end; + local_store_lo = strtoul (optarg, &end, 0); + if (*end == '\'':'\'') + { + local_store_hi = strtoul (end + 1, &end, 0); + if (*end == 0) + break; + } + einfo (_("%P%F: invalid --local-store address range `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_STACK_ANALYSIS: + stack_analysis = 1; + break; + + case OPTION_SPU_STACK_SYMS: + emit_stack_syms = 1; + break; +' + +LDEMUL_AFTER_OPEN=spu_after_open +LDEMUL_BEFORE_ALLOCATION=spu_before_allocation +LDEMUL_FINISH=gld${EMULATION_NAME}_finish diff --git a/ld/emultempl/sunos.em b/ld/emultempl/sunos.em index a480558c90691..53a572a909d45 100644 --- a/ld/emultempl/sunos.em +++ b/ld/emultempl/sunos.em @@ -10,7 +10,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* SunOS emulation code for ${EMULATION_NAME} Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> SunOS shared library support by Ian Lance Taylor <ian@cygnus.com> @@ -32,8 +32,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libiberty.h" #include "safe-ctype.h" @@ -160,7 +160,7 @@ gld${EMULATION_NAME}_find_so (lang_input_statement_type *inp) || ! inp->dynamic) return; - ASSERT (strncmp (inp->local_sym_name, "-l", 2) == 0); + ASSERT (CONST_STRNEQ (inp->local_sym_name, "-l")); for (search = search_head; search != NULL; search = search->next) { @@ -273,7 +273,7 @@ gld${EMULATION_NAME}_search_dir const char *s; int found_maj, found_min; - if (strncmp (entry->d_name, "lib", 3) != 0 + if (! CONST_STRNEQ (entry->d_name, "lib") || strncmp (entry->d_name + 3, filename, len) != 0) continue; @@ -288,7 +288,7 @@ gld${EMULATION_NAME}_search_dir native linker does not. This is more convenient for packages which just generate .so files for shared libraries, as on ELF systems. */ - if (strncmp (entry->d_name + 3 + len, ".so", 3) != 0) + if (! CONST_STRNEQ (entry->d_name + 3 + len, ".so")) continue; if (entry->d_name[6 + len] == '\0') ; @@ -400,7 +400,7 @@ gld${EMULATION_NAME}_after_open (void) if (global_found) continue; - if (strncmp (lname, "-l", 2) != 0) + if (! CONST_STRNEQ (lname, "-l")) { bfd *abfd; @@ -586,7 +586,7 @@ gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) { if (s->filename == NULL) return; - if (strncmp (global_needed->name, "-l", 2) != 0) + if (! CONST_STRNEQ (global_needed->name, "-l")) { if (strcmp (s->filename, global_needed->name) == 0) global_found = TRUE; @@ -605,7 +605,7 @@ gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) else ++sname; - if (strncmp (sname, "lib", 3) != 0) + if (! CONST_STRNEQ (sname, "lib")) return; sname += 3; diff --git a/ld/emultempl/ticoff.em b/ld/emultempl/ticoff.em index 0382bbdd8658e..113c2b42d7d00 100644 --- a/ld/emultempl/ticoff.em +++ b/ld/emultempl/ticoff.em @@ -3,7 +3,8 @@ (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, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright 1999, 2000, 2002, 2003, 2004, 2007 + 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 @@ -24,8 +25,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_IS_${EMULATION_NAME} -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "getopt.h" diff --git a/ld/emultempl/vanilla.em b/ld/emultempl/vanilla.em index 2124852687340..ece005e8b6e4c 100644 --- a/ld/emultempl/vanilla.em +++ b/ld/emultempl/vanilla.em @@ -2,7 +2,7 @@ # It does some substitutions. cat >e${EMULATION_NAME}.c <<EOF /* A vanilla emulation with no defaults - Copyright 1991, 1992, 1994, 2000, 2001, 2002, 2003 + Copyright 1991, 1992, 1994, 2000, 2001, 2002, 2003, 2007 Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com @@ -22,9 +22,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" - +#include "bfd.h" #include "ld.h" #include "ldmisc.h" diff --git a/ld/emultempl/vxworks.em b/ld/emultempl/vxworks.em index eafbb58d8ef08..b03419fe3fc1b 100644 --- a/ld/emultempl/vxworks.em +++ b/ld/emultempl/vxworks.em @@ -7,18 +7,27 @@ cat >>e${EMULATION_NAME}.c <<EOF static int force_dynamic; static void +vxworks_before_parse (void) +{ + ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse} (); + config.rpath_separator = ';'; +} + +static void vxworks_after_open (void) { ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open} (); if (force_dynamic && link_info.input_bfds + && output_bfd->xvec->flavour == bfd_target_elf_flavour && !_bfd_elf_link_create_dynamic_sections (link_info.input_bfds, &link_info)) einfo ("%X%P: Cannot create dynamic sections %E\n"); if (!force_dynamic && !link_info.shared + && output_bfd->xvec->flavour == bfd_target_elf_flavour && elf_hash_table (&link_info)->dynamic_sections_created) einfo ("%X%P: Dynamic sections created in non-dynamic link\n"); } @@ -46,4 +55,27 @@ PARSE_AND_LIST_ARGS_CASES=$PARSE_AND_LIST_ARGS_CASES' break; ' -LDEMUL_AFTER_OPEN=vxworks_after_open +# Hook in our routines above. There are three possibilities: +# +# (1) VXWORKS_BASE_EM_FILE did not set the hook's LDEMUL_FOO variable. +# We want to define LDEMUL_FOO to vxworks_foo in that case, +# +# (2) VXWORKS_BASE_EM_FILE set the hook's LDEMUL_FOO variable to +# gld${EMULATION_NAME}_foo. This means that the file has +# replaced elf32.em's default definition, so we simply #define +# the current value of LDEMUL_FOO to vxworks_foo. +# +# (3) VXWORKS_BASE_EM_FILE set the hook's LDEMUL_FOO variable to +# something other than gld${EMULATION_NAME}_foo. We handle +# this case in the same way as (1). +for override in before_parse after_open; do + var="LDEMUL_`echo ${override} | tr a-z A-Z`" + eval value=\$${var} + if test "${value}" = "gld${EMULATION_NAME}_${override}"; then + cat >>e${EMULATION_NAME}.c <<EOF +#define ${value} vxworks_${override} +EOF + else + eval $var=vxworks_${override} + fi +done diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index f5d2ba9ceae53..e303e59ce52a5 100644 --- a/ld/emultempl/xtensaelf.em +++ b/ld/emultempl/xtensaelf.em @@ -16,7 +16,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301 USA. # # This file is sourced from elf32.em, and defines extra xtensa-elf @@ -30,6 +31,11 @@ cat >>e${EMULATION_NAME}.c <<EOF #include "elf/xtensa.h" #include "bfd.h" +/* Provide default values for new configuration settings. */ +#ifndef XSHAL_ABI +#define XSHAL_ABI 0 +#endif + static void xtensa_wild_group_interleave (lang_statement_union_type *); static void xtensa_colocate_output_literals (lang_statement_union_type *); static void xtensa_strip_inconsistent_linkonce_sections @@ -128,25 +134,17 @@ replace_insn_sec_with_prop_sec (bfd *abfd, } } - /* Create a Property table section and relocation section for it. */ + /* Create a property table section for it. */ prop_sec_name = strdup (prop_sec_name); - prop_sec = bfd_make_section (abfd, prop_sec_name); + prop_sec = bfd_make_section_with_flags + (abfd, prop_sec_name, bfd_get_section_flags (abfd, insn_sec)); if (prop_sec == NULL - || ! bfd_set_section_flags (abfd, prop_sec, - bfd_get_section_flags (abfd, insn_sec)) || ! bfd_set_section_alignment (abfd, prop_sec, 2)) { *error_message = _("could not create new section"); goto cleanup; } - if (! bfd_set_section_flags (abfd, prop_sec, - bfd_get_section_flags (abfd, insn_sec)) - || ! bfd_set_section_alignment (abfd, prop_sec, 2)) - { - *error_message = _("could not set new section properties"); - goto cleanup; - } prop_sec->size = entry_count * 12; prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size); elf_section_data (prop_sec)->this_hdr.contents = prop_contents; @@ -196,7 +194,7 @@ replace_insn_sec_with_prop_sec (bfd *abfd, for (entry = 0; entry < entry_count; ++entry) { unsigned value; - unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_INSN_NO_TRANSFORM + unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM | XTENSA_PROP_INSN_NO_REORDER); value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0); bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0); @@ -267,8 +265,7 @@ replace_instruction_table_sections (bfd *abfd, asection *sec) insn_sec_name = INSN_SEC_BASE_NAME; prop_sec_name = PROP_SEC_BASE_NAME; } - else if (strncmp (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME, - strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)) == 0) + else if (CONST_STRNEQ (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME)) { insn_sec_name = sec_name; owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20); @@ -298,17 +295,13 @@ replace_instruction_table_sections (bfd *abfd, asection *sec) static void elf_xtensa_after_open (void) { - bfd *abfd; - /* First call the ELF version. */ gld${EMULATION_NAME}_after_open (); /* Now search the input files looking for instruction table sections. */ - for (abfd = link_info.input_bfds; - abfd != NULL; - abfd = abfd->link_next) + LANG_FOR_EACH_INPUT_STATEMENT (f) { - asection *sec = abfd->sections; + asection *sec = f->the_bfd->sections; asection *next_sec; /* Do not use bfd_map_over_sections here since we are removing @@ -316,20 +309,122 @@ elf_xtensa_after_open (void) while (sec != NULL) { next_sec = sec->next; - replace_instruction_table_sections (abfd, sec); + replace_instruction_table_sections (f->the_bfd, sec); sec = next_sec; } } } +static bfd_boolean +xt_config_info_unpack_and_check (char *data, + bfd_boolean *pmismatch, + char **pmsg) +{ + char *d, *key; + unsigned num; + + *pmismatch = FALSE; + + d = data; + while (*d) + { + key = d; + d = strchr (d, '='); + if (! d) + goto error; + + /* Overwrite the equal sign. */ + *d++ = 0; + + /* Check if this is a quoted string or a number. */ + if (*d == '"') + { + /* No string values are currently checked by LD; + just skip over the quotes. */ + d++; + d = strchr (d, '"'); + if (! d) + goto error; + /* Overwrite the trailing quote. */ + *d++ = 0; + } + else + { + if (*d == 0) + goto error; + num = strtoul (d, &d, 0); + + if (! strcmp (key, "ABI")) + { + if (num != XSHAL_ABI) + { + *pmismatch = TRUE; + *pmsg = "ABI does not match"; + } + } + else if (! strcmp (key, "USE_ABSOLUTE_LITERALS")) + { + if (num != XSHAL_USE_ABSOLUTE_LITERALS) + { + *pmismatch = TRUE; + *pmsg = "incompatible use of the Extended L32R option"; + } + } + } + + if (*d++ != '\n') + goto error; + } + + return TRUE; + + error: + return FALSE; +} + + +#define XTINFO_NAME "Xtensa_Info" +#define XTINFO_NAMESZ 12 +#define XTINFO_TYPE 1 + +static void +check_xtensa_info (bfd *abfd, asection *info_sec) +{ + char *data, *errmsg = ""; + bfd_boolean mismatch; + + data = xmalloc (info_sec->size); + if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size)) + einfo (_("%F%P:%B: cannot read contents of section %A\n"), abfd, info_sec); + + if (info_sec->size > 24 + && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4) + && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ + && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE + && strcmp (data + 12, XTINFO_NAME) == 0 + && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ, + &mismatch, &errmsg)) + { + if (mismatch) + einfo (_("%P:%B: warning: incompatible Xtensa configuration (%s)\n"), + abfd, errmsg); + } + else + einfo (_("%P:%B: warning: cannot parse .xtensa.info section\n"), abfd); + + free (data); +} + + /* This is called after the sections have been attached to output sections, but before any sizes or addresses have been set. */ static void elf_xtensa_before_allocation (void) { - bfd *in_bfd; + asection *info_sec, *first_info_sec; + bfd *first_bfd; bfd_boolean is_big_endian = XCHAL_HAVE_BE; /* Check that the output endianness matches the Xtensa @@ -350,18 +445,80 @@ elf_xtensa_before_allocation (void) "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. */ + /* Keep track of the first input .xtensa.info section, and as a fallback, + the first input bfd where a .xtensa.info section could be created. + After the input .xtensa.info has been checked, the contents of the + first one will be replaced with the output .xtensa.info table. */ + first_info_sec = 0; + first_bfd = 0; - for (in_bfd = link_info.input_bfds; - in_bfd != NULL; - in_bfd = in_bfd->link_next) + LANG_FOR_EACH_INPUT_STATEMENT (f) { - 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")); + /* Check that the endianness for each input file matches the output. + The merge_private_bfd_data hook has already reported any mismatches + as errors, but those errors are not fatal. At this point, we + cannot go any further if there are any mismatches. */ + if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG)) + einfo (_("%F%P: cross-endian linking for %B not supported\n"), + f->the_bfd); + + if (! first_bfd) + first_bfd = f->the_bfd; + + info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info"); + if (! info_sec) + continue; + + if (! first_info_sec) + first_info_sec = info_sec; + + /* Unpack the .xtensa.info section and check it against the current + Xtensa configuration. */ + check_xtensa_info (f->the_bfd, info_sec); + + /* Do not include this copy of .xtensa.info in the output. */ + info_sec->size = 0; + info_sec->flags |= SEC_EXCLUDE; + } + + /* Reuse the first .xtensa.info input section to hold the output + .xtensa.info; or, if none were found, create a new section in the + first input bfd (assuming there is one). */ + info_sec = first_info_sec; + if (! info_sec && first_bfd) + { + info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info", + SEC_HAS_CONTENTS | SEC_READONLY); + if (! info_sec) + einfo (_("%F%P: failed to create .xtensa.info section\n")); + } + if (info_sec) + { + int xtensa_info_size; + char *data; + + info_sec->flags &= ~SEC_EXCLUDE; + info_sec->flags |= SEC_IN_MEMORY; + + data = xmalloc (100); + sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n", + XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI); + xtensa_info_size = strlen (data) + 1; + + /* Add enough null terminators to pad to a word boundary. */ + do + data[xtensa_info_size++] = 0; + while ((xtensa_info_size & 3) != 0); + + info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size; + info_sec->contents = xmalloc (info_sec->size); + bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0); + bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4); + bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8); + memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ); + memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size); + free (data); } /* Enable relaxation by default if the "--no-relax" option was not @@ -1185,7 +1342,7 @@ input_section_linked (asection *sec) } -/* Strip out any linkonce literal sections or property tables where the +/* Strip out any linkonce property tables or XCC exception tables where the associated linkonce text is from a different object file. Normally, a matching set of linkonce sections is taken from the same object file, but sometimes the files are compiled differently so that some of the @@ -1200,28 +1357,33 @@ is_inconsistent_linkonce_section (asection *sec) { bfd *abfd = sec->owner; const char *sec_name = bfd_get_section_name (abfd, sec); - char *prop_tag = 0; + const char *name; if ((bfd_get_section_flags (abfd, sec) & SEC_LINK_ONCE) == 0 || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0) return FALSE; - /* Check if this is an Xtensa property section. */ - if (strncmp (sec_name + linkonce_len, "p.", 2) == 0) - prop_tag = "p."; - else if (strncmp (sec_name + linkonce_len, "prop.", 5) == 0) - prop_tag = "prop."; - if (prop_tag) + /* Check if this is an Xtensa property section or an exception table + for Tensilica's XCC compiler. */ + name = sec_name + linkonce_len; + if (CONST_STRNEQ (name, "prop.")) + name = strchr (name + 5, '.') + 1; + else if (name[1] == '.' + && (name[0] == 'p' || name[0] == 'e' || name[0] == 'h')) + name += 2; + else + name = 0; + + if (name) { - int tag_len = strlen (prop_tag); - char *dep_sec_name = xmalloc (strlen (sec_name)); + char *dep_sec_name = xmalloc (strlen (sec_name) + 1); asection *dep_sec; /* Get the associated linkonce text section and check if it is included in the link. If not, this section is inconsistent and should be stripped. */ - strcpy (dep_sec_name, ".gnu.linkonce."); - strcat (dep_sec_name, sec_name + linkonce_len + tag_len); + strcpy (dep_sec_name, ".gnu.linkonce.t."); + strcat (dep_sec_name, name); dep_sec = bfd_get_section_by_name (abfd, dep_sec_name); if (dep_sec == NULL || ! input_section_linked (dep_sec)) { @@ -1249,6 +1411,7 @@ xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist) case lang_input_section_enum: if (is_inconsistent_linkonce_section (s->input_section.section)) { + s->input_section.section->output_section = bfd_abs_section_ptr; *s_p = s_next; continue; } |