* pe-dll.c: (make_one) Conditionally include jump stubs.
authorNick Clifton <nickc@redhat.com>
Fri, 19 Jan 2007 15:40:55 +0000 (15:40 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 19 Jan 2007 15:40:55 +0000 (15:40 +0000)
* emultempl/pe.em (gld_${EMULATION_NAME}_after_open): Identify
  redundant jump stubs from import libraries and exclude them from link.

ld/ChangeLog
ld/emultempl/pe.em
ld/pe-dll.c

index 48a9b3e75508596a543298acc5dbd6358cdfbe4c..3d7029735884ab2c292f01352d4d1f35f5c39d93 100644 (file)
@@ -1,3 +1,10 @@
+2007-01-19  Murali Vemulapati  <murali.vemulapati@gmail.com>
+
+       * pe-dll.c: (make_one) Conditionally include jump stubs.
+       * emultempl/pe.em (gld_${EMULATION_NAME}_after_open): Identify
+       redundant jump stubs from import libraries and exclude them from 
+       link.
+
 2007-01-19 H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld.h (args_type): Add new symbolic and dynamic_list fields.
index 1396e9842f270ef6bf243007ace532e29b1a0bf5..ae4356f559f16dad004bfe3dd4d4f96e686d43ca 100644 (file)
@@ -11,7 +11,7 @@ rm -f e${EMULATION_NAME}.c
 cat >>e${EMULATION_NAME}.c <<EOF
 /* This file is part of GLD, the Gnu Linker.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006 Free Software Foundation, Inc.
+   2005, 2006, 2007 Free Software Foundation, Inc.
 
    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
@@ -1250,6 +1250,74 @@ gld_${EMULATION_NAME}_after_open (void)
          }
       }
   }
+
+  {
+    /* The following chunk of code tries to identify jump stubs in
+       import libraries which are dead code and eliminates them
+       from the final link. For each exported symbol <sym>, there
+       is a object file in the import library with a .text section
+       and several .idata$* sections. The .text section contains the
+       symbol definition for <sym> which is a jump stub of the form
+       jmp *__imp_<sym>. The .idata$5 contains the symbol definition
+       for __imp_<sym> which is the address of the slot for <sym> in
+       the import address table. When a symbol is imported explicitly
+       using __declspec(dllimport) declaration, the compiler generates
+       a reference to __imp_<sym> which directly resolves to the
+       symbol in .idata$5, in which case the jump stub code is not
+       needed. The following code tries to identify jump stub sections
+       in import libraries which are not referred to by anyone and
+       marks them for exclusion from the final link.  */
+    LANG_FOR_EACH_INPUT_STATEMENT (is)
+      {
+       if (is->the_bfd->my_archive)
+         {
+           int is_imp = 0;
+           asection *sec, *stub_sec = NULL;
+
+           /* See if this is an import library thunk.  */
+           for (sec = is->the_bfd->sections; sec; sec = sec->next)
+             {
+               if (strncmp (sec->name, ".idata\$", 7) == 0)
+                 is_imp = 1;
+               /* The section containing the jmp stub has code
+                  and has a reloc.  */
+               if ((sec->flags & SEC_CODE) && sec->reloc_count)
+                 stub_sec = sec;
+             }
+   
+           if (is_imp && stub_sec)
+             {
+               long symsize;
+               asymbol **symbols;
+               long src_count;
+               struct bfd_link_hash_entry * blhe;
+
+               symsize = bfd_get_symtab_upper_bound (is->the_bfd);
+               symbols = xmalloc (symsize);
+               symsize = bfd_canonicalize_symtab (is->the_bfd, symbols);
+
+               for (src_count = 0; src_count < symsize; src_count++)
+                 {
+                   if (symbols[src_count]->section->id == stub_sec->id)
+                     {
+                       /* This symbol belongs to the section containing
+                          the stub.  */
+                       blhe = bfd_link_hash_lookup (link_info.hash,
+                                                    symbols[src_count]->name,
+                                                    FALSE, FALSE, TRUE);
+                       /* If the symbol in the stub section has no other
+                          undefined references, exclude the stub section
+                          from the final link.  */
+                       if (blhe && (blhe->type == bfd_link_hash_defined)
+                           && (blhe->u.undef.next == NULL))
+                         stub_sec->flags |= SEC_EXCLUDE;
+                     }
+                 }
+               free (symbols);
+             }
+         }
+      }
+  }
 }
 \f
 static void
index 335bc05c4ca8ae313c07051714e44962d9c8b400..a7951c9f79a020590c6d3e6e0c210c09e09a6571 100644 (file)
@@ -1,5 +1,5 @@
 /* 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>
 
@@ -1873,7 +1873,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 +1883,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 +1939,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 +1950,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 +1965,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);
@@ -1986,6 +1995,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 +2061,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,7 +2410,8 @@ 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 = make_one (def->exports + i, outarch,
+                   ! (def->exports + i)->flag_data);
       n->next = head;
       head = n;
       def->exports[i].internal_name = internal;
@@ -2474,6 +2487,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 +2499,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 +2513,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 +2536,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.030127 seconds and 4 git commands to generate.