2009-11-15 Kai Tietz <kai.tietz@onevision.com>
authorKai Tietz <kai.tietz@onevision.com>
Sun, 15 Nov 2009 07:52:45 +0000 (07:52 +0000)
committerKai Tietz <kai.tietz@onevision.com>
Sun, 15 Nov 2009 07:52:45 +0000 (07:52 +0000)
* pe-dll.c (pe_undef_alias_cdecl_match): New function.
(pe_find_cdecl_alias_match): New function.
(pe_process_import_defs): Add matching for import symbols
declared as cdecl for fastcall/stdcall.
* emultempl/pe.em (pe_undef_cdecl_match): Treat fastcall
symbols, too.
(pe_fixup_stdcalls): Likewise.
(gld_XXX_after_open): Redo scanning for imported
fastcall/stdcall symbols as cdecl one.
* emultempl/pep.em (pep_undef_cdecl_match): Treat fastcall
symbols, too.
(pep_fixup_stdcalls): Likewise.
(gld_XXX_after_open): Redo scanning for imported
fastcall/stdcall symbols as cdecl one.

2009-11-15  Kai Tietz  <kai.tietz@onevision.com>

* ld-pe/direct2_client.c: New file.
* ld-pe/direct2_dll.c: Likewise.
* ld-pe/direct2_dll.def: Likewise.
* ld-pe/pe-run2.exp: Likewise.

ld/ChangeLog
ld/emultempl/pe.em
ld/emultempl/pep.em
ld/pe-dll.c
ld/testsuite/ChangeLog
ld/testsuite/ld-pe/direct2_client.c [new file with mode: 0644]
ld/testsuite/ld-pe/direct2_dll.c [new file with mode: 0644]
ld/testsuite/ld-pe/direct2_dll.def [new file with mode: 0644]
ld/testsuite/ld-pe/pe-run2.exp [new file with mode: 0644]

index 1fa6f620585683bf6e339fca61b84c0b61c35744..c4d0f42e87edbb219237ab23f371280f9993b59e 100644 (file)
@@ -1,3 +1,20 @@
+2009-11-15  Kai Tietz  <kai.tietz@onevision.com>
+
+       * pe-dll.c (pe_undef_alias_cdecl_match): New function.
+       (pe_find_cdecl_alias_match): New function.
+       (pe_process_import_defs): Add matching for import symbols
+       declared as cdecl for fastcall/stdcall.
+       * emultempl/pe.em (pe_undef_cdecl_match): Treat fastcall
+       symbols, too.
+       (pe_fixup_stdcalls): Likewise.
+       (gld_XXX_after_open): Redo scanning for imported
+       fastcall/stdcall symbols as cdecl one.
+       * emultempl/pep.em (pep_undef_cdecl_match): Treat fastcall
+       symbols, too.
+       (pep_fixup_stdcalls): Likewise.
+       (gld_XXX_after_open): Redo scanning for imported
+       fastcall/stdcall symbols as cdecl one.
+
 2009-11-11  Nick Clifton  <nickc@redhat.com>
 
        * po/id.po: Updated Indonesian translation.
index 4326e7e8266b758640a775d664cc5b7e3e64a85d..b936199e10722baf5c756eeefd4a8e4cbea7e1b4 100644 (file)
@@ -942,10 +942,13 @@ pe_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf)
 {
   int sl;
   char *string = inf;
+  const char *hs = h->root.string;
 
   sl = strlen (string);
   if (h->type == bfd_link_hash_defined
-      && strncmp (h->root.string, string, sl) == 0
+      && ((*hs == '@' && *string == '_'
+                  && strncmp (hs + 1, string + 1, sl - 1) == 0)
+                 || strncmp (hs, string, sl) == 0)
       && h->root.string[sl] == '@')
     {
       pe_undef_found_sym = h;
@@ -968,15 +971,20 @@ pe_fixup_stdcalls (void)
       {
        char* at = strchr (undef->root.string, '@');
        int lead_at = (*undef->root.string == '@');
-       /* For now, don't try to fixup fastcall symbols.  */
+       if (lead_at)
+         at = strchr (undef->root.string + 1, '@');
 
-       if (at && !lead_at)
+       if (at || lead_at)
          {
            /* The symbol is a stdcall symbol, so let's look for a
               cdecl symbol with the same name and resolve to that.  */
-           char *cname = xstrdup (undef->root.string /* + lead_at */);
+           char *cname = xstrdup (undef->root.string);
+
+           if (lead_at)
+             *cname = '_';
            at = strchr (cname, '@');
-           *at = 0;
+           if (at)
+             *at = 0;
            sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1);
 
            if (sym && sym->type == bfd_link_hash_defined)
@@ -1212,6 +1220,11 @@ gld_${EMULATION_NAME}_after_open (void)
 
   pe_find_data_imports ();
 
+  /* As possibly new symbols are added by imports, we rerun
+     stdcall/fastcall fixup here.  */
+  if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */
+    pe_fixup_stdcalls ();
+
 #if defined (TARGET_IS_i386pe) \
     || defined (TARGET_IS_armpe) \
     || defined (TARGET_IS_arm_epoc_pe) \
index a7ea8e110a0a2d87cb8597ad5ca73069e88a9239..753f4252d1690b470315fcc56ecfbee666a2b454 100644 (file)
@@ -871,10 +871,13 @@ pep_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf)
 {
   int sl;
   char *string = inf;
+  const char *hs = h->root.string;
 
   sl = strlen (string);
   if (h->type == bfd_link_hash_defined
-      && strncmp (h->root.string, string, sl) == 0
+      && ((*hs == '@' && *string == '_'
+                  && strncmp (hs + 1, string + 1, sl - 1) == 0)
+                 || strncmp (hs, string, sl) == 0)
       && h->root.string[sl] == '@')
     {
       pep_undef_found_sym = h;
@@ -897,15 +900,19 @@ pep_fixup_stdcalls (void)
       {
        char* at = strchr (undef->root.string, '@');
        int lead_at = (*undef->root.string == '@');
-       /* For now, don't try to fixup fastcall symbols.  */
-
-       if (at && !lead_at)
+       if (lead_at)
+         at = strchr (undef->root.string + 1, '@');
+       if (at || lead_at)
          {
            /* The symbol is a stdcall symbol, so let's look for a
               cdecl symbol with the same name and resolve to that.  */
-           char *cname = xstrdup (undef->root.string /* + lead_at */);
+           char *cname = xstrdup (undef->root.string);
+
+           if (lead_at)
+             *cname = '_';
            at = strchr (cname, '@');
-           *at = 0;
+           if (at)
+             *at = 0;
            sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1);
 
            if (sym && sym->type == bfd_link_hash_defined)
@@ -1179,6 +1186,11 @@ gld_${EMULATION_NAME}_after_open (void)
 
   pep_find_data_imports ();
 
+  /* As possibly new symbols are added by imports, we rerun
+     stdcall/fastcall fixup here.  */
+  if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */
+    pep_fixup_stdcalls ();
+
 #ifndef TARGET_IS_i386pep
   if (link_info.shared)
 #else
index dbf1b5e467e59ef64eb92b3eb123fc9f7491d4ab..beeb580f20380087e19a5e815741fc3bd98743ee 100644 (file)
@@ -2761,6 +2761,37 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
     }
 }
 
+static struct bfd_link_hash_entry *found_sym;
+
+static bfd_boolean
+pe_undef_alias_cdecl_match (struct bfd_link_hash_entry *h, void *inf)
+{
+  int sl;
+  char *string = inf;
+  const char *hs = h->root.string;
+
+  sl = strlen (string);
+  if (h->type == bfd_link_hash_undefined
+      && ((*hs == '@' && *string == '_'
+          && strncmp (hs + 1, string + 1, sl - 1) == 0)
+         || strncmp (hs, string, sl) == 0)
+      && h->root.string[sl] == '@')
+    {
+      found_sym = h;
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static struct bfd_link_hash_entry *
+pe_find_cdecl_alias_match (char *name)
+{
+  found_sym = 0;
+  bfd_link_hash_traverse (link_info.hash, pe_undef_alias_cdecl_match,
+                         (char *) name);
+  return found_sym;
+}
+
 static void
 add_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *link_info)
 {
@@ -2808,6 +2839,9 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
            size_t len = strlen (pe_def_file->imports[i].internal_name);
            char *name = xmalloc (len + 2 + 6);
            bfd_boolean include_jmp_stub = FALSE;
+           bfd_boolean is_cdecl = FALSE;
+           if (!lead_at && strchr (pe_def_file->imports[i].internal_name, '@') == NULL)
+               is_cdecl = TRUE;
 
            if (lead_at)
              sprintf (name, "%s",
@@ -2836,6 +2870,14 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
            else
              include_jmp_stub = TRUE;
 
+           if (is_cdecl && !blhe)
+             {
+               sprintf (name, "%s%s",U (""),
+                        pe_def_file->imports[i].internal_name);
+               blhe = pe_find_cdecl_alias_match (name);
+               include_jmp_stub = TRUE;
+             }
+
            free (name);
 
            if (blhe && blhe->type == bfd_link_hash_undefined)
index c6a4d7a2534e572b3ed2f34662daa9bb9906dc8d..9b7b6684796e5d5517a637ae45a871b3069b445a 100644 (file)
@@ -1,3 +1,10 @@
+2009-11-15  Kai Tietz  <kai.tietz@onevision.com>
+
+       * ld-pe/direct2_client.c: New file.
+       * ld-pe/direct2_dll.c: Likewise.
+       * ld-pe/direct2_dll.def: Likewise.
+       * ld-pe/pe-run2.exp: Likewise.
+
 2009-11-13  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld-x86-64/tlsbin.dd: Updated for prefix processing.
diff --git a/ld/testsuite/ld-pe/direct2_client.c b/ld/testsuite/ld-pe/direct2_client.c
new file mode 100644 (file)
index 0000000..84cdcb6
--- /dev/null
@@ -0,0 +1,47 @@
+extern void abort (void);
+
+void
+__cdecl
+lib2foocdecl(int junk1, int* junk2);
+
+void
+__stdcall
+lib2foostdcall(int junk1, int* junk2);
+
+void
+__fastcall
+lib2foofastcall(int junk1, int* junk2);
+
+void
+__cdecl
+lib1foocdecl(int junk1, int* junk2)
+{
+    lib2foocdecl(junk1, junk2);
+}
+
+void
+__stdcall
+lib1foostdcall(int junk1, int* junk2)
+{
+    lib2foostdcall(junk1, junk2);
+}
+
+void
+__fastcall
+lib1foofastcall(int junk1, int* junk2)
+{
+    lib2foofastcall(junk1, junk2);
+}
+
+int main()
+{
+  int junk[3];
+  lib1foofastcall (1, &junk[0]);
+  lib1foostdcall (2, &junk[1]);
+  lib1foocdecl (3, &junk[2]);
+  if (junk[1] != 2 || junk[0] != 1 || junk[2] != 3)
+    abort ();
+
+  return 0;
+}
+
diff --git a/ld/testsuite/ld-pe/direct2_dll.c b/ld/testsuite/ld-pe/direct2_dll.c
new file mode 100644 (file)
index 0000000..115f9b9
--- /dev/null
@@ -0,0 +1,20 @@
+void
+__cdecl
+lib2foocdecl(int junk1, int* junk2)
+{
+    *junk2 = junk1;
+}
+
+void
+__stdcall
+lib2foostdcall(int junk1, int* junk2)
+{
+    *junk2 = junk1;
+}
+
+void
+__fastcall
+lib2foofastcall(int junk1, int* junk2)
+{
+    *junk2 = junk1;
+}
diff --git a/ld/testsuite/ld-pe/direct2_dll.def b/ld/testsuite/ld-pe/direct2_dll.def
new file mode 100644 (file)
index 0000000..2e8986d
--- /dev/null
@@ -0,0 +1,6 @@
+LIBRARY "direct2_dll.dll"
+
+EXPORTS
+lib2foocdecl
+lib2foostdcall
+lib2foofastcall
diff --git a/ld/testsuite/ld-pe/pe-run2.exp b/ld/testsuite/ld-pe/pe-run2.exp
new file mode 100644 (file)
index 0000000..9862037
--- /dev/null
@@ -0,0 +1,151 @@
+# Expect script for complex PE tests that require a C compiler and the ability
+# to run target executables natively, in addition to the just-built binutils.
+#   Copyright 2006, 2007, 2009
+#   Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Based on the script pe-run.exp written by Pedro Alves.
+# Written by Kai Tietz <kai.tietz@onevision.com>
+#
+# Note:
+# 
+# This test checks the "direct linking to a dll" functionality with stdcall
+# and fastcall fixup.
+# 
+# The test has 7 stages:
+# 
+# 1. compile and link a test dll with ".dll" extension.
+#
+# 2. compile and link a test dll with ".sl" (i.e. != ".dll") extension.
+#
+# 3. compile and link a client application linking directly to the ".dll" dll built in 1.
+#    This should produce no errors.
+#
+# 4. compile and link a client application linking directly to the ".sl" dll built in 2.
+#    This should produce no errors.
+#
+# 5. compile and link a client application linking directly to a symlink into 
+#    the ".dll" dll built in 1.
+#    This should produce no errors.
+#
+# 6. compile and link a client application linking directly to a symlink into 
+#    the ".sl" dll built in 1.
+#    This should produce no errors.
+#
+# 7. run the produced executables
+
+# This test can only be run on PE/COFF platforms.
+if {![is_pecoff_format]} {
+    return
+}
+
+# No compiler, no test.
+if { [which $CC] == 0 } {
+    untested "Direct linking to dll fastcall/stdcall test"
+    return
+}
+
+set tmpdir tmpdir
+
+proc test_direct2_link_dll {} {
+    global CC
+    global CFLAGS
+    global srcdir
+    global subdir
+    global tmpdir
+
+    # Compile the dll.
+    if ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/direct2_dll.c $tmpdir/direct2_dll.o ] {
+       fail "compiling shared lib fastcall/stdcall"
+    } elseif ![ld_simple_link "$CC -shared -Wl,--enable-stdcall-fixup -Wl,--kill-at " $tmpdir/direct2_dll.dll "$tmpdir/direct2_dll.o" ] {
+       fail "linking shared lib (.dll) fastcall/stdcall"
+    } elseif ![ld_simple_link "$CC -shared -Wl,--enable-stdcall-fixup -Wl,--kill-at " $tmpdir/direct2_dll.sl "$tmpdir/direct2_dll.o" ] {
+       fail "linking shared lib (.sl) fastcall/stdcall"
+    } else {
+       # Compile and link the client program.
+       if ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/direct2_client.c $tmpdir/direct2_client.o ] {
+           fail "compiling client fastcall/stdcall"
+       } else {
+           # Check linking directly to direct2_dll.dll.
+           set msg "linking client (.dll) fastcall/stdcall"
+           if [ld_simple_link "$CC -Wl,--enable-stdcall-fixup --enable-auto-import" $tmpdir/direct2_client_dll.exe \
+             "$tmpdir/direct2_client.o $tmpdir/direct2_dll.dll" ] {
+               pass $msg
+           } else {
+               fail $msg 
+           }
+
+           # Check linking directly to direct2_dll.sl.
+           set msg "linking client (.sl) fastcall/stdcall"
+           if [ld_simple_link "$CC -Wl,--enable-stdcall-fixup -Wl,--enable-auto-import" $tmpdir/direct2_client_sl.exe \
+             "$tmpdir/direct2_client.o $tmpdir/direct2_dll.sl" ] {
+               pass $msg
+           } else {
+               fail $msg 
+           }
+
+           # Check dll direct linking through symlink to .dll.
+           # Create symbolic link.
+           catch "exec ln -fs direct2_dll.dll $tmpdir/libdirect2_dll.dll.a" ln_catch
+           set msg "linking client (symlink -> .dll) fastcall/stdcall"
+           if [ld_simple_link "$CC -Wl,--enable-stdcall-fixup -Wl,--enable-auto-import" $tmpdir/direct2_client_symlink_dll.exe \
+             "$tmpdir/direct2_client.o $tmpdir/libdirect2_dll.dll.a" ] {
+               pass $msg
+           } else {
+               fail $msg
+           }
+               
+           # Check dll direct linking through symlink to .sl.
+           # Create symbolic link.
+           catch "exec ln -fs direct2_dll.sl $tmpdir/libdirect2_sl.dll.a" ln_catch
+           set msg "linking client (symlink -> .sl) fastcall/stdcall"
+           if [ld_simple_link "$CC -Wl,--enable-stdcall-fixup -Wl,--enable-auto-import" $tmpdir/direct2_client_symlink_sl.exe \
+             "$tmpdir/direct2_client.o $tmpdir/libdirect2_sl.dll.a" ] {
+               pass $msg
+           } else {
+               fail $msg 
+           }
+       }
+    }
+}
+
+proc directdll_execute {exe msg} {
+    set expected ""
+    catch "exec $exe" prog_output
+    if [string match $expected $prog_output] then {
+        pass $msg
+    } else {
+        verbose $prog_output
+        fail $msg
+    }
+}
+
+test_direct2_link_dll
+
+# This is as far as we can go with a cross-compiler
+if ![isnative] then {
+    verbose "Not running natively, so cannot execute binaries"
+    return
+}
+
+directdll_execute "$tmpdir/direct2_client_dll.exe" "running direct linked dll (.dll) fastcall/stdcall"
+directdll_execute "$tmpdir/direct2_client_sl.exe" "running direct linked dll (.sl) fastcall/stdcall"
+directdll_execute "$tmpdir/direct2_client_symlink_sl.exe" "running direct linked dll (symlink -> .sl) fastcall/stdcall"
+directdll_execute "$tmpdir/direct2_client_symlink_dll.exe" "running direct linked dll (symlink -> .dll) fastcall/stdcall"