X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fpe-dll.c;h=397af8780e47f5cd9ccc1c24a104906876edd38e;hb=71780f455fbf35ed4c48e94b4228c55c11a213c8;hp=055a6cf32c0ef7b873ce8864d367e10ee59d9c97;hpb=370dfff4c4b46fc194cf1ab2b0762c2a9deae7ba;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/pe-dll.c b/ld/pe-dll.c index 055a6cf32c..397af8780e 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-2016 Free Software Foundation, Inc. + Copyright (C) 1998-2020 Free Software Foundation, Inc. Written by DJ Delorie This file is part of the GNU Binutils. @@ -25,6 +25,7 @@ #include "libiberty.h" #include "filenames.h" #include "safe-ctype.h" +#include "ctf-api.h" #include @@ -159,6 +160,7 @@ int pe_dll_extra_pe_debug = 0; int pe_use_nul_prefixed_import_tables = 0; int pe_use_coff_long_section_names = -1; int pe_leading_underscore = -1; +int pe_dll_enable_reloc_section = 0; /* Static variables and types. */ @@ -168,7 +170,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 +245,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 +270,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 +308,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 +336,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 +434,7 @@ pe_dll_id_target (const char *target) pe_leading_underscore = (u != 0 ? 1 : 0); return; } - einfo (_("%XUnsupported PEI architecture: %s\n"), target); + einfo (_("%X%P: unsupported PEI architecture: %s\n"), target); exit (1); } @@ -440,16 +446,25 @@ typedef struct bfd_vma vma; char type; short extra; + int idx; } reloc_data_type; static int reloc_sort (const void *va, const void *vb) { - bfd_vma a = ((const reloc_data_type *) va)->vma; - bfd_vma b = ((const reloc_data_type *) vb)->vma; + const reloc_data_type *a = (const reloc_data_type *) va; + const reloc_data_type *b = (const reloc_data_type *) vb; - return (a > b) ? 1 : ((a < b) ? -1 : 0); + if (a->vma > b->vma) + return 1; + if (a->vma < b->vma) + return -1; + if (a->idx > b->idx) + return 1; + if (a->idx < b->idx) + return -1; + return 0; } static int @@ -541,7 +556,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 +696,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 +723,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 +740,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 +751,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 +776,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 +810,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 (_("%XCannot 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 +824,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 +845,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 +864,14 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * { if (pe_dll_warn_dup_exports) /* xgettext:c-format */ - einfo (_("%XError, 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 (_("Warning, duplicate EXPORT: %s\n"), + einfo (_("%P: warning, duplicate EXPORT: %s\n"), e[j - 1].name); } @@ -942,7 +957,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 +981,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 (_("%XCannot 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 (_("%XCannot 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 (_("%XCannot export %s: symbol not found\n"), + einfo (_("%X%P: cannot export %s: symbol not found\n"), int_name); } free (name); @@ -1002,7 +1017,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; } @@ -1010,33 +1025,31 @@ build_filler_bfd (int include_edata) { edata_s = bfd_make_section_old_way (filler_bfd, ".edata"); if (edata_s == NULL - || !bfd_set_section_flags (filler_bfd, edata_s, - (SEC_HAS_CONTENTS - | SEC_ALLOC - | SEC_LOAD - | SEC_KEEP - | SEC_IN_MEMORY))) + || !bfd_set_section_flags (edata_s, (SEC_HAS_CONTENTS + | SEC_ALLOC + | SEC_LOAD + | 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); + bfd_set_section_size (edata_s, edata_sz); } reloc_s = bfd_make_section_old_way (filler_bfd, ".reloc"); if (reloc_s == NULL - || !bfd_set_section_flags (filler_bfd, reloc_s, - (SEC_HAS_CONTENTS - | SEC_ALLOC - | SEC_LOAD - | SEC_KEEP - | SEC_IN_MEMORY))) - { - einfo ("%X%P: can not create .reloc section: %E\n"); + || !bfd_set_section_flags (reloc_s, (SEC_HAS_CONTENTS + | SEC_ALLOC + | SEC_LOAD + | SEC_KEEP + | SEC_IN_MEMORY))) + { + einfo (_("%X%P: can not create .reloc section: %E\n")); return; } - bfd_set_section_size (filler_bfd, reloc_s, 0); + bfd_set_section_size (reloc_s, 0); ldlang_add_file (filler_file); } @@ -1082,8 +1095,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 +1106,7 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) if (pi != -1) { /* xgettext:c-format */ - einfo (_("%XError, 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 +1128,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++; @@ -1126,6 +1139,12 @@ generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) pe_def_file->exports[i].ordinal = next_ordinal; } + /* PR 12969: Check for more than 1^16 ordinals. */ + if (max_ordinal > 65535 || next_ordinal > 65535) + /* xgettext:c-format */ + 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. */ edata_sz = (40 /* directory */ + 4 * export_table_size /* addresses */ @@ -1149,7 +1168,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); @@ -1217,21 +1236,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; @@ -1243,7 +1262,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) @@ -1267,10 +1286,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, - const char *name, - int (*cb) (arelent *, asection *)) +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; @@ -1281,7 +1302,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; } @@ -1291,7 +1312,7 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info, { arelent **relocs; int relsize, nrelocs, i; - int flags = bfd_get_section_flags (b, s); + int flags = bfd_section_flags (s); /* Skip discarded linkonce sections. */ if (flags & SEC_LINK_ONCE @@ -1308,8 +1329,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); + /* 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); @@ -1321,6 +1354,143 @@ 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; + + /* We replace the original name with the __imp_ prefixed one, this + 1) may trash memory 2) leads to duplicate symbols. But this is + better than having a misleading name that can confuse GDB. */ + undef->root.string = sym->root.string; + + 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 @@ -1368,7 +1538,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; @@ -1376,7 +1546,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; } @@ -1436,6 +1606,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) } reloc_data[total_relocs].vma = sec_vma + relocs[i]->address; + reloc_data[total_relocs].idx = total_relocs; #define BITS_AND_SHIFT(bits, shift) (bits * 1000 | shift) @@ -1483,7 +1654,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) /* Fall through. */ default: /* xgettext:c-format */ - einfo (_("%XError: %d-bit reloc in dll\n"), + einfo (_("%X%P: error: %d-bit reloc in dll\n"), relocs[i]->howto->bitsize); break; } @@ -1611,8 +1782,8 @@ pe_dll_generate_def_file (const char *pe_out_def_filename) if (out == NULL) /* xgettext:c-format */ - einfo (_("%s: Can't open output def file %s\n"), - program_name, pe_out_def_filename); + einfo (_("%P: can't open output def file %s\n"), + pe_out_def_filename); if (pe_def_file) { @@ -1766,7 +1937,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. */ @@ -1774,7 +1945,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; @@ -1787,8 +1957,8 @@ quick_section (bfd *abfd, const char *name, int flags, int align) asymbol *sym; sec = bfd_make_section_old_way (abfd, name); - bfd_set_section_flags (abfd, sec, flags | SEC_ALLOC | SEC_LOAD | SEC_KEEP); - bfd_set_section_alignment (abfd, sec, align); + bfd_set_section_flags (sec, flags | SEC_ALLOC | SEC_LOAD | SEC_KEEP); + bfd_set_section_alignment (sec, align); /* Remember to undo this before trying to link internally! */ sec->output_section = sec; @@ -1863,20 +2033,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 * @@ -1912,7 +2082,7 @@ make_head (bfd *parent) pointer to the list points to the *end* of this section, which is the start of the list of sections from other objects. */ - bfd_set_section_size (abfd, id2, 20); + bfd_set_section_size (id2, 20); d2 = xmalloc (20); id2->contents = d2; memset (d2, 0, 20); @@ -1924,16 +2094,16 @@ make_head (bfd *parent) save_relocs (id2); if (pe_use_nul_prefixed_import_tables) - bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + bfd_set_section_size (id5, PE_IDATA5_SIZE); else - bfd_set_section_size (abfd, id5, 0); + bfd_set_section_size (id5, 0); d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; memset (d5, 0, PE_IDATA5_SIZE); if (pe_use_nul_prefixed_import_tables) - bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + bfd_set_section_size (id4, PE_IDATA4_SIZE); else - bfd_set_section_size (abfd, id4, 0); + bfd_set_section_size (id4, 0); d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; memset (d4, 0, PE_IDATA4_SIZE); @@ -1957,15 +2127,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) @@ -1994,12 +2164,12 @@ make_tail (bfd *parent) id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); quick_symbol (abfd, U (""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); - bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + bfd_set_section_size (id4, PE_IDATA4_SIZE); d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; memset (d4, 0, PE_IDATA4_SIZE); - bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + bfd_set_section_size (id5, PE_IDATA5_SIZE); d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; memset (d5, 0, PE_IDATA5_SIZE); @@ -2007,7 +2177,7 @@ make_tail (bfd *parent) len = strlen (dll_filename) + 1; if (len & 1) len++; - bfd_set_section_size (abfd, id7, len); + bfd_set_section_size (id7, len); d7 = xmalloc (len); id7->contents = d7; strcpy ((char *) d7, dll_filename); @@ -2027,25 +2197,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[] = { @@ -2053,11 +2223,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[] = { @@ -2065,10 +2235,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[] = { @@ -2118,7 +2288,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); @@ -2180,7 +2349,7 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) if (include_jmp_stub) { - bfd_set_section_size (abfd, tx, jmp_byte_count); + bfd_set_section_size (tx, jmp_byte_count); td = xmalloc (jmp_byte_count); tx->contents = td; memcpy (td, jmp_bytes, jmp_byte_count); @@ -2194,7 +2363,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: @@ -2206,8 +2375,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: @@ -2216,16 +2384,16 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) save_relocs (tx); } else - bfd_set_section_size (abfd, tx, 0); + bfd_set_section_size (tx, 0); - bfd_set_section_size (abfd, id7, 4); + bfd_set_section_size (id7, 4); d7 = xmalloc (4); id7->contents = d7; memset (d7, 0, 4); quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); save_relocs (id7); - bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + bfd_set_section_size (id5, PE_IDATA5_SIZE); d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; memset (d5, 0, PE_IDATA5_SIZE); @@ -2242,7 +2410,7 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) save_relocs (id5); } - bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + bfd_set_section_size (id4, PE_IDATA4_SIZE); d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; memset (d4, 0, PE_IDATA4_SIZE); @@ -2262,10 +2430,12 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) if (exp->flag_noname) { len = 0; - bfd_set_section_size (abfd, id6, 0); + bfd_set_section_size (id6, 0); } else { + int ord; + /* { short, asciz } */ if (exp->its_name) len = 2 + strlen (exp->its_name) + 1; @@ -2273,12 +2443,17 @@ make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) len = 2 + strlen (exp->name) + 1; if (len & 1) len++; - bfd_set_section_size (abfd, id6, len); + bfd_set_section_size (id6, len); d6 = xmalloc (len); id6->contents = d6; memset (d6, 0, len); - d6[0] = exp->hint & 0xff; - d6[1] = exp->hint >> 8; + + /* PR 20880: Use exp->hint as a backup, just in case exp->ordinal + contains an invalid value (-1). */ + ord = (exp->ordinal >= 0) ? exp->ordinal : exp->hint; + d6[0] = ord; + d6[1] = ord >> 8; + if (exp->its_name) strcpy ((char*) d6 + 2, exp->its_name); else @@ -2299,47 +2474,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) { @@ -2367,7 +2501,7 @@ make_singleton_name_thunk (const char *import, bfd *parent) quick_symbol (abfd, "__nm_", import, "", UNDSEC, BSF_GLOBAL, 0); /* We need space for the real thunk and for the null terminator. */ - bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE * 2); + bfd_set_section_size (id4, PE_IDATA4_SIZE * 2); d4 = xmalloc (PE_IDATA4_SIZE * 2); id4->contents = d4; memset (d4, 0, PE_IDATA4_SIZE * 2); @@ -2382,53 +2516,37 @@ make_singleton_name_thunk (const char *import, bfd *parent) return abfd; } -static char * -make_import_fixup_mark (arelent *rel) +static const char * +make_import_fixup_mark (arelent *rel, char *name) { /* We convert reloc to symbol, for later reference. */ - static int counter; - static char *fixup_name = NULL; - static size_t buffer_len = 0; - + static unsigned int counter; struct bfd_symbol *sym = *rel->sym_ptr_ptr; - bfd *abfd = bfd_asymbol_bfd (sym); struct bfd_link_hash_entry *bh; + char *fixup_name, buf[26]; + size_t prefix_len; - if (!fixup_name) - { - fixup_name = xmalloc (384); - buffer_len = 384; - } - - if (strlen (sym->name) + 25 > buffer_len) - /* Assume 25 chars for "__fu" + counter + "_". If counter is - bigger than 20 digits long, we've got worse problems than - overflowing this buffer... */ - { - free (fixup_name); - /* New buffer size is length of symbol, plus 25, but - then rounded up to the nearest multiple of 128. */ - buffer_len = ((strlen (sym->name) + 25) + 127) & ~127; - fixup_name = xmalloc (buffer_len); - } - - sprintf (fixup_name, "__fu%d_%s", counter++, sym->name); + /* "name" buffer has space before the symbol name for prefixes. */ + sprintf (buf, "__fu%d_", counter++); + prefix_len = strlen (buf); + fixup_name = name - prefix_len; + memcpy (fixup_name, buf, prefix_len); bh = NULL; bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, 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, @@ -2458,14 +2576,9 @@ 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); + bfd_set_section_size (id2, 20); d2 = xmalloc (20); id2->contents = d2; memset (d2, 0, 20); @@ -2484,8 +2597,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, @@ -2498,6 +2611,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++; @@ -2509,48 +2624,53 @@ 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); + bfd_set_section_size (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); + { + bfd_set_section_size (rt_rel, 8); rt_rel_d = xmalloc (8); rt_rel->contents = rt_rel_d; memset (rt_rel_d, 0, 8); @@ -2564,12 +2684,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) @@ -2597,7 +2718,7 @@ pe_create_runtime_relocator_reference (bfd *parent) quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC, BSF_NO_FLAGS, 0); - bfd_set_section_size (abfd, extern_rt_rel, PE_IDATA5_SIZE); + bfd_set_section_size (extern_rt_rel, PE_IDATA5_SIZE); extern_rt_rel_d = xcalloc (1, PE_IDATA5_SIZE); extern_rt_rel->contents = extern_rt_rel_d; @@ -2613,89 +2734,68 @@ pe_create_runtime_relocator_reference (bfd *parent) } void -pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend) +pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name, + const char *symname) { - char buf[300]; - struct bfd_symbol *sym = *rel->sym_ptr_ptr; - struct bfd_link_hash_entry *name_thunk_sym; - struct bfd_link_hash_entry *name_imp_sym; - const char *name = sym->name; - char *fixup_name = make_import_fixup_mark (rel); + const char *fixup_name = make_import_fixup_mark (rel, name); bfd *b; - int need_import_table = 1; - sprintf (buf, "__imp_%s", name); - name_imp_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); - - sprintf (buf, "__nm_thnk_%s", name); - - name_thunk_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + /* 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 (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), - s->owner, s, rel->address, sym->name); - einfo ("%X"); - } + 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) { @@ -2719,7 +2819,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ if (!outarch) { /* xgettext:c-format */ - einfo (_("%XCan't open .lib file: %s\n"), impfilename); + einfo (_("%X%P: can't open .lib file: %s\n"), impfilename); return; } @@ -2746,15 +2846,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 (_("%Xbfd_openr %s: %E\n"), ibfd->filename); + einfo (_("%X%P: bfd_openr %s: %E\n"), ibfd->filename); return; } if (ibfd->my_archive) @@ -2766,7 +2866,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 (_("%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; } @@ -2778,7 +2878,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ } if (!newbfd) { - einfo (_("%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; } @@ -2853,10 +2953,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 ("%Xbfd_set_archive_head: %E\n"); + einfo ("%X%P: bfd_set_archive_head: %E\n"); if (! bfd_close (outarch)) - einfo ("%Xbfd_close %s: %E\n", impfilename); + einfo ("%X%P: bfd_close %s: %E\n", impfilename); while (head != NULL) { @@ -2906,7 +3006,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] == '?') @@ -2915,7 +3015,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 @@ -2931,7 +3031,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); @@ -2972,7 +3072,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: @@ -2984,7 +3084,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++; @@ -3002,7 +3102,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++; } @@ -3040,7 +3140,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 ("%Xaddsym %s: %E\n", name); + einfo (_("%X%P: add symbols %s: %E\n"), name); } void @@ -3066,7 +3166,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); @@ -3110,7 +3210,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 { @@ -3124,7 +3224,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); @@ -3190,7 +3290,7 @@ pe_get32 (bfd *abfd, int where) bfd_seek (abfd, (file_ptr) where, SEEK_SET); bfd_bread (b, (bfd_size_type) 4, abfd); - return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); + return b[0] + (b[1] << 8) + (b[2] << 16) + ((unsigned) b[3] << 24); } static unsigned int @@ -3198,7 +3298,7 @@ pe_as32 (void *ptr) { unsigned char *b = ptr; - return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); + return b[0] + (b[1] << 8) + (b[2] << 16) + ((unsigned) b[3] << 24); } bfd_boolean @@ -3220,20 +3320,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 ("%Xopen %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 ("%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; } @@ -3360,6 +3461,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++) { @@ -3373,26 +3508,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; @@ -3404,7 +3539,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 (_("%XError: 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 @@ -3420,7 +3555,14 @@ pe_dll_build_sections (bfd *abfd, struct bfd_link_info *info) process_def_file_and_drectve (abfd, info); if (pe_def_file->num_exports == 0 && !bfd_link_pic (info)) - return; + { + if (pe_dll_enable_reloc_section) + { + build_filler_bfd (0); + pe_output_file_set_long_section_names (filler_bfd); + } + return; + } generate_edata (abfd, info); build_filler_bfd (1); @@ -3439,33 +3581,16 @@ pe_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) void pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info) { - pe_dll_id_target (bfd_get_target (abfd)); - pe_output_file_set_long_section_names (abfd); - image_base = pe_data (abfd)->pe_opthdr.ImageBase; + pe_exe_fill_sections (abfd, info); - generate_reloc (abfd, info); - if (reloc_sz > 0) + if (edata_s) { - bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); - - /* Resize the sections. */ - lang_reset_memory_regions (); - lang_size_sections (NULL, TRUE); - - /* Redo special stuff. */ - ldemul_after_allocation (); - - /* Do the assignments again. */ - lang_do_assignments (lang_final_phase_enum); + fill_edata (abfd, info); + edata_s->contents = edata_d; } - fill_edata (abfd, info); - if (bfd_link_dll (info)) pe_data (abfd)->dll = 1; - - edata_s->contents = edata_d; - reloc_s->contents = reloc_d; } void @@ -3478,7 +3603,7 @@ pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info) generate_reloc (abfd, info); if (reloc_sz > 0) { - bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); + bfd_set_section_size (reloc_s, reloc_sz); /* Resize the sections. */ lang_reset_memory_regions (); @@ -3497,6 +3622,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); }