ld/
[deliverable/binutils-gdb.git] / ld / pe-dll.c
index 335bc05c4ca8ae313c07051714e44962d9c8b400..d75474770083dcc1a1b2c49cf413e543c342aa45 100644 (file)
@@ -1,27 +1,27 @@
 /* Routines to help build PEI-format DLLs (Win32 etc)
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Written by DJ Delorie <dj@cygnus.com>
 
-   This file is part of GLD, the Gnu Linker.
+   This file is part of the GNU Binutils.
 
-   GLD is free software; you can redistribute it and/or modify
+   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 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-   GLD is distributed in the hope that it will be useful,
+   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 GLD; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
@@ -195,7 +195,7 @@ static const autofilter_entry_type autofilter_symbollist_generic[] =
   /* Runtime pseudo-reloc.  */
   { STRING_COMMA_LEN ("_pei386_runtime_relocator") },
   { STRING_COMMA_LEN ("do_pseudo_reloc") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 static const autofilter_entry_type autofilter_symbollist_i386[] =
@@ -203,6 +203,14 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
   { STRING_COMMA_LEN (".text") },
   /* Entry point symbols, and entry hooks.  */
   { STRING_COMMA_LEN ("cygwin_crt0") },
+#ifdef pe_use_x86_64
+  { STRING_COMMA_LEN ("DllMain") },
+  { STRING_COMMA_LEN ("DllEntryPoint") },
+  { STRING_COMMA_LEN ("DllMainCRTStartup") },
+  { STRING_COMMA_LEN ("_cygwin_dll_entry") },
+  { STRING_COMMA_LEN ("_cygwin_crt0_common") },
+  { STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry") },
+#else
   { STRING_COMMA_LEN ("DllMain@12") },
   { STRING_COMMA_LEN ("DllEntryPoint@0") },
   { STRING_COMMA_LEN ("DllMainCRTStartup@12") },
@@ -210,6 +218,7 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
   { STRING_COMMA_LEN ("_cygwin_crt0_common@8") },
   { STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry@12") },
   { STRING_COMMA_LEN ("cygwin_attach_dll") },
+#endif  
   { STRING_COMMA_LEN ("cygwin_premain0") },
   { STRING_COMMA_LEN ("cygwin_premain1") },
   { STRING_COMMA_LEN ("cygwin_premain2") },
@@ -222,7 +231,7 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
   { STRING_COMMA_LEN ("_impure_ptr") },
   { STRING_COMMA_LEN ("_fmode") },
   { STRING_COMMA_LEN ("environ") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 #define PE_ARCH_i386    1
@@ -312,7 +321,7 @@ static const autofilter_entry_type autofilter_liblist[] =
   { STRING_COMMA_LEN ("libsupc++") },
   { STRING_COMMA_LEN ("libobjc") },
   { STRING_COMMA_LEN ("libgcj") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 static const autofilter_entry_type autofilter_objlist[] =
@@ -327,7 +336,7 @@ static const autofilter_entry_type autofilter_objlist[] =
   { STRING_COMMA_LEN ("gcrt2.o") },
   { STRING_COMMA_LEN ("crtbegin.o") },
   { STRING_COMMA_LEN ("crtend.o") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 static const autofilter_entry_type autofilter_symbolprefixlist[] =
@@ -341,13 +350,13 @@ static const autofilter_entry_type autofilter_symbolprefixlist[] =
   { STRING_COMMA_LEN ("_nm_") },
   /* Don't export symbols specifying internal DLL layout.  */
   { STRING_COMMA_LEN ("_head_") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 static const autofilter_entry_type autofilter_symbolsuffixlist[] =
 {
   { STRING_COMMA_LEN ("_iname") },
-  { STRING_COMMA_LEN (NULL) }
+  { NULL, 0 }
 };
 
 #define U(str) (pe_details->underscored ? "_" str : str)
@@ -1873,7 +1882,7 @@ static const unsigned char jmp_arm_bytes[] =
 
 
 static bfd *
-make_one (def_file_export *exp, bfd *parent)
+make_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub)
 {
   asection *tx, *id7, *id5, *id4, *id6;
   unsigned char *td = NULL, *d7, *d5, *d4, *d6 = NULL;
@@ -1883,28 +1892,37 @@ make_one (def_file_export *exp, bfd *parent)
   const unsigned char *jmp_bytes = NULL;
   int jmp_byte_count = 0;
 
-  switch (pe_details->pe_arch)
+  /* Include the jump stub section only if it is needed. A jump
+     stub is needed if the symbol being imported <sym> is a function
+     symbol and there is at least one undefined reference to that
+     symbol. In other words, if all the import references to <sym> are
+     explicitly through _declspec(dllimport) then the jump stub is not
+     needed.  */
+  if (include_jmp_stub)
     {
-    case PE_ARCH_i386:
-      jmp_bytes = jmp_ix86_bytes;
-      jmp_byte_count = sizeof (jmp_ix86_bytes);
-      break;
-    case PE_ARCH_sh:
-      jmp_bytes = jmp_sh_bytes;
-      jmp_byte_count = sizeof (jmp_sh_bytes);
-      break;
-    case PE_ARCH_mips:
-      jmp_bytes = jmp_mips_bytes;
-      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);
-      break;
-    default:
-      abort ();
+      switch (pe_details->pe_arch)
+       {
+       case PE_ARCH_i386:
+         jmp_bytes = jmp_ix86_bytes;
+         jmp_byte_count = sizeof (jmp_ix86_bytes);
+         break;
+       case PE_ARCH_sh:
+         jmp_bytes = jmp_sh_bytes;
+         jmp_byte_count = sizeof (jmp_sh_bytes);
+         break;
+       case PE_ARCH_mips:
+         jmp_bytes = jmp_mips_bytes;
+         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);
+         break;
+       default:
+         abort ();
+       }
     }
 
   oname = xmalloc (20);
@@ -1930,7 +1948,7 @@ make_one (def_file_export *exp, bfd *parent)
     {
       quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
                    BSF_GLOBAL, 0);
-      if (! exp->flag_data)
+      if (include_jmp_stub)
        quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0);
       quick_symbol (abfd, "__imp_", exp->internal_name, "", id5,
                    BSF_GLOBAL, 0);
@@ -1941,7 +1959,7 @@ make_one (def_file_export *exp, bfd *parent)
     {
       quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
                    BSF_GLOBAL, 0);
-      if (! exp->flag_data)
+      if (include_jmp_stub)
        quick_symbol (abfd, U (""), exp->internal_name, "", tx,
                      BSF_GLOBAL, 0);
       quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5,
@@ -1956,7 +1974,7 @@ make_one (def_file_export *exp, bfd *parent)
     quick_symbol (abfd, U ("__imp_"), exp->internal_name, "", id5,
                  BSF_GLOBAL, 0);
 
-  if (! exp->flag_data)
+  if (include_jmp_stub)
     {
       bfd_set_section_size (abfd, tx, jmp_byte_count);
       td = xmalloc (jmp_byte_count);
@@ -1966,7 +1984,11 @@ make_one (def_file_export *exp, bfd *parent)
       switch (pe_details->pe_arch)
        {
        case PE_ARCH_i386:
-         quick_reloc (abfd, 2, BFD_RELOC_32, 2);
+#ifdef pe_use_x86_64
+         quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2);
+#else
+          quick_reloc (abfd, 2, BFD_RELOC_32, 2);
+#endif
          break;
        case PE_ARCH_sh:
          quick_reloc (abfd, 8, BFD_RELOC_32, 2);
@@ -1986,6 +2008,8 @@ make_one (def_file_export *exp, bfd *parent)
        }
       save_relocs (tx);
     }
+  else
+    bfd_set_section_size (abfd, tx, 0);
 
   bfd_set_section_size (abfd, id7, 4);
   d7 = xmalloc (4);
@@ -2050,7 +2074,8 @@ make_one (def_file_export *exp, bfd *parent)
 
   bfd_set_symtab (abfd, symtab, symptr);
 
-  bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count);
+  if (include_jmp_stub)
+    bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count);
   bfd_set_section_contents (abfd, id7, d7, 0, 4);
   bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE);
   bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE);
@@ -2398,8 +2423,9 @@ pe_dll_generate_implib (def_file *def, const char *impfilename)
       if (pe_def_file->exports[i].flag_private)
        continue;
       def->exports[i].internal_name = def->exports[i].name;
-      n = make_one (def->exports + i, outarch);
-      n->next = head;
+      n = make_one (def->exports + i, outarch,
+                   ! (def->exports + i)->flag_data);
+      n->archive_next = head;
       head = n;
       def->exports[i].internal_name = internal;
     }
@@ -2410,8 +2436,8 @@ pe_dll_generate_implib (def_file *def, const char *impfilename)
     return;
 
   /* Now stick them all into the archive.  */
-  ar_head->next = head;
-  ar_tail->next = ar_head;
+  ar_head->archive_next = head;
+  ar_tail->archive_next = ar_head;
   head = ar_tail;
 
   if (! bfd_set_archive_head (outarch, head))
@@ -2422,7 +2448,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename)
 
   while (head != NULL)
     {
-      bfd *n = head->next;
+      bfd *n = head->archive_next;
       bfd_close (head);
       head = n;
     }
@@ -2474,6 +2500,7 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
            /* See if we need this import.  */
            size_t len = strlen (pe_def_file->imports[i].internal_name);
            char *name = xmalloc (len + 2 + 6);
+           bfd_boolean include_jmp_stub = FALSE;
 
            if (lead_at)
              sprintf (name, "%s",
@@ -2485,6 +2512,8 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
            blhe = bfd_link_hash_lookup (link_info->hash, name,
                                         FALSE, FALSE, FALSE);
 
+           /* Include the jump stub for <sym> only if the <sym>
+              is undefined.  */
            if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined))
              {
                if (lead_at)
@@ -2497,6 +2526,9 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
                blhe = bfd_link_hash_lookup (link_info->hash, name,
                                             FALSE, FALSE, FALSE);
              }
+           else
+             include_jmp_stub = TRUE;
+
            free (name);
 
            if (blhe && blhe->type == bfd_link_hash_undefined)
@@ -2517,7 +2549,7 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info)
                exp.flag_constant = 0;
                exp.flag_data = pe_def_file->imports[i].data;
                exp.flag_noname = exp.name ? 0 : 1;
-               one = make_one (&exp, output_bfd);
+               one = make_one (&exp, output_bfd, (! exp.flag_data) && include_jmp_stub);
                add_bfd_to_link (one, one->filename, link_info);
              }
          }
This page took 0.027533 seconds and 4 git commands to generate.