diff options
author | Nick Clifton <nickc@redhat.com> | 2007-01-19 15:40:55 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2007-01-19 15:40:55 +0000 |
commit | 54727719911a60fc42f9fe74a4762c00add6cb75 (patch) | |
tree | a3bde54c7c2dbbaf713d71f998d7828d4e9e947a /ld | |
parent | d8cf8b513333c644cc5305eff9d5c0dfcac69de5 (diff) | |
download | gdb-54727719911a60fc42f9fe74a4762c00add6cb75.zip gdb-54727719911a60fc42f9fe74a4762c00add6cb75.tar.gz gdb-54727719911a60fc42f9fe74a4762c00add6cb75.tar.bz2 |
* 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.
Diffstat (limited to 'ld')
-rw-r--r-- | ld/ChangeLog | 7 | ||||
-rw-r--r-- | ld/emultempl/pe.em | 70 | ||||
-rw-r--r-- | ld/pe-dll.c | 77 |
3 files changed, 124 insertions, 30 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index 48a9b3e..3d70297 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -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. diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 1396e98..ae4356f 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -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 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); } } |