/* 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>
- This file is part of GLD, the Gnu Linker.
+ This file is part of the GNU Binutils.
- GLD 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
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
- GLD is distributed in the hope that it will be useful,
+ This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GLD; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "coff/internal.h"
#include "../bfd/libcoff.h"
#include "deffile.h"
+#include "pe-dll.h"
#ifdef pe_use_x86_64
(so, DLL name is referenced by multiple entries), and pointer to symbol
name thunk. Symbol name thunk is singleton vector (__nm_th_<symbol>)
pointing to IMAGE_IMPORT_BY_NAME structure (__nm_<symbol>) directly
- containing imported name. Here comes that "om the edge" problem mentioned
+ containing imported name. Here comes that "on the edge" problem mentioned
above: PE specification rambles that name vector (OriginalFirstThunk)
should run in parallel with addresses vector (FirstThunk), i.e. that they
should have same number of elements and terminated with zero. We violate
typedef struct
{
- char *name;
+ const char *name;
int len;
}
autofilter_entry_type;
typedef struct
{
- char *target_name;
- char *object_target;
+ const char *target_name;
+ const char *object_target;
unsigned int imagebase_reloc;
int pe_arch;
int bfd_arch;
bfd_boolean underscored;
- autofilter_entry_type* autofilter_symbollist;
+ const autofilter_entry_type* autofilter_symbollist;
}
pe_details_type;
-static autofilter_entry_type autofilter_symbollist_generic[] =
+static const autofilter_entry_type autofilter_symbollist_generic[] =
{
{ STRING_COMMA_LEN (".text") },
/* Entry point symbols. */
{ STRING_COMMA_LEN (NULL) }
};
-static autofilter_entry_type autofilter_symbollist_i386[] =
+static const autofilter_entry_type autofilter_symbollist_i386[] =
{
{ STRING_COMMA_LEN (".text") },
/* Entry point symbols, and entry hooks. */
#define PE_ARCH_arm_epoc 5
#define PE_ARCH_arm_wince 6
-static pe_details_type pe_detail_list[] =
+static const pe_details_type pe_detail_list[] =
{
{
#ifdef pe_use_x86_64
{ NULL, NULL, 0, 0, 0, FALSE, NULL }
};
-static pe_details_type *pe_details;
+static const pe_details_type *pe_details;
/* Do not specify library suffix explicitly, to allow for dllized versions. */
-static autofilter_entry_type autofilter_liblist[] =
+static const autofilter_entry_type autofilter_liblist[] =
{
{ STRING_COMMA_LEN ("libcegcc") },
{ STRING_COMMA_LEN ("libcygwin") },
{ STRING_COMMA_LEN (NULL) }
};
-static autofilter_entry_type autofilter_objlist[] =
+static const autofilter_entry_type autofilter_objlist[] =
{
{ STRING_COMMA_LEN ("crt0.o") },
{ STRING_COMMA_LEN ("crt1.o") },
{ STRING_COMMA_LEN (NULL) }
};
-static autofilter_entry_type autofilter_symbolprefixlist[] =
+static const autofilter_entry_type autofilter_symbolprefixlist[] =
{
- { STRING_COMMA_LEN ("__imp_") },
- /* Do __imp_ explicitly to save time. */
+ /* _imp_ is treated specially, as it is always underscored. */
+ /* { STRING_COMMA_LEN ("_imp_") }, */
+ /* Don't export some c++ symbols. */
{ STRING_COMMA_LEN ("__rtti_") },
+ { STRING_COMMA_LEN ("__builtin_") },
/* Don't re-export auto-imported symbols. */
{ STRING_COMMA_LEN ("_nm_") },
- { STRING_COMMA_LEN ("__builtin_") },
/* Don't export symbols specifying internal DLL layout. */
{ STRING_COMMA_LEN ("_head_") },
{ STRING_COMMA_LEN (NULL) }
};
-static autofilter_entry_type autofilter_symbolsuffixlist[] =
+static const autofilter_entry_type autofilter_symbolsuffixlist[] =
{
{ STRING_COMMA_LEN ("_iname") },
{ STRING_COMMA_LEN (NULL) }
free (local_copy);
}
+static bfd_boolean
+is_import (const char* n)
+{
+ return (CONST_STRNEQ (n, "__imp_"));
+}
/* abfd is a bfd containing n (or NULL)
It can be used for contextual checks. */
{
int i;
struct exclude_list_struct *ex;
- autofilter_entry_type *afptr;
+ const autofilter_entry_type *afptr;
const char * libname = 0;
if (abfd && abfd->my_archive)
libname = lbasename (abfd->my_archive->filename);
- /* We should not re-export imported stuff. */
- if (CONST_STRNEQ (n, "_imp_"))
- return 0;
-
for (i = 0; i < d->num_exports; i++)
if (strcmp (d->exports[i].name, n) == 0)
return 0;
/* We should not re-export imported stuff. */
{
- char *name = xmalloc (strlen (sn) + 2 + 6);
- sprintf (name, "%s%s", U("_imp_"), sn);
+ char *name;
+ if (is_import (sn))
+ continue;
+
+ name = xmalloc (strlen ("__imp_") + strlen (sn) + 1);
+ sprintf (name, "%s%s", "__imp_", sn);
blhe = bfd_link_hash_lookup (info->hash, name,
FALSE, FALSE, FALSE);
continue;
}
- if (*sn == '_')
+ if (pe_details->underscored && *sn == '_')
sn++;
if (auto_export (b, pe_def_file, sn))
{
for (i = 0; i < NE; i++)
{
+ if (is_import (pe_def_file->exports[i].name))
+ continue;
+
if (strchr (pe_def_file->exports[i].name, '@'))
{
int lead_at = (*pe_def_file->exports[i].name == '@');
d7 = xmalloc (len);
id7->contents = d7;
strcpy ((char *) d7, dll_filename);
+ /* If len was odd, the above
+ strcpy leaves behind an undefined byte. That is harmless,
+ but we set it to 0 just so the binary dumps are pretty. */
+ d7[len - 1] = 0;
bfd_set_symtab (abfd, symtab, symptr);
.short <hint>
.asciz "function" xlate? (add underscore, kill at) */
-static unsigned char jmp_ix86_bytes[] =
+static const unsigned char jmp_ix86_bytes[] =
{
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90
};
nop
.dw __imp_function */
-static unsigned char jmp_sh_bytes[] =
+static const unsigned char jmp_sh_bytes[] =
{
0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00
};
jr $t0
nop */
-static unsigned char jmp_mips_bytes[] =
+static const unsigned char jmp_mips_bytes[] =
{
0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d,
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
};
-static unsigned char jmp_arm_bytes[] =
+static const unsigned char jmp_arm_bytes[] =
{
0x00, 0xc0, 0x9f, 0xe5, /* ldr ip, [pc] */
0x00, 0xf0, 0x9c, 0xe5, /* ldr pc, [ip] */
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;
int len;
char *oname;
bfd *abfd;
- unsigned char *jmp_bytes = NULL;
+ 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);
{
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, U ("_imp_"), exp->internal_name, "", id5,
+ quick_symbol (abfd, "__imp_", exp->internal_name, "", id5,
BSF_GLOBAL, 0);
/* Fastcall applies only to functions,
so no need for auto-import symbol. */
{
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, U ("_imp__"), exp->internal_name, "", id5,
+ quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5,
BSF_GLOBAL, 0);
/* Symbol to reference ord/name of imported
data symbol, used to implement auto-import. */
if (exp->flag_data)
- quick_symbol (abfd, U("_nm__"), exp->internal_name, "", id6,
+ quick_symbol (abfd, U ("_nm_"), U (""), exp->internal_name, id6,
BSF_GLOBAL,0);
}
if (pe_dll_compat_implib)
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);
switch (pe_details->pe_arch)
{
case PE_ARCH_i386:
- quick_reloc (abfd, 2, BFD_RELOC_32, 2);
+#ifdef pe_use_x86_64
+ quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2);
+#else
+ quick_reloc (abfd, 2, BFD_RELOC_32, 2);
+#endif
break;
case PE_ARCH_sh:
quick_reloc (abfd, 8, BFD_RELOC_32, 2);
}
save_relocs (tx);
}
+ else
+ bfd_set_section_size (abfd, tx, 0);
bfd_set_section_size (abfd, id7, 4);
d7 = xmalloc (4);
}
else
{
- len = strlen (exp->name) + 3;
+ /* { short, asciz } */
+ len = 2 + strlen (exp->name) + 1;
if (len & 1)
len++;
bfd_set_section_size (abfd, id6, len);
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);
quick_symbol (abfd, U ("_nm_thnk_"), import, "", id4, BSF_GLOBAL, 0);
quick_symbol (abfd, U ("_nm_"), import, "", UNDSEC, BSF_GLOBAL, 0);
- bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE);
- d4 = xmalloc (PE_IDATA4_SIZE);
+ /* We need space for the real thunk and for the null terminator. */
+ bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE * 2);
+ d4 = xmalloc (PE_IDATA4_SIZE * 2);
id4->contents = d4;
- memset (d4, 0, PE_IDATA4_SIZE);
+ memset (d4, 0, PE_IDATA4_SIZE * 2);
quick_reloc (abfd, 0, BFD_RELOC_RVA, 2);
save_relocs (id4);
bfd_set_symtab (abfd, symtab, symptr);
- bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE);
+ bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE * 2);
bfd_make_readable (abfd);
return abfd;
symtab = xmalloc (2 * sizeof (asymbol *));
extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2);
- quick_symbol (abfd, "", "__pei386_runtime_relocator", "", UNDSEC,
+ quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC,
BSF_NO_FLAGS, 0);
bfd_set_section_size (abfd, extern_rt_rel, 4);
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->next = head;
+ n = make_one (def->exports + i, outarch,
+ ! (def->exports + i)->flag_data);
+ n->archive_next = head;
head = n;
def->exports[i].internal_name = internal;
}
return;
/* Now stick them all into the archive. */
- ar_head->next = head;
- ar_tail->next = ar_head;
+ ar_head->archive_next = head;
+ ar_tail->archive_next = ar_head;
head = ar_tail;
if (! bfd_set_archive_head (outarch, head))
while (head != NULL)
{
- bfd *n = head->next;
+ bfd *n = head->archive_next;
bfd_close (head);
head = n;
}
/* 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%s", "",
+ sprintf (name, "%s",
pe_def_file->imports[i].internal_name);
else
sprintf (name, "%s%s",U (""),
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)
- sprintf (name, "%s%s", U ("_imp_"),
+ sprintf (name, "%s%s", "__imp_",
pe_def_file->imports[i].internal_name);
else
- sprintf (name, "%s%s", U ("_imp__"),
+ sprintf (name, "%s%s%s", "__imp_", U (""),
pe_def_file->imports[i].internal_name);
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)
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);
}
}
}
reloc_s->contents = reloc_d;
}
+
+bfd_boolean
+pe_bfd_is_dll (bfd *abfd)
+{
+ return (bfd_get_format (abfd) == bfd_object
+ && obj_pe (abfd)
+ && pe_data (abfd)->dll);
+}