ld: pe-dll: Fix MS link.exe linking against two ld generated import libraries

Message ID 20220104201426.1006716-1-martin@martin.st
State New
Headers show
Series
  • ld: pe-dll: Fix MS link.exe linking against two ld generated import libraries
Related show

Commit Message

Martin Storsjö Jan. 4, 2022, 8:14 p.m.
MS link.exe can successfully link against import libraries generated
by ld (via the --out-implib option). However, if linking against more
than one such import library at a time, then MS link.exe produces
intermixed import tables for those DLL files.

MS link.exe seems to sort the individual object files in the import
library based on their member names, without taking library
boundaries into consideration. E.g. when both libfoo.a and libbar.a
contain object files named d000.o, d001.o, d002.o, MS link.exe orders
them as libfoo.a(d000.o) libbar.a(d000.o) libfoo.a(d001.o) libbar.a(d001.o)
etc. This breaks the implicit assumption that these object files need
to be grouped tightly together within one import library.

This has not been an issue when MS link.exe links against import
libraries produced by dlltool, as the object files there use a
pseudorandom prefix (based on the dlltool process ID).

Thus this avoids needing to regenerate import libraries with dlltool, if
linking a DLL which is going to be linked against by MS link.exe.

Signed-off-by: Martin Storsjö <martin@martin.st>

---
 ld/pe-dll.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

-- 
2.25.1

Comments

H.J. Lu via Binutils Jan. 11, 2022, 3:45 p.m. | #1
Hi Martin,

> MS link.exe can successfully link against import libraries generated

> by ld (via the --out-implib option). However, if linking against more

> than one such import library at a time, then MS link.exe produces

> intermixed import tables for those DLL files.

> 

> MS link.exe seems to sort the individual object files in the import

> library based on their member names, without taking library

> boundaries into consideration. E.g. when both libfoo.a and libbar.a

> contain object files named d000.o, d001.o, d002.o, MS link.exe orders

> them as libfoo.a(d000.o) libbar.a(d000.o) libfoo.a(d001.o) libbar.a(d001.o)

> etc. This breaks the implicit assumption that these object files need

> to be grouped tightly together within one import library.

> 

> This has not been an issue when MS link.exe links against import

> libraries produced by dlltool, as the object files there use a

> pseudorandom prefix (based on the dlltool process ID).

> 

> Thus this avoids needing to regenerate import libraries with dlltool, if

> linking a DLL which is going to be linked against by MS link.exe.

> 


Patch approved and applied.  Thanks for fixing this problem.

Cheers
   Nick
Martin Storsjö Jan. 11, 2022, 7:49 p.m. | #2
Hi Nick,

On Tue, 11 Jan 2022, Nick Clifton wrote:

> Patch approved and applied.  Thanks for fixing this problem.


Thanks for the review!

// Martin

Patch

diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 907fafc6208..4e47abd9b24 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -1972,6 +1972,7 @@  static int symptr;
 static int tmp_seq;
 static const char *dll_filename;
 static char *dll_symname;
+static int dll_symname_len;
 
 #define UNDSEC bfd_und_section_ptr
 
@@ -2082,8 +2083,8 @@  make_head (bfd *parent)
   char *oname;
   bfd *abfd;
 
-  oname = xmalloc (20);
-  sprintf (oname, "d%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_d%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2171,8 +2172,8 @@  make_tail (bfd *parent)
   char *oname;
   bfd *abfd;
 
-  oname = xmalloc (20);
-  sprintf (oname, "d%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_d%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2322,8 +2323,8 @@  make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
 	}
     }
 
-  oname = xmalloc (20);
-  sprintf (oname, "d%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_d%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2508,8 +2509,8 @@  make_singleton_name_thunk (const char *import, bfd *parent)
   char *oname;
   bfd *abfd;
 
-  oname = xmalloc (20);
-  sprintf (oname, "nmth%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_nmth%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2584,8 +2585,8 @@  make_import_fixup_entry (const char *name,
   char *oname;
   bfd *abfd;
 
-  oname = xmalloc (20);
-  sprintf (oname, "fu%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_fu%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2638,8 +2639,8 @@  make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED,
   bfd *abfd;
   bfd_size_type size;
 
-  oname = xmalloc (20);
-  sprintf (oname, "rtr%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_rtr%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2725,8 +2726,8 @@  pe_create_runtime_relocator_reference (bfd *parent)
   char *oname;
   bfd *abfd;
 
-  oname = xmalloc (20);
-  sprintf (oname, "ertr%06d.o", tmp_seq);
+  oname = xmalloc (20 + dll_symname_len);
+  sprintf (oname, "%s_ertr%06d.o", dll_symname, tmp_seq);
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
@@ -2833,6 +2834,7 @@  pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
 
   dll_filename = (def->name) ? def->name : dll_name;
   dll_symname = xstrdup (dll_filename);
+  dll_symname_len = strlen (dll_symname);
   for (i = 0; dll_symname[i]; i++)
     if (!ISALNUM (dll_symname[i]))
       dll_symname[i] = '_';
@@ -3201,6 +3203,7 @@  pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
 
       dll_filename = module->name;
       dll_symname = xstrdup (module->name);
+      dll_symname_len = strlen (dll_symname);
       for (j = 0; dll_symname[j]; j++)
 	if (!ISALNUM (dll_symname[j]))
 	  dll_symname[j] = '_';