* 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:
parent
d8cf8b5133
commit
5472771991
3 changed files with 124 additions and 30 deletions
|
@ -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>
|
2007-01-19 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* ld.h (args_type): Add new symbolic and dynamic_list fields.
|
* ld.h (args_type): Add new symbolic and dynamic_list fields.
|
||||||
|
|
|
@ -11,7 +11,7 @@ rm -f e${EMULATION_NAME}.c
|
||||||
cat >>e${EMULATION_NAME}.c <<EOF
|
cat >>e${EMULATION_NAME}.c <<EOF
|
||||||
/* This file is part of GLD, the Gnu Linker.
|
/* This file is part of GLD, the Gnu Linker.
|
||||||
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
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
|
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
|
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
|
static void
|
||||||
|
|
77
ld/pe-dll.c
77
ld/pe-dll.c
|
@ -1,5 +1,5 @@
|
||||||
/* Routines to help build PEI-format DLLs (Win32 etc)
|
/* 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.
|
Free Software Foundation, Inc.
|
||||||
Written by DJ Delorie <dj@cygnus.com>
|
Written by DJ Delorie <dj@cygnus.com>
|
||||||
|
|
||||||
|
@ -1873,7 +1873,7 @@ static const unsigned char jmp_arm_bytes[] =
|
||||||
|
|
||||||
|
|
||||||
static bfd *
|
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;
|
asection *tx, *id7, *id5, *id4, *id6;
|
||||||
unsigned char *td = NULL, *d7, *d5, *d4, *d6 = NULL;
|
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;
|
const unsigned char *jmp_bytes = NULL;
|
||||||
int jmp_byte_count = 0;
|
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:
|
switch (pe_details->pe_arch)
|
||||||
jmp_bytes = jmp_ix86_bytes;
|
{
|
||||||
jmp_byte_count = sizeof (jmp_ix86_bytes);
|
case PE_ARCH_i386:
|
||||||
break;
|
jmp_bytes = jmp_ix86_bytes;
|
||||||
case PE_ARCH_sh:
|
jmp_byte_count = sizeof (jmp_ix86_bytes);
|
||||||
jmp_bytes = jmp_sh_bytes;
|
break;
|
||||||
jmp_byte_count = sizeof (jmp_sh_bytes);
|
case PE_ARCH_sh:
|
||||||
break;
|
jmp_bytes = jmp_sh_bytes;
|
||||||
case PE_ARCH_mips:
|
jmp_byte_count = sizeof (jmp_sh_bytes);
|
||||||
jmp_bytes = jmp_mips_bytes;
|
break;
|
||||||
jmp_byte_count = sizeof (jmp_mips_bytes);
|
case PE_ARCH_mips:
|
||||||
break;
|
jmp_bytes = jmp_mips_bytes;
|
||||||
case PE_ARCH_arm:
|
jmp_byte_count = sizeof (jmp_mips_bytes);
|
||||||
case PE_ARCH_arm_epoc:
|
break;
|
||||||
case PE_ARCH_arm_wince:
|
case PE_ARCH_arm:
|
||||||
jmp_bytes = jmp_arm_bytes;
|
case PE_ARCH_arm_epoc:
|
||||||
jmp_byte_count = sizeof (jmp_arm_bytes);
|
case PE_ARCH_arm_wince:
|
||||||
break;
|
jmp_bytes = jmp_arm_bytes;
|
||||||
default:
|
jmp_byte_count = sizeof (jmp_arm_bytes);
|
||||||
abort ();
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oname = xmalloc (20);
|
oname = xmalloc (20);
|
||||||
|
@ -1930,7 +1939,7 @@ make_one (def_file_export *exp, bfd *parent)
|
||||||
{
|
{
|
||||||
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
|
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
|
||||||
BSF_GLOBAL, 0);
|
BSF_GLOBAL, 0);
|
||||||
if (! exp->flag_data)
|
if (include_jmp_stub)
|
||||||
quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0);
|
quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0);
|
||||||
quick_symbol (abfd, "__imp_", exp->internal_name, "", id5,
|
quick_symbol (abfd, "__imp_", exp->internal_name, "", id5,
|
||||||
BSF_GLOBAL, 0);
|
BSF_GLOBAL, 0);
|
||||||
|
@ -1941,7 +1950,7 @@ make_one (def_file_export *exp, bfd *parent)
|
||||||
{
|
{
|
||||||
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
|
quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
|
||||||
BSF_GLOBAL, 0);
|
BSF_GLOBAL, 0);
|
||||||
if (! exp->flag_data)
|
if (include_jmp_stub)
|
||||||
quick_symbol (abfd, U (""), exp->internal_name, "", tx,
|
quick_symbol (abfd, U (""), exp->internal_name, "", tx,
|
||||||
BSF_GLOBAL, 0);
|
BSF_GLOBAL, 0);
|
||||||
quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5,
|
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,
|
quick_symbol (abfd, U ("__imp_"), exp->internal_name, "", id5,
|
||||||
BSF_GLOBAL, 0);
|
BSF_GLOBAL, 0);
|
||||||
|
|
||||||
if (! exp->flag_data)
|
if (include_jmp_stub)
|
||||||
{
|
{
|
||||||
bfd_set_section_size (abfd, tx, jmp_byte_count);
|
bfd_set_section_size (abfd, tx, jmp_byte_count);
|
||||||
td = xmalloc (jmp_byte_count);
|
td = xmalloc (jmp_byte_count);
|
||||||
|
@ -1986,6 +1995,8 @@ make_one (def_file_export *exp, bfd *parent)
|
||||||
}
|
}
|
||||||
save_relocs (tx);
|
save_relocs (tx);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
bfd_set_section_size (abfd, tx, 0);
|
||||||
|
|
||||||
bfd_set_section_size (abfd, id7, 4);
|
bfd_set_section_size (abfd, id7, 4);
|
||||||
d7 = xmalloc (4);
|
d7 = xmalloc (4);
|
||||||
|
@ -2050,7 +2061,8 @@ make_one (def_file_export *exp, bfd *parent)
|
||||||
|
|
||||||
bfd_set_symtab (abfd, symtab, symptr);
|
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, id7, d7, 0, 4);
|
||||||
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE);
|
bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE);
|
||||||
bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_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)
|
if (pe_def_file->exports[i].flag_private)
|
||||||
continue;
|
continue;
|
||||||
def->exports[i].internal_name = def->exports[i].name;
|
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;
|
n->next = head;
|
||||||
head = n;
|
head = n;
|
||||||
def->exports[i].internal_name = internal;
|
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. */
|
/* See if we need this import. */
|
||||||
size_t len = strlen (pe_def_file->imports[i].internal_name);
|
size_t len = strlen (pe_def_file->imports[i].internal_name);
|
||||||
char *name = xmalloc (len + 2 + 6);
|
char *name = xmalloc (len + 2 + 6);
|
||||||
|
bfd_boolean include_jmp_stub = FALSE;
|
||||||
|
|
||||||
if (lead_at)
|
if (lead_at)
|
||||||
sprintf (name, "%s",
|
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,
|
blhe = bfd_link_hash_lookup (link_info->hash, name,
|
||||||
FALSE, FALSE, FALSE);
|
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 (!blhe || (blhe && blhe->type != bfd_link_hash_undefined))
|
||||||
{
|
{
|
||||||
if (lead_at)
|
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,
|
blhe = bfd_link_hash_lookup (link_info->hash, name,
|
||||||
FALSE, FALSE, FALSE);
|
FALSE, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
include_jmp_stub = TRUE;
|
||||||
|
|
||||||
free (name);
|
free (name);
|
||||||
|
|
||||||
if (blhe && blhe->type == bfd_link_hash_undefined)
|
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_constant = 0;
|
||||||
exp.flag_data = pe_def_file->imports[i].data;
|
exp.flag_data = pe_def_file->imports[i].data;
|
||||||
exp.flag_noname = exp.name ? 0 : 1;
|
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);
|
add_bfd_to_link (one, one->filename, link_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue