X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Femultempl%2Fpe.em;h=37146ab59f843f9e248f9232f3812e269233a16c;hb=c553bb910d30224f6d5e1e10a67a839093e97fa0;hp=b556fac90d841772070de37490afd69e08f01476;hpb=45b1f63c8cdded5c3b874abc87b02ee079ac4e93;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index b556fac90d..37146ab59f 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -1,10 +1,16 @@ # This shell script emits a C file. -*- C -*- # It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi rm -f e${EMULATION_NAME}.c (echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) cat >>e${EMULATION_NAME}.c < /* Permit the emulation parameters to override the default section alignment by setting OVERRIDE_SECTION_ALIGNMENT. FIXME: This makes @@ -86,27 +104,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define PE_DEF_FILE_ALIGNMENT 0x00000200 #endif -#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 - static void gld_${EMULATION_NAME}_set_symbols PARAMS ((void)); static void gld_${EMULATION_NAME}_after_open PARAMS ((void)); static void gld_${EMULATION_NAME}_before_parse PARAMS ((void)); static void gld_${EMULATION_NAME}_after_parse PARAMS ((void)); static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void)); +static asection *output_prev_sec_find + PARAMS ((lang_output_section_statement_type *)); static boolean gld_${EMULATION_NAME}_place_orphan PARAMS ((lang_input_statement_type *, asection *)); static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *)); static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **)); static void gld_${EMULATION_NAME}_finish PARAMS ((void)); -static boolean gld_${EMULATION_NAME}_open_dynamic_archive +static boolean gld_${EMULATION_NAME}_open_dynamic_archive PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *)); +static void gld_${EMULATION_NAME}_list_options PARAMS ((FILE *)); +static void set_pe_name PARAMS ((char *, long)); +static void set_pe_subsystem PARAMS ((void)); +static void set_pe_value PARAMS ((char *)); +static void set_pe_stack_heap PARAMS ((char *, char *)); + +#ifdef DLL_SUPPORT +static boolean pe_undef_cdecl_match + PARAMS ((struct bfd_link_hash_entry *, PTR)); +static void pe_fixup_stdcalls PARAMS ((void)); +static int make_import_fixup PARAMS ((arelent *, asection *)); +static void pe_find_data_imports PARAMS ((void)); +#endif + +static boolean pr_sym PARAMS ((struct bfd_hash_entry *, PTR string)); +static boolean gld_${EMULATION_NAME}_unrecognized_file + PARAMS ((lang_input_statement_type *)); +static boolean gld_${EMULATION_NAME}_recognized_file + PARAMS ((lang_input_statement_type *)); +static int gld_${EMULATION_NAME}_find_potential_libraries + PARAMS ((char *, lang_input_statement_type *)); + static struct internal_extra_pe_aouthdr pe; static int dll; @@ -119,6 +152,7 @@ static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */ static char *pe_out_def_filename = NULL; static char *pe_implib_filename = NULL; static int pe_enable_auto_image_base = 0; +static char *pe_dll_search_prefix = NULL; #endif extern const char *output_filename; @@ -126,10 +160,20 @@ extern const char *output_filename; static void gld_${EMULATION_NAME}_before_parse() { + const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}"); + if (arch) + { + ldfile_output_architecture = arch->arch; + ldfile_output_machine = arch->mach; + ldfile_output_machine_name = arch->printable_name; + } + else + ldfile_output_architecture = bfd_arch_${ARCH}; output_filename = "${EXECUTABLE_NAME:-a.exe}"; - ldfile_output_architecture = bfd_arch_${ARCH}; #ifdef DLL_SUPPORT + config.dynamic_link = true; config.has_shared = 1; + link_info.pei386_auto_import = -1; #if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2) #if defined TARGET_IS_mipspe || defined TARGET_IS_armpe @@ -172,14 +216,19 @@ gld_${EMULATION_NAME}_before_parse() #define OPTION_IMP_COMPAT (OPTION_WARN_DUPLICATE_EXPORTS + 1) #define OPTION_ENABLE_AUTO_IMAGE_BASE (OPTION_IMP_COMPAT + 1) #define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1) - -static struct option longopts[] = -{ +#define OPTION_DLL_SEARCH_PREFIX (OPTION_DISABLE_AUTO_IMAGE_BASE + 1) +#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_DLL_SEARCH_PREFIX + 1) +#define OPTION_DLL_ENABLE_AUTO_IMPORT (OPTION_NO_DEFAULT_EXCLUDES + 1) +#define OPTION_DLL_DISABLE_AUTO_IMPORT (OPTION_DLL_ENABLE_AUTO_IMPORT + 1) +#define OPTION_ENABLE_EXTRA_PE_DEBUG (OPTION_DLL_DISABLE_AUTO_IMPORT + 1) +#define OPTION_EXCLUDE_LIBS (OPTION_ENABLE_EXTRA_PE_DEBUG + 1) + +static struct option longopts[] = { /* 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}, + {"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}, @@ -199,6 +248,7 @@ static struct option longopts[] = {"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}, @@ -208,6 +258,11 @@ static struct option longopts[] = {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE}, + {"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX}, + {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES}, + {"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT}, + {"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT}, + {"enable-extra-pe-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG}, #endif {NULL, no_argument, NULL, 0} }; @@ -247,7 +302,7 @@ static definfo init[] = #endif D(MinorSubsystemVersion,"__minor_subsystem_version__", 0), D(Subsystem,"__subsystem__", ${SUBSYSTEM}), - D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x2000000), + 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), @@ -280,16 +335,25 @@ gld_${EMULATION_NAME}_list_options (file) 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 Generate import library\n")); fprintf (file, _(" --output-def 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")); - fprintf (file, _(" create __imp_ as well.\n")); - fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n")); - fprintf (file, _(" unless user specifies one\n")); + fprintf (file, _(" --compat-implib Create backward compatible import libs;\n\ + create __imp_ 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= When linking dynamically to a dll without an\n\ + importlib, use .dll \n\ + in preference to lib.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-extra-pe-debug Enable verbose debug output when building\n\ + or linking to DLLs (esp. auto-import)\n")); #endif } @@ -319,7 +383,7 @@ set_pe_subsystem () const char *sver; int len; int i; - static const struct + static const struct { const char *name; const int value; @@ -387,12 +451,12 @@ set_pe_subsystem () entry = alc_entry; } - lang_add_entry (entry, 1); + lang_add_entry (entry, 0); return; } } - + einfo (_("%P%F: invalid subsystem type %s\n"), optarg); } @@ -401,12 +465,12 @@ set_pe_subsystem () static void set_pe_value (name) char *name; - + { char *end; - + set_pe_name (name, strtoul (optarg, &end, 0)); - + if (end == optarg) einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); @@ -419,7 +483,7 @@ set_pe_stack_heap (resname, comname) char *comname; { set_pe_value (resname); - + if (*optarg == ',') { optarg++; @@ -472,10 +536,10 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) break; /* PE options */ - case OPTION_HEAP: + case OPTION_HEAP: set_pe_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); break; - case OPTION_STACK: + case OPTION_STACK: set_pe_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); break; case OPTION_SUBSYSTEM: @@ -525,7 +589,10 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) pe_dll_export_everything = 1; break; case OPTION_EXCLUDE_SYMBOLS: - pe_dll_add_excludes (optarg); + pe_dll_add_excludes (optarg, 0); + break; + case OPTION_EXCLUDE_LIBS: + pe_dll_add_excludes (optarg, 1); break; case OPTION_KILL_ATS: pe_dll_kill_ats = 1; @@ -554,6 +621,21 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) case OPTION_DISABLE_AUTO_IMAGE_BASE: pe_enable_auto_image_base = 0; break; + case OPTION_DLL_SEARCH_PREFIX: + pe_dll_search_prefix = xstrdup( optarg ); + break; + case OPTION_NO_DEFAULT_EXCLUDES: + pe_dll_do_default_excludes = 0; + break; + case OPTION_DLL_ENABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 1; + break; + case OPTION_DLL_DISABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 0; + break; + case OPTION_ENABLE_EXTRA_PE_DEBUG: + pe_dll_extra_pe_debug = 1; + break; #endif } return 1; @@ -561,7 +643,7 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) #ifdef DLL_SUPPORT -static unsigned long +static unsigned long strhash (const char *str) { const unsigned char *s; @@ -632,7 +714,8 @@ gld_${EMULATION_NAME}_set_symbols () { long val = init[j].value; lang_assignment_statement_type *rv; - rv = lang_add_assignment (exp_assop ('=' ,init[j].symbol, exp_intop (val))); + 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)) @@ -648,7 +731,7 @@ gld_${EMULATION_NAME}_set_symbols () } /* Restore the pointer. */ stat_ptr = save; - + if (pe.FileAlignment > pe.SectionAlignment) { @@ -675,10 +758,17 @@ gld_${EMULATION_NAME}_after_parse () opened, so registering the symbol as undefined will make a difference. */ - if (! link_info.relocateable && entry_symbol != NULL) - ldlang_add_undef (entry_symbol); + if (! link_info.relocateable && entry_symbol.name != NULL) + ldlang_add_undef (entry_symbol.name); } +/* pe-dll.c directly accesses pe_data_import_dll, + so it must be defined outside of #ifdef DLL_SUPPORT. + Note - this variable is deliberately not initialised. + This allows it to be treated as a common varaible, and only + exist in one incarnation in a multiple target enabled linker. */ +char * pe_data_import_dll; + #ifdef DLL_SUPPORT static struct bfd_link_hash_entry *pe_undef_found_sym; @@ -687,14 +777,15 @@ pe_undef_cdecl_match (h, string) struct bfd_link_hash_entry *h; PTR string; { - int sl = strlen (string); + int sl; + sl = strlen (string); /* silence compiler warning */ if (h->type == bfd_link_hash_defined && strncmp (h->root.string, string, sl) == 0 && h->root.string[sl] == '@') - { - pe_undef_found_sym = h; - return false; - } + { + pe_undef_found_sym = h; + return false; + } return true; } @@ -704,6 +795,11 @@ pe_fixup_stdcalls () static int gave_warning_message = 0; struct bfd_link_hash_entry *undef, *sym; char *at; + if (pe_dll_extra_pe_debug) + { + printf ("%s\n", __FUNCTION__); + } + for (undef = link_info.hash->undefs; undef; undef=undef->next) if (undef->type == bfd_link_hash_undefined) { @@ -762,16 +858,142 @@ pe_fixup_stdcalls () } } } + +static int +make_import_fixup (rel, s) + arelent *rel; + asection *s; +{ + struct symbol_cache_entry *sym = *rel->sym_ptr_ptr; + + if (pe_dll_extra_pe_debug) + { + printf ("arelent: %s@%#lx: add=%li\n", sym->name, + (long) rel->address, (long) rel->addend); + } + + { + int addend = 0; + 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); + } + + if (addend == 0) + pe_create_import_fixup (rel); + else + { + einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), + s->owner, s, rel->address, sym->name); + einfo ("%X"); + } + } + + return 1; +} + +static void +pe_find_data_imports () +{ + struct bfd_link_hash_entry *undef, *sym; + for (undef = link_info.hash->undefs; undef; undef=undef->next) + { + if (undef->type == bfd_link_hash_undefined) + { + /* C++ symbols are *long* */ + char buf[4096]; + if (pe_dll_extra_pe_debug) + { + printf ("%s:%s\n", __FUNCTION__, undef->root.string); + } + sprintf (buf, "__imp_%s", undef->root.string); + + sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + if (sym && sym->type == bfd_link_hash_defined) + { + if (link_info.pei386_auto_import == -1) + info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), + undef->root.string, buf); + { + bfd *b = sym->u.def.section->owner; + asymbol **symbols; + int nsyms, symsize, i; + + symsize = bfd_get_symtab_upper_bound (b); + symbols = (asymbol **) xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (i = 0; i < nsyms; i++) + { + if (memcmp(symbols[i]->name, "__head_", + sizeof ("__head_") - 1)) + continue; + if (pe_dll_extra_pe_debug) + { + printf ("->%s\n", symbols[i]->name); + } + pe_data_import_dll = (char*) (symbols[i]->name + + sizeof ("__head_") - 1); + break; + } + } + + pe_walk_relocs_of_symbol (&link_info, undef->root.string, + make_import_fixup); + + /* let's differentiate it somehow from defined */ + undef->type = bfd_link_hash_defweak; + /* we replace original name with __imp_ prefixed, this + 1) may trash memory 2) leads to duplicate symbol generation. + Still, IMHO it's better than having name poluted. */ + undef->root.string = sym->root.string; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + } + } + } +} #endif /* DLL_SUPPORT */ +static boolean +pr_sym (h, string) + struct bfd_hash_entry *h; + PTR string ATTRIBUTE_UNUSED; +{ + if (pe_dll_extra_pe_debug) + { + printf("+%s\n",h->string); + } + return true; +} + + static void gld_${EMULATION_NAME}_after_open () { + + if (pe_dll_extra_pe_debug) + { + bfd *a; + struct bfd_link_hash_entry *sym; + printf ("%s()\n", __FUNCTION__); + + for (sym = link_info.hash->undefs; sym; sym=sym->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); + } + } + /* 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)->pe) + + if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == 0) einfo (_("%F%P: PE operations on non PE file.\n")); pe_data (output_bfd)->pe_opthdr = pe; @@ -781,6 +1003,8 @@ gld_${EMULATION_NAME}_after_open () if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */ pe_fixup_stdcalls (); + pe_find_data_imports (); + pe_process_import_defs(output_bfd, &link_info); if (link_info.shared) pe_dll_build_sections (output_bfd, &link_info); @@ -813,6 +1037,116 @@ gld_${EMULATION_NAME}_after_open () } #endif + { + /* This next chunk of code tries to detect the case where you have + two import libraries for the same DLL (specifically, + symbolically linking libm.a and libc.a in cygwin to + libcygwin.a). In those cases, it's possible for function + thunks from the second implib to be used but without the + head/tail objects, causing an improper import table. We detect + those cases and rename the "other" import libraries to match + the one the head/tail come from, so that the linker will sort + things nicely and produce a valid import table. */ + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + int idata2 = 0, reloc_count=0, is_imp = 0; + asection *sec; + + /* See if this is an import library thunk. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strcmp (sec->name, ".idata\$2") == 0) + idata2 = 1; + if (strncmp (sec->name, ".idata\$", 7) == 0) + 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 = (asymbol **) xmalloc (symsize); + symsize = bfd_canonicalize_symtab (is->the_bfd, symbols); + if (symsize < 0) + { + einfo ("%X%P: unable to process symbols: %E"); + return; + } + + relocs = (arelent **) 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 symbol_cache_entry *s; + struct bfd_link_hash_entry * blhe; + bfd *other_bfd; + 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 = blhe->u.def.section->owner; + + if (strcmp (is->the_bfd->my_archive->filename, + other_bfd->my_archive->filename) == 0) + continue; + + /* Rename this implib to match the other. */ + n = (char *) xmalloc (strlen (other_bfd->my_archive->filename) + 1); + + strcpy (n, other_bfd->my_archive->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; @@ -876,30 +1210,9 @@ gld_${EMULATION_NAME}_after_open () } } } - - { - LANG_FOR_EACH_INPUT_STATEMENT (is) - { - asection *sec; - char *new_name, seq; - - - if (is->the_bfd->my_archive) - for (sec = is->the_bfd->sections; sec; sec = sec->next) - if (strcmp (sec->name, ".idata\$7") == 0 - && sec->reloc_count == 0) - { - char *name = xmalloc (sec->_raw_size + 1); - bfd_get_section_contents (is->the_bfd, sec, name, 0, sec->_raw_size); - name[sec->_raw_size] = 0; - printf ("dj: implib \"%s\" for dll \"%s\" %d\n", - is->the_bfd->my_archive->filename, name, sec->_raw_size); - } - } - } } -static void +static void gld_${EMULATION_NAME}_before_allocation() { #ifdef TARGET_IS_ppcpe @@ -1041,7 +1354,7 @@ gld_${EMULATION_NAME}_unrecognized_file(entry) } #endif return false; - + } static boolean @@ -1080,7 +1393,7 @@ gld_${EMULATION_NAME}_finish () if (thumb_entry_symbol != NULL) { h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, false, false, true); - + if (h != (struct bfd_link_hash_entry *) NULL && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak) @@ -1088,27 +1401,27 @@ gld_${EMULATION_NAME}_finish () { 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 != NULL && entry_from_cmdline) + + if (entry_symbol.name != NULL && entry_from_cmdline) einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), - thumb_entry_symbol, entry_symbol); - entry_symbol = buffer; + thumb_entry_symbol, entry_symbol.name); + entry_symbol.name = buffer; } else einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); @@ -1129,13 +1442,49 @@ gld_${EMULATION_NAME}_finish () pe_exe_fill_sections (output_bfd, &link_info); } #endif - + if (pe_out_def_filename) pe_dll_generate_def_file (pe_out_def_filename); #endif /* DLL_SUPPORT */ + + /* I don't know where .idata gets set as code, but it shouldn't be */ + { + asection *asec = bfd_get_section_by_name (output_bfd, ".idata"); + if (asec) + { + asec->flags &= ~SEC_CODE; + asec->flags |= SEC_DATA; + } + } } +/* Find the last output section before given output statement. + Used by place_orphan. */ + +static asection * +output_prev_sec_find (os) + lang_output_section_statement_type *os; +{ + asection *s = (asection *) NULL; + lang_statement_union_type *u; + lang_output_section_statement_type *lookup; + + for (u = lang_output_section_statement.head; + u != (lang_statement_union_type *) NULL; + u = lookup->next) + { + lookup = &u->output_section_statement; + if (lookup == os) + return s; + + if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) + s = lookup->bfd_section; + } + + return NULL; +} + /* Place an orphan section. We use this to put sections in a reasonable place in the file, and @@ -1165,6 +1514,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s) const char *secname; char *hold_section_name; char *dollar = NULL; + const char *ps = NULL; lang_output_section_statement_type *os; lang_statement_list_type add_child; @@ -1185,10 +1535,13 @@ gld_${EMULATION_NAME}_place_orphan (file, s) lang_list_init (&add_child); if (os != NULL - && os->bfd_section != NULL - && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0) + && (os->bfd_section == NULL + || ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0)) { - wild_doit (&add_child, s, os, file); + /* We already have an output section statement with this + name, and its bfd section, if any, has compatible flags. */ + lang_add_section (&add_child, s, os, file); } else { @@ -1228,7 +1581,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s) /* 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 allocateable characteristics. */ + different loadable or allocatable characteristics. */ outsecname = xstrdup (hold_section_name); if (bfd_get_section_by_name (output_bfd, outsecname) != NULL) { @@ -1256,6 +1609,26 @@ gld_${EMULATION_NAME}_place_orphan (file, s) stat_ptr = &add; lang_list_init (stat_ptr); + if (config.build_constructors) + { + /* If the name of the section is representable in C, then create + symbols to mark the start and the end of the section. */ + for (ps = outsecname; *ps != '\0'; ps++) + if (! isalnum ((unsigned char) *ps) && *ps != '_') + break; + if (*ps == '\0') + { + char *symname; + etree_type *e_align; + + symname = (char *) xmalloc (ps - outsecname + sizeof "___start_"); + sprintf (symname, "___start_%s", outsecname); + e_align = exp_unop (ALIGN_K, + exp_intop ((bfd_vma) 1 << s->alignment_power)); + lang_add_assignment (exp_assop ('=', symname, e_align)); + } + } + if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) address = exp_intop ((bfd_vma) 0); else @@ -1272,63 +1645,101 @@ gld_${EMULATION_NAME}_place_orphan (file, s) (etree_type *) NULL, (etree_type *) NULL); - wild_doit (&add_child, s, os, file); + lang_add_section (&add_child, s, os, file); lang_leave_output_section_statement ((bfd_vma) 0, "*default*", - (struct lang_output_section_phdr_list *) NULL, "*default*"); + (struct lang_output_section_phdr_list *) NULL, NULL); + + if (config.build_constructors && *ps == '\0') + { + char *symname; + + /* lang_leave_ouput_section_statement resets stat_ptr. Put + stat_ptr back where we want it. */ + if (place != NULL) + stat_ptr = &add; + + symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_"); + sprintf (symname, "___stop_%s", outsecname); + lang_add_assignment (exp_assop ('=', symname, + exp_nameop (NAME, "."))); + } stat_ptr = old; - if (place != NULL) + if (place != NULL && os->bfd_section != NULL) { asection *snew, **pps; snew = os->bfd_section; - if (place->os->bfd_section != NULL || place->section != NULL) + + /* Shuffle the bfd section list to make the output file look + neater. This is really only cosmetic. */ + if (place->section == NULL) { - /* Shuffle the section to make the output file look neater. */ - if (place->section == NULL) - { -#if 0 - /* Finding the end of the list is a little tricky. We - make a wild stab at it by comparing section flags. */ - flagword first_flags = place->os->bfd_section->flags; - for (pps = &place->os->bfd_section->next; - *pps != NULL && (*pps)->flags == first_flags; - pps = &(*pps)->next) - ; - place->section = pps; -#else - /* Put orphans after the first section on the list. */ - place->section = &place->os->bfd_section->next; -#endif - } + asection *bfd_section = place->os->bfd_section; - /* Unlink the section. */ - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - *pps = snew->next; + /* If the output statement hasn't been used to place + any input sections (and thus doesn't have an output + bfd_section), look for the closest prior output statement + having an output section. */ + if (bfd_section == NULL) + bfd_section = output_prev_sec_find (place->os); - /* Now tack it on to the "place->os" section list. */ - snew->next = *place->section; - *place->section = snew; + if (bfd_section != NULL && bfd_section != snew) + place->section = &bfd_section->next; } - place->section = &snew->next; /* Save the end of this list. */ - if (place->stmt == NULL) + if (place->section != NULL) { - /* Put the new statement list right at the head. */ - *add.tail = place->os->header.next; - place->os->header.next = add.head; + /* Unlink the section. */ + for (pps = &output_bfd->sections; + *pps != snew; + pps = &(*pps)->next) + ; + bfd_section_list_remove (output_bfd, pps); + + /* Now tack it on to the "place->os" section list. */ + bfd_section_list_insert (output_bfd, place->section, snew); } - else + + /* Save the end of this list. Further ophans of this type will + follow the one we've just added. */ + place->section = &snew->next; + + /* The following is non-cosmetic. We try to put the output + statements in some sort of reasonable order here, because + they determine the final load addresses of the orphan + sections. In addition, placing output statements in the + wrong order may require extra segments. For instance, + given a typical situation of all read-only sections placed + in one segment and following that a segment containing all + the read-write sections, we wouldn't want to place an orphan + read/write section before or amongst the read-only ones. */ + if (add.head != NULL) { - /* Put it after the last orphan statement we added. */ - *add.tail = *place->stmt; - *place->stmt = add.head; + if (place->stmt == NULL) + { + /* Put the new statement list right at the head. */ + *add.tail = place->os->header.next; + place->os->header.next = add.head; + } + else + { + /* Put it after the last orphan statement we added. */ + *add.tail = *place->stmt; + *place->stmt = add.head; + } + + /* Fix the global list pointer if we happened to tack our + new list at the tail. */ + if (*old->tail == add.head) + old->tail = add.tail; + + /* Save the end of this list. */ + place->stmt = add.tail; } - place->stmt = add.tail; /* Save the end of this list. */ } } @@ -1343,7 +1754,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s) sections. */ found_dollar = false; - for ( ; *pl != NULL; pl = &(*pl)->next) + for ( ; *pl != NULL; pl = &(*pl)->header.next) { lang_input_section_type *ls; const char *lname; @@ -1370,7 +1781,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s) if (add_child.head != NULL) { - add_child.head->next = *pl; + add_child.head->header.next = *pl; *pl = add_child.head; } } @@ -1395,8 +1806,11 @@ gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) filename = entry->filename; string = (char *) xmalloc (strlen (search->name) - + strlen (filename) + + strlen (filename) + sizeof "/lib.a.dll" +#ifdef DLL_SUPPORT + + (pe_dll_search_prefix ? strlen (pe_dll_search_prefix) : 0) +#endif + 1); /* Try "libfoo.dll.a" first (preferred explicit import library for dll's */ @@ -1423,17 +1837,42 @@ gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) take precedence over dll's) */ sprintf (string, "%s/lib%s.a", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) - { - /* Try "libfoo.dll" (preferred dll name) */ - sprintf (string, "%s/lib%s.dll", search->name, filename); - if (! ldfile_try_open_bfd (string, entry)) + { +#ifdef DLL_SUPPORT + if (pe_dll_search_prefix) + { + /* Try "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 { - /* Finally, try "foo.dll" (alternate dll name) */ - sprintf (string, "%s/%s.dll", search->name, filename); + /* Try "libfoo.dll" (preferred dll name) */ + sprintf (string, "%s/lib%s.dll", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) { - free (string); - return false; + /* 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; + } } } } @@ -1462,7 +1901,7 @@ EOF sc="-f stringify.sed" cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME} cat >>e${EMULATION_NAME}.c <