* 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.
This commit is contained in:
Nick Clifton 2007-01-19 15:40:55 +00:00
parent d8cf8b5133
commit 5472771991
3 changed files with 124 additions and 30 deletions

View 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.

View 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);
}
}
}
}
}
static void

View 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);
}
}