X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Femultempl%2Fpe.em;h=60882cef9095c174a17224d0af8355ab51637701;hb=837a17b36c9e297f4bf33727e25dfa9f38360c17;hp=1336a318999558b13daa777de987cc8d0b134c63;hpb=75be928bd2cbcc431c59bb3b9f20a7c002fc2022;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 1336a31899..60882cef90 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -7,14 +7,14 @@ else 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 <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c < Set size of the initial stack\n")); fprintf (file, _(" --subsystem [:] Set required OS subsystem [& version]\n")); fprintf (file, _(" --support-old-code Support interworking with old code\n")); + fprintf (file, _(" --[no-]leading-underscore Set explicit symbol underscore prefix mode\n")); fprintf (file, _(" --thumb-entry= Set the entry point to be Thumb \n")); + fprintf (file, _(" --[no-]insert-timestamp Use a real timestamp rather than zero (default).\n")); + fprintf (file, _(" This makes binaries non-deterministic\n")); #ifdef DLL_SUPPORT fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n")); fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n")); fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n")); fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n")); + fprintf (file, _(" --exclude-all-symbols Exclude all symbols from automatic export\n")); fprintf (file, _(" --exclude-libs lib,lib,... Exclude libraries from automatic export\n")); + fprintf (file, _(" --exclude-modules-for-implib mod,mod,...\n")); + fprintf (file, _(" Exclude objects, archive members from auto\n")); + fprintf (file, _(" export, place into import library instead.\n")); fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n")); fprintf (file, _(" --kill-at Remove @nn from exported symbols\n")); fprintf (file, _(" --out-implib 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, _(" --warn-duplicate-exports Warn about duplicate exports\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, _(" --enable-auto-image-base[=
] Automatically choose image base for DLLs\n\ + (optionally starting with address) unless\n\ + specifically set with --image-base\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\n\ an importlib, use .dll\n\ in preference to lib.dll \n")); - fprintf (file, _(" --enable-auto-import Do sophistcated linking of _sym to\n\ + fprintf (file, _(" --enable-auto-import Do sophisticated linking of _sym to\n\ __imp_sym for DATA references\n")); fprintf (file, _(" --disable-auto-import Do not auto-import DATA items from DLLs\n")); fprintf (file, _(" --enable-runtime-pseudo-reloc Work around auto-import limitations by\n\ @@ -346,6 +486,23 @@ gld_${EMULATION_NAME}_list_options (FILE *file) #endif fprintf (file, _(" --large-address-aware Executable supports virtual addresses\n\ greater than 2 gigabytes\n")); + fprintf (file, _(" --disable-large-address-aware Executable does not support virtual\n\ + addresses greater than 2 gigabytes\n")); + fprintf (file, _(" --enable-long-section-names Use long COFF section names even in\n\ + executable image files\n")); + fprintf (file, _(" --disable-long-section-names Never use long COFF section names, even\n\ + in object files\n")); + fprintf (file, _(" --dynamicbase Image base address may be relocated using\n\ + address space layout randomization (ASLR)\n")); + fprintf (file, _(" --forceinteg Code integrity checks are enforced\n")); + fprintf (file, _(" --nxcompat Image is compatible with data execution prevention\n")); + fprintf (file, _(" --no-isolation Image understands isolation but do not isolate the image\n")); + fprintf (file, _(" --no-seh Image does not use SEH. No SE handler may\n\ + be called in this image\n")); + fprintf (file, _(" --no-bind Do not bind this image\n")); + fprintf (file, _(" --wdmdriver Driver uses the WDM model\n")); + fprintf (file, _(" --tsaware Image is Terminal Server aware\n")); + fprintf (file, _(" --build-id[=STYLE] Generate build ID\n")); } @@ -353,50 +510,113 @@ static void set_pe_name (char *name, long val) { int i; + is_underscoring (); /* Find the name and set it. */ for (i = 0; init[i].ptr; i++) { - if (strcmp (name, init[i].symbol) == 0) + if (strcmp (name, GET_INIT_SYMBOL_NAME (i)) == 0) { init[i].value = val; init[i].inited = 1; + if (strcmp (name,"__image_base__") == 0) + set_pe_name (U ("__ImageBase"), val); return; } } abort (); } +static void +set_entry_point (void) +{ + const char *entry; + const char *initial_symbol_char; + int i; + + static const struct + { + const int value; + const char *entry; + } + v[] = + { + { 1, "NtProcessStartup" }, + { 2, "WinMainCRTStartup" }, + { 3, "mainCRTStartup" }, + { 7, "__PosixProcessStartup"}, + { 9, "WinMainCRTStartup" }, + {14, "mainCRTStartup" }, + { 0, NULL } + }; + + /* Entry point name for arbitrary subsystem numbers. */ + static const char default_entry[] = "mainCRTStartup"; + + if (link_info.shared || dll) + { +#if defined (TARGET_IS_i386pe) + entry = "DllMainCRTStartup@12"; +#else + entry = "DllMainCRTStartup"; +#endif + } + else + { + + for (i = 0; v[i].entry; i++) + if (v[i].value == pe_subsystem) + break; + + /* If no match, use the default. */ + if (v[i].entry != NULL) + entry = v[i].entry; + else + entry = default_entry; + } + + initial_symbol_char = (is_underscoring () != 0 ? "_" : ""); + + if (*initial_symbol_char != '\0') + { + char *alc_entry; + + /* lang_default_entry expects its argument to be permanently + allocated, so we don't free this string. */ + alc_entry = xmalloc (strlen (initial_symbol_char) + + strlen (entry) + + 1); + strcpy (alc_entry, initial_symbol_char); + strcat (alc_entry, entry); + entry = alc_entry; + } + + lang_default_entry (entry); +} static void set_pe_subsystem (void) { const char *sver; - 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 } + { "native", 1}, + { "windows", 2}, + { "console", 3}, + { "posix", 7}, + { "wince", 9}, + { "xbox", 14}, + { NULL, 0 } }; - /* Entry point name for arbitrary subsystem numbers. */ - static const char default_entry[] = "mainCRTStartup"; /* Check for the presence of a version number. */ sver = strchr (optarg, ':'); @@ -406,10 +626,10 @@ set_pe_subsystem (void) { len = sver - optarg; set_pe_name ("__major_subsystem_version__", - strtoul (sver + 1, &end, 0)); + strtoul (sver + 1, &end, 0)); if (*end == '.') set_pe_name ("__minor_subsystem_version__", - strtoul (end + 1, &end, 0)); + strtoul (end + 1, &end, 0)); if (*end != '\0') einfo (_("%P: warning: bad version number in -subsystem option\n")); } @@ -423,14 +643,8 @@ set_pe_subsystem (void) 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; + pe_subsystem = (int) temp_subsystem; } else { @@ -446,28 +660,10 @@ set_pe_subsystem (void) return; } - entry = v[i].entry; - subsystem = v[i].value; + pe_subsystem = v[i].value; } - set_pe_name ("__subsystem__", subsystem); - - initial_symbol_char = ${INITIAL_SYMBOL_CHAR}; - if (*initial_symbol_char != '\0') - { - char *alc_entry; - - /* lang_add_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_add_entry (entry, FALSE); + set_pe_name ("__subsystem__", pe_subsystem); return; } @@ -501,6 +697,7 @@ set_pe_stack_heap (char *resname, char *comname) einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); } +#define DEFAULT_BUILD_ID_STYLE "md5" static bfd_boolean gld${EMULATION_NAME}_handle_option (int optc) @@ -513,12 +710,7 @@ gld${EMULATION_NAME}_handle_option (int optc) 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); - } + einfo (_("%F%P: cannot open base file %s\n"), optarg); break; /* PE options. */ @@ -567,6 +759,21 @@ gld${EMULATION_NAME}_handle_option (int optc) case OPTION_THUMB_ENTRY: thumb_entry_symbol = optarg; break; + case OPTION_USE_NUL_PREFIXED_IMPORT_TABLES: + pe_use_nul_prefixed_import_tables = TRUE; + break; + case OPTION_NO_LEADING_UNDERSCORE: + pe_leading_underscore = 0; + break; + case OPTION_LEADING_UNDERSCORE: + pe_leading_underscore = 1; + break; + case OPTION_INSERT_TIMESTAMP: + insert_timestamp = TRUE; + break; + case OPTION_NO_INSERT_TIMESTAMP: + insert_timestamp = FALSE; + break; #ifdef DLL_SUPPORT case OPTION_OUT_DEF: pe_out_def_filename = xstrdup (optarg); @@ -575,10 +782,16 @@ gld${EMULATION_NAME}_handle_option (int optc) pe_dll_export_everything = 1; break; case OPTION_EXCLUDE_SYMBOLS: - pe_dll_add_excludes (optarg, 0); + pe_dll_add_excludes (optarg, EXCLUDESYMS); + break; + case OPTION_EXCLUDE_ALL_SYMBOLS: + pe_dll_exclude_all_symbols = 1; break; case OPTION_EXCLUDE_LIBS: - pe_dll_add_excludes (optarg, 1); + pe_dll_add_excludes (optarg, EXCLUDELIBS); + break; + case OPTION_EXCLUDE_MODULES_FOR_IMPLIB: + pe_dll_add_excludes (optarg, EXCLUDEFORIMPLIB); break; case OPTION_KILL_ATS: pe_dll_kill_ats = 1; @@ -603,6 +816,12 @@ gld${EMULATION_NAME}_handle_option (int optc) break; case OPTION_ENABLE_AUTO_IMAGE_BASE: pe_enable_auto_image_base = 1; + if (optarg && *optarg) + { + char *end; + pe_auto_image_base = strtoul (optarg, &end, 0); + /* XXX should check that we actually parsed something */ + } break; case OPTION_DISABLE_AUTO_IMAGE_BASE: pe_enable_auto_image_base = 0; @@ -620,8 +839,15 @@ gld${EMULATION_NAME}_handle_option (int optc) link_info.pei386_auto_import = 0; break; case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = + DEFAULT_PSEUDO_RELOC_VERSION; + break; + case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1: link_info.pei386_runtime_pseudo_reloc = 1; break; + case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2: + link_info.pei386_runtime_pseudo_reloc = 2; + break; case OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC: link_info.pei386_runtime_pseudo_reloc = 0; break; @@ -632,7 +858,56 @@ gld${EMULATION_NAME}_handle_option (int optc) case OPTION_LARGE_ADDRESS_AWARE: real_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE; break; + case OPTION_DISABLE_LARGE_ADDRESS_AWARE: + real_flags &= ~ IMAGE_FILE_LARGE_ADDRESS_AWARE; + break; + case OPTION_ENABLE_LONG_SECTION_NAMES: + pe_use_coff_long_section_names = 1; + break; + case OPTION_DISABLE_LONG_SECTION_NAMES: + pe_use_coff_long_section_names = 0; + break; +/* Get DLLCharacteristics bits */ + case OPTION_DYNAMIC_BASE: + pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + break; + case OPTION_FORCE_INTEGRITY: + pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; + break; + case OPTION_NX_COMPAT: + pe_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + break; + case OPTION_NO_ISOLATION: + pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION; + break; + case OPTION_NO_SEH: + pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_SEH; + break; + case OPTION_NO_BIND: + pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NO_BIND; + break; + case OPTION_WDM_DRIVER: + pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_WDM_DRIVER; + break; + case OPTION_TERMINAL_SERVER_AWARE: + pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; + break; + case OPTION_BUILD_ID: + if (emit_build_id != NULL) + { + free ((char *) emit_build_id); + emit_build_id = NULL; + } + if (optarg == NULL) + optarg = DEFAULT_BUILD_ID_STYLE; + if (strcmp (optarg, "none")) + emit_build_id = xstrdup (optarg); + break; } + + /* Set DLLCharacteristics bits */ + set_pe_name ("__dll_characteristics__", pe_dll_characteristics); + return TRUE; } @@ -667,7 +942,7 @@ static unsigned long compute_dll_image_base (const char *ofile) { unsigned long hash = strhash (ofile); - return 0x60000000 | ((hash << 16) & 0x0FFC0000); + return pe_auto_image_base + ((hash << 16) & 0x0FFC0000); } #endif @@ -680,21 +955,26 @@ 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; + + is_underscoring (); if (!init[IMAGEBASEOFF].inited) { if (link_info.relocatable) init[IMAGEBASEOFF].value = 0; else if (init[DLLOFF].value || (link_info.shared && !link_info.pie)) + { #ifdef DLL_SUPPORT - init[IMAGEBASEOFF].value = (pe_enable_auto_image_base) ? - compute_dll_image_base (output_filename) : NT_DLL_IMAGE_BASE; + init[IMAGEBASEOFF].value = (pe_enable_auto_image_base + ? compute_dll_image_base (output_filename) + : NT_DLL_IMAGE_BASE); #else - init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE; + 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. */ @@ -702,16 +982,15 @@ gld_${EMULATION_NAME}_set_symbols (void) return; /* Glue the assignments into the abs section. */ - save = stat_ptr; - - stat_ptr = &(abs_output_section->children); + push_stat_ptr (&abs_output_section->children); for (j = 0; init[j].ptr; j++) { long val = init[j].value; lang_assignment_statement_type *rv; - rv = lang_add_assignment (exp_assop ('=', init[j].symbol, - exp_intop (val))); + + rv = lang_add_assignment (exp_assign (GET_INIT_SYMBOL_NAME (j), + exp_intop (val), FALSE)); if (init[j].size == sizeof (short)) *(short *) init[j].ptr = val; else if (init[j].size == sizeof (int)) @@ -726,10 +1005,9 @@ gld_${EMULATION_NAME}_set_symbols (void) image_base_statement = rv; } /* Restore the pointer. */ - stat_ptr = save; + pop_stat_ptr (); - if (pe.FileAlignment > - pe.SectionAlignment) + if (pe.FileAlignment > pe.SectionAlignment) { einfo (_("%P: warning, file alignment > section alignment.\n")); } @@ -741,21 +1019,15 @@ gld_${EMULATION_NAME}_set_symbols (void) 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); + /* PR ld/6744: Warn the user if they have used an ELF-only + option hoping it will work on PE. */ + if (link_info.export_dynamic) + einfo (_("%P: warning: --export-dynamic is not supported for PE " + "targets, did you mean --export-all-symbols?\n")); + + set_entry_point (); + + after_parse_default (); } /* pe-dll.c directly accesses pe_data_import_dll, @@ -773,10 +1045,13 @@ pe_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf) { int sl; char *string = inf; + const char *hs = h->root.string; sl = strlen (string); if (h->type == bfd_link_hash_defined - && strncmp (h->root.string, string, sl) == 0 + && ((*hs == '@' && *string == '_' + && strncmp (hs + 1, string + 1, sl - 1) == 0) + || strncmp (hs, string, sl) == 0) && h->root.string[sl] == '@') { pe_undef_found_sym = h; @@ -799,15 +1074,20 @@ pe_fixup_stdcalls (void) { char* at = strchr (undef->root.string, '@'); int lead_at = (*undef->root.string == '@'); - /* For now, don't try to fixup fastcall symbols. */ + if (lead_at) + at = strchr (undef->root.string + 1, '@'); - if (at && !lead_at) + 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 */); + char *cname = xstrdup (undef->root.string); + + if (lead_at) + *cname = '_'; at = strchr (cname, '@'); - *at = 0; + if (at) + *at = 0; sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); if (sym && sym->type == bfd_link_hash_defined) @@ -867,7 +1147,7 @@ make_import_fixup (arelent *rel, asection *s) if (pe_dll_extra_pe_debug) printf ("arelent: %s@%#lx: add=%li\n", sym->name, - (long) rel->address, (long) rel->addend); + (unsigned long) rel->address, (long) rel->addend); if (! bfd_get_section_contents (s->owner, s, addend, rel->address, sizeof (addend))) einfo (_("%C: Cannot get section contents - auto-import exception\n"), @@ -904,27 +1184,44 @@ pe_find_data_imports (void) { bfd *b = sym->u.def.section->owner; asymbol **symbols; - int nsyms, symsize, i; + int nsyms, i; if (link_info.pei386_auto_import == -1) - info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), - undef->root.string, buf); + { + static bfd_boolean warned = FALSE; + + info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), + undef->root.string, buf); - symsize = bfd_get_symtab_upper_bound (b); - symbols = (asymbol **) xmalloc (symsize); - nsyms = bfd_canonicalize_symtab (b, symbols); + /* PR linker/4844. */ + if (! warned) + { + warned = TRUE; + einfo (_("%P: warning: auto-importing has been activated without --enable-auto-import specified on the command line.\n\ +This should work unless it involves constant data structures referencing symbols from auto-imported DLLs.\n")); + } + } + + if (!bfd_generic_link_read_symbols (b)) + { + einfo (_("%B%F: could not read symbols: %E\n"), b); + return; + } + + symbols = bfd_get_outsymbols (b); + nsyms = bfd_get_symcount (b); for (i = 0; i < nsyms; i++) { - if (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); + pe_data_import_dll = (char *) (symbols[i]->name + + U_SIZE ("_head_") - 1); break; } @@ -947,17 +1244,188 @@ pe_find_data_imports (void) static bfd_boolean pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) { - if (pe_dll_extra_pe_debug) - printf ("+%s\n", h->string); + printf ("+%s\n", h->string); return TRUE; } #endif /* DLL_SUPPORT */ +static void +debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj) +{ + int *found = (int *) obj; + if (strncmp (".debug_", sect->name, sizeof (".debug_") - 1) == 0) + *found = 1; +} + +static bfd_boolean +pecoff_checksum_contents (bfd *abfd, + void (*process) (const void *, size_t, void *), + void *arg) +{ + file_ptr filepos = (file_ptr) 0; + + while (1) + { + unsigned char b; + int status; + + if (bfd_seek (abfd, filepos, SEEK_SET) != 0) + return 0; + + status = bfd_bread (&b, (bfd_size_type) 1, abfd); + if (status < 1) + { + break; + } + + (*process) (&b, 1, arg); + filepos += 1; + } + + return TRUE; +} + +static bfd_boolean +write_build_id (bfd *abfd) +{ + struct pe_tdata *t = pe_data (abfd); + asection *asec; + struct bfd_link_order *link_order = NULL; + unsigned char *contents; + bfd_size_type size; + bfd_size_type build_id_size; + unsigned char *build_id; + + /* Find the section the .buildid output section has been merged info. */ + for (asec = abfd->sections; asec != NULL; asec = asec->next) + { + struct bfd_link_order *l = NULL; + for (l = asec->map_head.link_order; l != NULL; l = l->next) + { + if ((l->type == bfd_indirect_link_order)) + { + if (l->u.indirect.section == t->build_id.sec) + { + link_order = l; + break; + } + } + } + + if (link_order) + break; + } + + if (!link_order) + { + einfo (_("%P: warning: .buildid section discarded," + " --build-id ignored.\n")); + return TRUE; + } + + if (t->build_id.sec->contents == NULL) + t->build_id.sec->contents = (unsigned char *) xmalloc (t->build_id.sec->size); + contents = t->build_id.sec->contents; + size = t->build_id.sec->size; + + build_id_size = compute_build_id_size (t->build_id.style); + build_id = xmalloc (build_id_size); + generate_build_id (abfd, t->build_id.style, pecoff_checksum_contents, build_id, build_id_size); + + bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase; + + /* Construct a debug directory entry which points to an immediately following CodeView record. */ + struct internal_IMAGE_DEBUG_DIRECTORY idd; + idd.Characteristics = 0; + idd.TimeDateStamp = 0; + idd.MajorVersion = 0; + idd.MinorVersion = 0; + idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW; + idd.SizeOfData = sizeof (CV_INFO_PDB70) + 1; + idd.AddressOfRawData = asec->vma - ib + link_order->offset + + sizeof (struct external_IMAGE_DEBUG_DIRECTORY); + idd.PointerToRawData = asec->filepos + link_order->offset + + sizeof (struct external_IMAGE_DEBUG_DIRECTORY); + + struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *)contents; + _bfd_XXi_swap_debugdir_out (abfd, &idd, ext); + + /* Write the debug directory entry. */ + if (bfd_seek (abfd, asec->filepos + link_order->offset, SEEK_SET) != 0) + return 0; + + if ((bfd_bwrite (contents, size, abfd) != size)) + return 0; + + /* Construct the CodeView record. */ + CODEVIEW_INFO cvinfo; + cvinfo.CVSignature = CVINFO_PDB70_CVSIGNATURE; + cvinfo.Age = 1; + + /* Zero pad or truncate the generated build_id to fit in the CodeView record. */ + memset (&(cvinfo.Signature), 0, CV_INFO_SIGNATURE_LENGTH); + memcpy (&(cvinfo.Signature), build_id, (build_id_size > CV_INFO_SIGNATURE_LENGTH) + ? CV_INFO_SIGNATURE_LENGTH : build_id_size); + + free (build_id); + + /* Write the codeview record. */ + if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo) == 0) + return 0; + + /* Record the location of the debug directory in the data directory. */ + pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress + = asec->vma - ib + link_order->offset; + pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size + = sizeof (struct external_IMAGE_DEBUG_DIRECTORY); + + return TRUE; +} + +/* Make .buildid section, and set up coff_tdata->build_id. */ +static bfd_boolean +setup_build_id (bfd *ibfd) +{ + asection *s; + flagword flags; + + if (!validate_build_id_style (emit_build_id)) + { + einfo ("%P: warning: unrecognized --build-id style ignored.\n"); + return FALSE; + } + + flags = (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA); + s = bfd_make_section_anyway_with_flags (ibfd, ".buildid", flags); + if (s != NULL) + { + struct pe_tdata *t = pe_data (link_info.output_bfd); + t->build_id.after_write_object_contents = &write_build_id; + t->build_id.style = emit_build_id; + t->build_id.sec = s; + + /* Section is a fixed size: + One IMAGE_DEBUG_DIRECTORY entry, of type IMAGE_DEBUG_TYPE_CODEVIEW, + pointing at a CV_INFO_PDB70 record containing the build-id, with a + null byte for PdbFileName. */ + s->size = sizeof (struct external_IMAGE_DEBUG_DIRECTORY) + + sizeof (CV_INFO_PDB70) + 1; + + return TRUE; + } + + einfo ("%P: warning: Cannot create .buildid section," + " --build-id ignored.\n"); + return FALSE; +} static void gld_${EMULATION_NAME}_after_open (void) { + after_open_default (); + #ifdef DLL_SUPPORT if (pe_dll_extra_pe_debug) { @@ -970,47 +1438,104 @@ gld_${EMULATION_NAME}_after_open (void) 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) + for (a = link_info.input_bfds; a; a = a->link.next) printf ("*%s\n",a->filename); } #endif + if (emit_build_id != NULL) + { + bfd *abfd; + + /* Find a COFF input. */ + for (abfd = link_info.input_bfds; + abfd != (bfd *) NULL; abfd = abfd->link.next) + if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) + break; + + /* If there are no COFF input files do not try to + add a build-id section. */ + if (abfd == NULL + || !setup_build_id (abfd)) + { + free ((char *) emit_build_id); + emit_build_id = NULL; + } + } + /* 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: PE operations on non PE file.\n")); + if (coff_data (link_info.output_bfd) == NULL + || coff_data (link_info.output_bfd)->pe == 0) + einfo (_("%F%P: cannot perform PE operations on non PE output file '%B'.\n"), + link_info.output_bfd); + + pe_data (link_info.output_bfd)->pe_opthdr = pe; + pe_data (link_info.output_bfd)->dll = init[DLLOFF].value; + pe_data (link_info.output_bfd)->real_flags |= real_flags; + pe_data (link_info.output_bfd)->insert_timestamp = insert_timestamp; + + /* At this point we must decide whether to use long section names + in the output or not. If the user hasn't explicitly specified + on the command line, we leave it to the default for the format + (object files yes, image files no), except if there is debug + information present; GDB relies on the long section names to + find it, so enable it in that case. */ + if (pe_use_coff_long_section_names < 0 && link_info.strip == strip_none) + { + if (link_info.relocatable) + pe_use_coff_long_section_names = 1; + else + { + /* Iterate over all sections of all input BFDs, checking + for any that begin 'debug_' and are long names. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + int found_debug = 0; + + bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug); + if (found_debug) + { + pe_use_coff_long_section_names = 1; + break; + } + } + } + } - pe_data (output_bfd)->pe_opthdr = pe; - pe_data (output_bfd)->dll = init[DLLOFF].value; - pe_data (output_bfd)->real_flags |= real_flags; + pe_output_file_set_long_section_names (link_info.output_bfd); #ifdef DLL_SUPPORT if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */ pe_fixup_stdcalls (); - pe_process_import_defs (output_bfd, & link_info); + pe_process_import_defs (link_info.output_bfd, &link_info); pe_find_data_imports (); -#if ! (defined (TARGET_IS_i386pe) || defined (TARGET_IS_armpe)) - if (link_info.shared) -#else - if (!link_info.relocatable) -#endif - pe_dll_build_sections (output_bfd, &link_info); + /* As possibly new symbols are added by imports, we rerun + stdcall/fastcall fixup here. */ + if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */ + pe_fixup_stdcalls (); -#ifndef TARGET_IS_i386pe -#ifndef TARGET_IS_armpe +#if defined (TARGET_IS_i386pe) \ + || defined (TARGET_IS_armpe) \ + || defined (TARGET_IS_arm_epoc_pe) \ + || defined (TARGET_IS_arm_wince_pe) + if (!link_info.relocatable) + pe_dll_build_sections (link_info.output_bfd, &link_info); +#else + if (link_info.shared) + pe_dll_build_sections (link_info.output_bfd, &link_info); else - pe_exe_build_sections (output_bfd, &link_info); -#endif -#endif + pe_exe_build_sections (link_info.output_bfd, &link_info); #endif +#endif /* DLL_SUPPORT */ -#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) - if (strstr (bfd_get_target (output_bfd), "arm") == NULL) +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) || defined(TARGET_IS_arm_wince_pe) + if (strstr (bfd_get_target (link_info.output_bfd), "arm") == NULL) { /* The arm backend needs special fields in the output hash structure. These will only be created if the output format is an arm format, @@ -1023,7 +1548,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; } } @@ -1052,7 +1577,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; } @@ -1064,34 +1589,30 @@ gld_${EMULATION_NAME}_after_open (void) 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) + if (!bfd_generic_link_read_symbols (is->the_bfd)) { - einfo ("%X%P: unable to process symbols: %E"); + einfo (_("%B%F: could not read symbols: %E\n"), + is->the_bfd); return; } + symbols = bfd_get_outsymbols (is->the_bfd); - relocs = (arelent **) xmalloc ((size_t) relsize); + 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"); + einfo ("%X%P: unable to process relocs: %E\n"); return; } @@ -1121,8 +1642,9 @@ gld_${EMULATION_NAME}_after_open (void) ? 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) + if (filename_cmp (bfd_get_filename + (is->the_bfd->my_archive), + other_bfd_filename) == 0) continue; /* Rename this implib to match the other one. */ @@ -1176,7 +1698,7 @@ gld_${EMULATION_NAME}_after_open (void) extension, and use that for the remainder of the comparisons. */ pnt = strrchr (is3->the_bfd->filename, '.'); - if (pnt != NULL && strcmp (pnt, ".dll") == 0) + if (pnt != NULL && filename_cmp (pnt, ".dll") == 0) break; } @@ -1193,11 +1715,11 @@ gld_${EMULATION_NAME}_after_open (void) /* Skip static members, ie anything with a .obj extension. */ pnt = strrchr (is2->the_bfd->filename, '.'); - if (pnt != NULL && strcmp (pnt, ".obj") == 0) + if (pnt != NULL && filename_cmp (pnt, ".obj") == 0) continue; - if (strcmp (is3->the_bfd->filename, - is2->the_bfd->filename)) + if (filename_cmp (is3->the_bfd->filename, + is2->the_bfd->filename)) { is_ms_arch = 0; break; @@ -1211,7 +1733,7 @@ gld_${EMULATION_NAME}_after_open (void) then leave the filename alone. */ pnt = strrchr (is->the_bfd->filename, '.'); - if (is_ms_arch && (strcmp (pnt, ".dll") == 0)) + if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0)) { int idata2 = 0, reloc_count=0; asection *sec; @@ -1242,6 +1764,79 @@ 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 , 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 which is a jump stub of the form + jmp *__imp_. The .idata\$5 contains the symbol definition + for __imp_ which is the address of the slot for in + the import address table. When a symbol is imported explicitly + using __declspec(dllimport) declaration, the compiler generates + a reference to __imp_ which directly resolves to the + symbol in .idata\$5, in which case the jump stub code is not + needed. The following code tries to identify jump stub sections + in import libraries which are not referred to by anyone and + marks them for exclusion from the final link. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + int is_imp = 0; + asection *sec, *stub_sec = NULL; + + /* See if this is an import library thunk. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strncmp (sec->name, ".idata\$", 7) == 0) + is_imp = 1; + /* The section containing the jmp stub has code + and has a reloc. */ + if ((sec->flags & SEC_CODE) && sec->reloc_count) + stub_sec = sec; + } + + if (is_imp && stub_sec) + { + asymbol **symbols; + long nsyms, src_count; + struct bfd_link_hash_entry * blhe; + + if (!bfd_generic_link_read_symbols (is->the_bfd)) + { + einfo (_("%B%F: could not read symbols: %E\n"), + is->the_bfd); + return; + } + symbols = bfd_get_outsymbols (is->the_bfd); + nsyms = bfd_get_symcount (is->the_bfd); + + for (src_count = 0; src_count < nsyms; src_count++) + { + if (symbols[src_count]->section->id == stub_sec->id) + { + /* This symbol belongs to the section containing + the stub. */ + blhe = bfd_link_hash_lookup (link_info.hash, + symbols[src_count]->name, + FALSE, FALSE, TRUE); + /* If the symbol in the stub section has no other + undefined references, exclude the stub section + from the final link. */ + if (blhe != NULL + && blhe->type == bfd_link_hash_defined + && blhe->u.undef.next == NULL + && blhe != link_info.hash->undefs_tail) + stub_sec->flags |= SEC_EXCLUDE; + } + } + } + } + } + } } static void @@ -1264,7 +1859,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. @@ -1274,22 +1869,21 @@ 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 */ - einfo (_("Errors encountered processing file %s for interworking"), + einfo (_("Errors encountered processing file %s for interworking\n"), is->filename); } } } /* 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 */ - if (!link_info.relocatable) - strip_excluded_output_sections (); + before_allocation_default (); } #ifdef DLL_SUPPORT @@ -1302,7 +1896,7 @@ saw_option (char *option) int i; for (i = 0; init[i].ptr; i++) - if (strcmp (init[i].symbol, option) == 0) + if (strcmp (GET_INIT_SYMBOL_NAME (i), option) == 0) return init[i].inited; return 0; } @@ -1314,7 +1908,7 @@ gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIB #ifdef DLL_SUPPORT const char *ext = entry->filename + strlen (entry->filename) - 4; - if (strcmp (ext, ".def") == 0 || strcmp (ext, ".DEF") == 0) + if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0) { pe_def_file = def_file_parse (entry->filename, pe_def_file); @@ -1330,13 +1924,14 @@ gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIB buflen = len + 2; } - buf = (char *) xmalloc (buflen); + buf = xmalloc (buflen); for (i = 0; i < pe_def_file->num_exports; i++) { 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) @@ -1356,13 +1951,15 @@ gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIB if (pe_def_file->base_address != (bfd_vma)(-1)) { - pe.ImageBase = - pe_data (output_bfd)->pe_opthdr.ImageBase = - init[IMAGEBASEOFF].value = pe_def_file->base_address; + pe.ImageBase + = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase + = init[IMAGEBASEOFF].value + = pe_def_file->base_address; init[IMAGEBASEOFF].inited = 1; if (image_base_statement) - image_base_statement->exp = - exp_assop ('=', "__image_base__", exp_intop (pe.ImageBase)); + image_base_statement->exp + = exp_assign ("__image_base__", exp_intop (pe.ImageBase), + FALSE); } if (pe_def_file->stack_reserve != -1 @@ -1396,25 +1993,17 @@ gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUT #ifdef TARGET_IS_shpe pe_dll_id_target ("pei-shl"); #endif -#ifdef TARGET_IS_mipspe - pe_dll_id_target ("pei-mips"); -#endif #ifdef TARGET_IS_armpe pe_dll_id_target ("pei-arm-little"); #endif - 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; } @@ -1422,7 +2011,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) @@ -1441,7 +2030,7 @@ gld_${EMULATION_NAME}_finish (void) /* 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, + + bfd_get_section_vma (link_info.output_bfd, h->u.def.section->output_section) + h->u.def.section->output_offset); @@ -1460,26 +2049,28 @@ gld_${EMULATION_NAME}_finish (void) entry_symbol.name = buffer; } else - einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); + einfo (_("%P: warning: cannot 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 (); #ifdef DLL_SUPPORT if (link_info.shared -#if !defined(TARGET_IS_shpe) && !defined(TARGET_IS_mipspe) - || (!link_info.relocatable && pe_def_file->num_exports != 0) +#if !defined(TARGET_IS_shpe) + || (!link_info.relocatable && pe_def_file->num_exports != 0) #endif ) { - pe_dll_fill_sections (output_bfd, &link_info); + pe_dll_fill_sections (link_info.output_bfd, &link_info); if (pe_implib_filename) - pe_dll_generate_implib (pe_def_file, pe_implib_filename); + pe_dll_generate_implib (pe_def_file, pe_implib_filename, &link_info); } -#if defined(TARGET_IS_shpe) || defined(TARGET_IS_mipspe) +#if defined(TARGET_IS_shpe) /* ARM doesn't need relocs. */ else { - pe_exe_fill_sections (output_bfd, &link_info); + pe_exe_fill_sections (link_info.output_bfd, &link_info); } #endif @@ -1489,7 +2080,7 @@ gld_${EMULATION_NAME}_finish (void) /* 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"); + asection *asec = bfd_get_section_by_name (link_info.output_bfd, ".idata"); if (asec) { @@ -1505,7 +2096,7 @@ gld_${EMULATION_NAME}_finish (void) 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 + 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. @@ -1513,53 +2104,79 @@ gld_${EMULATION_NAME}_finish (void) default linker script using wildcards, and are sorted by sort_sections. */ -static bfd_boolean -gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s) +static lang_output_section_statement_type * +gld_${EMULATION_NAME}_place_orphan (asection *s, + const char *secname, + int constraint) { - const char *secname; - const char *orig_secname; + const char *orig_secname = secname; char *dollar = NULL; lang_output_section_statement_type *os; lang_statement_list_type add_child; - - secname = bfd_get_section_name (s->owner, s); + lang_output_section_statement_type *match_by_name = NULL; + lang_statement_union_type **pl; /* Look through the script to see where to place this section. */ - orig_secname = secname; if (!link_info.relocatable - && (dollar = strchr (secname, '$')) != NULL) + && (dollar = strchr (secname, '\$')) != NULL) { - size_t len = dollar - orig_secname; + size_t len = dollar - secname; char *newname = xmalloc (len + 1); - memcpy (newname, orig_secname, len); + memcpy (newname, 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)) + os = NULL; + if (constraint == 0) + for (os = lang_output_section_find (secname); + os != NULL; + os = next_matching_output_section_statement (os, 0)) + { + /* If we don't match an existing output section, tell + lang_insert_orphan to create a new output section. */ + constraint = SPECIAL; + + if (os->bfd_section != NULL + && (os->bfd_section->flags == 0 + || ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0)) + { + /* We already have an output section statement with this + name, and its bfd section has compatible flags. + If the section already exists but does not have any flags set, + then it has been created by the linker, probably as a result of + a --section-start command line switch. */ + lang_add_section (&add_child, s, NULL, os); + break; + } + + /* Save unused output sections in case we can match them + against orphans later. */ + if (os->bfd_section == NULL) + match_by_name = os; + } + + /* If we didn't match an active output section, see if we matched an + unused one and use that. */ + if (os == NULL && match_by_name) { - /* 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, file); + lang_add_section (&match_by_name->children, s, NULL, match_by_name); + return match_by_name; } - else + + if (os == NULL) { static struct orphan_save hold[] = { { ".text", SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, 0, 0, 0, 0 }, + { ".idata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, { ".rdata", SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, 0, 0, 0, 0 }, @@ -1573,6 +2190,7 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s enum orphan_save_index { orphan_text = 0, + orphan_idata, orphan_rodata, orphan_data, orphan_bss @@ -1606,7 +2224,10 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s else if ((s->flags & SEC_READONLY) == 0) place = &hold[orphan_data]; else if ((s->flags & SEC_CODE) == 0) - place = &hold[orphan_rodata]; + { + place = (!strncmp (secname, ".idata\$", 7) ? &hold[orphan_idata] + : &hold[orphan_rodata]); + } else place = &hold[orphan_text]; @@ -1617,161 +2238,153 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s place->os = lang_output_section_find (place->name); after = place->os; if (after == NULL) - after = lang_output_section_find_by_flags (s, &place->os); + 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. */ + /* All sections in an executable must be aligned to a page boundary. + In a relocatable link, just preserve the incoming alignment; the + address is discarded by lang_insert_orphan in that case, anyway. */ address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); - os = lang_insert_orphan (file, s, secname, after, place, address, + os = lang_insert_orphan (s, secname, constraint, after, place, address, &add_child); + if (link_info.relocatable) + { + os->section_alignment = s->alignment_power; + os->bfd_section->alignment_power = s->alignment_power; + } } - { - 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 the section name has a '\$', sort it with the other '\$' + sections. */ + for (pl = &os->children.head; *pl != NULL; pl = &(*pl)->header.next) + { + lang_input_section_type *ls; + const char *lname; - if ((*pl)->header.type != lang_input_section_enum) - continue; + if ((*pl)->header.type != lang_input_section_enum) + continue; - ls = &(*pl)->input_section; + ls = &(*pl)->input_section; - lname = bfd_get_section_name (ls->ifile->the_bfd, ls->section); - if (strchr (lname, '$') == NULL) - { - if (found_dollar) - break; - } - else - { - found_dollar = TRUE; - if (strcmp (orig_secname, lname) < 0) - break; - } - } - } + lname = bfd_get_section_name (ls->section->owner, ls->section); + if (strchr (lname, '\$') != NULL + && (dollar == NULL || strcmp (orig_secname, lname) < 0)) + break; + } - if (add_child.head != NULL) - { - add_child.head->header.next = *pl; - *pl = add_child.head; - } - } + if (add_child.head != NULL) + { + *add_child.tail = *pl; + *pl = add_child.head; + } - return TRUE; + return os; } static bfd_boolean gld_${EMULATION_NAME}_open_dynamic_archive - (const char *arch ATTRIBUTE_UNUSED, search_dirs_type *search, + (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 "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) + + if (! entry->flags.maybe_archive || entry->flags.full_name_provided) 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)) - { - /* 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 "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 (libname_fmt[i].use_prefix) + { + if (!pe_dll_search_prefix) + continue; + sprintf (base_string, libname_fmt[i].format, pe_dll_search_prefix, filename); } + else +#endif + sprintf (base_string, libname_fmt[i].format, filename); + + if (ldfile_try_open_bfd (full_string, entry)) + break; } - entry->filename = string; + if (!libname_fmt[i].format) + { + free (full_string); + return FALSE; + } + + entry->filename = full_string; return TRUE; } @@ -1790,7 +2403,7 @@ EOF # sed commands to quote an ld script as a C string. sc="-f stringify.sed" -cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +if test -n "$GENERATE_AUTO_IMPORT_SCRIPT" ; then +echo ' ; else if (link_info.pei386_auto_import == 1 && (MERGE_RDATA_V2 || link_info.pei386_runtime_pseudo_reloc != 2)) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xa >> e${EMULATION_NAME}.c +fi echo ' ; else return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c echo '; }' >> e${EMULATION_NAME}.c -cat >>e${EMULATION_NAME}.c <