X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fpe-dll.c;h=cdbfa70f0e346bc10d6db1796bc50fb04c232d21;hb=7e976ae46d73ba3b38c95fba78385837295b0440;hp=2f326481170d5b07fd865a115a9a63cf9081179c;hpb=775cabad23f71e5edd62343a54c0fc318970916f;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/pe-dll.c b/ld/pe-dll.c index 2f32648117..cdbfa70f0e 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -1,38 +1,39 @@ /* Routines to help build PEI-format DLLs (Win32 etc) - Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. Written by DJ Delorie - 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, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, 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 -#include #include "ld.h" #include "ldexp.h" #include "ldlang.h" #include "ldwrite.h" #include "ldmisc.h" -#include "ldgram.h" +#include #include "ldmain.h" #include "ldfile.h" #include "ldemul.h" @@ -41,14 +42,37 @@ #include "deffile.h" #include "pe-dll.h" +#ifdef pe_use_x86_64 + +#define PE_IDATA4_SIZE 8 +#define PE_IDATA5_SIZE 8 +#include "pep-dll.h" +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +#else + +#include "pe-dll.h" + +#endif + +#ifndef PE_IDATA4_SIZE +#define PE_IDATA4_SIZE 4 +#endif + +#ifndef PE_IDATA5_SIZE +#define PE_IDATA5_SIZE 4 +#endif + /* This file turns a regular Windows PE image into a DLL. Because of the complexity of this operation, it has been broken down into a number of separate modules which are all called by the main function at the end of this file. This function is not re-entrant and is normally only called once, so static variables are used to reduce the number of parameters and return values required. - - See also: ld/emultempl/pe.em. */ + + See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ /* Auto-import feature by Paul Sokolovsky @@ -59,7 +83,7 @@ code modifications). 2. This is done completely in bounds of the PE specification (to be fair, - there's a place where it pokes nose out of, but in practise it works). + there's a place where it pokes nose out of, but in practice it works). So, resulting module can be used with any other PE compiler/linker. 3. Auto-import is fully compatible with standard import method and they @@ -74,7 +98,7 @@ The obvious and only way to get rid of dllimport insanity is to make client access variable directly in the DLL, bypassing extra dereference. I.e., - whenever client contains someting like + whenever client contains something like mov dll_var,%eax, @@ -82,7 +106,7 @@ DLL. The aim is to make OS loader do so, and than make ld help with that. Import section of PE made following way: there's a vector of structures each describing imports from particular DLL. Each such structure points - to two other parellel vectors: one holding imported names, and one which + to two other parallel vectors: one holding imported names, and one which will hold address of corresponding imported name. So, the solution is de-vectorize these structures, making import locations be sparse and pointing directly into code. Before continuing, it is worth a note that, @@ -94,17 +118,17 @@ For each reference of data symbol to be imported from DLL (to set of which belong symbols with name , if __imp_ is found in implib), the import fixup entry is generated. That entry is of type - IMAGE_IMPORT_DESCRIPTOR and stored in .idata$3 subsection. Each + IMAGE_IMPORT_DESCRIPTOR and stored in .idata$2 subsection. Each fixup entry contains pointer to symbol's address within .text section (marked with __fuN_ symbol, where N is integer), pointer to DLL name (so, DLL name is referenced by multiple entries), and pointer to symbol name thunk. Symbol name thunk is singleton vector (__nm_th_) pointing to IMAGE_IMPORT_BY_NAME structure (__nm_) 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 - this, since FirstThunk points directly into machine code. But in practise, + this, since FirstThunk points directly into machine code. But in practice, OS loader implemented the sane way: it goes thru OriginalFirstThunk and puts addresses to FirstThunk, not something else. It once again should be noted that dll and symbol name structures are reused across fixup entries @@ -115,13 +139,12 @@ in windows9x kernel32.dll, so if you use it, you have two IMAGE_IMPORT_DESCRIPTORS for kernel32.dll). Yet other question is whether referencing the same PE structures several times is valid. The answer is why - not, prohibitting that (detecting violation) would require more work on + not, prohibiting that (detecting violation) would require more work on behalf of loader than not doing it. - See also: ld/emultempl/pe.em. */ + See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ -static void -add_bfd_to_link PARAMS ((bfd *, const char *, struct bfd_link_info *)); +static void add_bfd_to_link (bfd *, const char *, struct bfd_link_info *); /* For emultempl/pe.em. */ @@ -138,43 +161,102 @@ int pe_dll_extra_pe_debug = 0; static bfd_vma image_base; static bfd *filler_bfd; -static struct sec *edata_s, *reloc_s; +static struct bfd_section *edata_s, *reloc_s; static unsigned char *edata_d, *reloc_d; static size_t edata_sz, reloc_sz; +static int runtime_pseudo_relocs_created = 0; typedef struct - { - char *target_name; - char *object_target; - unsigned int imagebase_reloc; - int pe_arch; - int bfd_arch; - int underscored; - } -pe_details_type; +{ + const char *name; + int len; +} +autofilter_entry_type; typedef struct - { - char *name; - int len; - } -autofilter_entry_type; +{ + const char *target_name; + const char *object_target; + unsigned int imagebase_reloc; + int pe_arch; + int bfd_arch; + bfd_boolean underscored; + const autofilter_entry_type* autofilter_symbollist; +} +pe_details_type; -#define PE_ARCH_i386 1 -#define PE_ARCH_sh 2 -#define PE_ARCH_mips 3 -#define PE_ARCH_arm 4 +static const autofilter_entry_type autofilter_symbollist_generic[] = +{ + { STRING_COMMA_LEN (".text") }, + /* Entry point symbols. */ + { STRING_COMMA_LEN ("DllMain") }, + { STRING_COMMA_LEN ("DllMainCRTStartup") }, + { STRING_COMMA_LEN ("_DllMainCRTStartup") }, + /* Runtime pseudo-reloc. */ + { STRING_COMMA_LEN ("_pei386_runtime_relocator") }, + { STRING_COMMA_LEN ("do_pseudo_reloc") }, + { STRING_COMMA_LEN (NULL) } +}; + +static const autofilter_entry_type autofilter_symbollist_i386[] = +{ + { STRING_COMMA_LEN (".text") }, + /* Entry point symbols, and entry hooks. */ + { STRING_COMMA_LEN ("cygwin_crt0") }, +#ifdef pe_use_x86_64 + { STRING_COMMA_LEN ("DllMain") }, + { STRING_COMMA_LEN ("DllEntryPoint") }, + { STRING_COMMA_LEN ("DllMainCRTStartup") }, + { STRING_COMMA_LEN ("_cygwin_dll_entry") }, + { STRING_COMMA_LEN ("_cygwin_crt0_common") }, + { STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry") }, +#else + { STRING_COMMA_LEN ("DllMain@12") }, + { STRING_COMMA_LEN ("DllEntryPoint@0") }, + { STRING_COMMA_LEN ("DllMainCRTStartup@12") }, + { STRING_COMMA_LEN ("_cygwin_dll_entry@12") }, + { STRING_COMMA_LEN ("_cygwin_crt0_common@8") }, + { STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry@12") }, + { STRING_COMMA_LEN ("cygwin_attach_dll") }, +#endif + { STRING_COMMA_LEN ("cygwin_premain0") }, + { STRING_COMMA_LEN ("cygwin_premain1") }, + { STRING_COMMA_LEN ("cygwin_premain2") }, + { STRING_COMMA_LEN ("cygwin_premain3") }, + /* Runtime pseudo-reloc. */ + { STRING_COMMA_LEN ("_pei386_runtime_relocator") }, + { STRING_COMMA_LEN ("do_pseudo_reloc") }, + /* Global vars that should not be exported. */ + { STRING_COMMA_LEN ("impure_ptr") }, + { STRING_COMMA_LEN ("_impure_ptr") }, + { STRING_COMMA_LEN ("_fmode") }, + { STRING_COMMA_LEN ("environ") }, + { STRING_COMMA_LEN (NULL) } +}; + +#define PE_ARCH_i386 1 +#define PE_ARCH_sh 2 +#define PE_ARCH_mips 3 +#define PE_ARCH_arm 4 #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 + "pei-x86-64", + "pe-x86-64", + 3 /* R_IMAGEBASE */, +#else "pei-i386", "pe-i386", 7 /* R_IMAGEBASE */, +#endif PE_ARCH_i386, bfd_arch_i386, - 1 + TRUE, + autofilter_symbollist_i386 }, { "pei-shl", @@ -182,7 +264,8 @@ static pe_details_type pe_detail_list[] = 16 /* R_SH_IMAGEBASE */, PE_ARCH_sh, bfd_arch_sh, - 1 + TRUE, + autofilter_symbollist_generic }, { "pei-mips", @@ -190,7 +273,8 @@ static pe_details_type pe_detail_list[] = 34 /* MIPS_R_RVA */, PE_ARCH_mips, bfd_arch_mips, - 0 + FALSE, + autofilter_symbollist_generic }, { "pei-arm-little", @@ -198,7 +282,8 @@ static pe_details_type pe_detail_list[] = 11 /* ARM_RVA32 */, PE_ARCH_arm, bfd_arch_arm, - 0 + TRUE, + autofilter_symbollist_generic }, { "epoc-pei-arm-little", @@ -206,96 +291,78 @@ static pe_details_type pe_detail_list[] = 11 /* ARM_RVA32 */, PE_ARCH_arm_epoc, bfd_arch_arm, - 0 + FALSE, + autofilter_symbollist_generic }, - { NULL, NULL, 0, 0, 0, 0 } + { + "pei-arm-wince-little", + "pe-arm-wince-little", + 2, /* ARM_RVA32 on Windows CE, see bfd/coff-arm.c. */ + PE_ARCH_arm_wince, + bfd_arch_arm, + FALSE, + autofilter_symbollist_generic + }, + { NULL, NULL, 0, 0, 0, FALSE, NULL } }; -static pe_details_type *pe_details; - -static autofilter_entry_type autofilter_symbollist[] = -{ - { "DllMain@12", 10 }, - { "DllEntryPoint@0", 15 }, - { "DllMainCRTStartup@12", 20 }, - { "_cygwin_dll_entry@12", 20 }, - { "_cygwin_crt0_common@8", 21 }, - { "_cygwin_noncygwin_dll_entry@12", 30 }, - { "impure_ptr", 10 }, - { NULL, 0 } -}; +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[] = { - { "libgcc.", 7 }, - { "libstdc++.", 10 }, - { "libmingw32.", 11 }, - { NULL, 0 } + { STRING_COMMA_LEN ("libcegcc") }, + { STRING_COMMA_LEN ("libcygwin") }, + { STRING_COMMA_LEN ("libgcc") }, + { STRING_COMMA_LEN ("libstdc++") }, + { STRING_COMMA_LEN ("libmingw32") }, + { STRING_COMMA_LEN ("libmingwex") }, + { STRING_COMMA_LEN ("libg2c") }, + { STRING_COMMA_LEN ("libsupc++") }, + { STRING_COMMA_LEN ("libobjc") }, + { STRING_COMMA_LEN ("libgcj") }, + { STRING_COMMA_LEN (NULL) } }; -static autofilter_entry_type autofilter_objlist[] = +static const autofilter_entry_type autofilter_objlist[] = { - { "crt0.o", 6 }, - { "crt1.o", 6 }, - { "crt2.o", 6 }, - { NULL, 0 } + { STRING_COMMA_LEN ("crt0.o") }, + { STRING_COMMA_LEN ("crt1.o") }, + { STRING_COMMA_LEN ("crt2.o") }, + { STRING_COMMA_LEN ("dllcrt1.o") }, + { STRING_COMMA_LEN ("dllcrt2.o") }, + { STRING_COMMA_LEN ("gcrt0.o") }, + { STRING_COMMA_LEN ("gcrt1.o") }, + { STRING_COMMA_LEN ("gcrt2.o") }, + { STRING_COMMA_LEN ("crtbegin.o") }, + { STRING_COMMA_LEN ("crtend.o") }, + { STRING_COMMA_LEN (NULL) } }; -static autofilter_entry_type autofilter_symbolprefixlist[] = +static const autofilter_entry_type autofilter_symbolprefixlist[] = { - /* { "__imp_", 6 }, */ - /* Do __imp_ explicitly to save time. */ - { "__rtti_", 7 }, - { "__builtin_", 10 }, + /* _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_") }, /* Don't export symbols specifying internal DLL layout. */ - { "_head_", 6 }, - { "_fmode", 6 }, - { "_impure_ptr", 11 }, - { "cygwin_attach_dll", 17 }, - { "cygwin_premain0", 15 }, - { "cygwin_premain1", 15 }, - { "cygwin_premain2", 15 }, - { "cygwin_premain3", 15 }, - { "environ", 7 }, - { NULL, 0 } + { STRING_COMMA_LEN ("_head_") }, + { STRING_COMMA_LEN (NULL) } }; -static autofilter_entry_type autofilter_symbolsuffixlist[] = +static const autofilter_entry_type autofilter_symbolsuffixlist[] = { - { "_iname", 6 }, - { NULL, 0 } + { STRING_COMMA_LEN ("_iname") }, + { STRING_COMMA_LEN (NULL) } }; #define U(str) (pe_details->underscored ? "_" str : str) -static int reloc_sort PARAMS ((const void *, const void *)); -static int pe_export_sort PARAMS ((const void *, const void *)); -static int auto_export PARAMS ((bfd *, def_file *, const char *)); -static void process_def_file PARAMS ((bfd *, struct bfd_link_info *)); -static void build_filler_bfd PARAMS ((int)); -static void generate_edata PARAMS ((bfd *, struct bfd_link_info *)); -static void fill_exported_offsets PARAMS ((bfd *, struct bfd_link_info *)); -static void fill_edata PARAMS ((bfd *, struct bfd_link_info *)); -static void generate_reloc PARAMS ((bfd *, struct bfd_link_info *)); -static void quoteput PARAMS ((char *, FILE *, int)); -static asection *quick_section PARAMS ((bfd *, const char *, int, int)); -static void quick_symbol - PARAMS ((bfd *, char *, char *, char *, asection *, int, int)); -static void quick_reloc PARAMS ((bfd *, int, int, int)); -static bfd *make_head PARAMS ((bfd *)); -static bfd *make_tail PARAMS ((bfd *)); -static bfd *make_one PARAMS ((def_file_export *, bfd *)); -static bfd *make_singleton_name_thunk PARAMS ((char *, bfd *)); -static char *make_import_fixup_mark PARAMS ((arelent *)); -static bfd *make_import_fixup_entry PARAMS ((char *, char *, char *, bfd *)); -static unsigned int pe_get16 PARAMS ((bfd *, int)); -static unsigned int pe_get32 PARAMS ((bfd *, int)); -static unsigned int pe_as32 PARAMS ((void *)); - void -pe_dll_id_target (target) - const char *target; +pe_dll_id_target (const char *target) { int i; @@ -310,7 +377,7 @@ pe_dll_id_target (target) exit (1); } -/* Helper functions for qsort. Relocs must be sorted so that we can write +/* Helper functions for qsort. Relocs must be sorted so that we can write them out by pages. */ typedef struct @@ -322,21 +389,19 @@ typedef struct reloc_data_type; static int -reloc_sort (va, vb) - const void *va, *vb; +reloc_sort (const void *va, const void *vb) { - bfd_vma a = ((reloc_data_type *) va)->vma; - bfd_vma b = ((reloc_data_type *) vb)->vma; + bfd_vma a = ((const reloc_data_type *) va)->vma; + bfd_vma b = ((const reloc_data_type *) vb)->vma; return (a > b) ? 1 : ((a < b) ? -1 : 0); } static int -pe_export_sort (va, vb) - const void *va, *vb; +pe_export_sort (const void *va, const void *vb) { - def_file_export *a = (def_file_export *) va; - def_file_export *b = (def_file_export *) vb; + const def_file_export *a = va; + const def_file_export *b = vb; return strcmp (a->name, b->name); } @@ -348,7 +413,7 @@ pe_export_sort (va, vb) defined, since we can't export symbols we don't have. */ static bfd_vma *exported_symbol_offsets; -static struct sec **exported_symbol_sections; +static struct bfd_section **exported_symbol_sections; static int export_table_size; static int count_exported; static int count_exported_byname; @@ -361,14 +426,14 @@ typedef struct exclude_list_struct { char *string; struct exclude_list_struct *next; + int type; } exclude_list_struct; static struct exclude_list_struct *excludes = 0; void -pe_dll_add_excludes (new_excludes) - const char *new_excludes; +pe_dll_add_excludes (const char *new_excludes, const int type) { char *local_copy; char *exclude_string; @@ -380,10 +445,10 @@ pe_dll_add_excludes (new_excludes) { struct exclude_list_struct *new_exclude; - new_exclude = ((struct exclude_list_struct *) - xmalloc (sizeof (struct exclude_list_struct))); - new_exclude->string = (char *) xmalloc (strlen (exclude_string) + 1); + new_exclude = xmalloc (sizeof (struct exclude_list_struct)); + new_exclude->string = xmalloc (strlen (exclude_string) + 1); strcpy (new_exclude->string, exclude_string); + new_exclude->type = type; new_exclude->next = excludes; excludes = new_exclude; } @@ -391,22 +456,24 @@ pe_dll_add_excludes (new_excludes) 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. */ static int -auto_export (abfd, d, n) - bfd *abfd; - def_file *d; - const char *n; +auto_export (bfd *abfd, def_file *d, const char *n) { int i; struct exclude_list_struct *ex; - autofilter_entry_type *afptr; - - /* We should not re-export imported stuff. */ - if (strncmp (n, "_imp__", 6) == 0) - return 0; + const autofilter_entry_type *afptr; + const char * libname = 0; + if (abfd && abfd->my_archive) + libname = lbasename (abfd->my_archive->filename); for (i = 0; i < d->num_exports; i++) if (strcmp (d->exports[i].name, n) == 0) @@ -414,7 +481,7 @@ auto_export (abfd, d, n) if (pe_dll_do_default_excludes) { - char * p; + const char * p; int len; if (pe_dll_extra_pe_debug) @@ -422,44 +489,44 @@ auto_export (abfd, d, n) n, abfd, abfd->my_archive); /* First of all, make context checks: - Don't export anything from libgcc. */ - if (abfd && abfd->my_archive) + Don't export anything from standard libs. */ + if (libname) { afptr = autofilter_liblist; while (afptr->name) { - if (strstr (abfd->my_archive->filename, afptr->name)) + if (strncmp (libname, afptr->name, afptr->len) == 0 ) return 0; afptr++; } } /* Next, exclude symbols from certain startup objects. */ - afptr = autofilter_objlist; - while (afptr->name) + if (abfd && (p = lbasename (abfd->filename))) { - if (abfd && - (p = strstr (abfd->filename, afptr->name)) && - (*(p + afptr->len - 1) == 0)) - return 0; - - afptr ++; + afptr = autofilter_objlist; + while (afptr->name) + { + if (strcmp (p, afptr->name) == 0) + return 0; + afptr++; + } } /* Don't try to blindly exclude all symbols that begin with '__'; this was tried and - it is too restrictive. */ + it is too restrictive. Instead we have + a target specific list to use: */ + afptr = pe_details->autofilter_symbollist; - /* Then, exclude specific symbols. */ - afptr = autofilter_symbollist; while (afptr->name) { if (strcmp (n, afptr->name) == 0) return 0; - afptr ++; + afptr++; } /* Next, exclude symbols starting with ... */ @@ -469,7 +536,7 @@ auto_export (abfd, d, n) if (strncmp (n, afptr->name, afptr->len) == 0) return 0; - afptr ++; + afptr++; } /* Finally, exclude symbols ending with ... */ @@ -477,32 +544,39 @@ auto_export (abfd, d, n) afptr = autofilter_symbolsuffixlist; while (afptr->name) { - if ((len >= afptr->len) && + if ((len >= afptr->len) /* Add 1 to insure match with trailing '\0'. */ - strncmp (n + len - afptr->len, afptr->name, - afptr->len + 1) == 0) + && strncmp (n + len - afptr->len, afptr->name, + afptr->len + 1) == 0) return 0; - afptr ++; + afptr++; } } for (ex = excludes; ex; ex = ex->next) - if (strcmp (n, ex->string) == 0) - return 0; + { + if (ex->type == 1) /* exclude-libs */ + { + if (libname + && ((strcmp (libname, ex->string) == 0) + || (strcasecmp ("ALL", ex->string) == 0))) + return 0; + } + else if (strcmp (n, ex->string) == 0) + return 0; + } return 1; } static void -process_def_file (abfd, info) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info; +process_def_file (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) { int i, j; struct bfd_link_hash_entry *blhe; bfd *b; - struct sec *s; + struct bfd_section *s; def_file_export *e = 0; if (!pe_def_file) @@ -515,7 +589,7 @@ process_def_file (abfd, info) s = bfd_get_section_by_name (b, ".drectve"); if (s) { - int size = bfd_get_section_size_before_reloc (s); + long size = s->size; char *buf = xmalloc (size); bfd_get_section_contents (b, s, buf, 0, size); @@ -524,6 +598,12 @@ process_def_file (abfd, info) } } + /* If we are not building a DLL, when there are no exports + we do not build an export table at all. */ + if (!pe_dll_export_everything && pe_def_file->num_exports == 0 + && info->executable) + return; + /* Now, maybe export everything else the default way. */ if (pe_dll_export_everything || pe_def_file->num_exports == 0) { @@ -533,14 +613,14 @@ process_def_file (abfd, info) int nsyms, symsize; symsize = bfd_get_symtab_upper_bound (b); - symbols = (asymbol **) xmalloc (symsize); + symbols = xmalloc (symsize); nsyms = bfd_canonicalize_symtab (b, symbols); for (j = 0; j < nsyms; j++) { /* We should export symbols which are either global or not - anything at all. (.bss data is the latter) - We should not export undefined symbols. */ + anything at all. (.bss data is the latter) + We should not export undefined symbols. */ if (symbols[j]->section != &bfd_und_section && ((symbols[j]->flags & BSF_GLOBAL) || (symbols[j]->flags == BFD_FORT_COMM_DEFAULT_VALUE))) @@ -549,18 +629,22 @@ process_def_file (abfd, info) /* We should not re-export imported stuff. */ { - char *name = (char *) 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); + FALSE, FALSE, FALSE); free (name); - if (blhe && blhe->type == bfd_link_hash_defined) + if (blhe && blhe->type == bfd_link_hash_defined) continue; } - if (*sn == '_') + if (pe_details->underscored && *sn == '_') sn++; if (auto_export (b, pe_def_file, sn)) @@ -586,11 +670,17 @@ process_def_file (abfd, info) if (strchr (pe_def_file->exports[i].name, '@')) { /* This will preserve internal_name, which may have been - pointing to the same memory as name, or might not - have. */ - char *tmp = xstrdup (pe_def_file->exports[i].name); - - *(strchr (tmp, '@')) = 0; + pointing to the same memory as name, or might not + have. */ + int lead_at = (*pe_def_file->exports[i].name == '@'); + char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); + char *tmp_at = strchr (tmp, '@'); + + if (tmp_at) + *tmp_at = 0; + else + einfo (_("%XCannot export %s: invalid export name\n"), + pe_def_file->exports[i].name); pe_def_file->exports[i].name = tmp; } } @@ -600,9 +690,13 @@ process_def_file (abfd, info) { for (i = 0; i < NE; i++) { + if (is_import (pe_def_file->exports[i].name)) + continue; + if (strchr (pe_def_file->exports[i].name, '@')) { - char *tmp = xstrdup (pe_def_file->exports[i].name); + int lead_at = (*pe_def_file->exports[i].name == '@'); + char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); *(strchr (tmp, '@')) = 0; if (auto_export (NULL, pe_def_file, tmp)) @@ -618,17 +712,18 @@ process_def_file (abfd, info) /* Convenience, but watch out for it changing. */ e = pe_def_file->exports; - exported_symbol_offsets = (bfd_vma *) xmalloc (NE * sizeof (bfd_vma)); - exported_symbol_sections = (struct sec **) xmalloc (NE * sizeof (struct sec *)); + exported_symbol_offsets = xmalloc (NE * sizeof (bfd_vma)); + exported_symbol_sections = xmalloc (NE * sizeof (struct bfd_section *)); - memset (exported_symbol_sections, 0, NE * sizeof (struct sec *)); + memset (exported_symbol_sections, 0, NE * sizeof (struct bfd_section *)); max_ordinal = 0; min_ordinal = 65536; count_exported = 0; count_exported_byname = 0; count_with_ordinals = 0; - qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), pe_export_sort); + qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), + pe_export_sort); for (i = 0, j = 0; i < NE; i++) { if (i > 0 && strcmp (e[i].name, e[i - 1].name) == 0) @@ -669,9 +764,32 @@ process_def_file (abfd, info) for (i = 0; i < NE; i++) { - char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); + char *name; + + /* Check for forward exports */ + if (strchr (pe_def_file->exports[i].internal_name, '.')) + { + count_exported++; + if (!pe_def_file->exports[i].flag_noname) + count_exported_byname++; + + pe_def_file->exports[i].flag_forward = 1; + + if (pe_def_file->exports[i].ordinal != -1) + { + if (max_ordinal < pe_def_file->exports[i].ordinal) + max_ordinal = pe_def_file->exports[i].ordinal; + if (min_ordinal > pe_def_file->exports[i].ordinal) + min_ordinal = pe_def_file->exports[i].ordinal; + count_with_ordinals++; + } + + continue; + } - if (pe_details->underscored) + name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); + if (pe_details->underscored + && (*pe_def_file->exports[i].internal_name != '@')) { *name = '_'; strcpy (name + 1, pe_def_file->exports[i].internal_name); @@ -681,7 +799,7 @@ process_def_file (abfd, info) blhe = bfd_link_hash_lookup (info->hash, name, - false, false, true); + FALSE, FALSE, TRUE); if (blhe && (blhe->type == bfd_link_hash_defined @@ -734,8 +852,7 @@ process_def_file (abfd, info) /* Build the bfd that will contain .edata and .reloc sections. */ static void -build_filler_bfd (include_edata) - int include_edata; +build_filler_bfd (int include_edata) { lang_input_statement_type *filler_file; filler_file = lang_add_input_file ("dll stuff", @@ -747,7 +864,7 @@ build_filler_bfd (include_edata) bfd_get_arch (output_bfd), bfd_get_mach (output_bfd))) { - einfo ("%X%P: can not create BFD %E\n"); + einfo ("%X%P: can not create BFD: %E\n"); return; } @@ -789,9 +906,7 @@ build_filler_bfd (include_edata) /* Gather all the exported symbols and build the .edata section. */ static void -generate_edata (abfd, info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; +generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) { int i, next_ordinal; int name_table_size = 0; @@ -822,14 +937,15 @@ generate_edata (abfd, info) } export_table_size = max_ordinal - min_ordinal + 1; - exported_symbols = (int *) xmalloc (export_table_size * sizeof (int)); + exported_symbols = xmalloc (export_table_size * sizeof (int)); for (i = 0; i < export_table_size; i++) exported_symbols[i] = -1; /* Now we need to assign ordinals to those that don't have them. */ for (i = 0; i < NE; i++) { - if (exported_symbol_sections[i]) + if (exported_symbol_sections[i] || + pe_def_file->exports[i].flag_forward) { if (pe_def_file->exports[i].ordinal != -1) { @@ -848,19 +964,26 @@ generate_edata (abfd, info) } name_table_size += strlen (pe_def_file->exports[i].name) + 1; } + + /* Reserve space for the forward name. */ + if (pe_def_file->exports[i].flag_forward) + { + name_table_size += strlen (pe_def_file->exports[i].internal_name) + 1; + } } next_ordinal = min_ordinal; for (i = 0; i < NE; i++) - if (exported_symbol_sections[i]) - if (pe_def_file->exports[i].ordinal == -1) - { - while (exported_symbols[next_ordinal - min_ordinal] != -1) - next_ordinal ++; + if ((exported_symbol_sections[i] || + pe_def_file->exports[i].flag_forward) && + pe_def_file->exports[i].ordinal == -1) + { + while (exported_symbols[next_ordinal - min_ordinal] != -1) + next_ordinal++; - exported_symbols[next_ordinal - min_ordinal] = i; - pe_def_file->exports[i].ordinal = next_ordinal; - } + exported_symbols[next_ordinal - min_ordinal] = i; + pe_def_file->exports[i].ordinal = next_ordinal; + } /* OK, now we can allocate some memory. */ edata_sz = (40 /* directory */ @@ -874,18 +997,18 @@ generate_edata (abfd, info) been done in process_def_file(). */ static void -fill_exported_offsets (abfd, info) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info; +fill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) { int i; struct bfd_link_hash_entry *blhe; for (i = 0; i < pe_def_file->num_exports; i++) { - char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); + char *name; - if (pe_details->underscored) + name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); + if (pe_details->underscored + && *pe_def_file->exports[i].internal_name != '@') { *name = '_'; strcpy (name + 1, pe_def_file->exports[i].internal_name); @@ -895,9 +1018,9 @@ fill_exported_offsets (abfd, info) blhe = bfd_link_hash_lookup (info->hash, name, - false, false, true); + FALSE, FALSE, TRUE); - if (blhe && (blhe->type == bfd_link_hash_defined)) + if (blhe && blhe->type == bfd_link_hash_defined) exported_symbol_offsets[i] = blhe->u.def.value; free (name); @@ -905,30 +1028,29 @@ fill_exported_offsets (abfd, info) } static void -fill_edata (abfd, info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; +fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) { - int i, hint; + int s, hint; unsigned char *edirectory; - unsigned long *eaddresses; - unsigned long *enameptrs; - unsigned short *eordinals; - unsigned char *enamestr; + unsigned char *eaddresses; + unsigned char *enameptrs; + unsigned char *eordinals; + char *enamestr; time_t now; time (&now); - edata_d = (unsigned char *) xmalloc (edata_sz); + edata_d = xmalloc (edata_sz); /* Note use of array pointer math here. */ edirectory = edata_d; - eaddresses = (unsigned long *) (edata_d + 40); - enameptrs = eaddresses + export_table_size; - eordinals = (unsigned short *) (enameptrs + count_exported_byname); - enamestr = (char *) (eordinals + count_exported_byname); + eaddresses = edata_d + 40; + enameptrs = eaddresses + 4 * export_table_size; + eordinals = enameptrs + 4 * count_exported_byname; + enamestr = (char *) eordinals + 2 * count_exported_byname; -#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) + edata_s->output_section->vma - image_base) +#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) \ + + edata_s->output_section->vma - image_base) memset (edata_d, 0, edata_sz); bfd_put_32 (abfd, now, edata_d + 4); @@ -950,32 +1072,49 @@ fill_edata (abfd, info) fill_exported_offsets (abfd, info); - /* Ok, now for the filling in part. */ + /* Ok, now for the filling in part. + Scan alphabetically - ie the ordering in the exports[] table, + rather than by ordinal - the ordering in the exported_symbol[] + table. See dlltool.c and: + http://sources.redhat.com/ml/binutils/2003-04/msg00379.html + for more information. */ hint = 0; - for (i = 0; i < export_table_size; i++) + for (s = 0; s < NE; s++) { - int s = exported_symbols[i]; - - if (s != -1) + struct bfd_section *ssec = exported_symbol_sections[s]; + if (pe_def_file->exports[s].ordinal != -1 && + (pe_def_file->exports[s].flag_forward || ssec != NULL)) { - struct sec *ssec = exported_symbol_sections[s]; - unsigned long srva = (exported_symbol_offsets[s] - + ssec->output_section->vma - + ssec->output_offset); int ord = pe_def_file->exports[s].ordinal; - bfd_put_32 (abfd, srva - image_base, - (void *) (eaddresses + ord - min_ordinal)); + if (pe_def_file->exports[s].flag_forward) + { + bfd_put_32 (abfd, ERVA (enamestr), + eaddresses + 4 * (ord - min_ordinal)); + + strcpy (enamestr, pe_def_file->exports[s].internal_name); + enamestr += strlen (pe_def_file->exports[s].internal_name) + 1; + } + else + { + unsigned long srva = (exported_symbol_offsets[s] + + ssec->output_section->vma + + ssec->output_offset); + + bfd_put_32 (abfd, srva - image_base, + eaddresses + 4 * (ord - min_ordinal)); + } if (!pe_def_file->exports[s].flag_noname) { char *ename = pe_def_file->exports[s].name; - bfd_put_32 (abfd, ERVA (enamestr), (void *) enameptrs); - enameptrs++; + + bfd_put_32 (abfd, ERVA (enamestr), enameptrs); + enameptrs += 4; strcpy (enamestr, ename); enamestr += strlen (enamestr) + 1; - bfd_put_16 (abfd, ord - min_ordinal, (void *) eordinals); - eordinals++; + bfd_put_16 (abfd, ord - min_ordinal, eordinals); + eordinals += 2; pe_def_file->exports[s].hint = hint++; } } @@ -983,13 +1122,12 @@ fill_edata (abfd, info) } -static struct sec *current_sec; +static struct bfd_section *current_sec; void -pe_walk_relocs_of_symbol (info, name, cb) - struct bfd_link_info *info; - CONST char *name; - int (*cb) (arelent *, asection *); +pe_walk_relocs_of_symbol (struct bfd_link_info *info, + const char *name, + int (*cb) (arelent *, asection *)) { bfd *b; asection *s; @@ -1000,7 +1138,7 @@ pe_walk_relocs_of_symbol (info, name, cb) int nsyms, symsize; symsize = bfd_get_symtab_upper_bound (b); - symbols = (asymbol **) xmalloc (symsize); + symbols = xmalloc (symsize); nsyms = bfd_canonicalize_symtab (b, symbols); for (s = b->sections; s; s = s->next) @@ -1017,12 +1155,12 @@ pe_walk_relocs_of_symbol (info, name, cb) current_sec = s; relsize = bfd_get_reloc_upper_bound (b, s); - relocs = (arelent **) xmalloc ((size_t) relsize); + relocs = xmalloc (relsize); nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); for (i = 0; i < nrelocs; i++) { - struct symbol_cache_entry *sym = *relocs[i]->sym_ptr_ptr; + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; if (!strcmp (name, sym->name)) cb (relocs[i], s); @@ -1040,28 +1178,25 @@ pe_walk_relocs_of_symbol (info, name, cb) /* Gather all the relocations and build the .reloc section. */ static void -generate_reloc (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +generate_reloc (bfd *abfd, struct bfd_link_info *info) { /* For .reloc stuff. */ reloc_data_type *reloc_data; int total_relocs = 0; int i; - unsigned long sec_page = (unsigned long) (-1); + unsigned long sec_page = (unsigned long) -1; unsigned long page_ptr, page_count; int bi; bfd *b; - struct sec *s; + struct bfd_section *s; total_relocs = 0; for (b = info->input_bfds; b; b = b->link_next) for (s = b->sections; s; s = s->next) total_relocs += s->reloc_count; - reloc_data = - (reloc_data_type *) xmalloc (total_relocs * sizeof (reloc_data_type)); + reloc_data = xmalloc (total_relocs * sizeof (reloc_data_type)); total_relocs = 0; bi = 0; @@ -1095,25 +1230,25 @@ generate_reloc (abfd, info) } symsize = bfd_get_symtab_upper_bound (b); - symbols = (asymbol **) xmalloc (symsize); + symbols = xmalloc (symsize); nsyms = bfd_canonicalize_symtab (b, symbols); relsize = bfd_get_reloc_upper_bound (b, s); - relocs = (arelent **) xmalloc ((size_t) relsize); + relocs = xmalloc (relsize); nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); for (i = 0; i < nrelocs; i++) { if (pe_dll_extra_pe_debug) - { - struct symbol_cache_entry *sym = *relocs[i]->sym_ptr_ptr; - printf("rel: %s\n",sym->name); + { + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; + printf ("rel: %s\n", sym->name); } if (!relocs[i]->howto->pc_relative && relocs[i]->howto->type != pe_details->imagebase_reloc) { bfd_vma sym_vma; - struct symbol_cache_entry *sym = *relocs[i]->sym_ptr_ptr; + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; sym_vma = (relocs[i]->addend + sym->value @@ -1127,6 +1262,12 @@ generate_reloc (abfd, info) switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, relocs[i]->howto->rightshift) { +#ifdef pe_use_x86_64 + case BITS_AND_SHIFT (64, 0): + reloc_data[total_relocs].type = 10; + total_relocs++; + break; +#endif case BITS_AND_SHIFT (32, 0): reloc_data[total_relocs].type = 3; total_relocs++; @@ -1148,6 +1289,18 @@ generate_reloc (abfd, info) reloc_data[total_relocs].type = 5; total_relocs++; break; + case BITS_AND_SHIFT (24, 2): + /* FIXME: 0 is ARM_26D, it is defined in bfd/coff-arm.c + Those ARM_xxx definitions should go in proper + header someday. */ + if (relocs[i]->howto->type == 0 + /* Older GNU linkers used 5 instead of 0 for this reloc. */ + || relocs[i]->howto->type == 5) + /* This is an ARM_26D reloc, which is an ARM_26 reloc + that has already been fully processed during a + previous link stage, so ignore it here. */ + break; + /* Fall through. */ default: /* xgettext:c-format */ einfo (_("%XError: %d-bit reloc in dll\n"), @@ -1159,9 +1312,6 @@ generate_reloc (abfd, info) free (relocs); /* Warning: the allocated symbols are remembered in BFD and reused later, so don't free them! */ -#if 0 - free (symbol); -#endif } } @@ -1186,12 +1336,12 @@ generate_reloc (abfd, info) if (reloc_data[i].type == 4) reloc_sz += 2; } - + reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ - reloc_d = (unsigned char *) xmalloc (reloc_sz); - sec_page = (unsigned long) (-1); + reloc_d = xmalloc (reloc_sz); + sec_page = (unsigned long) -1; reloc_sz = 0; - page_ptr = (unsigned long) (-1); + page_ptr = (unsigned long) -1; page_count = 0; for (i = 0; i < total_relocs; i++) @@ -1204,7 +1354,7 @@ generate_reloc (abfd, info) while (reloc_sz & 3) reloc_d[reloc_sz++] = 0; - if (page_ptr != (unsigned long) (-1)) + if (page_ptr != (unsigned long) -1) bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); bfd_put_32 (abfd, this_page, reloc_d + reloc_sz); @@ -1230,10 +1380,10 @@ generate_reloc (abfd, info) while (reloc_sz & 3) reloc_d[reloc_sz++] = 0; - if (page_ptr != (unsigned long) (-1)) + if (page_ptr != (unsigned long) -1) bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); - while (reloc_sz < reloc_s->_raw_size) + while (reloc_sz < reloc_s->size) reloc_d[reloc_sz++] = 0; } @@ -1241,10 +1391,7 @@ generate_reloc (abfd, info) corresponds to it. */ static void -quoteput (s, f, needs_quotes) - char *s; - FILE *f; - int needs_quotes; +quoteput (char *s, FILE *f, int needs_quotes) { char *cp; @@ -1252,7 +1399,7 @@ quoteput (s, f, needs_quotes) if (*cp == '\'' || *cp == '"' || *cp == '\\' - || isspace ((unsigned char) *cp) + || ISSPACE (*cp) || *cp == ',' || *cp == ';') needs_quotes = 1; @@ -1277,8 +1424,7 @@ quoteput (s, f, needs_quotes) } void -pe_dll_generate_def_file (pe_out_def_filename) - const char *pe_out_def_filename; +pe_dll_generate_def_file (const char *pe_out_def_filename) { int i; FILE *out = fopen (pe_out_def_filename, "w"); @@ -1446,11 +1592,7 @@ static char *dll_symname; #define UNDSEC (asection *) &bfd_und_section static asection * -quick_section (abfd, name, flags, align) - bfd *abfd; - const char *name; - int flags; - int align; +quick_section (bfd *abfd, const char *name, int flags, int align) { asection *sec; asymbol *sym; @@ -1472,17 +1614,16 @@ quick_section (abfd, name, flags, align) } static void -quick_symbol (abfd, n1, n2, n3, sec, flags, addr) - bfd *abfd; - char *n1; - char *n2; - char *n3; - asection *sec; - int flags; - int addr; +quick_symbol (bfd *abfd, + const char *n1, + const char *n2, + const char *n3, + asection *sec, + int flags, + int addr) { asymbol *sym; - char *name = (char *) xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); + char *name = xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); strcpy (name, n1); strcat (name, n2); @@ -1499,19 +1640,15 @@ static arelent *reltab = 0; static int relcount = 0, relsize = 0; static void -quick_reloc (abfd, address, which_howto, symidx) - bfd *abfd; - int address; - int which_howto; - int symidx; +quick_reloc (bfd *abfd, int address, int which_howto, int symidx) { - if (relcount >= (relsize - 1)) + if (relcount >= relsize - 1) { relsize += 10; if (reltab) - reltab = (arelent *) xrealloc (reltab, relsize * sizeof (arelent)); + reltab = xrealloc (reltab, relsize * sizeof (arelent)); else - reltab = (arelent *) xmalloc (relsize * sizeof (arelent)); + reltab = xmalloc (relsize * sizeof (arelent)); } reltab[relcount].address = address; reltab[relcount].addend = 0; @@ -1527,7 +1664,7 @@ save_relocs (asection *sec) sec->relocation = reltab; sec->reloc_count = relcount; - sec->orelocation = (arelent **) xmalloc ((relcount + 1) * sizeof (arelent *)); + sec->orelocation = xmalloc ((relcount + 1) * sizeof (arelent *)); for (i = 0; i < relcount; i++) sec->orelocation[i] = sec->relocation + i; sec->orelocation[relcount] = 0; @@ -1544,25 +1681,24 @@ save_relocs (asection *sec) .long 0 .rva __my_dll_iname .rva fthunk - + .section .idata$5 .long 0 fthunk: - + .section .idata$4 .long 0 hname: */ static bfd * -make_head (parent) - bfd *parent; +make_head (bfd *parent) { asection *id2, *id5, *id4; unsigned char *d2, *d5, *d4; char *oname; bfd *abfd; - oname = (char *) xmalloc (20); + oname = xmalloc (20); sprintf (oname, "d%06d.o", tmp_seq); tmp_seq++; @@ -1574,7 +1710,7 @@ make_head (parent) bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); symptr = 0; - symtab = (asymbol **) xmalloc (6 * sizeof (asymbol *)); + symtab = xmalloc (6 * sizeof (asymbol *)); id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); @@ -1588,7 +1724,7 @@ make_head (parent) the start of the list of sections from other objects. */ bfd_set_section_size (abfd, id2, 20); - d2 = (unsigned char *) xmalloc (20); + d2 = xmalloc (20); id2->contents = d2; memset (d2, 0, 20); d2[0] = d2[16] = 4; /* Reloc addend. */ @@ -1597,21 +1733,21 @@ make_head (parent) quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); save_relocs (id2); - bfd_set_section_size (abfd, id5, 4); - d5 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); - bfd_set_section_size (abfd, id4, 4); - d4 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); bfd_set_symtab (abfd, symtab, symptr); bfd_set_section_contents (abfd, id2, d2, 0, 20); - bfd_set_section_contents (abfd, id5, d5, 0, 4); - bfd_set_section_contents (abfd, id4, d4, 0, 4); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); bfd_make_readable (abfd); return abfd; @@ -1619,16 +1755,17 @@ make_head (parent) /* .section .idata$4 .long 0 + [.long 0] for PE+ .section .idata$5 .long 0 + [.long 0] for PE+ .section idata$7 .global __my_dll_iname __my_dll_iname: .asciz "my.dll" */ static bfd * -make_tail (parent) - bfd *parent; +make_tail (bfd *parent) { asection *id4, *id5, *id7; unsigned char *d4, *d5, *d7; @@ -1636,7 +1773,7 @@ make_tail (parent) char *oname; bfd *abfd; - oname = (char *) xmalloc (20); + oname = xmalloc (20); sprintf (oname, "d%06d.o", tmp_seq); tmp_seq++; @@ -1648,34 +1785,38 @@ make_tail (parent) bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); symptr = 0; - symtab = (asymbol **) xmalloc (5 * sizeof (asymbol *)); + symtab = xmalloc (5 * sizeof (asymbol *)); id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); quick_symbol (abfd, U (""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); - bfd_set_section_size (abfd, id4, 4); - d4 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); - bfd_set_section_size (abfd, id5, 4); - d5 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); len = strlen (dll_filename) + 1; if (len & 1) len++; bfd_set_section_size (abfd, id7, len); - d7 = (unsigned char *) xmalloc (len); + d7 = xmalloc (len); id7->contents = d7; - strcpy (d7, dll_filename); + 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); - bfd_set_section_contents (abfd, id4, d4, 0, 4); - bfd_set_section_contents (abfd, id5, d5, 0, 4); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); bfd_set_section_contents (abfd, id7, d7, 0, len); bfd_make_readable (abfd); @@ -1688,10 +1829,10 @@ make_tail (parent) .global __imp__function _function: jmp *__imp__function: - + .section idata$7 .long __head_my_dll - + .section .idata$5 ___imp_function: __imp__function: @@ -1703,7 +1844,7 @@ make_tail (parent) .short .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 }; @@ -1715,7 +1856,7 @@ static unsigned char jmp_ix86_bytes[] = 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 }; @@ -1726,44 +1867,65 @@ static unsigned char jmp_sh_bytes[] = 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 const unsigned char jmp_arm_bytes[] = +{ + 0x00, 0xc0, 0x9f, 0xe5, /* ldr ip, [pc] */ + 0x00, 0xf0, 0x9c, 0xe5, /* ldr pc, [ip] */ + 0, 0, 0, 0 +}; + + static bfd * -make_one (exp, parent) - 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 is a function + symbol and there is at least one undefined reference to that + symbol. In other words, if all the import references to 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; - 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 = (char *) xmalloc (20); + oname = xmalloc (20); sprintf (oname, "d%06d.o", tmp_seq); tmp_seq++; @@ -1775,34 +1937,58 @@ make_one (exp, parent) bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); symptr = 0; - symtab = (asymbol **) xmalloc (11 * sizeof (asymbol *)); + symtab = xmalloc (11 * sizeof (asymbol *)); tx = quick_section (abfd, ".text", SEC_CODE|SEC_HAS_CONTENTS, 2); id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); - if (! exp->flag_data) - quick_symbol (abfd, U (""), exp->internal_name, "", tx, BSF_GLOBAL, 0); - quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, BSF_GLOBAL, 0); - quick_symbol (abfd, U ("_imp__"), exp->internal_name, "", id5, BSF_GLOBAL, 0); - /* Symbol to reference ord/name of imported - symbol, used to implement auto-import. */ - quick_symbol (abfd, U("_nm__"), exp->internal_name, "", id6, BSF_GLOBAL, 0); + + if (*exp->internal_name == '@') + { + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, + BSF_GLOBAL, 0); + 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); + /* Fastcall applies only to functions, + so no need for auto-import symbol. */ + } + else + { + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, + BSF_GLOBAL, 0); + if (include_jmp_stub) + quick_symbol (abfd, U (""), exp->internal_name, "", tx, + BSF_GLOBAL, 0); + 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_"), 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); + 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 = (unsigned char *) xmalloc (jmp_byte_count); + td = xmalloc (jmp_byte_count); tx->contents = td; memcpy (td, jmp_bytes, 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); @@ -1812,29 +1998,36 @@ make_one (exp, parent) quick_reloc (abfd, 0, BFD_RELOC_LO16, 0); /* MIPS_R_PAIR */ quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); break; + case PE_ARCH_arm: + case PE_ARCH_arm_epoc: + case PE_ARCH_arm_wince: + quick_reloc (abfd, 8, BFD_RELOC_32, 2); + break; default: abort (); } save_relocs (tx); } + else + bfd_set_section_size (abfd, tx, 0); bfd_set_section_size (abfd, id7, 4); - d7 = (unsigned char *) xmalloc (4); + d7 = xmalloc (4); id7->contents = d7; memset (d7, 0, 4); - quick_reloc (abfd, 0, BFD_RELOC_RVA, 6); + quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); save_relocs (id7); - bfd_set_section_size (abfd, id5, 4); - d5 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); if (exp->flag_noname) { d5[0] = exp->ordinal; d5[1] = exp->ordinal >> 8; - d5[3] = 0x80; + d5[PE_IDATA5_SIZE - 1] = 0x80; } else { @@ -1842,16 +2035,16 @@ make_one (exp, parent) save_relocs (id5); } - bfd_set_section_size (abfd, id4, 4); - d4 = (unsigned char *) xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); if (exp->flag_noname) { d4[0] = exp->ordinal; d4[1] = exp->ordinal >> 8; - d4[3] = 0x80; + d4[PE_IDATA4_SIZE - 1] = 0x80; } else { @@ -1866,24 +2059,26 @@ make_one (exp, parent) } 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); - d6 = (unsigned char *) xmalloc (len); + d6 = xmalloc (len); id6->contents = d6; memset (d6, 0, len); d6[0] = exp->hint & 0xff; d6[1] = exp->hint >> 8; - strcpy (d6 + 2, exp->name); + strcpy ((char *) d6 + 2, exp->name); } 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, 4); - bfd_set_section_contents (abfd, id4, d4, 0, 4); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); if (!exp->flag_noname) bfd_set_section_contents (abfd, id6, d6, 0, len); @@ -1892,9 +2087,7 @@ make_one (exp, parent) } static bfd * -make_singleton_name_thunk (import, parent) - char *import; - bfd *parent; +make_singleton_name_thunk (const char *import, bfd *parent) { /* Name thunks go to idata$4. */ asection *id4; @@ -1902,7 +2095,7 @@ make_singleton_name_thunk (import, parent) char *oname; bfd *abfd; - oname = (char *) xmalloc (20); + oname = xmalloc (20); sprintf (oname, "nmth%06d.o", tmp_seq); tmp_seq++; @@ -1914,73 +2107,69 @@ make_singleton_name_thunk (import, parent) bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); symptr = 0; - symtab = (asymbol **) xmalloc (3 * sizeof (asymbol *)); + symtab = xmalloc (3 * sizeof (asymbol *)); id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 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, 8); - d4 = (unsigned char *) xmalloc (4); + /* 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, 8); + 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, 8); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE * 2); bfd_make_readable (abfd); return abfd; } static char * -make_import_fixup_mark (rel) - arelent *rel; +make_import_fixup_mark (arelent *rel) { /* We convert reloc to symbol, for later reference. */ static int counter; static char *fixup_name = NULL; - static unsigned int buffer_len = 0; - - struct symbol_cache_entry *sym = *rel->sym_ptr_ptr; - + static size_t buffer_len = 0; + + struct bfd_symbol *sym = *rel->sym_ptr_ptr; + bfd *abfd = bfd_asymbol_bfd (sym); - struct coff_link_hash_entry *myh = NULL; + struct bfd_link_hash_entry *bh; if (!fixup_name) { - fixup_name = (char *) xmalloc (384); + fixup_name = xmalloc (384); buffer_len = 384; } if (strlen (sym->name) + 25 > buffer_len) - /* Assume 25 chars for "__fu" + counter + "_". If counter is + /* Assume 25 chars for "__fu" + counter + "_". If counter is bigger than 20 digits long, we've got worse problems than overflowing this buffer... */ { free (fixup_name); - /* New buffer size is length of symbol, plus 25, but then - rounded up to the nearest multiple of 128. */ + /* New buffer size is length of symbol, plus 25, but + then rounded up to the nearest multiple of 128. */ buffer_len = ((strlen (sym->name) + 25) + 127) & ~127; - fixup_name = (char *) xmalloc (buffer_len); + fixup_name = xmalloc (buffer_len); } - + sprintf (fixup_name, "__fu%d_%s", counter++, sym->name); - bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, + bh = NULL; + bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, current_sec, /* sym->section, */ - rel->address, NULL, true, false, - (struct bfd_link_hash_entry **) &myh); + rel->address, NULL, TRUE, FALSE, &bh); -#if 0 - printf ("type:%d\n", myh->type); - printf ("%s\n", myh->root.u.def.section->name); -#endif return fixup_name; } -/* .section .idata$3 +/* .section .idata$2 .rva __nm_thnk_SYM (singleton thunk with name of func) .long 0 .long 0 @@ -1988,18 +2177,17 @@ make_import_fixup_mark (rel) .rva __fuNN_SYM (pointer to reference (address) in text) */ static bfd * -make_import_fixup_entry (name, fixup_name, dll_symname,parent) - char *name; - char *fixup_name; - char *dll_symname; - bfd *parent; +make_import_fixup_entry (const char *name, + const char *fixup_name, + const char *dll_symname, + bfd *parent) { - asection *id3; - unsigned char *d3; + asection *id2; + unsigned char *d2; char *oname; bfd *abfd; - oname = (char *) xmalloc (20); + oname = xmalloc (20); sprintf (oname, "fu%06d.o", tmp_seq); tmp_seq++; @@ -2011,43 +2199,134 @@ make_import_fixup_entry (name, fixup_name, dll_symname,parent) bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); symptr = 0; - symtab = (asymbol **) xmalloc (6 * sizeof (asymbol *)); - id3 = quick_section (abfd, ".idata$3", SEC_HAS_CONTENTS, 2); + symtab = xmalloc (6 * sizeof (asymbol *)); + id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); -#if 0 - quick_symbol (abfd, U ("_head_"), dll_symname, "", id2, BSF_GLOBAL, 0); -#endif quick_symbol (abfd, U ("_nm_thnk_"), name, "", UNDSEC, BSF_GLOBAL, 0); quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); - bfd_set_section_size (abfd, id3, 20); - d3 = (unsigned char *) xmalloc (20); - id3->contents = d3; - memset (d3, 0, 20); + bfd_set_section_size (abfd, id2, 20); + d2 = xmalloc (20); + id2->contents = d2; + memset (d2, 0, 20); quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); quick_reloc (abfd, 12, BFD_RELOC_RVA, 2); quick_reloc (abfd, 16, BFD_RELOC_RVA, 3); - save_relocs (id3); + save_relocs (id2); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, id2, d2, 0, 20); + + bfd_make_readable (abfd); + return abfd; +} + +/* .section .rdata_runtime_pseudo_reloc + .long addend + .rva __fuNN_SYM (pointer to reference (address) in text) */ + +static bfd * +make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, + const char *fixup_name, + int addend, + bfd *parent) +{ + asection *rt_rel; + unsigned char *rt_rel_d; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "rtr%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pe_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (2 * sizeof (asymbol *)); + rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", + SEC_HAS_CONTENTS, 2); + + quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); + + bfd_set_section_size (abfd, rt_rel, 8); + rt_rel_d = xmalloc (8); + rt_rel->contents = rt_rel_d; + memset (rt_rel_d, 0, 8); + bfd_put_32 (abfd, addend, rt_rel_d); + + quick_reloc (abfd, 4, BFD_RELOC_RVA, 1); + save_relocs (rt_rel); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8); + + bfd_make_readable (abfd); + return abfd; +} + +/* .section .rdata + .rva __pei386_runtime_relocator */ + +static bfd * +pe_create_runtime_relocator_reference (bfd *parent) +{ + asection *extern_rt_rel; + unsigned char *extern_rt_rel_d; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "ertr%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pe_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (2 * sizeof (asymbol *)); + extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2); + + quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC, + BSF_NO_FLAGS, 0); + + bfd_set_section_size (abfd, extern_rt_rel, 4); + extern_rt_rel_d = xmalloc (4); + extern_rt_rel->contents = extern_rt_rel_d; + + quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); + save_relocs (extern_rt_rel); bfd_set_symtab (abfd, symtab, symptr); - bfd_set_section_contents (abfd, id3, d3, 0, 20); + bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, 4); bfd_make_readable (abfd); return abfd; } void -pe_create_import_fixup (rel) - arelent *rel; +pe_create_import_fixup (arelent *rel, asection *s, int addend) { char buf[300]; - struct symbol_cache_entry *sym = *rel->sym_ptr_ptr; + struct bfd_symbol *sym = *rel->sym_ptr_ptr; struct bfd_link_hash_entry *name_thunk_sym; - CONST char *name = sym->name; + const char *name = sym->name; char *fixup_name = make_import_fixup_mark (rel); + bfd *b; sprintf (buf, U ("_nm_thnk_%s"), name); @@ -2059,23 +2338,48 @@ pe_create_import_fixup (rel) add_bfd_to_link (b, b->filename, &link_info); /* If we ever use autoimport, we have to cast text section writable. */ - config.text_read_only = false; + config.text_read_only = FALSE; + output_bfd->flags &= ~WP_TEXT; } - { - extern char * pe_data_import_dll; /* Defined in emultempl/pe.em. */ - - bfd *b = make_import_fixup_entry (name, fixup_name, pe_data_import_dll, - output_bfd); - add_bfd_to_link (b, b->filename, &link_info); - } + if (addend == 0 || link_info.pei386_runtime_pseudo_reloc) + { + extern char * pe_data_import_dll; + char * dll_symname = pe_data_import_dll ? pe_data_import_dll : "unknown"; + + b = make_import_fixup_entry (name, fixup_name, dll_symname, output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + } + + if (addend != 0) + { + if (link_info.pei386_runtime_pseudo_reloc) + { + if (pe_dll_extra_pe_debug) + printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", + fixup_name, addend); + b = make_runtime_pseudo_reloc (name, fixup_name, addend, output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + + if (runtime_pseudo_relocs_created == 0) + { + b = pe_create_runtime_relocator_reference (output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + } + runtime_pseudo_relocs_created++; + } + else + { + einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), + s->owner, s, rel->address, sym->name); + einfo ("%X"); + } + } } void -pe_dll_generate_implib (def, impfilename) - def_file *def; - const char *impfilename; +pe_dll_generate_implib (def_file *def, const char *impfilename) { int i; bfd *ar_head; @@ -2086,10 +2390,10 @@ pe_dll_generate_implib (def, impfilename) dll_filename = (def->name) ? def->name : dll_name; dll_symname = xstrdup (dll_filename); for (i = 0; dll_symname[i]; i++) - if (!isalnum ((unsigned char) dll_symname[i])) + if (!ISALNUM (dll_symname[i])) dll_symname[i] = '_'; - unlink (impfilename); + unlink_if_ordinary (impfilename); outarch = bfd_openw (impfilename, 0); @@ -2101,8 +2405,8 @@ pe_dll_generate_implib (def, impfilename) } /* xgettext:c-format */ - einfo (_("Creating library file: %s\n"), impfilename); - + info_msg (_("Creating library file: %s\n"), impfilename); + bfd_set_format (outarch, bfd_archive); outarch->has_armap = 1; @@ -2115,9 +2419,13 @@ pe_dll_generate_implib (def, impfilename) char *internal = def->exports[i].internal_name; bfd *n; + /* Don't add PRIVATE entries to import lib. */ + 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; } @@ -2128,29 +2436,26 @@ pe_dll_generate_implib (def, impfilename) 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)) - einfo ("%Xbfd_set_archive_head: %s\n", bfd_errmsg (bfd_get_error ())); + einfo ("%Xbfd_set_archive_head: %E\n"); if (! bfd_close (outarch)) - einfo ("%Xbfd_close %s: %s\n", impfilename, bfd_errmsg (bfd_get_error ())); + einfo ("%Xbfd_close %s: %E\n", impfilename); while (head != NULL) { - bfd *n = head->next; + bfd *n = head->archive_next; bfd_close (head); head = n; } } static void -add_bfd_to_link (abfd, name, link_info) - bfd *abfd; - CONST char *name; - struct bfd_link_info *link_info; +add_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *link_info) { lang_input_statement_type *fake_file; @@ -2161,13 +2466,11 @@ add_bfd_to_link (abfd, name, link_info) ldlang_add_file (fake_file); if (!bfd_link_add_symbols (abfd, link_info)) - einfo ("%Xaddsym %s: %s\n", name, bfd_errmsg (bfd_get_error ())); + einfo ("%Xaddsym %s: %E\n", name); } void -pe_process_import_defs (output_bfd, link_info) - bfd *output_bfd; - struct bfd_link_info *link_info; +pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info) { def_file_module *module; @@ -2183,7 +2486,7 @@ pe_process_import_defs (output_bfd, link_info) dll_filename = module->name; dll_symname = xstrdup (module->name); for (i = 0; dll_symname[i]; i++) - if (!isalnum (dll_symname[i])) + if (!ISALNUM (dll_symname[i])) dll_symname[i] = '_'; do_this_dll = 0; @@ -2193,20 +2496,41 @@ pe_process_import_defs (output_bfd, link_info) { def_file_export exp; struct bfd_link_hash_entry *blhe; - + int lead_at = (*pe_def_file->imports[i].internal_name == '@'); /* See if we need this import. */ - char *name = (char *) xmalloc (strlen (pe_def_file->imports[i].internal_name) + 2 + 6); - sprintf (name, "%s%s", U (""), pe_def_file->imports[i].internal_name); + 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", + pe_def_file->imports[i].internal_name); + else + sprintf (name, "%s%s",U (""), + pe_def_file->imports[i].internal_name); + blhe = bfd_link_hash_lookup (link_info->hash, name, - false, false, false); + FALSE, FALSE, FALSE); + + /* Include the jump stub for only if the + is undefined. */ if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)) { - sprintf (name, "%s%s", U ("_imp__"), - pe_def_file->imports[i].internal_name); + if (lead_at) + sprintf (name, "%s%s", "__imp_", + pe_def_file->imports[i].internal_name); + else + 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); + FALSE, FALSE, FALSE); } + else + include_jmp_stub = TRUE; + free (name); + if (blhe && blhe->type == bfd_link_hash_undefined) { bfd *one; @@ -2223,9 +2547,9 @@ pe_process_import_defs (output_bfd, link_info) exp.hint = exp.ordinal >= 0 ? exp.ordinal : 0; exp.flag_private = 0; exp.flag_constant = 0; - exp.flag_data = 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); } } @@ -2240,101 +2564,99 @@ pe_process_import_defs (output_bfd, link_info) } /* We were handed a *.DLL file. Parse it and turn it into a set of - IMPORTS directives in the def file. Return true if the file was - handled, false if not. */ + IMPORTS directives in the def file. Return TRUE if the file was + handled, FALSE if not. */ static unsigned int -pe_get16 (abfd, where) - bfd *abfd; - int where; +pe_get16 (bfd *abfd, int where) { unsigned char b[2]; - bfd_seek (abfd, where, SEEK_SET); - bfd_read (b, 1, 2, abfd); + bfd_seek (abfd, (file_ptr) where, SEEK_SET); + bfd_bread (b, (bfd_size_type) 2, abfd); return b[0] + (b[1] << 8); } static unsigned int -pe_get32 (abfd, where) - bfd *abfd; - int where; +pe_get32 (bfd *abfd, int where) { unsigned char b[4]; - bfd_seek (abfd, where, SEEK_SET); - bfd_read (b, 1, 4, abfd); + bfd_seek (abfd, (file_ptr) where, SEEK_SET); + bfd_bread (b, (bfd_size_type) 4, abfd); return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); } -#if 0 /* This is not currently used. */ - static unsigned int -pe_as16 (ptr) - void *ptr; -{ - unsigned char *b = ptr; - - return b[0] + (b[1] << 8); -} - -#endif - -static unsigned int -pe_as32 (ptr) - void *ptr; +pe_as32 (void *ptr) { unsigned char *b = ptr; return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); } -boolean -pe_implied_import_dll (filename) - const char *filename; +bfd_boolean +pe_implied_import_dll (const char *filename) { bfd *dll; unsigned long pe_header_offset, opthdr_ofs, num_entries, i; unsigned long export_rva, export_size, nsections, secptr, expptr; - unsigned char *expdata, *erva; + unsigned long exp_funcbase; + unsigned char *expdata; + char *erva; unsigned long name_rvas, ordinals, nexp, ordbase; const char *dll_name; + /* Initialization with start > end guarantees that is_data + will not be set by mistake, and avoids compiler warning. */ + unsigned long data_start = 1; + unsigned long data_end = 0; + unsigned long rdata_start = 1; + unsigned long rdata_end = 0; + unsigned long bss_start = 1; + unsigned long bss_end = 0; /* No, I can't use bfd here. kernel32.dll puts its export table in the middle of the .rdata section. */ dll = bfd_openr (filename, pe_details->target_name); if (!dll) { - einfo ("%Xopen %s: %s\n", filename, bfd_errmsg (bfd_get_error ())); - return false; + einfo ("%Xopen %s: %E\n", filename); + return FALSE; } /* PEI dlls seem to be bfd_objects. */ if (!bfd_check_format (dll, bfd_object)) { einfo ("%X%s: this doesn't appear to be a DLL\n", filename); - return false; + return FALSE; } - dll_name = filename; - for (i = 0; filename[i]; i++) - if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') - dll_name = filename + i + 1; - + /* Get pe_header, optional header and numbers of export entries. */ pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; +#ifdef pe_use_x86_64 + num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /* & NumberOfRvaAndSizes. */ +#else num_entries = pe_get32 (dll, opthdr_ofs + 92); +#endif if (num_entries < 1) /* No exports. */ - return false; + return FALSE; +#ifdef pe_use_x86_64 + export_rva = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4); + export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4); +#else export_rva = pe_get32 (dll, opthdr_ofs + 96); export_size = pe_get32 (dll, opthdr_ofs + 100); +#endif + nsections = pe_get16 (dll, pe_header_offset + 4 + 2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); expptr = 0; + /* Get the rva and size of the export section. */ for (i = 0; i < nsections; i++) { char sname[8]; @@ -2343,8 +2665,8 @@ pe_implied_import_dll (filename) unsigned long vsize = pe_get32 (dll, secptr1 + 16); unsigned long fptr = pe_get32 (dll, secptr1 + 20); - bfd_seek (dll, secptr1, SEEK_SET); - bfd_read (sname, 1, 8, dll); + bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); + bfd_bread (sname, (bfd_size_type) 8, dll); if (vaddr <= export_rva && vaddr + vsize > export_rva) { @@ -2355,10 +2677,53 @@ pe_implied_import_dll (filename) } } - expdata = (unsigned char *) xmalloc (export_size); - bfd_seek (dll, expptr, SEEK_SET); - bfd_read (expdata, 1, export_size, dll); - erva = expdata - export_rva; + /* Scan sections and store the base and size of the + data and bss segments in data/base_start/end. */ + for (i = 0; i < nsections; i++) + { + unsigned long secptr1 = secptr + 40 * i; + unsigned long vsize = pe_get32 (dll, secptr1 + 8); + unsigned long vaddr = pe_get32 (dll, secptr1 + 12); + unsigned long flags = pe_get32 (dll, secptr1 + 36); + char sec_name[9]; + + sec_name[8] = '\0'; + bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); + bfd_bread (sec_name, (bfd_size_type) 8, dll); + + if (strcmp(sec_name,".data") == 0) + { + data_start = vaddr; + data_end = vaddr + vsize; + + if (pe_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + else if (strcmp(sec_name,".rdata") == 0) + { + rdata_start = vaddr; + rdata_end = vaddr + vsize; + + if (pe_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + else if (strcmp (sec_name,".bss") == 0) + { + bss_start = vaddr; + bss_end = vaddr + vsize; + + if (pe_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + } + + expdata = xmalloc (export_size); + bfd_seek (dll, (file_ptr) expptr, SEEK_SET); + bfd_bread (expdata, (bfd_size_type) export_size, dll); + erva = (char *) expdata - export_rva; if (pe_def_file == 0) pe_def_file = def_file_empty (); @@ -2367,17 +2732,56 @@ pe_implied_import_dll (filename) name_rvas = pe_as32 (expdata + 32); ordinals = pe_as32 (expdata + 36); ordbase = pe_as32 (expdata + 16); + exp_funcbase = pe_as32 (expdata + 28); + + /* Use internal dll name instead of filename + to enable symbolic dll linking. */ + dll_name = erva + pe_as32 (expdata + 12); + /* Check to see if the dll has already been added to + the definition list and if so return without error. + This avoids multiple symbol definitions. */ + if (def_get_module (pe_def_file, dll_name)) + { + if (pe_dll_extra_pe_debug) + printf ("%s is already loaded\n", dll_name); + return TRUE; + } + + /* Iterate through the list of symbols. */ for (i = 0; i < nexp; i++) { + /* Pointer to the names vector. */ unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); def_file_import *imp; - - imp = def_file_add_import (pe_def_file, erva + name_rva, dll_name, - i, 0); + /* Pointer to the function address vector. */ + unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4); + int is_data = 0; + + /* Skip unwanted symbols, which are + exported in buggy auto-import releases. */ + if (! CONST_STRNEQ (erva + name_rva, "_nm_")) + { + /* is_data is true if the address is in the data, rdata or bss + segment. */ + is_data = + (func_rva >= data_start && func_rva < data_end) + || (func_rva >= rdata_start && func_rva < rdata_end) + || (func_rva >= bss_start && func_rva < bss_end); + + imp = def_file_add_import (pe_def_file, erva + name_rva, + dll_name, i, 0); + /* Mark symbol type. */ + imp->data = is_data; + + if (pe_dll_extra_pe_debug) + printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", + __FUNCTION__, dll_name, erva + name_rva, + func_rva, is_data ? "(data)" : ""); + } } - return true; + return TRUE; } /* These are the main functions, called from the emulation. The first @@ -2386,30 +2790,27 @@ pe_implied_import_dll (filename) can put the right values in place. */ void -pe_dll_build_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +pe_dll_build_sections (bfd *abfd, struct bfd_link_info *info) { pe_dll_id_target (bfd_get_target (abfd)); process_def_file (abfd, info); + if (pe_def_file->num_exports == 0 && !info->shared) + return; + generate_edata (abfd, info); build_filler_bfd (1); } void -pe_exe_build_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; +pe_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) { pe_dll_id_target (bfd_get_target (abfd)); build_filler_bfd (0); } void -pe_dll_fill_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info) { pe_dll_id_target (bfd_get_target (abfd)); image_base = pe_data (abfd)->pe_opthdr.ImageBase; @@ -2420,30 +2821,27 @@ pe_dll_fill_sections (abfd, info) bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); /* Resize the sections. */ - lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL); + lang_reset_memory_regions (); + lang_size_sections (NULL, TRUE); /* Redo special stuff. */ ldemul_after_allocation (); /* Do the assignments again. */ - lang_do_assignments (stat_ptr->head, - abs_output_section, - (fill_type) 0, (bfd_vma) 0); + lang_do_assignments (); } fill_edata (abfd, info); - pe_data (abfd)->dll = 1; + if (info->shared && !info->pie) + pe_data (abfd)->dll = 1; edata_s->contents = edata_d; reloc_s->contents = reloc_d; } void -pe_exe_fill_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info) { pe_dll_id_target (bfd_get_target (abfd)); image_base = pe_data (abfd)->pe_opthdr.ImageBase; @@ -2454,16 +2852,22 @@ pe_exe_fill_sections (abfd, info) bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); /* Resize the sections. */ - lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, NULL); + lang_reset_memory_regions (); + lang_size_sections (NULL, TRUE); /* Redo special stuff. */ ldemul_after_allocation (); /* Do the assignments again. */ - lang_do_assignments (stat_ptr->head, - abs_output_section, - (fill_type) 0, (bfd_vma) 0); + lang_do_assignments (); } 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); +}