X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fpe-dll.c;h=4679fca6d52c91f973bd011a5634559f98655d46;hb=bc754168c7c3fc64e40bb7ddd97ea1ad07fb32d2;hp=d1bd32c4c70ba4affc70df275e62f65d8148e547;hpb=871b3ab29e87cf0de15f7e49ad19acc4f7f6f84c;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/pe-dll.c b/ld/pe-dll.c index d1bd32c4c7..4679fca6d5 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-2018 Free Software Foundation, Inc. + Copyright (C) 1998-2019 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 @@ -168,7 +169,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 +244,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. */ @@ -307,15 +307,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", @@ -442,7 +433,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); } @@ -454,16 +445,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 @@ -722,7 +722,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%pB%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -811,7 +811,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * if (tmp_at) *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; @@ -863,14 +863,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); } @@ -980,20 +980,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); @@ -1016,7 +1016,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; } @@ -1024,33 +1024,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")); 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))) + || !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); } @@ -1107,7 +1105,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); @@ -1143,7 +1141,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. */ @@ -1287,10 +1285,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; @@ -1301,7 +1301,7 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info, if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%pB%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -1311,7 +1311,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 @@ -1328,8 +1328,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); @@ -1341,6 +1353,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 @@ -1388,7 +1537,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 (_("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; @@ -1396,7 +1545,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) if (!bfd_generic_link_read_symbols (b)) { - einfo (_("%pB%F: could not read symbols: %E\n"), b); + einfo (_("%F%P: %pB: could not read symbols: %E\n"), b); return; } @@ -1456,6 +1605,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) @@ -1503,7 +1653,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; } @@ -1631,7 +1781,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) @@ -1786,7 +1936,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. */ @@ -1794,7 +1944,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; @@ -1807,8 +1956,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; @@ -1932,7 +2081,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); @@ -1944,16 +2093,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); @@ -2014,12 +2163,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); @@ -2027,7 +2176,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); @@ -2138,7 +2287,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) 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); @@ -2226,7 +2374,6 @@ 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: quick_reloc (abfd, 8, BFD_RELOC_32, 2); break; @@ -2236,16 +2383,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); @@ -2262,7 +2409,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); @@ -2282,7 +2429,7 @@ 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 { @@ -2295,7 +2442,7 @@ 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); @@ -2326,47 +2473,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) { @@ -2394,7 +2500,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); @@ -2409,7 +2515,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. */ @@ -2431,7 +2537,7 @@ 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 @@ -2469,14 +2575,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); @@ -2509,6 +2610,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++; @@ -2520,48 +2623,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); @@ -2575,6 +2683,7 @@ 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; } @@ -2608,7 +2717,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; @@ -2624,65 +2733,46 @@ 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); - - /* 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 (need_import_table == 1 - && (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined)) + /* 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) { - b = make_singleton_name_thunk (name, link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); + 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); - /* 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) + 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 we ever use autoimport, we have to cast text section writable. */ config.text_read_only = FALSE; link_info.output_bfd->flags &= ~WP_TEXT; } - if (link_info.pei386_runtime_pseudo_reloc == 2) + + if (addend == 0 || link_info.pei386_runtime_pseudo_reloc == 1) { - b = make_singleton_name_imp (name, link_info.output_bfd); + 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) - { - extern char * pe_data_import_dll; - char * symname = pe_data_import_dll ? pe_data_import_dll : "unknown"; - - b = make_import_fixup_entry (name, fixup_name, symname, - link_info.output_bfd); - add_bfd_to_link (b, b->filename, &link_info); - } - - if ((link_info.pei386_runtime_pseudo_reloc != 0 && addend != 0) + /* 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) { if (pe_dll_extra_pe_debug) @@ -2693,19 +2783,18 @@ pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name) link_info.output_bfd); add_bfd_to_link (b, b->filename, &link_info); - if (runtime_pseudo_relocs_created == 0) + 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); + 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) { @@ -2729,7 +2818,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; } @@ -2764,7 +2853,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_ ? 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) @@ -2776,7 +2865,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; } @@ -2788,7 +2877,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; } @@ -2863,10 +2952,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) { @@ -3050,7 +3139,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: add symbols %s: %E\n"), name); + einfo (_("%X%P: add symbols %s: %E\n"), name); } void @@ -3230,20 +3319,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; } @@ -3370,6 +3460,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++) { @@ -3414,7 +3538,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 @@ -3456,7 +3580,7 @@ pe_dll_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 (); @@ -3488,7 +3612,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 ();