Speed up direct linking with DLLs on Windows (1/2).
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 4 Apr 2018 10:07:50 +0000 (12:07 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 4 Apr 2018 10:07:50 +0000 (12:07 +0200)
This patch deals with the auto-import feature.  There are 2 versions
of this feature: the original one, which was piggybacked on the OS
loader with an optional help from the runtime (--enable-auto-import
--enable-runtime-pseudo-reloc-v1) and is still the one mostly
documented in the sources and manual; the enhanced one by Kai Tietz,
which is entirely piggybacked on the runtime (--enable-auto-import
--enable-runtime-pseudo-reloc-v2) and is the default for Mingw and
Cygwin nowadays.

The implementation is inefficient because of pe[p]_find_data_imports:
for every undefined symbol, the function walks the entire set of
relocations for all the input files and does a direct name comparison
for each of them.

This is easily fixable by using a hash-based map for v1 and a simple
hash table for v2.  This patch leaves v1 alone and only changes v2.
It also factors out pe[p]_find_data_imports into a common function,
removes old cruft left and right, and attempts to better separate
the implementations of v1 and v2 in the code.

ld/
* emultempl/pe.em (U_SIZE): Delete.
(pe_data_import_dll): Likewise.
(make_import_fixup): Return void, take 4th parameter and pass it down
in call to pe_create_import_fixup.
(pe_find_data_imports): Move to...
(gld_${EMULATION_NAME}_after_open): Run the stdcall fixup pass after
the auto-import pass and add a guard before running the latter.
* emultempl/pep.em (U_SIZE): Delete.
(pep_data_import_dll): Likewise.
(make_import_fixup): Return void, take 4th parameter and pass it down
in call to pe_create_import_fixup.
(pep_find_data_imports): Move to...
(gld_${EMULATION_NAME}_after_open): Run the stdcall fixup pass after
the auto-import pass and add a guard before running the latter.
* pe-dll.c (runtime_pseudp_reloc_v2_init): Change type to bfd_boolean.
(pe_walk_relocs_of_symbol): Rename into...
(pe_walk_relocs): ...this.  Add 2 more parameters,4th parameter to the
callback prototype and pass 4th parameter in calls to the callback.
If the import hash table is present, invoke the callback on the reloc
if the symbol name is in the table.
(pe_find_data_imports): ...here.  Take 2 parameters.  Build an import
hash table for the pseudo-relocation support version 2.  When it is
built, walk the relocations only once at the end; when it is not, do
not build a fixup when the symbol isn't part of an import table.
Issue the associated warning only after a first fixup is built.
(tmp_seq2): Delete.
(make_singleton_name_imp): Likewise.
(make_import_fixup_mark): Return const char * and a stable string.
(make_import_fixup_entry): Do not deal with the pseudo-relocation
support version 2.
(make_runtime_pseudo_reloc): Factor out code and fix formatting.
(pe_create_import_fixup): Add 5th parameter.  Clearly separate the
pseudo-relocation support version 2 from the rest.  Fix formatting.
* pe-dll.h (pe_walk_relocs_of_symbol): Delete.
(pe_find_data_imports): Declare.
(pe_create_import_fixup): Add 5th parameter.
* pep-dll.c (pe_data_import_dll): Delete.
(pe_find_data_imports): Define.
(pe_walk_relocs_of_symbol): Delete.
* pep-dll.h (pep_walk_relocs_of_symbol): Delete.
(pep_find_data_imports): Declare.
(pep_create_import_fixup): Add 5th parameter.
* ld.texinfo (--enable-auto-import): Adjust to new implementation.

ld/ChangeLog
ld/emultempl/pe.em
ld/emultempl/pep.em
ld/ld.texinfo
ld/pe-dll.c
ld/pe-dll.h
ld/pep-dll.c
ld/pep-dll.h

index f6a65d7b50147601b9079ba3527d81771b61dea0..b1a1dda62b760f4dcfe84bdbfaa4422ce8f768c6 100644 (file)
@@ -1,3 +1,49 @@
+2018-04-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * emultempl/pe.em (U_SIZE): Delete.
+       (pe_data_import_dll): Likewise.
+       (make_import_fixup): Return void, take 4th parameter and pass it down
+       in call to pe_create_import_fixup.
+       (pe_find_data_imports): Move to...
+       (gld_${EMULATION_NAME}_after_open): Run the stdcall fixup pass after
+       the auto-import pass and add a guard before running the latter.
+       * emultempl/pep.em (U_SIZE): Delete.
+       (pep_data_import_dll): Likewise.
+       (make_import_fixup): Return void, take 4th parameter and pass it down
+       in call to pe_create_import_fixup.
+       (pep_find_data_imports): Move to...
+       (gld_${EMULATION_NAME}_after_open): Run the stdcall fixup pass after
+       the auto-import pass and add a guard before running the latter.
+       * pe-dll.c (runtime_pseudp_reloc_v2_init): Change type to bfd_boolean.
+       (pe_walk_relocs_of_symbol): Rename into...
+       (pe_walk_relocs): ...this.  Add 2 more parameters,4th parameter to the
+       callback prototype and pass 4th parameter in calls to the callback.
+       If the import hash table is present, invoke the callback on the reloc
+       if the symbol name is in the table.
+       (pe_find_data_imports): ...here.  Take 2 parameters.  Build an import
+       hash table for the pseudo-relocation support version 2.  When it is
+       built, walk the relocations only once at the end; when it is not, do
+       not build a fixup when the symbol isn't part of an import table.
+       Issue the associated warning only after a first fixup is built.
+       (tmp_seq2): Delete.
+       (make_singleton_name_imp): Likewise.
+       (make_import_fixup_mark): Return const char * and a stable string.
+       (make_import_fixup_entry): Do not deal with the pseudo-relocation
+       support version 2.
+       (make_runtime_pseudo_reloc): Factor out code and fix formatting.
+       (pe_create_import_fixup): Add 5th parameter.  Clearly separate the
+       pseudo-relocation support version 2 from the rest.  Fix formatting.
+       * pe-dll.h (pe_walk_relocs_of_symbol): Delete.
+       (pe_find_data_imports): Declare.
+       (pe_create_import_fixup): Add 5th parameter.
+       * pep-dll.c (pe_data_import_dll): Delete.
+       (pe_find_data_imports): Define.
+       (pe_walk_relocs_of_symbol): Delete.
+       * pep-dll.h (pep_walk_relocs_of_symbol): Delete.
+       (pep_find_data_imports): Declare.
+       (pep_create_import_fixup): Add 5th parameter.
+       * ld.texinfo (--enable-auto-import): Adjust to new implementation.
+
 2018-04-04  Nick Clifton  <nickc@redhat.com>
 
        * po/es.po: Updated Spanish translation.
index 5cc933a91c5f3704e445b3f2fbb0453a133e0776..06cfe7d45d666595d83b0d3e0113dd12832d6f86 100644 (file)
@@ -385,11 +385,6 @@ typedef struct
 #define U(CSTR) \
   ((is_underscoring () == 0) ? CSTR : "_" CSTR)
 
-/* Get size of constant string for a possible underscore prefixed
-   C visible symbol.  */
-#define U_SIZE(CSTR) \
-  (sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-
 #define D(field,symbol,def,usc)  {&pe.field, sizeof (pe.field), def, symbol, 0, usc}
 
 static definfo init[] =
@@ -1022,13 +1017,6 @@ gld_${EMULATION_NAME}_after_parse (void)
   after_parse_default ();
 }
 
-/* pe-dll.c directly accesses pe_data_import_dll,
-   so it must be defined outside of #ifdef DLL_SUPPORT.
-   Note - this variable is deliberately not initialised.
-   This allows it to be treated as a common varaible, and only
-   exist in one incarnation in a multiple target enabled linker.  */
-char * pe_data_import_dll;
-
 #ifdef DLL_SUPPORT
 static struct bfd_link_hash_entry *pe_undef_found_sym;
 
@@ -1129,11 +1117,12 @@ pe_fixup_stdcalls (void)
       }
 }
 
-static int
-make_import_fixup (arelent *rel, asection *s, char *name)
+static void
+make_import_fixup (arelent *rel, asection *s, char *name, const char *symname)
 {
   struct bfd_symbol *sym = *rel->sym_ptr_ptr;
   char addend[4];
+  bfd_vma _addend;
 
   if (pe_dll_extra_pe_debug)
     printf ("arelent: %s@%#lx: add=%li\n", sym->name,
@@ -1143,117 +1132,8 @@ make_import_fixup (arelent *rel, asection *s, char *name)
     einfo (_("%P: %C: cannot get section contents - auto-import exception\n"),
           s->owner, s, rel->address);
 
-  pe_create_import_fixup (rel, s, bfd_get_32 (s->owner, addend), name);
-
-  return 1;
-}
-
-static void
-pe_find_data_imports (void)
-{
-  struct bfd_link_hash_entry *undef, *sym;
-  size_t namelen;
-  char *buf, *name;
-
-  if (link_info.pei386_auto_import == 0)
-    return;
-
-  namelen = 0;
-  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;
-
-  /* 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)
-       {
-         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)
-           {
-             bfd *b = sym->u.def.section->owner;
-             asymbol **symbols;
-             int nsyms, i;
-
-             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)
-                   {
-                     warned = TRUE;
-                     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"));
-                   }
-               }
-
-             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 (! CONST_STRNEQ (symbols[i]->name, U ("_head_")))
-                   continue;
-
-                 if (pe_dll_extra_pe_debug)
-                   printf ("->%s\n", symbols[i]->name);
-
-                 pe_data_import_dll = (char *) (symbols[i]->name
-                                                + U_SIZE ("_head_") - 1);
-                 break;
-               }
-
-             pe_walk_relocs_of_symbol (&link_info, name, make_import_fixup);
-
-             /* Let's differentiate it somehow from defined.  */
-             undef->type = bfd_link_hash_defweak;
-             /* We replace original name with __imp_ prefixed, this
-                1) may trash memory 2) leads to duplicate symbol generation.
-                Still, IMHO it's better than having name polluted.  */
-             undef->root.string = sym->root.string;
-             undef->u.def.value = sym->u.def.value;
-             undef->u.def.section = sym->u.def.section;
-           }
-       }
-    }
-  free (buf);
+  _addend = bfd_get_32 (s->owner, addend);
+  pe_create_import_fixup (rel, s, _addend, name, symname);
 }
 
 static bfd_boolean
@@ -1523,16 +1403,15 @@ gld_${EMULATION_NAME}_after_open (void)
   pe_output_file_set_long_section_names (link_info.output_bfd);
 
 #ifdef DLL_SUPPORT
-  if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */
-    pe_fixup_stdcalls ();
-
   pe_process_import_defs (link_info.output_bfd, &link_info);
 
-  pe_find_data_imports ();
+  if (link_info.pei386_auto_import) /* -1=warn or 1=enable */
+    pe_find_data_imports (U ("_head_"), make_import_fixup);
 
-  /* As possibly new symbols are added by imports, we rerun
-     stdcall/fastcall fixup here.  */
-  if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */
+  /* The implementation of the feature is rather dumb and would cause the
+     compilation time to go through the roof if there are many undefined
+     symbols in the link, so it needs to be run after auto-import.  */
+  if (pe_enable_stdcall_fixup) /* -1=warn or 1=enable */
     pe_fixup_stdcalls ();
 
 #if defined (TARGET_IS_i386pe) \
index 96942ecba8e662562a9e54cc73a278360570fcb9..1a7394ea465fdb3f0a7787318710f0ddca0ab9e3 100644 (file)
@@ -356,11 +356,6 @@ typedef struct
 #define U(CSTR) \
   ((is_underscoring () == 0) ? CSTR : "_" CSTR)
 
-/* Get size of constant string for a possible underscore prefixed
-   C visible symbol.  */
-#define U_SIZE(CSTR) \
-  (sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-
 #define D(field,symbol,def,usc)  {&pep.field, sizeof (pep.field), def, symbol, 0, usc}
 
 static definfo init[] =
@@ -966,13 +961,6 @@ gld_${EMULATION_NAME}_after_parse (void)
   after_parse_default ();
 }
 
-/* pep-dll.c directly accesses pep_data_import_dll,
-   so it must be defined outside of #ifdef DLL_SUPPORT.
-   Note - this variable is deliberately not initialised.
-   This allows it to be treated as a common varaible, and only
-   exist in one incarnation in a multiple target enabled linker.  */
-char * pep_data_import_dll;
-
 #ifdef DLL_SUPPORT
 static struct bfd_link_hash_entry *pep_undef_found_sym;
 
@@ -1074,8 +1062,8 @@ pep_fixup_stdcalls (void)
       }
 }
 
-static int
-make_import_fixup (arelent *rel, asection *s, char *name)
+static void
+make_import_fixup (arelent *rel, asection *s, char *name, const char *symname)
 {
   struct bfd_symbol *sym = *rel->sym_ptr_ptr;
   char addend[8];
@@ -1128,98 +1116,8 @@ make_import_fixup (arelent *rel, asection *s, char *name)
        printf (" pcrel");
       printf (" %d bit rel.\n", (int) rel->howto->bitsize);
     }
-  pep_create_import_fixup (rel, s, _addend, name);
 
-  return 1;
-}
-
-static void
-pep_find_data_imports (void)
-{
-  struct bfd_link_hash_entry *undef, *sym;
-  size_t namelen;
-  char *buf, *name;
-
-  if (link_info.pei386_auto_import == 0)
-    return;
-
-  namelen = 0;
-  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;
-
-  /* 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)
-       {
-         char *impname;
-
-         if (pep_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)
-           {
-             bfd *b = sym->u.def.section->owner;
-             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 (! CONST_STRNEQ (symbols[i]->name, U ("_head_")))
-                   continue;
-
-                 if (pep_dll_extra_pe_debug)
-                   printf ("->%s\n", symbols[i]->name);
-
-                 pep_data_import_dll = (char *) (symbols[i]->name
-                                                 + U_SIZE ("_head_") - 1);
-                 break;
-               }
-
-             pep_walk_relocs_of_symbol (&link_info, name, make_import_fixup);
-
-             /* Let's differentiate it somehow from defined.  */
-             undef->type = bfd_link_hash_defweak;
-             /* We replace original name with __imp_ prefixed, this
-                1) may trash memory 2) leads to duplicate symbol generation.
-                Still, IMHO it's better than having name polluted.  */
-             undef->root.string = sym->root.string;
-             undef->u.def.value = sym->u.def.value;
-             undef->u.def.section = sym->u.def.section;
-           }
-       }
-    }
-  free (buf);
+  pep_create_import_fixup (rel, s, _addend, name, symname);
 }
 
 static bfd_boolean
@@ -1491,16 +1389,15 @@ gld_${EMULATION_NAME}_after_open (void)
   pep_output_file_set_long_section_names (link_info.output_bfd);
 
 #ifdef DLL_SUPPORT
-  if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */
-    pep_fixup_stdcalls ();
-
   pep_process_import_defs (link_info.output_bfd, &link_info);
 
-  pep_find_data_imports ();
+  if (link_info.pei386_auto_import) /* -1=warn or 1=enable */
+    pep_find_data_imports (U ("_head_"), make_import_fixup);
 
-  /* As possibly new symbols are added by imports, we rerun
-     stdcall/fastcall fixup here.  */
-  if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */
+  /* The implementation of the feature is rather dumb and would cause the
+     compilation time to go through the roof if there are many undefined
+     symbols in the link, so it needs to be run after auto-import.  */
+  if (pep_enable_stdcall_fixup) /* -1=warn or 1=enable */
     pep_fixup_stdcalls ();
 
 #ifndef TARGET_IS_i386pep
index 391f52bf59275d22c3d9665a9b255641799b78fb..9425c658434afa6d6080d3da2b357f75959c84f3 100644 (file)
@@ -2752,11 +2752,16 @@ uwin, pw, etc.  For instance, cygwin DLLs typically use
 @kindex --enable-auto-import
 @item --enable-auto-import
 Do sophisticated linking of @code{_symbol} to @code{__imp__symbol} for
-DATA imports from DLLs, and create the necessary thunking symbols when
-building the import libraries with those DATA exports. Note: Use of the
-'auto-import' extension will cause the text section of the image file
-to be made writable. This does not conform to the PE-COFF format
-specification published by Microsoft.
+DATA imports from DLLs, thus making it possible to bypass the dllimport
+mechanism on the user side and to reference unmangled symbol names.
+[This option is specific to the i386 PE targeted port of the linker]
+
+The following remarks pertain to the original implementation of the
+feature and are obsolete nowadays for Cygwin and MinGW targets.
+
+Note: Use of the 'auto-import' extension will cause the text section
+of the image file to be made writable. This does not conform to the
+PE-COFF format specification published by Microsoft.
 
 Note - use of the 'auto-import' extension will also cause read only
 data which would normally be placed into the .rdata section to be
@@ -2878,7 +2883,6 @@ A fourth way to avoid this problem is to re-code your
 library to use a functional interface rather than a data interface
 for the offending variables (e.g. set_foo() and get_foo() accessor
 functions).
-[This option is specific to the i386 PE targeted port of the linker]
 
 @kindex --disable-auto-import
 @item --disable-auto-import
@@ -2896,8 +2900,7 @@ environment to adjust references to such data in your client code.
 
 @kindex --disable-runtime-pseudo-reloc
 @item --disable-runtime-pseudo-reloc
-Do not create pseudo relocations for non-zero offset DATA imports from
-DLLs.
+Do not create pseudo relocations for non-zero offset DATA imports from DLLs.
 [This option is specific to the i386 PE targeted port of the linker]
 
 @kindex --enable-extra-pe-debug
index c087bf23bc1d66da449334288eabb55138e9469d..ad0ffcffea062cbac33852f35c0ee15df38dc4fc 100644 (file)
@@ -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
 {
@@ -1287,10 +1287,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;
@@ -1328,8 +1330,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 +1355,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
@@ -1794,7 +1940,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;
 
@@ -2326,47 +2471,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)
 {
@@ -2409,7 +2513,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 +2535,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,12 +2573,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);
@@ -2509,6 +2608,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,47 +2621,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;
@@ -2575,6 +2681,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;
 }
@@ -2624,65 +2731,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 +2781,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 (_("%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, sym->name);
+          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)
 {
index 48d169b6cc27bc5c7d3c54977a18664ce224ce77..38655f70d240374692df184b0716a050b2baeb4b 100644 (file)
@@ -61,10 +61,10 @@ extern void pe_dll_fill_sections
   (bfd *, struct bfd_link_info *);
 extern void pe_exe_fill_sections
   (bfd *, struct bfd_link_info *);
-extern void pe_walk_relocs_of_symbol
-  (struct bfd_link_info *, char *, int (*) (arelent *, asection *, char *));
+extern void pe_find_data_imports
+  (const char *, void (*cb) (arelent *, asection *, char *, const char *));
 extern void pe_create_import_fixup
-  (arelent * rel, asection *, bfd_vma, char *);
+  (arelent * rel, asection *, bfd_vma, char *, const char *);
 extern bfd_boolean pe_bfd_is_dll
   (bfd *);
 extern void pe_output_file_set_long_section_names
index b8c017f86da4d477d96bfb5e5676f655a4716f5e..c53a676d98729c5e64bc09014f6d3cde1a20436c 100644 (file)
                                    pep_use_coff_long_section_names
 #define pe_leading_underscore      pep_leading_underscore
 
-/* External globals.  */
-#define pe_data_import_dll          pep_data_import_dll
-
 /* Unique global name for functions to avoid double defined symbols.  */
+#define pe_find_data_imports        pep_find_data_imports
 #define pe_create_import_fixup      pep_create_import_fixup
 #define pe_dll_generate_def_file    pep_dll_generate_def_file
 #define pe_process_import_defs      pep_process_import_defs
@@ -55,7 +53,6 @@
 #define pe_exe_fill_sections        pep_exe_fill_sections
 #define pe_dll_generate_implib      pep_dll_generate_implib
 #define pe_dll_add_excludes         pep_dll_add_excludes
-#define pe_walk_relocs_of_symbol    pep_walk_relocs_of_symbol
 #define pe_bfd_is_dll              pep_bfd_is_dll
 #define pe_output_file_set_long_section_names \
                                    pep_output_file_set_long_section_names
index 0a27c1fc0271bcce9903e64145dd7906ab760eea..611c8cdb275f9333bf8799cd3de20128baa69f6c 100644 (file)
@@ -52,10 +52,11 @@ extern void pep_dll_build_sections  (bfd *, struct bfd_link_info *);
 extern void pep_exe_build_sections  (bfd *, struct bfd_link_info *);
 extern void pep_dll_fill_sections  (bfd *, struct bfd_link_info *);
 extern void pep_exe_fill_sections  (bfd *, struct bfd_link_info *);
-extern void pep_walk_relocs_of_symbol
-  (struct bfd_link_info *, char *, int (*) (arelent *, asection *, char *));
+extern void pep_find_data_imports  (const char *,
+                                   void (*cb) (arelent *, asection *, char *,
+                                               const char *));
 extern void pep_create_import_fixup  (arelent * rel, asection *, bfd_vma,
-                                     char *);
+                                     char *, const char *);
 extern bfd_boolean pep_bfd_is_dll  (bfd *);
 extern void pep_output_file_set_long_section_names (bfd *);