aboutsummaryrefslogtreecommitdiff
path: root/ld/pe-dll.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/pe-dll.c')
-rw-r--r--ld/pe-dll.c77
1 files changed, 48 insertions, 29 deletions
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 335bc05..a7951c9 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -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);
}
}