X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fpe-dll.c;h=8cf522b15feeb01351a5aa768fbb6152dd1c24c5;hb=cbb09508e4b515501273288aaa11a8ef5e15e0ff;hp=4ce7a3638cb40f325bc4d460fc5fa7f251966783;hpb=fbea15088db59186960134d11b8bf98070224d6c;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/pe-dll.c b/ld/pe-dll.c index 4ce7a3638c..8cf522b15f 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -1,5 +1,5 @@ /* Routines to help build PEI-format DLLs (Win32 etc) - Copyright (C) 1998-2017 Free Software Foundation, Inc. + Copyright (C) 1998-2018 Free Software Foundation, Inc. Written by DJ Delorie This file is part of the GNU Binutils. @@ -168,7 +168,7 @@ static struct bfd_section *edata_s, *reloc_s; static unsigned char *edata_d, *reloc_d; static size_t edata_sz, reloc_sz; static int runtime_pseudo_relocs_created = 0; -static int runtime_pseudp_reloc_v2_init = 0; +static bfd_boolean runtime_pseudp_reloc_v2_init = FALSE; typedef struct { @@ -243,8 +243,7 @@ static const autofilter_entry_type autofilter_symbollist_i386[] = #define PE_ARCH_sh 2 #define PE_ARCH_mips 3 #define PE_ARCH_arm 4 -#define PE_ARCH_arm_epoc 5 -#define PE_ARCH_arm_wince 6 +#define PE_ARCH_arm_wince 5 /* Don't make it constant as underscore mode gets possibly overriden by target or -(no-)leading-underscore option. */ @@ -269,6 +268,17 @@ static pe_details_type pe_detail_list[] = #endif autofilter_symbollist_i386 }, +#ifdef pe_use_x86_64 + { + "pei-x86-64", + "pe-bigobj-x86-64", + 3 /* R_IMAGEBASE */, + PE_ARCH_i386, + bfd_arch_i386, + FALSE, + autofilter_symbollist_i386 + }, +#endif { "pei-shl", "pe-shl", @@ -296,15 +306,6 @@ static pe_details_type pe_detail_list[] = TRUE, autofilter_symbollist_generic }, - { - "epoc-pei-arm-little", - "epoc-pe-arm-little", - 11 /* ARM_RVA32 */, - PE_ARCH_arm_epoc, - bfd_arch_arm, - FALSE, - autofilter_symbollist_generic - }, { "pei-arm-wince-little", "pe-arm-wince-little", @@ -333,6 +334,9 @@ static const autofilter_entry_type autofilter_liblist[] = { STRING_COMMA_LEN ("libsupc++") }, { STRING_COMMA_LEN ("libobjc") }, { STRING_COMMA_LEN ("libgcj") }, + { STRING_COMMA_LEN ("libmsvcrt") }, + { STRING_COMMA_LEN ("libmsvcrt-os") }, + { STRING_COMMA_LEN ("libucrtbase") }, { NULL, 0 } }; @@ -428,7 +432,7 @@ pe_dll_id_target (const char *target) pe_leading_underscore = (u != 0 ? 1 : 0); return; } - einfo (_("%P%X: Unsupported PEI architecture: %s\n"), target); + einfo (_("%X%P: unsupported PEI architecture: %s\n"), target); exit (1); } @@ -541,7 +545,7 @@ auto_export (bfd *abfd, def_file *d, const char *n) /* Return false if n is in the d->exports table. */ if (bsearch (&key, d->exports, d->num_exports, - sizeof (pe_def_file->exports[0]), pe_export_sort)) + sizeof (pe_def_file->exports[0]), pe_export_sort)) return 0; if (pe_dll_do_default_excludes) @@ -681,9 +685,9 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * { struct coff_link_hash_entry *sym_hash; sym_hash = coff_link_hash_lookup (coff_hash_table (info), - ac->symbol_name, FALSE, FALSE, FALSE); + ac->symbol_name, FALSE, FALSE, FALSE); if (sym_hash && sym_hash->root.type == bfd_link_hash_common - && sym_hash->root.u.c.p->alignment_power < (unsigned) ac->alignment) + && sym_hash->root.u.c.p->alignment_power < (unsigned) ac->alignment) { sym_hash->root.u.c.p->alignment_power = (unsigned) ac->alignment; } @@ -708,7 +712,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%B%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -725,9 +729,9 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * && ((symbols[j]->flags & BSF_GLOBAL) || (symbols[j]->flags == 0))); if (link_info.version_info && would_export) - would_export - = !bfd_hide_sym_by_version (link_info.version_info, - symbols[j]->name); + would_export + = !bfd_hide_sym_by_version (link_info.version_info, + symbols[j]->name); if (would_export) { const char *sn = symbols[j]->name; @@ -736,7 +740,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * { char *name; if (is_import (sn)) - continue; + continue; name = xmalloc (strlen ("__imp_") + strlen (sn) + 1); sprintf (name, "%s%s", "__imp_", sn); @@ -761,7 +765,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * NULL, &is_dup); /* Fill data flag properly, from dlltool.c. */ if (!is_dup) - p->flag_data = !(symbols[j]->flags & BSF_FUNCTION); + p->flag_data = !(symbols[j]->flags & BSF_FUNCTION); } } } @@ -795,12 +799,12 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * char *tmp_at = strrchr (tmp, '@'); if (tmp_at) - *tmp_at = 0; + *tmp_at = 0; else - einfo (_("%P%X: Cannot export %s: invalid export name\n"), + einfo (_("%X%P: cannot export %s: invalid export name\n"), pe_def_file->exports[i].name); pe_def_file->exports[i].name = tmp; - resort_needed = TRUE; + resort_needed = TRUE; } } } @@ -809,7 +813,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * by removing leading @. */ if (resort_needed) qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), - pe_export_sort); + pe_export_sort); if (pe_dll_stdcall_aliases) { @@ -830,7 +834,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * pe_def_file->exports[i].internal_name, -1, NULL, &is_dup); if (is_dup) - free (tmp); + free (tmp); } } } @@ -849,14 +853,14 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * { if (pe_dll_warn_dup_exports) /* xgettext:c-format */ - einfo (_("%P%X: Error, duplicate EXPORT with ordinals: %s (%d vs %d)\n"), + einfo (_("%X%P: error, duplicate EXPORT with ordinals: %s (%d vs %d)\n"), e[j - 1].name, e[j - 1].ordinal, e[i].ordinal); } else { if (pe_dll_warn_dup_exports) /* xgettext:c-format */ - einfo (_("%P: Warning, duplicate EXPORT: %s\n"), + einfo (_("%P: warning, duplicate EXPORT: %s\n"), e[j - 1].name); } @@ -942,7 +946,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * } } /* Check for forward exports. These are indicated in DEF files by an - export directive of the form NAME1 = MODULE-NAME.EXTERNAL-NAME + export directive of the form NAME1 = MODULE-NAME.EXTERNAL-NAME but we must take care not to be fooled when the user wants to export a symbol that actually really has a dot in it, so we only check for them here, after real defined symbols have already been matched. */ @@ -966,20 +970,20 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * else if (blhe && blhe->type == bfd_link_hash_undefined) { /* xgettext:c-format */ - einfo (_("%P%X: Cannot export %s: symbol not defined\n"), + einfo (_("%X%P: cannot export %s: symbol not defined\n"), int_name); } else if (blhe) { /* xgettext:c-format */ - einfo (_("%P%X: Cannot export %s: symbol wrong type (%d vs %d)\n"), + einfo (_("%X%P: cannot export %s: symbol wrong type (%d vs %d)\n"), int_name, blhe->type, bfd_link_hash_defined); } else { /* xgettext:c-format */ - einfo (_("%P%X: Cannot export %s: symbol not found\n"), + einfo (_("%X%P: cannot export %s: symbol not found\n"), int_name); } free (name); @@ -1002,7 +1006,7 @@ build_filler_bfd (int include_edata) bfd_get_arch (link_info.output_bfd), bfd_get_mach (link_info.output_bfd))) { - einfo ("%X%P: can not create BFD: %E\n"); + einfo (_("%F%P: can not create BFD: %E\n")); return; } @@ -1017,7 +1021,7 @@ build_filler_bfd (int include_edata) | SEC_KEEP | SEC_IN_MEMORY))) { - einfo ("%X%P: can not create .edata section: %E\n"); + einfo (_("%X%P: can not create .edata section: %E\n")); return; } bfd_set_section_size (filler_bfd, edata_s, edata_sz); @@ -1032,7 +1036,7 @@ build_filler_bfd (int include_edata) | SEC_KEEP | SEC_IN_MEMORY))) { - einfo ("%X%P: can not create .reloc section: %E\n"); + einfo (_("%X%P: can not create .reloc section: %E\n")); return; } @@ -1082,8 +1086,8 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) /* Now we need to assign ordinals to those that don't have them. */ for (i = 0; i < NE; i++) { - if (exported_symbol_sections[i] || - pe_def_file->exports[i].flag_forward) + if (exported_symbol_sections[i] + || pe_def_file->exports[i].flag_forward) { if (pe_def_file->exports[i].ordinal != -1) { @@ -1093,7 +1097,7 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) if (pi != -1) { /* xgettext:c-format */ - einfo (_("%P%X: Error: ordinal used twice: %d (%s vs %s)\n"), + einfo (_("%X%P: error: ordinal used twice: %d (%s vs %s)\n"), pe_def_file->exports[i].ordinal, pe_def_file->exports[i].name, pe_def_file->exports[pi].name); @@ -1115,9 +1119,9 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) next_ordinal = min_ordinal; for (i = 0; i < NE; i++) - if ((exported_symbol_sections[i] || - pe_def_file->exports[i].flag_forward) && - pe_def_file->exports[i].ordinal == -1) + if ((exported_symbol_sections[i] + || pe_def_file->exports[i].flag_forward) + && pe_def_file->exports[i].ordinal == -1) { while (exported_symbols[next_ordinal - min_ordinal] != -1) next_ordinal++; @@ -1129,7 +1133,7 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) /* PR 12969: Check for more than 1^16 ordinals. */ if (max_ordinal > 65535 || next_ordinal > 65535) /* xgettext:c-format */ - einfo(_("%P%X: Error: export ordinal too large: %d\n"), + einfo(_("%X%P: error: export ordinal too large: %d\n"), max_ordinal > next_ordinal ? max_ordinal : next_ordinal); /* OK, now we can allocate some memory. */ @@ -1155,7 +1159,7 @@ fill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); if (pe_details->underscored - && *pe_def_file->exports[i].internal_name != '@') + && *pe_def_file->exports[i].internal_name != '@') { *name = '_'; strcpy (name + 1, pe_def_file->exports[i].internal_name); @@ -1223,21 +1227,21 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) Scan alphabetically - ie the ordering in the exports[] table, rather than by ordinal - the ordering in the exported_symbol[] table. See dlltool.c and: - http://sources.redhat.com/ml/binutils/2003-04/msg00379.html + http://sources.redhat.com/ml/binutils/2003-04/msg00379.html for more information. */ hint = 0; for (s = 0; s < NE; s++) { struct bfd_section *ssec = exported_symbol_sections[s]; - if (pe_def_file->exports[s].ordinal != -1 && - (pe_def_file->exports[s].flag_forward || ssec != NULL)) + if (pe_def_file->exports[s].ordinal != -1 + && (pe_def_file->exports[s].flag_forward || ssec != NULL)) { int ord = pe_def_file->exports[s].ordinal; if (pe_def_file->exports[s].flag_forward) { bfd_put_32 (abfd, ERVA (enamestr), - eaddresses + 4 * (ord - min_ordinal)); + eaddresses + 4 * (ord - min_ordinal)); strcpy (enamestr, pe_def_file->exports[s].internal_name); enamestr += strlen (pe_def_file->exports[s].internal_name) + 1; @@ -1249,7 +1253,7 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) + ssec->output_offset); bfd_put_32 (abfd, srva - image_base, - eaddresses + 4 * (ord - min_ordinal)); + eaddresses + 4 * (ord - min_ordinal)); } if (!pe_def_file->exports[s].flag_noname) @@ -1273,10 +1277,12 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) static struct bfd_section *current_sec; -void -pe_walk_relocs_of_symbol (struct bfd_link_info *info, - char *name, - int (*cb) (arelent *, asection *, char *)) +static void +pe_walk_relocs (struct bfd_link_info *info, + char *name, + const char *symname, + struct bfd_hash_table *import_hash, + void (*cb) (arelent *, asection *, char *, const char *)) { bfd *b; asection *s; @@ -1287,7 +1293,7 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info, if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%B%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -1314,8 +1320,20 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info, { struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; - if (!strcmp (name, sym->name)) - cb (relocs[i], s, name); + /* Warning: the callback needs to be passed NAME directly. */ + if (import_hash) + { + if (bfd_hash_lookup (import_hash, sym->name, FALSE, FALSE)) + { + strcpy (name, sym->name); + cb (relocs[i], s, name, symname); + } + } + else + { + if (strcmp (name, sym->name) == 0) + cb (relocs[i], s, name, symname); + } } free (relocs); @@ -1327,6 +1345,138 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info, } } +void +pe_find_data_imports (const char *symhead, + void (*cb) (arelent *, asection *, char *, const char *)) +{ + struct bfd_link_hash_entry *undef; + const size_t headlen = strlen (symhead); + size_t namelen = 0; + char *buf, *name; + struct bfd_hash_table *import_hash; + + for (undef = link_info.hash->undefs; undef; undef = undef->u.undef.next) + if (undef->type == bfd_link_hash_undefined) + { + size_t len = strlen (undef->root.string); + if (namelen < len) + namelen = len; + } + if (namelen == 0) + return; + + /* For the pseudo-relocation support version 2, we can collect the symbols + that are subject to auto-import and adjust the relocations en masse. */ + if (link_info.pei386_runtime_pseudo_reloc == 2) + { + import_hash + = (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table)); + if (!bfd_hash_table_init (import_hash, + bfd_hash_newfunc, + sizeof (struct bfd_hash_entry))) + einfo (_("%F%P: bfd_hash_table_init failed: %E\n")); + } + else + import_hash = NULL; + + /* We are being a bit cunning here. The buffer will have space for + prefixes at the beginning. The prefix is modified here and in a + number of functions called from this function. */ +#define PREFIX_LEN 32 + buf = xmalloc (PREFIX_LEN + namelen + 1); + name = buf + PREFIX_LEN; + + for (undef = link_info.hash->undefs; undef; undef = undef->u.undef.next) + if (undef->type == bfd_link_hash_undefined) + { + struct bfd_link_hash_entry *sym; + char *impname; + + if (pe_dll_extra_pe_debug) + printf ("%s:%s\n", __FUNCTION__, undef->root.string); + + strcpy (name, undef->root.string); + impname = name - (sizeof "__imp_" - 1); + memcpy (impname, "__imp_", sizeof "__imp_" - 1); + + sym = bfd_link_hash_lookup (link_info.hash, impname, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + if (import_hash) + bfd_hash_lookup (import_hash, undef->root.string, TRUE, FALSE); + else + { + bfd *b = sym->u.def.section->owner; + const char *symname = NULL; + asymbol **symbols; + int nsyms, i; + + if (!bfd_generic_link_read_symbols (b)) + { + einfo (_("%F%P: %pB: 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 (strncmp (symbols[i]->name, symhead, headlen) == 0) + { + if (pe_dll_extra_pe_debug) + printf ("->%s\n", symbols[i]->name); + + symname = symbols[i]->name + headlen; + break; + } + + /* If the symobl isn't part of an import table, there is no + point in building a fixup, this would give rise to link + errors for mangled symbols instead of the original one. */ + if (symname) + pe_walk_relocs (&link_info, name, symname, NULL, cb); + else + continue; + } + + /* Let's differentiate it somehow from defined. */ + undef->type = bfd_link_hash_defweak; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + + if (link_info.pei386_auto_import == -1) + { + static bfd_boolean warned = FALSE; + + info_msg (_("Info: resolving %s by linking to %s " + "(auto-import)\n"), name, impname); + + /* PR linker/4844. */ + if (!warned) + { + einfo (_("%P: warning: auto-importing has been activated " + "without --enable-auto-import specified on the " + "command line; this should work unless it " + "involves constant data structures referencing " + "symbols from auto-imported DLLs\n")); + warned = TRUE; + } + } + } + } + + /* If we have the import hash table, walk the relocations only once. */ + if (import_hash) + { + pe_walk_relocs (&link_info, name, NULL, import_hash, cb); + bfd_hash_table_free (import_hash); + free (import_hash); + } + + free (buf); +} + /* Gather all the relocations and build the .reloc section. */ static void @@ -1374,7 +1524,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) if (s->output_section->vma == 0) { /* Huh? Shouldn't happen, but punt if it does. */ - einfo ("DJ: zero vma section reloc detected: `%s' #%d f=%d\n", + einfo (_("%P: zero vma section reloc detected: `%s' #%d f=%d\n"), s->output_section->name, s->output_section->index, s->output_section->flags); continue; @@ -1382,7 +1532,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%B%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -1489,7 +1639,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) /* Fall through. */ default: /* xgettext:c-format */ - einfo (_("%P%X: Error: %d-bit reloc in dll\n"), + einfo (_("%X%P: error: %d-bit reloc in dll\n"), relocs[i]->howto->bitsize); break; } @@ -1617,7 +1767,7 @@ pe_dll_generate_def_file (const char *pe_out_def_filename) if (out == NULL) /* xgettext:c-format */ - einfo (_("%P: Can't open output def file %s\n"), + einfo (_("%P: can't open output def file %s\n"), pe_out_def_filename); if (pe_def_file) @@ -1772,7 +1922,7 @@ pe_dll_generate_def_file (const char *pe_out_def_filename) if (fclose (out) == EOF) /* xgettext:c-format */ - einfo (_("%P: Error closing file `%s'\n"), pe_out_def_filename); + einfo (_("%P: error closing file `%s'\n"), pe_out_def_filename); } /* Generate the import library. */ @@ -1780,7 +1930,6 @@ pe_dll_generate_def_file (const char *pe_out_def_filename) static asymbol **symtab; static int symptr; static int tmp_seq; -static int tmp_seq2; static const char *dll_filename; static char *dll_symname; @@ -1869,20 +2018,20 @@ save_relocs (asection *sec) } /* .section .idata$2 - .global __head_my_dll + .global __head_my_dll __head_my_dll: - .rva hname - .long 0 - .long 0 - .rva __my_dll_iname - .rva fthunk - - .section .idata$5 - .long 0 + .rva hname + .long 0 + .long 0 + .rva __my_dll_iname + .rva fthunk + + .section .idata$5 + .long 0 fthunk: - .section .idata$4 - .long 0 + .section .idata$4 + .long 0 hname: */ static bfd * @@ -1963,15 +2112,15 @@ make_head (bfd *parent) } /* .section .idata$4 - .long 0 + .long 0 [.long 0] for PE+ - .section .idata$5 - .long 0 + .section .idata$5 + .long 0 [.long 0] for PE+ - .section idata$7 - .global __my_dll_iname + .section idata$7 + .global __my_dll_iname __my_dll_iname: - .asciz "my.dll" */ + .asciz "my.dll" */ static bfd * make_tail (bfd *parent) @@ -2033,25 +2182,25 @@ make_tail (bfd *parent) } /* .text - .global _function - .global ___imp_function - .global __imp__function + .global _function + .global ___imp_function + .global __imp__function _function: - jmp *__imp__function: + jmp *__imp__function: - .section idata$7 - .long __head_my_dll + .section idata$7 + .long __head_my_dll - .section .idata$5 + .section .idata$5 ___imp_function: __imp__function: iat? - .section .idata$4 + .section .idata$4 iat? - .section .idata$6 + .section .idata$6 ID: - .short - .asciz "function" xlate? (add underscore, kill at) */ + .short + .asciz "function" xlate? (add underscore, kill at) */ static const unsigned char jmp_ix86_bytes[] = { @@ -2059,11 +2208,11 @@ static const unsigned char jmp_ix86_bytes[] = }; /* _function: - mov.l ip+8,r0 - mov.l @r0,r0 - jmp @r0 - nop - .dw __imp_function */ + mov.l ip+8,r0 + mov.l @r0,r0 + jmp @r0 + nop + .dw __imp_function */ static const unsigned char jmp_sh_bytes[] = { @@ -2071,10 +2220,10 @@ static const unsigned char jmp_sh_bytes[] = }; /* _function: - lui $t0, - lw $t0, - jr $t0 - nop */ + lui $t0, + lw $t0, + jr $t0 + nop */ static const unsigned char jmp_mips_bytes[] = { @@ -2124,7 +2273,6 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) jmp_byte_count = sizeof (jmp_mips_bytes); break; case PE_ARCH_arm: - case PE_ARCH_arm_epoc: case PE_ARCH_arm_wince: jmp_bytes = jmp_arm_bytes; jmp_byte_count = sizeof (jmp_arm_bytes); @@ -2200,7 +2348,7 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) /* Mark this object as SAFESEH compatible. */ quick_symbol (abfd, "", "@feat.00", "", bfd_abs_section_ptr, BSF_LOCAL, 1); - quick_reloc (abfd, 2, BFD_RELOC_32, 2); + quick_reloc (abfd, 2, BFD_RELOC_32, 2); #endif break; case PE_ARCH_sh: @@ -2212,8 +2360,7 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); break; case PE_ARCH_arm: - case PE_ARCH_arm_epoc: - case PE_ARCH_arm_wince: + case PE_ARCH_arm_wince: quick_reloc (abfd, 8, BFD_RELOC_32, 2); break; default: @@ -2312,47 +2459,6 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) return abfd; } -static bfd * -make_singleton_name_imp (const char *import, bfd *parent) -{ - /* Name thunks go to idata$4. */ - asection *id5; - unsigned char *d5; - char *oname; - bfd *abfd; - - oname = xmalloc (20); - sprintf (oname, "nmimp%06d.o", tmp_seq2); - tmp_seq2++; - - abfd = bfd_create (oname, parent); - bfd_find_target (pe_details->object_target, abfd); - bfd_make_writable (abfd); - - bfd_set_format (abfd, bfd_object); - bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); - - symptr = 0; - symtab = xmalloc (3 * sizeof (asymbol *)); - id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); - quick_symbol (abfd, "__imp_", import, "", id5, BSF_GLOBAL, 0); - - /* We need space for the real thunk and for the null terminator. */ - bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE * 2); - d5 = xmalloc (PE_IDATA5_SIZE * 2); - id5->contents = d5; - memset (d5, 0, PE_IDATA5_SIZE * 2); - quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); - save_relocs (id5); - - bfd_set_symtab (abfd, symtab, symptr); - - bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA4_SIZE * 2); - - bfd_make_readable (abfd); - return abfd; -} - static bfd * make_singleton_name_thunk (const char *import, bfd *parent) { @@ -2395,7 +2501,7 @@ make_singleton_name_thunk (const char *import, bfd *parent) return abfd; } -static char * +static const char * make_import_fixup_mark (arelent *rel, char *name) { /* We convert reloc to symbol, for later reference. */ @@ -2417,15 +2523,15 @@ make_import_fixup_mark (arelent *rel, char *name) current_sec, /* sym->section, */ rel->address, NULL, TRUE, FALSE, &bh); - return fixup_name; + return bh->root.string; } /* .section .idata$2 - .rva __nm_thnk_SYM (singleton thunk with name of func) - .long 0 - .long 0 - .rva __my_dll_iname (name of dll) - .rva __fuNN_SYM (pointer to reference (address) in text) */ + .rva __nm_thnk_SYM (singleton thunk with name of func) + .long 0 + .long 0 + .rva __my_dll_iname (name of dll) + .rva __fuNN_SYM (pointer to reference (address) in text) */ static bfd * make_import_fixup_entry (const char *name, @@ -2455,12 +2561,7 @@ make_import_fixup_entry (const char *name, quick_symbol (abfd, "__nm_thnk_", name, "", UNDSEC, BSF_GLOBAL, 0); quick_symbol (abfd, U (""), symname, "_iname", UNDSEC, BSF_GLOBAL, 0); - /* For relocator v2 we have to use the .idata$5 element and not - fixup_name. */ - if (link_info.pei386_runtime_pseudo_reloc == 2) - quick_symbol (abfd, "__imp_", name, "", UNDSEC, BSF_GLOBAL, 0); - else - quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); + quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); bfd_set_section_size (abfd, id2, 20); d2 = xmalloc (20); @@ -2481,8 +2582,8 @@ make_import_fixup_entry (const char *name, } /* .section .rdata_runtime_pseudo_reloc - .long addend - .rva __fuNN_SYM (pointer to reference (address) in text) */ + .long addend + .rva __fuNN_SYM (pointer to reference (address) in text) */ static bfd * make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, @@ -2495,6 +2596,8 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, unsigned char *rt_rel_d; char *oname; bfd *abfd; + bfd_size_type size; + oname = xmalloc (20); sprintf (oname, "rtr%06d.o", tmp_seq); tmp_seq++; @@ -2506,47 +2609,52 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, bfd_set_format (abfd, bfd_object); bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); - symptr = 0; if (link_info.pei386_runtime_pseudo_reloc == 2) { - symtab = xmalloc ((runtime_pseudp_reloc_v2_init ? 3 : 6) * sizeof (asymbol *)); + if (runtime_pseudp_reloc_v2_init) + size = 3 * sizeof (asymbol *); + else + size = 6 * sizeof (asymbol *); } else - { - symtab = xmalloc (2 * sizeof (asymbol *)); - } - rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", - SEC_HAS_CONTENTS, 2); + size = 2 * sizeof (asymbol *); + + symptr = 0; + symtab = xmalloc (size); + + rt_rel + = quick_section (abfd, ".rdata_runtime_pseudo_reloc", SEC_HAS_CONTENTS, 2); quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); if (link_info.pei386_runtime_pseudo_reloc == 2) { - size_t size = 12; - if (! runtime_pseudp_reloc_v2_init) - { - size += 12; - runtime_pseudp_reloc_v2_init = 1; - } + size = 12; + if (!runtime_pseudp_reloc_v2_init) + { + size += 12; + runtime_pseudp_reloc_v2_init = TRUE; + } + quick_symbol (abfd, "__imp_", name, "", UNDSEC, BSF_GLOBAL, 0); bfd_set_section_size (abfd, rt_rel, size); rt_rel_d = xmalloc (size); rt_rel->contents = rt_rel_d; memset (rt_rel_d, 0, size); - quick_reloc (abfd, size - 8, BFD_RELOC_RVA, 1); - quick_reloc (abfd, size - 12, BFD_RELOC_RVA, 2); - bfd_put_32 (abfd, bitsize, rt_rel_d + (size - 4)); - if (size != 12) - bfd_put_32 (abfd, 1, rt_rel_d + 8); + quick_reloc (abfd, size - 8, BFD_RELOC_RVA, 1); + quick_reloc (abfd, size - 12, BFD_RELOC_RVA, 2); + bfd_put_32 (abfd, bitsize, rt_rel_d + (size - 4)); + if (size != 12) + bfd_put_32 (abfd, 1, rt_rel_d + 8); save_relocs (rt_rel); bfd_set_symtab (abfd, symtab, symptr); bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, size); - } + } else - { + { bfd_set_section_size (abfd, rt_rel, 8); rt_rel_d = xmalloc (8); rt_rel->contents = rt_rel_d; @@ -2561,12 +2669,13 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8); } + bfd_make_readable (abfd); return abfd; } /* .section .rdata - .rva __pei386_runtime_relocator */ + .rva __pei386_runtime_relocator */ static bfd * pe_create_runtime_relocator_reference (bfd *parent) @@ -2610,88 +2719,68 @@ pe_create_runtime_relocator_reference (bfd *parent) } void -pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name) +pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name, + const char *symname) { - struct bfd_symbol *sym = *rel->sym_ptr_ptr; - struct bfd_link_hash_entry *name_thunk_sym; - struct bfd_link_hash_entry *name_imp_sym; - char *fixup_name, *impname; + const char *fixup_name = make_import_fixup_mark (rel, name); bfd *b; - int need_import_table = 1; - - /* name buffer is allocated with space at beginning for prefixes. */ - impname = name - (sizeof "__imp_" - 1); - memcpy (impname, "__imp_", sizeof "__imp_" - 1); - name_imp_sym = bfd_link_hash_lookup (link_info.hash, impname, 0, 0, 1); - impname = name - (sizeof "__nm_thnk_" - 1); - memcpy (impname, "__nm_thnk_", sizeof "__nm_thnk_" - 1); - name_thunk_sym = bfd_link_hash_lookup (link_info.hash, impname, 0, 0, 1); - - fixup_name = make_import_fixup_mark (rel, name); + /* This is the original implementation of the auto-import feature, which + primarily relied on the OS loader to patch things up with some help + from the pseudo-relocator to overcome the main limitation. See the + comment at the beginning of the file for an overview of the feature. */ + if (link_info.pei386_runtime_pseudo_reloc != 2) + { + struct bfd_link_hash_entry *name_thunk_sym; + /* name buffer is allocated with space at beginning for prefixes. */ + char *thname = name - (sizeof "__nm_thnk_" - 1); + memcpy (thname, "__nm_thnk_", sizeof "__nm_thnk_" - 1); + name_thunk_sym = bfd_link_hash_lookup (link_info.hash, thname, 0, 0, 1); - /* For version 2 pseudo relocation we don't need to add an import - if the import symbol is already present. */ - if (link_info.pei386_runtime_pseudo_reloc == 2 - && name_imp_sym - && name_imp_sym->type == bfd_link_hash_defined) - need_import_table = 0; + if (!(name_thunk_sym && name_thunk_sym->type == bfd_link_hash_defined)) + { + b = make_singleton_name_thunk (name, link_info.output_bfd); + add_bfd_to_link (b, b->filename, &link_info); - if (need_import_table == 1 - && (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined)) - { - b = make_singleton_name_thunk (name, link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); + /* If we ever use autoimport, we have to cast text section writable. */ + config.text_read_only = FALSE; + link_info.output_bfd->flags &= ~WP_TEXT; + } - /* If we ever use autoimport, we have to cast text section writable. - But not for version 2. */ - if (link_info.pei386_runtime_pseudo_reloc != 2) - { - config.text_read_only = FALSE; - link_info.output_bfd->flags &= ~WP_TEXT; - } - if (link_info.pei386_runtime_pseudo_reloc == 2) - { - b = make_singleton_name_imp (name, link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); + if (addend == 0 || link_info.pei386_runtime_pseudo_reloc == 1) + { + b = make_import_fixup_entry (name, fixup_name, symname, + link_info.output_bfd); + add_bfd_to_link (b, b->filename, &link_info); } } - if ((addend == 0 || link_info.pei386_runtime_pseudo_reloc) - && need_import_table == 1) + /* In the original implementation, the pseudo-relocator was only used when + the addend was not null. In the new implementation, the OS loader is + completely bypassed and the pseudo-relocator does the entire work. */ + if ((addend != 0 && link_info.pei386_runtime_pseudo_reloc == 1) + || link_info.pei386_runtime_pseudo_reloc == 2) { - extern char * pe_data_import_dll; - char * symname = pe_data_import_dll ? pe_data_import_dll : "unknown"; + if (pe_dll_extra_pe_debug) + printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", + fixup_name, (int) addend); - b = make_import_fixup_entry (name, fixup_name, symname, - link_info.output_bfd); + b = make_runtime_pseudo_reloc (name, fixup_name, addend, rel->howto->bitsize, + link_info.output_bfd); add_bfd_to_link (b, b->filename, &link_info); - } - if ((link_info.pei386_runtime_pseudo_reloc != 0 && addend != 0) - || link_info.pei386_runtime_pseudo_reloc == 2) - { - if (pe_dll_extra_pe_debug) - printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", - fixup_name, (int) addend); - - b = make_runtime_pseudo_reloc (name, fixup_name, addend, rel->howto->bitsize, - link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); + if (runtime_pseudo_relocs_created++ == 0) + { + b = pe_create_runtime_relocator_reference (link_info.output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + } + } - if (runtime_pseudo_relocs_created == 0) - { - b = pe_create_runtime_relocator_reference (link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); - } - runtime_pseudo_relocs_created++; - } - else if (addend != 0) - einfo (_("%P%X%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); + else if (addend != 0) + einfo (_("%X%P: %C: variable '%pT' can't be auto-imported; please read the documentation for ld's --enable-auto-import for details\n"), + s->owner, s, rel->address, (*rel->sym_ptr_ptr)->name); } - void pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_info *info) { @@ -2715,7 +2804,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ if (!outarch) { /* xgettext:c-format */ - einfo (_("%P%X: Can't open .lib file: %s\n"), impfilename); + einfo (_("%X%P: can't open .lib file: %s\n"), impfilename); return; } @@ -2742,15 +2831,15 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ found = (filename_cmp (ex->string, ibfd->filename) == 0); } /* If it matched, we must open a fresh BFD for it (the original - input BFD is still needed for the DLL's final link) and add - it into the archive member chain. */ + input BFD is still needed for the DLL's final link) and add + it into the archive member chain. */ if (found) { bfd *newbfd = bfd_openr (ibfd->my_archive ? ibfd->my_archive->filename : ibfd->filename, NULL); if (!newbfd) { - einfo (_("%P%X: bfd_openr %s: %E\n"), ibfd->filename); + einfo (_("%X%P: bfd_openr %s: %E\n"), ibfd->filename); return; } if (ibfd->my_archive) @@ -2762,7 +2851,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ bfd *arbfd = newbfd; if (!bfd_check_format_matches (arbfd, bfd_archive, NULL)) { - einfo (_("%P%X: %s(%s): can't find member in non-archive file"), + einfo (_("%X%P: %s(%s): can't find member in non-archive file"), ibfd->my_archive->filename, ibfd->filename); return; } @@ -2774,7 +2863,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ } if (!newbfd) { - einfo (_("%P%X: %s(%s): can't find member in archive"), + einfo (_("%X%P: %s(%s): can't find member in archive"), ibfd->my_archive->filename, ibfd->filename); return; } @@ -2849,10 +2938,10 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ head = ar_tail; if (! bfd_set_archive_head (outarch, head)) - einfo ("%P%X: bfd_set_archive_head: %E\n"); + einfo ("%X%P: bfd_set_archive_head: %E\n"); if (! bfd_close (outarch)) - einfo ("%P%X: bfd_close %s: %E\n", impfilename); + einfo ("%X%P: bfd_close %s: %E\n", impfilename); while (head != NULL) { @@ -2902,7 +2991,7 @@ pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) { h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); if (h->type == bfd_link_hash_undefined) - goto return_h; + goto return_h; } if (lname[0] == '?') @@ -2911,7 +3000,7 @@ pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) if (at || lname[0] == '@') { if (lname[0] == '@') - { + { if (pe_details->underscored) lname[0] = '_'; else @@ -2927,7 +3016,7 @@ pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) } } if (at) - *strchr (lname, '@') = 0; + *strchr (lname, '@') = 0; key.key = lname; kv = bsearch (&key, udef_table, undef_count, sizeof (struct key_value), undef_sort_cmp); @@ -2968,7 +3057,7 @@ pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) { h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE); if (h->type == bfd_link_hash_undefined) - goto return_h; + goto return_h; } return_NULL: @@ -2980,7 +3069,7 @@ pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name) static bfd_boolean pe_undef_count (struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED, - void *inf ATTRIBUTE_UNUSED) + void *inf ATTRIBUTE_UNUSED) { if (h->type == bfd_link_hash_undefined) undef_count++; @@ -2998,7 +3087,7 @@ pe_undef_fill (struct bfd_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) at = strchr (udef_table[undef_count].key + (udef_table[undef_count].key[0] == '@'), '@'); if (at) - at[1] = 0; + at[1] = 0; udef_table[undef_count].oname = h->root.string; undef_count++; } @@ -3036,7 +3125,7 @@ add_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *linfo) ldlang_add_file (fake_file); if (!bfd_link_add_symbols (abfd, linfo)) - einfo ("%P%X: addsym %s: %E\n", name); + einfo (_("%X%P: add symbols %s: %E\n"), name); } void @@ -3062,7 +3151,7 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo) for (i = 0; i < pe_def_file->num_imports && imp[i].module != module; i++) ; if (i >= pe_def_file->num_imports) - continue; + continue; dll_filename = module->name; dll_symname = xstrdup (module->name); @@ -3106,7 +3195,7 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo) blhe = bfd_link_hash_lookup (linfo->hash, name, FALSE, FALSE, FALSE); if (blhe) - is_undef = (blhe->type == bfd_link_hash_undefined); + is_undef = (blhe->type == bfd_link_hash_undefined); } else { @@ -3120,7 +3209,7 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo) blhe = pe_find_cdecl_alias_match (linfo, name); include_jmp_stub = TRUE; if (blhe) - is_undef = (blhe->type == bfd_link_hash_undefined); + is_undef = (blhe->type == bfd_link_hash_undefined); } free (name); @@ -3216,20 +3305,21 @@ pe_implied_import_dll (const char *filename) bfd_vma rdata_end = 0; bfd_vma bss_start = 1; bfd_vma bss_end = 0; + int from; /* No, I can't use bfd here. kernel32.dll puts its export table in the middle of the .rdata section. */ dll = bfd_openr (filename, pe_details->target_name); if (!dll) { - einfo ("%P%X: open %s: %E\n", filename); + einfo (_("%X%P: open %s: %E\n"), filename); return FALSE; } /* PEI dlls seem to be bfd_objects. */ if (!bfd_check_format (dll, bfd_object)) { - einfo ("%P%X: %s: this doesn't appear to be a DLL\n", filename); + einfo (_("%X%P: %s: this doesn't appear to be a DLL\n"), filename); return FALSE; } @@ -3356,6 +3446,40 @@ pe_implied_import_dll (const char *filename) return TRUE; } + /* This is an optimized version of the insertion loop, which avoids lots of + calls to realloc and memmove from def_file_add_import. */ + if ((from = def_file_add_import_from (pe_def_file, nexp, + erva + pe_as32 (erva + name_rvas), + dllname, 0, NULL, NULL)) >= 0) + { + for (i = 0; i < nexp; i++) + { + /* Pointer to the names vector. */ + bfd_vma name_rva = pe_as32 (erva + name_rvas + i * 4); + def_file_import *imp; + /* Pointer to the function address vector. */ + bfd_vma func_rva = pe_as32 (erva + exp_funcbase + i * 4); + /* is_data is true if the address is in the data, rdata or bss + segment. */ + const int is_data = + (func_rva >= data_start && func_rva < data_end) + || (func_rva >= rdata_start && func_rva < rdata_end) + || (func_rva >= bss_start && func_rva < bss_end); + + imp = def_file_add_import_at (pe_def_file, from + i, erva + name_rva, + dllname, i, NULL, NULL); + /* Mark symbol type. */ + imp->data = is_data; + + if (pe_dll_extra_pe_debug) + printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", + __FUNCTION__, dllname, erva + name_rva, + (unsigned long) func_rva, is_data ? "(data)" : ""); + } + + return TRUE; + } + /* Iterate through the list of symbols. */ for (i = 0; i < nexp; i++) { @@ -3369,26 +3493,26 @@ pe_implied_import_dll (const char *filename) /* Skip unwanted symbols, which are exported in buggy auto-import releases. */ if (! CONST_STRNEQ (erva + name_rva, "__nm_")) - { + { int is_dup = 0; - /* is_data is true if the address is in the data, rdata or bss + /* is_data is true if the address is in the data, rdata or bss segment. */ - is_data = + is_data = (func_rva >= data_start && func_rva < data_end) || (func_rva >= rdata_start && func_rva < rdata_end) || (func_rva >= bss_start && func_rva < bss_end); imp = def_file_add_import (pe_def_file, erva + name_rva, dllname, i, NULL, NULL, &is_dup); - /* Mark symbol type. */ - if (!is_dup) - imp->data = is_data; + /* Mark symbol type. */ + if (!is_dup) + imp->data = is_data; - if (pe_dll_extra_pe_debug) + if (pe_dll_extra_pe_debug) printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", __FUNCTION__, dllname, erva + name_rva, (unsigned long) func_rva, is_data ? "(data)" : ""); - } + } } return TRUE; @@ -3400,7 +3524,7 @@ pe_output_file_set_long_section_names (bfd *abfd) if (pe_use_coff_long_section_names < 0) return; if (!bfd_coff_set_long_section_names (abfd, pe_use_coff_long_section_names)) - einfo (_("%P%X: Error: can't use long section names on this arch\n")); + einfo (_("%X%P: error: can't use long section names on this arch\n")); } /* These are the main functions, called from the emulation. The first @@ -3493,6 +3617,6 @@ bfd_boolean pe_bfd_is_dll (bfd *abfd) { return (bfd_get_format (abfd) == bfd_object - && obj_pe (abfd) - && pe_data (abfd)->dll); + && obj_pe (abfd) + && pe_data (abfd)->dll); }