160484Sobrien/* Routines to help build PEI-format DLLs (Win32 etc) 2218822Sdim Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3130561Sobrien Free Software Foundation, Inc. 460484Sobrien Written by DJ Delorie <dj@cygnus.com> 560484Sobrien 660484Sobrien This file is part of GLD, the Gnu Linker. 760484Sobrien 860484Sobrien GLD is free software; you can redistribute it and/or modify 960484Sobrien it under the terms of the GNU General Public License as published by 1060484Sobrien the Free Software Foundation; either version 2, or (at your option) 1160484Sobrien any later version. 1260484Sobrien 1360484Sobrien GLD is distributed in the hope that it will be useful, 1460484Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1560484Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1660484Sobrien GNU General Public License for more details. 1760484Sobrien 1860484Sobrien You should have received a copy of the GNU General Public License 1960484Sobrien along with GLD; see the file COPYING. If not, write to the Free 20218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2260484Sobrien 23218822Sdim#include "sysdep.h" 2460484Sobrien#include "bfd.h" 2560484Sobrien#include "bfdlink.h" 2660484Sobrien#include "libiberty.h" 2789857Sobrien#include "safe-ctype.h" 2860484Sobrien 2960484Sobrien#include <time.h> 3060484Sobrien 3160484Sobrien#include "ld.h" 3260484Sobrien#include "ldexp.h" 3360484Sobrien#include "ldlang.h" 3460484Sobrien#include "ldwrite.h" 3560484Sobrien#include "ldmisc.h" 36107492Sobrien#include <ldgram.h> 3760484Sobrien#include "ldmain.h" 3877298Sobrien#include "ldfile.h" 3960484Sobrien#include "ldemul.h" 4060484Sobrien#include "coff/internal.h" 4160484Sobrien#include "../bfd/libcoff.h" 4260484Sobrien#include "deffile.h" 4360484Sobrien#include "pe-dll.h" 4460484Sobrien 45218822Sdim#ifdef pe_use_x86_64 46218822Sdim 47218822Sdim#define PE_IDATA4_SIZE 8 48218822Sdim#define PE_IDATA5_SIZE 8 49218822Sdim#include "pep-dll.h" 50218822Sdim#undef AOUTSZ 51218822Sdim#define AOUTSZ PEPAOUTSZ 52218822Sdim#define PEAOUTHDR PEPAOUTHDR 53218822Sdim 54218822Sdim#else 55218822Sdim 56218822Sdim#include "pe-dll.h" 57218822Sdim 58218822Sdim#endif 59218822Sdim 60218822Sdim#ifndef PE_IDATA4_SIZE 61218822Sdim#define PE_IDATA4_SIZE 4 62218822Sdim#endif 63218822Sdim 64218822Sdim#ifndef PE_IDATA5_SIZE 65218822Sdim#define PE_IDATA5_SIZE 4 66218822Sdim#endif 67218822Sdim 6889857Sobrien/* This file turns a regular Windows PE image into a DLL. Because of 6989857Sobrien the complexity of this operation, it has been broken down into a 7089857Sobrien number of separate modules which are all called by the main function 7189857Sobrien at the end of this file. This function is not re-entrant and is 7289857Sobrien normally only called once, so static variables are used to reduce 7389857Sobrien the number of parameters and return values required. 74104834Sobrien 75218822Sdim See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ 7660484Sobrien 7789857Sobrien/* Auto-import feature by Paul Sokolovsky 7860484Sobrien 7989857Sobrien Quick facts: 8060484Sobrien 8189857Sobrien 1. With this feature on, DLL clients can import variables from DLL 8289857Sobrien without any concern from their side (for example, without any source 8389857Sobrien code modifications). 8460484Sobrien 8589857Sobrien 2. This is done completely in bounds of the PE specification (to be fair, 86130561Sobrien there's a place where it pokes nose out of, but in practice it works). 8789857Sobrien So, resulting module can be used with any other PE compiler/linker. 8860484Sobrien 8989857Sobrien 3. Auto-import is fully compatible with standard import method and they 9089857Sobrien can be mixed together. 9189857Sobrien 9289857Sobrien 4. Overheads: space: 8 bytes per imported symbol, plus 20 for each 9389857Sobrien reference to it; load time: negligible; virtual/physical memory: should be 9489857Sobrien less than effect of DLL relocation, and I sincerely hope it doesn't affect 9589857Sobrien DLL sharability (too much). 9689857Sobrien 9789857Sobrien Idea 9889857Sobrien 9989857Sobrien The obvious and only way to get rid of dllimport insanity is to make client 10089857Sobrien access variable directly in the DLL, bypassing extra dereference. I.e., 101130561Sobrien whenever client contains something like 10289857Sobrien 10389857Sobrien mov dll_var,%eax, 10489857Sobrien 10589857Sobrien address of dll_var in the command should be relocated to point into loaded 10689857Sobrien DLL. The aim is to make OS loader do so, and than make ld help with that. 10789857Sobrien Import section of PE made following way: there's a vector of structures 10889857Sobrien each describing imports from particular DLL. Each such structure points 109130561Sobrien to two other parallel vectors: one holding imported names, and one which 11089857Sobrien will hold address of corresponding imported name. So, the solution is 11189857Sobrien de-vectorize these structures, making import locations be sparse and 11289857Sobrien pointing directly into code. Before continuing, it is worth a note that, 11389857Sobrien while authors strives to make PE act ELF-like, there're some other people 11489857Sobrien make ELF act PE-like: elfvector, ;-) . 11589857Sobrien 11689857Sobrien Implementation 11789857Sobrien 11889857Sobrien For each reference of data symbol to be imported from DLL (to set of which 11989857Sobrien belong symbols with name <sym>, if __imp_<sym> is found in implib), the 12089857Sobrien import fixup entry is generated. That entry is of type 121218822Sdim IMAGE_IMPORT_DESCRIPTOR and stored in .idata$2 subsection. Each 12289857Sobrien fixup entry contains pointer to symbol's address within .text section 12389857Sobrien (marked with __fuN_<sym> symbol, where N is integer), pointer to DLL name 12489857Sobrien (so, DLL name is referenced by multiple entries), and pointer to symbol 12589857Sobrien name thunk. Symbol name thunk is singleton vector (__nm_th_<symbol>) 12689857Sobrien pointing to IMAGE_IMPORT_BY_NAME structure (__nm_<symbol>) directly 127218822Sdim containing imported name. Here comes that "on the edge" problem mentioned 12889857Sobrien above: PE specification rambles that name vector (OriginalFirstThunk) 12989857Sobrien should run in parallel with addresses vector (FirstThunk), i.e. that they 13089857Sobrien should have same number of elements and terminated with zero. We violate 131130561Sobrien this, since FirstThunk points directly into machine code. But in practice, 13289857Sobrien OS loader implemented the sane way: it goes thru OriginalFirstThunk and 13389857Sobrien puts addresses to FirstThunk, not something else. It once again should be 13489857Sobrien noted that dll and symbol name structures are reused across fixup entries 13589857Sobrien and should be there anyway to support standard import stuff, so sustained 13689857Sobrien overhead is 20 bytes per reference. Other question is whether having several 13789857Sobrien IMAGE_IMPORT_DESCRIPTORS for the same DLL is possible. Answer is yes, it is 13889857Sobrien done even by native compiler/linker (libth32's functions are in fact reside 13989857Sobrien in windows9x kernel32.dll, so if you use it, you have two 14089857Sobrien IMAGE_IMPORT_DESCRIPTORS for kernel32.dll). Yet other question is whether 14189857Sobrien referencing the same PE structures several times is valid. The answer is why 142130561Sobrien not, prohibiting that (detecting violation) would require more work on 14389857Sobrien behalf of loader than not doing it. 14489857Sobrien 145218822Sdim See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ 14689857Sobrien 147130561Sobrienstatic void add_bfd_to_link (bfd *, const char *, struct bfd_link_info *); 14889857Sobrien 14989857Sobrien/* For emultempl/pe.em. */ 15089857Sobrien 15189857Sobriendef_file * pe_def_file = 0; 15260484Sobrienint pe_dll_export_everything = 0; 15360484Sobrienint pe_dll_do_default_excludes = 1; 15460484Sobrienint pe_dll_kill_ats = 0; 15560484Sobrienint pe_dll_stdcall_aliases = 0; 15660484Sobrienint pe_dll_warn_dup_exports = 0; 15760484Sobrienint pe_dll_compat_implib = 0; 15889857Sobrienint pe_dll_extra_pe_debug = 0; 15960484Sobrien 16089857Sobrien/* Static variables and types. */ 16160484Sobrien 16260484Sobrienstatic bfd_vma image_base; 16360484Sobrienstatic bfd *filler_bfd; 164130561Sobrienstatic struct bfd_section *edata_s, *reloc_s; 16560484Sobrienstatic unsigned char *edata_d, *reloc_d; 16660484Sobrienstatic size_t edata_sz, reloc_sz; 167130561Sobrienstatic int runtime_pseudo_relocs_created = 0; 16860484Sobrien 16989857Sobrientypedef struct 170218822Sdim{ 171218822Sdim const char *name; 172218822Sdim int len; 173218822Sdim} 174218822Sdimautofilter_entry_type; 17560484Sobrien 17689857Sobrientypedef struct 177218822Sdim{ 178218822Sdim const char *target_name; 179218822Sdim const char *object_target; 180218822Sdim unsigned int imagebase_reloc; 181218822Sdim int pe_arch; 182218822Sdim int bfd_arch; 183218822Sdim bfd_boolean underscored; 184218822Sdim const autofilter_entry_type* autofilter_symbollist; 185218822Sdim} 186218822Sdimpe_details_type; 18789857Sobrien 188218822Sdimstatic const autofilter_entry_type autofilter_symbollist_generic[] = 189218822Sdim{ 190218822Sdim { STRING_COMMA_LEN (".text") }, 191218822Sdim /* Entry point symbols. */ 192218822Sdim { STRING_COMMA_LEN ("DllMain") }, 193218822Sdim { STRING_COMMA_LEN ("DllMainCRTStartup") }, 194218822Sdim { STRING_COMMA_LEN ("_DllMainCRTStartup") }, 195218822Sdim /* Runtime pseudo-reloc. */ 196218822Sdim { STRING_COMMA_LEN ("_pei386_runtime_relocator") }, 197218822Sdim { STRING_COMMA_LEN ("do_pseudo_reloc") }, 198218822Sdim { STRING_COMMA_LEN (NULL) } 199218822Sdim}; 200218822Sdim 201218822Sdimstatic const autofilter_entry_type autofilter_symbollist_i386[] = 202218822Sdim{ 203218822Sdim { STRING_COMMA_LEN (".text") }, 204218822Sdim /* Entry point symbols, and entry hooks. */ 205218822Sdim { STRING_COMMA_LEN ("cygwin_crt0") }, 206218822Sdim { STRING_COMMA_LEN ("DllMain@12") }, 207218822Sdim { STRING_COMMA_LEN ("DllEntryPoint@0") }, 208218822Sdim { STRING_COMMA_LEN ("DllMainCRTStartup@12") }, 209218822Sdim { STRING_COMMA_LEN ("_cygwin_dll_entry@12") }, 210218822Sdim { STRING_COMMA_LEN ("_cygwin_crt0_common@8") }, 211218822Sdim { STRING_COMMA_LEN ("_cygwin_noncygwin_dll_entry@12") }, 212218822Sdim { STRING_COMMA_LEN ("cygwin_attach_dll") }, 213218822Sdim { STRING_COMMA_LEN ("cygwin_premain0") }, 214218822Sdim { STRING_COMMA_LEN ("cygwin_premain1") }, 215218822Sdim { STRING_COMMA_LEN ("cygwin_premain2") }, 216218822Sdim { STRING_COMMA_LEN ("cygwin_premain3") }, 217218822Sdim /* Runtime pseudo-reloc. */ 218218822Sdim { STRING_COMMA_LEN ("_pei386_runtime_relocator") }, 219218822Sdim { STRING_COMMA_LEN ("do_pseudo_reloc") }, 220218822Sdim /* Global vars that should not be exported. */ 221218822Sdim { STRING_COMMA_LEN ("impure_ptr") }, 222218822Sdim { STRING_COMMA_LEN ("_impure_ptr") }, 223218822Sdim { STRING_COMMA_LEN ("_fmode") }, 224218822Sdim { STRING_COMMA_LEN ("environ") }, 225218822Sdim { STRING_COMMA_LEN (NULL) } 226218822Sdim}; 227218822Sdim 228218822Sdim#define PE_ARCH_i386 1 229218822Sdim#define PE_ARCH_sh 2 230218822Sdim#define PE_ARCH_mips 3 231218822Sdim#define PE_ARCH_arm 4 23289857Sobrien#define PE_ARCH_arm_epoc 5 233218822Sdim#define PE_ARCH_arm_wince 6 23460484Sobrien 235218822Sdimstatic const pe_details_type pe_detail_list[] = 23689857Sobrien{ 23760484Sobrien { 238218822Sdim#ifdef pe_use_x86_64 239218822Sdim "pei-x86-64", 240218822Sdim "pe-x86-64", 241218822Sdim 3 /* R_IMAGEBASE */, 242218822Sdim#else 24360484Sobrien "pei-i386", 24460484Sobrien "pe-i386", 24560484Sobrien 7 /* R_IMAGEBASE */, 246218822Sdim#endif 24760484Sobrien PE_ARCH_i386, 24860484Sobrien bfd_arch_i386, 249218822Sdim TRUE, 250218822Sdim autofilter_symbollist_i386 25160484Sobrien }, 25260484Sobrien { 25360484Sobrien "pei-shl", 25460484Sobrien "pe-shl", 25560484Sobrien 16 /* R_SH_IMAGEBASE */, 25660484Sobrien PE_ARCH_sh, 25760484Sobrien bfd_arch_sh, 258218822Sdim TRUE, 259218822Sdim autofilter_symbollist_generic 26060484Sobrien }, 26160484Sobrien { 26260484Sobrien "pei-mips", 26360484Sobrien "pe-mips", 26460484Sobrien 34 /* MIPS_R_RVA */, 26560484Sobrien PE_ARCH_mips, 26660484Sobrien bfd_arch_mips, 267218822Sdim FALSE, 268218822Sdim autofilter_symbollist_generic 26960484Sobrien }, 27060484Sobrien { 27160484Sobrien "pei-arm-little", 27260484Sobrien "pe-arm-little", 27360484Sobrien 11 /* ARM_RVA32 */, 27460484Sobrien PE_ARCH_arm, 27560484Sobrien bfd_arch_arm, 276218822Sdim TRUE, 277218822Sdim autofilter_symbollist_generic 27860484Sobrien }, 27989857Sobrien { 28089857Sobrien "epoc-pei-arm-little", 28189857Sobrien "epoc-pe-arm-little", 28289857Sobrien 11 /* ARM_RVA32 */, 28389857Sobrien PE_ARCH_arm_epoc, 28489857Sobrien bfd_arch_arm, 285218822Sdim FALSE, 286218822Sdim autofilter_symbollist_generic 28789857Sobrien }, 288218822Sdim { 289218822Sdim "pei-arm-wince-little", 290218822Sdim "pe-arm-wince-little", 291218822Sdim 2, /* ARM_RVA32 on Windows CE, see bfd/coff-arm.c. */ 292218822Sdim PE_ARCH_arm_wince, 293218822Sdim bfd_arch_arm, 294218822Sdim FALSE, 295218822Sdim autofilter_symbollist_generic 296218822Sdim }, 297218822Sdim { NULL, NULL, 0, 0, 0, FALSE, NULL } 29860484Sobrien}; 29960484Sobrien 300218822Sdimstatic const pe_details_type *pe_details; 30160484Sobrien 30289857Sobrien/* Do not specify library suffix explicitly, to allow for dllized versions. */ 303218822Sdimstatic const autofilter_entry_type autofilter_liblist[] = 30489857Sobrien{ 305218822Sdim { STRING_COMMA_LEN ("libcegcc") }, 306218822Sdim { STRING_COMMA_LEN ("libcygwin") }, 307218822Sdim { STRING_COMMA_LEN ("libgcc") }, 308218822Sdim { STRING_COMMA_LEN ("libstdc++") }, 309218822Sdim { STRING_COMMA_LEN ("libmingw32") }, 310218822Sdim { STRING_COMMA_LEN ("libmingwex") }, 311218822Sdim { STRING_COMMA_LEN ("libg2c") }, 312218822Sdim { STRING_COMMA_LEN ("libsupc++") }, 313218822Sdim { STRING_COMMA_LEN ("libobjc") }, 314218822Sdim { STRING_COMMA_LEN ("libgcj") }, 315218822Sdim { STRING_COMMA_LEN (NULL) } 31689857Sobrien}; 31789857Sobrien 318218822Sdimstatic const autofilter_entry_type autofilter_objlist[] = 31989857Sobrien{ 320218822Sdim { STRING_COMMA_LEN ("crt0.o") }, 321218822Sdim { STRING_COMMA_LEN ("crt1.o") }, 322218822Sdim { STRING_COMMA_LEN ("crt2.o") }, 323218822Sdim { STRING_COMMA_LEN ("dllcrt1.o") }, 324218822Sdim { STRING_COMMA_LEN ("dllcrt2.o") }, 325218822Sdim { STRING_COMMA_LEN ("gcrt0.o") }, 326218822Sdim { STRING_COMMA_LEN ("gcrt1.o") }, 327218822Sdim { STRING_COMMA_LEN ("gcrt2.o") }, 328218822Sdim { STRING_COMMA_LEN ("crtbegin.o") }, 329218822Sdim { STRING_COMMA_LEN ("crtend.o") }, 330218822Sdim { STRING_COMMA_LEN (NULL) } 33189857Sobrien}; 33289857Sobrien 333218822Sdimstatic const autofilter_entry_type autofilter_symbolprefixlist[] = 33489857Sobrien{ 335218822Sdim /* _imp_ is treated specially, as it is always underscored. */ 336218822Sdim /* { STRING_COMMA_LEN ("_imp_") }, */ 337218822Sdim /* Don't export some c++ symbols. */ 338218822Sdim { STRING_COMMA_LEN ("__rtti_") }, 339218822Sdim { STRING_COMMA_LEN ("__builtin_") }, 340107492Sobrien /* Don't re-export auto-imported symbols. */ 341218822Sdim { STRING_COMMA_LEN ("_nm_") }, 34289857Sobrien /* Don't export symbols specifying internal DLL layout. */ 343218822Sdim { STRING_COMMA_LEN ("_head_") }, 344218822Sdim { STRING_COMMA_LEN (NULL) } 34589857Sobrien}; 34689857Sobrien 347218822Sdimstatic const autofilter_entry_type autofilter_symbolsuffixlist[] = 34889857Sobrien{ 349218822Sdim { STRING_COMMA_LEN ("_iname") }, 350218822Sdim { STRING_COMMA_LEN (NULL) } 35189857Sobrien}; 35289857Sobrien 35360484Sobrien#define U(str) (pe_details->underscored ? "_" str : str) 35460484Sobrien 35560484Sobrienvoid 356130561Sobrienpe_dll_id_target (const char *target) 35760484Sobrien{ 35860484Sobrien int i; 35989857Sobrien 36077298Sobrien for (i = 0; pe_detail_list[i].target_name; i++) 36177298Sobrien if (strcmp (pe_detail_list[i].target_name, target) == 0 36277298Sobrien || strcmp (pe_detail_list[i].object_target, target) == 0) 36360484Sobrien { 36477298Sobrien pe_details = pe_detail_list + i; 36560484Sobrien return; 36660484Sobrien } 36760484Sobrien einfo (_("%XUnsupported PEI architecture: %s\n"), target); 36860484Sobrien exit (1); 36960484Sobrien} 37060484Sobrien 371104834Sobrien/* Helper functions for qsort. Relocs must be sorted so that we can write 37289857Sobrien them out by pages. */ 37360484Sobrien 37489857Sobrientypedef struct 37589857Sobrien { 37689857Sobrien bfd_vma vma; 37789857Sobrien char type; 37889857Sobrien short extra; 37989857Sobrien } 38089857Sobrienreloc_data_type; 38160484Sobrien 38260484Sobrienstatic int 383130561Sobrienreloc_sort (const void *va, const void *vb) 38460484Sobrien{ 385130561Sobrien bfd_vma a = ((const reloc_data_type *) va)->vma; 386130561Sobrien bfd_vma b = ((const reloc_data_type *) vb)->vma; 38789857Sobrien 38860484Sobrien return (a > b) ? 1 : ((a < b) ? -1 : 0); 38960484Sobrien} 39060484Sobrien 39160484Sobrienstatic int 392130561Sobrienpe_export_sort (const void *va, const void *vb) 39360484Sobrien{ 394130561Sobrien const def_file_export *a = va; 395130561Sobrien const def_file_export *b = vb; 39689857Sobrien 39760484Sobrien return strcmp (a->name, b->name); 39860484Sobrien} 39960484Sobrien 40089857Sobrien/* Read and process the .DEF file. */ 40160484Sobrien 40260484Sobrien/* These correspond to the entries in pe_def_file->exports[]. I use 40360484Sobrien exported_symbol_sections[i] to tag whether or not the symbol was 40477298Sobrien defined, since we can't export symbols we don't have. */ 40560484Sobrien 40660484Sobrienstatic bfd_vma *exported_symbol_offsets; 407130561Sobrienstatic struct bfd_section **exported_symbol_sections; 40860484Sobrienstatic int export_table_size; 40960484Sobrienstatic int count_exported; 41060484Sobrienstatic int count_exported_byname; 41160484Sobrienstatic int count_with_ordinals; 41260484Sobrienstatic const char *dll_name; 41360484Sobrienstatic int min_ordinal, max_ordinal; 41460484Sobrienstatic int *exported_symbols; 41560484Sobrien 41689857Sobrientypedef struct exclude_list_struct 41789857Sobrien { 41889857Sobrien char *string; 41989857Sobrien struct exclude_list_struct *next; 420104834Sobrien int type; 42189857Sobrien } 42289857Sobrienexclude_list_struct; 42377298Sobrien 42460484Sobrienstatic struct exclude_list_struct *excludes = 0; 42560484Sobrien 42660484Sobrienvoid 427130561Sobrienpe_dll_add_excludes (const char *new_excludes, const int type) 42860484Sobrien{ 42960484Sobrien char *local_copy; 43060484Sobrien char *exclude_string; 43160484Sobrien 43260484Sobrien local_copy = xstrdup (new_excludes); 43360484Sobrien 43460484Sobrien exclude_string = strtok (local_copy, ",:"); 43560484Sobrien for (; exclude_string; exclude_string = strtok (NULL, ",:")) 43660484Sobrien { 43760484Sobrien struct exclude_list_struct *new_exclude; 43860484Sobrien 439130561Sobrien new_exclude = xmalloc (sizeof (struct exclude_list_struct)); 440130561Sobrien new_exclude->string = xmalloc (strlen (exclude_string) + 1); 44160484Sobrien strcpy (new_exclude->string, exclude_string); 442104834Sobrien new_exclude->type = type; 44360484Sobrien new_exclude->next = excludes; 44460484Sobrien excludes = new_exclude; 44560484Sobrien } 44660484Sobrien 44760484Sobrien free (local_copy); 44860484Sobrien} 44960484Sobrien 450218822Sdimstatic bfd_boolean 451218822Sdimis_import (const char* n) 452218822Sdim{ 453218822Sdim return (CONST_STRNEQ (n, "__imp_")); 454218822Sdim} 455104834Sobrien 45689857Sobrien/* abfd is a bfd containing n (or NULL) 45789857Sobrien It can be used for contextual checks. */ 45889857Sobrien 45960484Sobrienstatic int 460130561Sobrienauto_export (bfd *abfd, def_file *d, const char *n) 46160484Sobrien{ 46260484Sobrien int i; 46360484Sobrien struct exclude_list_struct *ex; 464218822Sdim const autofilter_entry_type *afptr; 465104834Sobrien const char * libname = 0; 466104834Sobrien if (abfd && abfd->my_archive) 467104834Sobrien libname = lbasename (abfd->my_archive->filename); 46889857Sobrien 46960484Sobrien for (i = 0; i < d->num_exports; i++) 47060484Sobrien if (strcmp (d->exports[i].name, n) == 0) 47160484Sobrien return 0; 47289857Sobrien 47360484Sobrien if (pe_dll_do_default_excludes) 47460484Sobrien { 47589857Sobrien const char * p; 47689857Sobrien int len; 47789857Sobrien 47889857Sobrien if (pe_dll_extra_pe_debug) 47989857Sobrien printf ("considering exporting: %s, abfd=%p, abfd->my_arc=%p\n", 48089857Sobrien n, abfd, abfd->my_archive); 48189857Sobrien 48289857Sobrien /* First of all, make context checks: 483130561Sobrien Don't export anything from standard libs. */ 484104834Sobrien if (libname) 48589857Sobrien { 48689857Sobrien afptr = autofilter_liblist; 48789857Sobrien 48889857Sobrien while (afptr->name) 48989857Sobrien { 490104834Sobrien if (strncmp (libname, afptr->name, afptr->len) == 0 ) 49189857Sobrien return 0; 49289857Sobrien afptr++; 49389857Sobrien } 49489857Sobrien } 49589857Sobrien 49689857Sobrien /* Next, exclude symbols from certain startup objects. */ 49789857Sobrien 49889857Sobrien if (abfd && (p = lbasename (abfd->filename))) 49989857Sobrien { 500104834Sobrien afptr = autofilter_objlist; 501104834Sobrien while (afptr->name) 50289857Sobrien { 503104834Sobrien if (strcmp (p, afptr->name) == 0) 504104834Sobrien return 0; 50589857Sobrien afptr++; 50689857Sobrien } 50789857Sobrien } 50889857Sobrien 50989857Sobrien /* Don't try to blindly exclude all symbols 51089857Sobrien that begin with '__'; this was tried and 511218822Sdim it is too restrictive. Instead we have 512218822Sdim a target specific list to use: */ 513218822Sdim afptr = pe_details->autofilter_symbollist; 51489857Sobrien 51589857Sobrien while (afptr->name) 51689857Sobrien { 51789857Sobrien if (strcmp (n, afptr->name) == 0) 51889857Sobrien return 0; 51989857Sobrien 520104834Sobrien afptr++; 52189857Sobrien } 52289857Sobrien 52389857Sobrien /* Next, exclude symbols starting with ... */ 52489857Sobrien afptr = autofilter_symbolprefixlist; 52589857Sobrien while (afptr->name) 52689857Sobrien { 52789857Sobrien if (strncmp (n, afptr->name, afptr->len) == 0) 52889857Sobrien return 0; 52989857Sobrien 530104834Sobrien afptr++; 53189857Sobrien } 53289857Sobrien 53389857Sobrien /* Finally, exclude symbols ending with ... */ 53489857Sobrien len = strlen (n); 53589857Sobrien afptr = autofilter_symbolsuffixlist; 53689857Sobrien while (afptr->name) 53789857Sobrien { 538104834Sobrien if ((len >= afptr->len) 53989857Sobrien /* Add 1 to insure match with trailing '\0'. */ 540104834Sobrien && strncmp (n + len - afptr->len, afptr->name, 541104834Sobrien afptr->len + 1) == 0) 54289857Sobrien return 0; 54389857Sobrien 544104834Sobrien afptr++; 54589857Sobrien } 54660484Sobrien } 54789857Sobrien 54860484Sobrien for (ex = excludes; ex; ex = ex->next) 549104834Sobrien { 550104834Sobrien if (ex->type == 1) /* exclude-libs */ 551104834Sobrien { 552104834Sobrien if (libname 553104834Sobrien && ((strcmp (libname, ex->string) == 0) 554104834Sobrien || (strcasecmp ("ALL", ex->string) == 0))) 555104834Sobrien return 0; 556104834Sobrien } 557104834Sobrien else if (strcmp (n, ex->string) == 0) 558104834Sobrien return 0; 559104834Sobrien } 56089857Sobrien 56160484Sobrien return 1; 56260484Sobrien} 56360484Sobrien 56460484Sobrienstatic void 565130561Sobrienprocess_def_file (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) 56660484Sobrien{ 56760484Sobrien int i, j; 56860484Sobrien struct bfd_link_hash_entry *blhe; 56960484Sobrien bfd *b; 570130561Sobrien struct bfd_section *s; 57177298Sobrien def_file_export *e = 0; 57260484Sobrien 57360484Sobrien if (!pe_def_file) 57460484Sobrien pe_def_file = def_file_empty (); 57560484Sobrien 57660484Sobrien /* First, run around to all the objects looking for the .drectve 57777298Sobrien sections, and push those into the def file too. */ 57860484Sobrien for (b = info->input_bfds; b; b = b->link_next) 57960484Sobrien { 58060484Sobrien s = bfd_get_section_by_name (b, ".drectve"); 58160484Sobrien if (s) 58260484Sobrien { 583218822Sdim long size = s->size; 58460484Sobrien char *buf = xmalloc (size); 58589857Sobrien 58660484Sobrien bfd_get_section_contents (b, s, buf, 0, size); 58760484Sobrien def_file_add_directive (pe_def_file, buf, size); 58860484Sobrien free (buf); 58960484Sobrien } 59060484Sobrien } 59160484Sobrien 592130561Sobrien /* If we are not building a DLL, when there are no exports 593130561Sobrien we do not build an export table at all. */ 594130561Sobrien if (!pe_dll_export_everything && pe_def_file->num_exports == 0 595218822Sdim && info->executable) 596130561Sobrien return; 597130561Sobrien 59877298Sobrien /* Now, maybe export everything else the default way. */ 59960484Sobrien if (pe_dll_export_everything || pe_def_file->num_exports == 0) 60060484Sobrien { 60160484Sobrien for (b = info->input_bfds; b; b = b->link_next) 60260484Sobrien { 60360484Sobrien asymbol **symbols; 60460484Sobrien int nsyms, symsize; 60560484Sobrien 60660484Sobrien symsize = bfd_get_symtab_upper_bound (b); 607130561Sobrien symbols = xmalloc (symsize); 60860484Sobrien nsyms = bfd_canonicalize_symtab (b, symbols); 60960484Sobrien 61060484Sobrien for (j = 0; j < nsyms; j++) 61160484Sobrien { 61277298Sobrien /* We should export symbols which are either global or not 613130561Sobrien anything at all. (.bss data is the latter) 614130561Sobrien We should not export undefined symbols. */ 61589857Sobrien if (symbols[j]->section != &bfd_und_section 61689857Sobrien && ((symbols[j]->flags & BSF_GLOBAL) 61789857Sobrien || (symbols[j]->flags == BFD_FORT_COMM_DEFAULT_VALUE))) 61860484Sobrien { 61960484Sobrien const char *sn = symbols[j]->name; 62089857Sobrien 62189857Sobrien /* We should not re-export imported stuff. */ 62289857Sobrien { 623218822Sdim char *name; 624218822Sdim if (is_import (sn)) 625218822Sdim continue; 62689857Sobrien 627218822Sdim name = xmalloc (strlen ("__imp_") + strlen (sn) + 1); 628218822Sdim sprintf (name, "%s%s", "__imp_", sn); 629218822Sdim 63089857Sobrien blhe = bfd_link_hash_lookup (info->hash, name, 631130561Sobrien FALSE, FALSE, FALSE); 63289857Sobrien free (name); 63389857Sobrien 634104834Sobrien if (blhe && blhe->type == bfd_link_hash_defined) 63589857Sobrien continue; 63689857Sobrien } 63789857Sobrien 638218822Sdim if (pe_details->underscored && *sn == '_') 63960484Sobrien sn++; 64089857Sobrien 64189857Sobrien if (auto_export (b, pe_def_file, sn)) 64289857Sobrien { 64389857Sobrien def_file_export *p; 64489857Sobrien p=def_file_add_export (pe_def_file, sn, 0, -1); 64589857Sobrien /* Fill data flag properly, from dlltool.c. */ 64689857Sobrien p->flag_data = !(symbols[j]->flags & BSF_FUNCTION); 64789857Sobrien } 64860484Sobrien } 64960484Sobrien } 65060484Sobrien } 65160484Sobrien } 65260484Sobrien 65360484Sobrien#undef NE 65460484Sobrien#define NE pe_def_file->num_exports 65560484Sobrien 65677298Sobrien /* Canonicalize the export list. */ 65760484Sobrien if (pe_dll_kill_ats) 65860484Sobrien { 65960484Sobrien for (i = 0; i < NE; i++) 66060484Sobrien { 66160484Sobrien if (strchr (pe_def_file->exports[i].name, '@')) 66260484Sobrien { 66377298Sobrien /* This will preserve internal_name, which may have been 664130561Sobrien pointing to the same memory as name, or might not 665130561Sobrien have. */ 666130561Sobrien int lead_at = (*pe_def_file->exports[i].name == '@'); 667130561Sobrien char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); 668218822Sdim char *tmp_at = strchr (tmp, '@'); 66989857Sobrien 670218822Sdim if (tmp_at) 671218822Sdim *tmp_at = 0; 672218822Sdim else 673218822Sdim einfo (_("%XCannot export %s: invalid export name\n"), 674218822Sdim pe_def_file->exports[i].name); 67560484Sobrien pe_def_file->exports[i].name = tmp; 67660484Sobrien } 67760484Sobrien } 67860484Sobrien } 67960484Sobrien 68060484Sobrien if (pe_dll_stdcall_aliases) 68160484Sobrien { 68260484Sobrien for (i = 0; i < NE; i++) 68360484Sobrien { 684218822Sdim if (is_import (pe_def_file->exports[i].name)) 685218822Sdim continue; 686218822Sdim 68760484Sobrien if (strchr (pe_def_file->exports[i].name, '@')) 68860484Sobrien { 689130561Sobrien int lead_at = (*pe_def_file->exports[i].name == '@'); 690130561Sobrien char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); 69189857Sobrien 69260484Sobrien *(strchr (tmp, '@')) = 0; 69389857Sobrien if (auto_export (NULL, pe_def_file, tmp)) 69460484Sobrien def_file_add_export (pe_def_file, tmp, 69589857Sobrien pe_def_file->exports[i].internal_name, 69689857Sobrien -1); 69760484Sobrien else 69860484Sobrien free (tmp); 69960484Sobrien } 70060484Sobrien } 70160484Sobrien } 70260484Sobrien 70377298Sobrien /* Convenience, but watch out for it changing. */ 70477298Sobrien e = pe_def_file->exports; 70560484Sobrien 706130561Sobrien exported_symbol_offsets = xmalloc (NE * sizeof (bfd_vma)); 707130561Sobrien exported_symbol_sections = xmalloc (NE * sizeof (struct bfd_section *)); 70860484Sobrien 709130561Sobrien memset (exported_symbol_sections, 0, NE * sizeof (struct bfd_section *)); 71060484Sobrien max_ordinal = 0; 71160484Sobrien min_ordinal = 65536; 71260484Sobrien count_exported = 0; 71360484Sobrien count_exported_byname = 0; 71460484Sobrien count_with_ordinals = 0; 71560484Sobrien 716130561Sobrien qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), 717130561Sobrien pe_export_sort); 71860484Sobrien for (i = 0, j = 0; i < NE; i++) 71960484Sobrien { 72060484Sobrien if (i > 0 && strcmp (e[i].name, e[i - 1].name) == 0) 72160484Sobrien { 72260484Sobrien /* This is a duplicate. */ 72360484Sobrien if (e[j - 1].ordinal != -1 72460484Sobrien && e[i].ordinal != -1 72560484Sobrien && e[j - 1].ordinal != e[i].ordinal) 72660484Sobrien { 72760484Sobrien if (pe_dll_warn_dup_exports) 72860484Sobrien /* xgettext:c-format */ 72977298Sobrien einfo (_("%XError, duplicate EXPORT with ordinals: %s (%d vs %d)\n"), 73060484Sobrien e[j - 1].name, e[j - 1].ordinal, e[i].ordinal); 73160484Sobrien } 73260484Sobrien else 73360484Sobrien { 73460484Sobrien if (pe_dll_warn_dup_exports) 73560484Sobrien /* xgettext:c-format */ 73660484Sobrien einfo (_("Warning, duplicate EXPORT: %s\n"), 73760484Sobrien e[j - 1].name); 73860484Sobrien } 73989857Sobrien 74077298Sobrien if (e[i].ordinal != -1) 74160484Sobrien e[j - 1].ordinal = e[i].ordinal; 74260484Sobrien e[j - 1].flag_private |= e[i].flag_private; 74360484Sobrien e[j - 1].flag_constant |= e[i].flag_constant; 74460484Sobrien e[j - 1].flag_noname |= e[i].flag_noname; 74560484Sobrien e[j - 1].flag_data |= e[i].flag_data; 74660484Sobrien } 74760484Sobrien else 74860484Sobrien { 74960484Sobrien if (i != j) 75060484Sobrien e[j] = e[i]; 75160484Sobrien j++; 75260484Sobrien } 75360484Sobrien } 75460484Sobrien pe_def_file->num_exports = j; /* == NE */ 75560484Sobrien 75660484Sobrien for (i = 0; i < NE; i++) 75760484Sobrien { 758130561Sobrien char *name; 75989857Sobrien 760218822Sdim /* Check for forward exports */ 761218822Sdim if (strchr (pe_def_file->exports[i].internal_name, '.')) 762218822Sdim { 763218822Sdim count_exported++; 764218822Sdim if (!pe_def_file->exports[i].flag_noname) 765218822Sdim count_exported_byname++; 766218822Sdim 767218822Sdim pe_def_file->exports[i].flag_forward = 1; 768218822Sdim 769218822Sdim if (pe_def_file->exports[i].ordinal != -1) 770218822Sdim { 771218822Sdim if (max_ordinal < pe_def_file->exports[i].ordinal) 772218822Sdim max_ordinal = pe_def_file->exports[i].ordinal; 773218822Sdim if (min_ordinal > pe_def_file->exports[i].ordinal) 774218822Sdim min_ordinal = pe_def_file->exports[i].ordinal; 775218822Sdim count_with_ordinals++; 776218822Sdim } 777218822Sdim 778218822Sdim continue; 779218822Sdim } 780218822Sdim 781130561Sobrien name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); 782130561Sobrien if (pe_details->underscored 783130561Sobrien && (*pe_def_file->exports[i].internal_name != '@')) 78460484Sobrien { 78560484Sobrien *name = '_'; 78660484Sobrien strcpy (name + 1, pe_def_file->exports[i].internal_name); 78760484Sobrien } 78860484Sobrien else 78960484Sobrien strcpy (name, pe_def_file->exports[i].internal_name); 79060484Sobrien 79160484Sobrien blhe = bfd_link_hash_lookup (info->hash, 79260484Sobrien name, 793130561Sobrien FALSE, FALSE, TRUE); 79460484Sobrien 79560484Sobrien if (blhe 79677298Sobrien && (blhe->type == bfd_link_hash_defined 79760484Sobrien || (blhe->type == bfd_link_hash_common))) 79860484Sobrien { 79960484Sobrien count_exported++; 80060484Sobrien if (!pe_def_file->exports[i].flag_noname) 80160484Sobrien count_exported_byname++; 80260484Sobrien 80360484Sobrien /* Only fill in the sections. The actual offsets are computed 80460484Sobrien in fill_exported_offsets() after common symbols are laid 80560484Sobrien out. */ 80677298Sobrien if (blhe->type == bfd_link_hash_defined) 80760484Sobrien exported_symbol_sections[i] = blhe->u.def.section; 80860484Sobrien else 80960484Sobrien exported_symbol_sections[i] = blhe->u.c.p->section; 81077298Sobrien 81160484Sobrien if (pe_def_file->exports[i].ordinal != -1) 81260484Sobrien { 81360484Sobrien if (max_ordinal < pe_def_file->exports[i].ordinal) 81460484Sobrien max_ordinal = pe_def_file->exports[i].ordinal; 81560484Sobrien if (min_ordinal > pe_def_file->exports[i].ordinal) 81660484Sobrien min_ordinal = pe_def_file->exports[i].ordinal; 81760484Sobrien count_with_ordinals++; 81860484Sobrien } 81960484Sobrien } 82060484Sobrien else if (blhe && blhe->type == bfd_link_hash_undefined) 82160484Sobrien { 82260484Sobrien /* xgettext:c-format */ 82360484Sobrien einfo (_("%XCannot export %s: symbol not defined\n"), 82460484Sobrien pe_def_file->exports[i].internal_name); 82560484Sobrien } 82660484Sobrien else if (blhe) 82760484Sobrien { 82860484Sobrien /* xgettext:c-format */ 82960484Sobrien einfo (_("%XCannot export %s: symbol wrong type (%d vs %d)\n"), 83060484Sobrien pe_def_file->exports[i].internal_name, 83160484Sobrien blhe->type, bfd_link_hash_defined); 83260484Sobrien } 83360484Sobrien else 83460484Sobrien { 83560484Sobrien /* xgettext:c-format */ 83660484Sobrien einfo (_("%XCannot export %s: symbol not found\n"), 83760484Sobrien pe_def_file->exports[i].internal_name); 83860484Sobrien } 83960484Sobrien free (name); 84060484Sobrien } 84160484Sobrien} 84260484Sobrien 84389857Sobrien/* Build the bfd that will contain .edata and .reloc sections. */ 84460484Sobrien 84560484Sobrienstatic void 846130561Sobrienbuild_filler_bfd (int include_edata) 84760484Sobrien{ 84860484Sobrien lang_input_statement_type *filler_file; 84960484Sobrien filler_file = lang_add_input_file ("dll stuff", 85060484Sobrien lang_input_file_is_fake_enum, 85160484Sobrien NULL); 85260484Sobrien filler_file->the_bfd = filler_bfd = bfd_create ("dll stuff", output_bfd); 85360484Sobrien if (filler_bfd == NULL 85460484Sobrien || !bfd_set_arch_mach (filler_bfd, 85560484Sobrien bfd_get_arch (output_bfd), 85660484Sobrien bfd_get_mach (output_bfd))) 85760484Sobrien { 858218822Sdim einfo ("%X%P: can not create BFD: %E\n"); 85960484Sobrien return; 86060484Sobrien } 86160484Sobrien 86260484Sobrien if (include_edata) 86360484Sobrien { 86460484Sobrien edata_s = bfd_make_section_old_way (filler_bfd, ".edata"); 86560484Sobrien if (edata_s == NULL 86660484Sobrien || !bfd_set_section_flags (filler_bfd, edata_s, 86760484Sobrien (SEC_HAS_CONTENTS 86860484Sobrien | SEC_ALLOC 86960484Sobrien | SEC_LOAD 87060484Sobrien | SEC_KEEP 87160484Sobrien | SEC_IN_MEMORY))) 87260484Sobrien { 87360484Sobrien einfo ("%X%P: can not create .edata section: %E\n"); 87460484Sobrien return; 87560484Sobrien } 87660484Sobrien bfd_set_section_size (filler_bfd, edata_s, edata_sz); 87760484Sobrien } 87860484Sobrien 87960484Sobrien reloc_s = bfd_make_section_old_way (filler_bfd, ".reloc"); 88060484Sobrien if (reloc_s == NULL 88160484Sobrien || !bfd_set_section_flags (filler_bfd, reloc_s, 88260484Sobrien (SEC_HAS_CONTENTS 88360484Sobrien | SEC_ALLOC 88460484Sobrien | SEC_LOAD 88560484Sobrien | SEC_KEEP 88660484Sobrien | SEC_IN_MEMORY))) 88760484Sobrien { 88860484Sobrien einfo ("%X%P: can not create .reloc section: %E\n"); 88960484Sobrien return; 89060484Sobrien } 89189857Sobrien 89260484Sobrien bfd_set_section_size (filler_bfd, reloc_s, 0); 89360484Sobrien 89460484Sobrien ldlang_add_file (filler_file); 89560484Sobrien} 89660484Sobrien 89789857Sobrien/* Gather all the exported symbols and build the .edata section. */ 89860484Sobrien 89960484Sobrienstatic void 900130561Sobriengenerate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) 90160484Sobrien{ 90260484Sobrien int i, next_ordinal; 90360484Sobrien int name_table_size = 0; 90460484Sobrien const char *dlnp; 90560484Sobrien 90660484Sobrien /* First, we need to know how many exported symbols there are, 90777298Sobrien and what the range of ordinals is. */ 90860484Sobrien if (pe_def_file->name) 90989857Sobrien dll_name = pe_def_file->name; 91060484Sobrien else 91160484Sobrien { 91260484Sobrien dll_name = abfd->filename; 91389857Sobrien 91460484Sobrien for (dlnp = dll_name; *dlnp; dlnp++) 91589857Sobrien if (*dlnp == '\\' || *dlnp == '/' || *dlnp == ':') 91689857Sobrien dll_name = dlnp + 1; 91760484Sobrien } 91860484Sobrien 91960484Sobrien if (count_with_ordinals && max_ordinal > count_exported) 92060484Sobrien { 92160484Sobrien if (min_ordinal > max_ordinal - count_exported + 1) 92260484Sobrien min_ordinal = max_ordinal - count_exported + 1; 92360484Sobrien } 92460484Sobrien else 92560484Sobrien { 92660484Sobrien min_ordinal = 1; 92760484Sobrien max_ordinal = count_exported; 92860484Sobrien } 92989857Sobrien 93060484Sobrien export_table_size = max_ordinal - min_ordinal + 1; 931130561Sobrien exported_symbols = xmalloc (export_table_size * sizeof (int)); 93260484Sobrien for (i = 0; i < export_table_size; i++) 93360484Sobrien exported_symbols[i] = -1; 93460484Sobrien 93577298Sobrien /* Now we need to assign ordinals to those that don't have them. */ 93660484Sobrien for (i = 0; i < NE; i++) 93760484Sobrien { 938218822Sdim if (exported_symbol_sections[i] || 939218822Sdim pe_def_file->exports[i].flag_forward) 94060484Sobrien { 94160484Sobrien if (pe_def_file->exports[i].ordinal != -1) 94260484Sobrien { 94360484Sobrien int ei = pe_def_file->exports[i].ordinal - min_ordinal; 94460484Sobrien int pi = exported_symbols[ei]; 94589857Sobrien 94660484Sobrien if (pi != -1) 94760484Sobrien { 94860484Sobrien /* xgettext:c-format */ 94977298Sobrien einfo (_("%XError, ordinal used twice: %d (%s vs %s)\n"), 95060484Sobrien pe_def_file->exports[i].ordinal, 95160484Sobrien pe_def_file->exports[i].name, 95260484Sobrien pe_def_file->exports[pi].name); 95360484Sobrien } 95460484Sobrien exported_symbols[ei] = i; 95560484Sobrien } 95660484Sobrien name_table_size += strlen (pe_def_file->exports[i].name) + 1; 95760484Sobrien } 958218822Sdim 959218822Sdim /* Reserve space for the forward name. */ 960218822Sdim if (pe_def_file->exports[i].flag_forward) 961218822Sdim { 962218822Sdim name_table_size += strlen (pe_def_file->exports[i].internal_name) + 1; 963218822Sdim } 96460484Sobrien } 96560484Sobrien 96660484Sobrien next_ordinal = min_ordinal; 96760484Sobrien for (i = 0; i < NE; i++) 968218822Sdim if ((exported_symbol_sections[i] || 969218822Sdim pe_def_file->exports[i].flag_forward) && 970218822Sdim pe_def_file->exports[i].ordinal == -1) 971218822Sdim { 972218822Sdim while (exported_symbols[next_ordinal - min_ordinal] != -1) 973218822Sdim next_ordinal++; 97489857Sobrien 975218822Sdim exported_symbols[next_ordinal - min_ordinal] = i; 976218822Sdim pe_def_file->exports[i].ordinal = next_ordinal; 977218822Sdim } 97860484Sobrien 97977298Sobrien /* OK, now we can allocate some memory. */ 98089857Sobrien edata_sz = (40 /* directory */ 98189857Sobrien + 4 * export_table_size /* addresses */ 98260484Sobrien + 4 * count_exported_byname /* name ptrs */ 98360484Sobrien + 2 * count_exported_byname /* ordinals */ 98460484Sobrien + name_table_size + strlen (dll_name) + 1); 98560484Sobrien} 98660484Sobrien 98760484Sobrien/* Fill the exported symbol offsets. The preliminary work has already 98860484Sobrien been done in process_def_file(). */ 98960484Sobrien 99060484Sobrienstatic void 991130561Sobrienfill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) 99260484Sobrien{ 99360484Sobrien int i; 99460484Sobrien struct bfd_link_hash_entry *blhe; 99577298Sobrien 99660484Sobrien for (i = 0; i < pe_def_file->num_exports; i++) 99760484Sobrien { 998130561Sobrien char *name; 99989857Sobrien 1000130561Sobrien name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); 1001130561Sobrien if (pe_details->underscored 1002130561Sobrien && *pe_def_file->exports[i].internal_name != '@') 100360484Sobrien { 100460484Sobrien *name = '_'; 100560484Sobrien strcpy (name + 1, pe_def_file->exports[i].internal_name); 100660484Sobrien } 100760484Sobrien else 100860484Sobrien strcpy (name, pe_def_file->exports[i].internal_name); 100960484Sobrien 101060484Sobrien blhe = bfd_link_hash_lookup (info->hash, 101160484Sobrien name, 1012130561Sobrien FALSE, FALSE, TRUE); 101360484Sobrien 1014130561Sobrien if (blhe && blhe->type == bfd_link_hash_defined) 101589857Sobrien exported_symbol_offsets[i] = blhe->u.def.value; 101689857Sobrien 101760484Sobrien free (name); 101860484Sobrien } 101960484Sobrien} 102060484Sobrien 102160484Sobrienstatic void 1022130561Sobrienfill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) 102360484Sobrien{ 1024130561Sobrien int s, hint; 102560484Sobrien unsigned char *edirectory; 1026130561Sobrien unsigned char *eaddresses; 1027130561Sobrien unsigned char *enameptrs; 1028130561Sobrien unsigned char *eordinals; 1029218822Sdim char *enamestr; 103060484Sobrien time_t now; 103160484Sobrien 103260484Sobrien time (&now); 103360484Sobrien 1034130561Sobrien edata_d = xmalloc (edata_sz); 103560484Sobrien 103677298Sobrien /* Note use of array pointer math here. */ 103760484Sobrien edirectory = edata_d; 1038130561Sobrien eaddresses = edata_d + 40; 1039130561Sobrien enameptrs = eaddresses + 4 * export_table_size; 1040130561Sobrien eordinals = enameptrs + 4 * count_exported_byname; 1041218822Sdim enamestr = (char *) eordinals + 2 * count_exported_byname; 104260484Sobrien 1043130561Sobrien#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) \ 1044130561Sobrien + edata_s->output_section->vma - image_base) 104560484Sobrien 104677298Sobrien memset (edata_d, 0, edata_sz); 104760484Sobrien bfd_put_32 (abfd, now, edata_d + 4); 104860484Sobrien if (pe_def_file->version_major != -1) 104960484Sobrien { 105060484Sobrien bfd_put_16 (abfd, pe_def_file->version_major, edata_d + 8); 105160484Sobrien bfd_put_16 (abfd, pe_def_file->version_minor, edata_d + 10); 105260484Sobrien } 105389857Sobrien 105460484Sobrien bfd_put_32 (abfd, ERVA (enamestr), edata_d + 12); 105560484Sobrien strcpy (enamestr, dll_name); 105660484Sobrien enamestr += strlen (enamestr) + 1; 105760484Sobrien bfd_put_32 (abfd, min_ordinal, edata_d + 16); 105860484Sobrien bfd_put_32 (abfd, export_table_size, edata_d + 20); 105960484Sobrien bfd_put_32 (abfd, count_exported_byname, edata_d + 24); 106060484Sobrien bfd_put_32 (abfd, ERVA (eaddresses), edata_d + 28); 106160484Sobrien bfd_put_32 (abfd, ERVA (enameptrs), edata_d + 32); 106260484Sobrien bfd_put_32 (abfd, ERVA (eordinals), edata_d + 36); 106360484Sobrien 106460484Sobrien fill_exported_offsets (abfd, info); 106560484Sobrien 1066130561Sobrien /* Ok, now for the filling in part. 1067130561Sobrien Scan alphabetically - ie the ordering in the exports[] table, 1068130561Sobrien rather than by ordinal - the ordering in the exported_symbol[] 1069130561Sobrien table. See dlltool.c and: 1070130561Sobrien http://sources.redhat.com/ml/binutils/2003-04/msg00379.html 1071130561Sobrien for more information. */ 107260484Sobrien hint = 0; 1073130561Sobrien for (s = 0; s < NE; s++) 107460484Sobrien { 1075130561Sobrien struct bfd_section *ssec = exported_symbol_sections[s]; 1076218822Sdim if (pe_def_file->exports[s].ordinal != -1 && 1077218822Sdim (pe_def_file->exports[s].flag_forward || ssec != NULL)) 107860484Sobrien { 107977298Sobrien int ord = pe_def_file->exports[s].ordinal; 108060484Sobrien 1081218822Sdim if (pe_def_file->exports[s].flag_forward) 1082218822Sdim { 1083218822Sdim bfd_put_32 (abfd, ERVA (enamestr), 1084218822Sdim eaddresses + 4 * (ord - min_ordinal)); 108589857Sobrien 1086218822Sdim strcpy (enamestr, pe_def_file->exports[s].internal_name); 1087218822Sdim enamestr += strlen (pe_def_file->exports[s].internal_name) + 1; 1088218822Sdim } 1089218822Sdim else 1090218822Sdim { 1091218822Sdim unsigned long srva = (exported_symbol_offsets[s] 1092218822Sdim + ssec->output_section->vma 1093218822Sdim + ssec->output_offset); 1094218822Sdim 1095218822Sdim bfd_put_32 (abfd, srva - image_base, 1096218822Sdim eaddresses + 4 * (ord - min_ordinal)); 1097218822Sdim } 1098218822Sdim 109960484Sobrien if (!pe_def_file->exports[s].flag_noname) 110060484Sobrien { 110160484Sobrien char *ename = pe_def_file->exports[s].name; 1102130561Sobrien 1103130561Sobrien bfd_put_32 (abfd, ERVA (enamestr), enameptrs); 1104130561Sobrien enameptrs += 4; 110560484Sobrien strcpy (enamestr, ename); 110660484Sobrien enamestr += strlen (enamestr) + 1; 1107130561Sobrien bfd_put_16 (abfd, ord - min_ordinal, eordinals); 1108130561Sobrien eordinals += 2; 110960484Sobrien pe_def_file->exports[s].hint = hint++; 111060484Sobrien } 111160484Sobrien } 111260484Sobrien } 111360484Sobrien} 111460484Sobrien 111560484Sobrien 1116130561Sobrienstatic struct bfd_section *current_sec; 111760484Sobrien 111889857Sobrienvoid 1119130561Sobrienpe_walk_relocs_of_symbol (struct bfd_link_info *info, 1120130561Sobrien const char *name, 1121130561Sobrien int (*cb) (arelent *, asection *)) 112289857Sobrien{ 112389857Sobrien bfd *b; 112489857Sobrien asection *s; 112560484Sobrien 112689857Sobrien for (b = info->input_bfds; b; b = b->link_next) 112789857Sobrien { 112889857Sobrien asymbol **symbols; 112989857Sobrien int nsyms, symsize; 113089857Sobrien 113189857Sobrien symsize = bfd_get_symtab_upper_bound (b); 1132130561Sobrien symbols = xmalloc (symsize); 113389857Sobrien nsyms = bfd_canonicalize_symtab (b, symbols); 113489857Sobrien 113589857Sobrien for (s = b->sections; s; s = s->next) 113689857Sobrien { 113789857Sobrien arelent **relocs; 113889857Sobrien int relsize, nrelocs, i; 113989857Sobrien int flags = bfd_get_section_flags (b, s); 114089857Sobrien 114189857Sobrien /* Skip discarded linkonce sections. */ 114289857Sobrien if (flags & SEC_LINK_ONCE 114389857Sobrien && s->output_section == bfd_abs_section_ptr) 114489857Sobrien continue; 114589857Sobrien 114689857Sobrien current_sec = s; 114789857Sobrien 114889857Sobrien relsize = bfd_get_reloc_upper_bound (b, s); 1149130561Sobrien relocs = xmalloc (relsize); 115089857Sobrien nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); 115189857Sobrien 115289857Sobrien for (i = 0; i < nrelocs; i++) 115389857Sobrien { 1154130561Sobrien struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; 115589857Sobrien 115689857Sobrien if (!strcmp (name, sym->name)) 115789857Sobrien cb (relocs[i], s); 115889857Sobrien } 115989857Sobrien 116089857Sobrien free (relocs); 116189857Sobrien 116289857Sobrien /* Warning: the allocated symbols are remembered in BFD and reused 116389857Sobrien later, so don't free them! */ 116489857Sobrien /* free (symbols); */ 116589857Sobrien } 116689857Sobrien } 116789857Sobrien} 116889857Sobrien 116989857Sobrien/* Gather all the relocations and build the .reloc section. */ 117089857Sobrien 117160484Sobrienstatic void 1172130561Sobriengenerate_reloc (bfd *abfd, struct bfd_link_info *info) 117360484Sobrien{ 117460484Sobrien 117577298Sobrien /* For .reloc stuff. */ 117660484Sobrien reloc_data_type *reloc_data; 117760484Sobrien int total_relocs = 0; 117860484Sobrien int i; 1179130561Sobrien unsigned long sec_page = (unsigned long) -1; 118060484Sobrien unsigned long page_ptr, page_count; 118160484Sobrien int bi; 118260484Sobrien bfd *b; 1183130561Sobrien struct bfd_section *s; 118460484Sobrien 118560484Sobrien total_relocs = 0; 118660484Sobrien for (b = info->input_bfds; b; b = b->link_next) 118760484Sobrien for (s = b->sections; s; s = s->next) 118860484Sobrien total_relocs += s->reloc_count; 118960484Sobrien 1190130561Sobrien reloc_data = xmalloc (total_relocs * sizeof (reloc_data_type)); 119160484Sobrien 119260484Sobrien total_relocs = 0; 119360484Sobrien bi = 0; 119460484Sobrien for (bi = 0, b = info->input_bfds; b; bi++, b = b->link_next) 119560484Sobrien { 119660484Sobrien arelent **relocs; 119760484Sobrien int relsize, nrelocs, i; 119860484Sobrien 119960484Sobrien for (s = b->sections; s; s = s->next) 120060484Sobrien { 120160484Sobrien unsigned long sec_vma = s->output_section->vma + s->output_offset; 120260484Sobrien asymbol **symbols; 120360484Sobrien int nsyms, symsize; 120460484Sobrien 120577298Sobrien /* If it's not loaded, we don't need to relocate it this way. */ 120660484Sobrien if (!(s->output_section->flags & SEC_LOAD)) 120760484Sobrien continue; 120860484Sobrien 120960484Sobrien /* I don't know why there would be a reloc for these, but I've 121077298Sobrien seen it happen - DJ */ 121160484Sobrien if (s->output_section == &bfd_abs_section) 121260484Sobrien continue; 121360484Sobrien 121460484Sobrien if (s->output_section->vma == 0) 121560484Sobrien { 121677298Sobrien /* Huh? Shouldn't happen, but punt if it does. */ 121760484Sobrien einfo ("DJ: zero vma section reloc detected: `%s' #%d f=%d\n", 121860484Sobrien s->output_section->name, s->output_section->index, 121960484Sobrien s->output_section->flags); 122060484Sobrien continue; 122160484Sobrien } 122260484Sobrien 122360484Sobrien symsize = bfd_get_symtab_upper_bound (b); 1224130561Sobrien symbols = xmalloc (symsize); 122560484Sobrien nsyms = bfd_canonicalize_symtab (b, symbols); 122660484Sobrien 122760484Sobrien relsize = bfd_get_reloc_upper_bound (b, s); 1228130561Sobrien relocs = xmalloc (relsize); 122960484Sobrien nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); 123060484Sobrien 123160484Sobrien for (i = 0; i < nrelocs; i++) 123260484Sobrien { 123389857Sobrien if (pe_dll_extra_pe_debug) 1234104834Sobrien { 1235130561Sobrien struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; 1236104834Sobrien printf ("rel: %s\n", sym->name); 123789857Sobrien } 123860484Sobrien if (!relocs[i]->howto->pc_relative 123960484Sobrien && relocs[i]->howto->type != pe_details->imagebase_reloc) 124060484Sobrien { 124160484Sobrien bfd_vma sym_vma; 1242130561Sobrien struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; 124389857Sobrien 124460484Sobrien sym_vma = (relocs[i]->addend 124560484Sobrien + sym->value 124660484Sobrien + sym->section->vma 124760484Sobrien + sym->section->output_offset 124860484Sobrien + sym->section->output_section->vma); 124960484Sobrien reloc_data[total_relocs].vma = sec_vma + relocs[i]->address; 125077298Sobrien 125160484Sobrien#define BITS_AND_SHIFT(bits, shift) (bits * 1000 | shift) 125277298Sobrien 125360484Sobrien switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, 125460484Sobrien relocs[i]->howto->rightshift) 125560484Sobrien { 1256218822Sdim#ifdef pe_use_x86_64 1257218822Sdim case BITS_AND_SHIFT (64, 0): 1258218822Sdim reloc_data[total_relocs].type = 10; 1259218822Sdim total_relocs++; 1260218822Sdim break; 1261218822Sdim#endif 126260484Sobrien case BITS_AND_SHIFT (32, 0): 126360484Sobrien reloc_data[total_relocs].type = 3; 126460484Sobrien total_relocs++; 126560484Sobrien break; 126660484Sobrien case BITS_AND_SHIFT (16, 0): 126760484Sobrien reloc_data[total_relocs].type = 2; 126860484Sobrien total_relocs++; 126960484Sobrien break; 127060484Sobrien case BITS_AND_SHIFT (16, 16): 127160484Sobrien reloc_data[total_relocs].type = 4; 127277298Sobrien /* FIXME: we can't know the symbol's right value 127377298Sobrien yet, but we probably can safely assume that 127477298Sobrien CE will relocate us in 64k blocks, so leaving 127577298Sobrien it zero is safe. */ 127660484Sobrien reloc_data[total_relocs].extra = 0; 127760484Sobrien total_relocs++; 127860484Sobrien break; 127960484Sobrien case BITS_AND_SHIFT (26, 2): 128060484Sobrien reloc_data[total_relocs].type = 5; 128160484Sobrien total_relocs++; 128260484Sobrien break; 1283130561Sobrien case BITS_AND_SHIFT (24, 2): 1284130561Sobrien /* FIXME: 0 is ARM_26D, it is defined in bfd/coff-arm.c 1285130561Sobrien Those ARM_xxx definitions should go in proper 1286130561Sobrien header someday. */ 1287130561Sobrien if (relocs[i]->howto->type == 0 1288130561Sobrien /* Older GNU linkers used 5 instead of 0 for this reloc. */ 1289130561Sobrien || relocs[i]->howto->type == 5) 1290130561Sobrien /* This is an ARM_26D reloc, which is an ARM_26 reloc 1291130561Sobrien that has already been fully processed during a 1292130561Sobrien previous link stage, so ignore it here. */ 1293130561Sobrien break; 1294130561Sobrien /* Fall through. */ 129560484Sobrien default: 129660484Sobrien /* xgettext:c-format */ 129760484Sobrien einfo (_("%XError: %d-bit reloc in dll\n"), 129860484Sobrien relocs[i]->howto->bitsize); 129960484Sobrien break; 130060484Sobrien } 130160484Sobrien } 130260484Sobrien } 130360484Sobrien free (relocs); 130477298Sobrien /* Warning: the allocated symbols are remembered in BFD and 130577298Sobrien reused later, so don't free them! */ 130660484Sobrien } 130760484Sobrien } 130860484Sobrien 130960484Sobrien /* At this point, we have total_relocs relocation addresses in 131060484Sobrien reloc_addresses, which are all suitable for the .reloc section. 131177298Sobrien We must now create the new sections. */ 131260484Sobrien qsort (reloc_data, total_relocs, sizeof (*reloc_data), reloc_sort); 131360484Sobrien 131460484Sobrien for (i = 0; i < total_relocs; i++) 131560484Sobrien { 131660484Sobrien unsigned long this_page = (reloc_data[i].vma >> 12); 131777298Sobrien 131860484Sobrien if (this_page != sec_page) 131960484Sobrien { 132089857Sobrien reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ 132160484Sobrien reloc_sz += 8; 132260484Sobrien sec_page = this_page; 132360484Sobrien } 132477298Sobrien 132560484Sobrien reloc_sz += 2; 132677298Sobrien 132760484Sobrien if (reloc_data[i].type == 4) 132860484Sobrien reloc_sz += 2; 132960484Sobrien } 1330104834Sobrien 133189857Sobrien reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ 1332130561Sobrien reloc_d = xmalloc (reloc_sz); 1333130561Sobrien sec_page = (unsigned long) -1; 133460484Sobrien reloc_sz = 0; 1335130561Sobrien page_ptr = (unsigned long) -1; 133660484Sobrien page_count = 0; 133789857Sobrien 133860484Sobrien for (i = 0; i < total_relocs; i++) 133960484Sobrien { 134060484Sobrien unsigned long rva = reloc_data[i].vma - image_base; 134160484Sobrien unsigned long this_page = (rva & ~0xfff); 134289857Sobrien 134360484Sobrien if (this_page != sec_page) 134460484Sobrien { 134560484Sobrien while (reloc_sz & 3) 134660484Sobrien reloc_d[reloc_sz++] = 0; 134789857Sobrien 1348130561Sobrien if (page_ptr != (unsigned long) -1) 134960484Sobrien bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); 135089857Sobrien 135160484Sobrien bfd_put_32 (abfd, this_page, reloc_d + reloc_sz); 135260484Sobrien page_ptr = reloc_sz; 135360484Sobrien reloc_sz += 8; 135460484Sobrien sec_page = this_page; 135560484Sobrien page_count = 0; 135660484Sobrien } 135789857Sobrien 135877298Sobrien bfd_put_16 (abfd, (rva & 0xfff) + (reloc_data[i].type << 12), 135960484Sobrien reloc_d + reloc_sz); 136060484Sobrien reloc_sz += 2; 136189857Sobrien 136260484Sobrien if (reloc_data[i].type == 4) 136360484Sobrien { 136460484Sobrien bfd_put_16 (abfd, reloc_data[i].extra, reloc_d + reloc_sz); 136560484Sobrien reloc_sz += 2; 136660484Sobrien } 136789857Sobrien 136860484Sobrien page_count++; 136960484Sobrien } 137089857Sobrien 137160484Sobrien while (reloc_sz & 3) 137260484Sobrien reloc_d[reloc_sz++] = 0; 137389857Sobrien 1374130561Sobrien if (page_ptr != (unsigned long) -1) 137560484Sobrien bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); 137689857Sobrien 1377218822Sdim while (reloc_sz < reloc_s->size) 137860484Sobrien reloc_d[reloc_sz++] = 0; 137960484Sobrien} 138060484Sobrien 138189857Sobrien/* Given the exiting def_file structure, print out a .DEF file that 138289857Sobrien corresponds to it. */ 138360484Sobrien 138460484Sobrienstatic void 1385130561Sobrienquoteput (char *s, FILE *f, int needs_quotes) 138660484Sobrien{ 138760484Sobrien char *cp; 138889857Sobrien 138960484Sobrien for (cp = s; *cp; cp++) 139060484Sobrien if (*cp == '\'' 139160484Sobrien || *cp == '"' 139260484Sobrien || *cp == '\\' 139389857Sobrien || ISSPACE (*cp) 139460484Sobrien || *cp == ',' 139560484Sobrien || *cp == ';') 139660484Sobrien needs_quotes = 1; 139789857Sobrien 139860484Sobrien if (needs_quotes) 139960484Sobrien { 140060484Sobrien putc ('"', f); 140189857Sobrien 140260484Sobrien while (*s) 140360484Sobrien { 140460484Sobrien if (*s == '"' || *s == '\\') 140560484Sobrien putc ('\\', f); 140689857Sobrien 140760484Sobrien putc (*s, f); 140860484Sobrien s++; 140960484Sobrien } 141089857Sobrien 141160484Sobrien putc ('"', f); 141260484Sobrien } 141360484Sobrien else 141460484Sobrien fputs (s, f); 141560484Sobrien} 141660484Sobrien 141760484Sobrienvoid 1418130561Sobrienpe_dll_generate_def_file (const char *pe_out_def_filename) 141960484Sobrien{ 142060484Sobrien int i; 142160484Sobrien FILE *out = fopen (pe_out_def_filename, "w"); 142289857Sobrien 142360484Sobrien if (out == NULL) 142489857Sobrien /* xgettext:c-format */ 142589857Sobrien einfo (_("%s: Can't open output def file %s\n"), 142689857Sobrien program_name, pe_out_def_filename); 142760484Sobrien 142860484Sobrien if (pe_def_file) 142960484Sobrien { 143060484Sobrien if (pe_def_file->name) 143160484Sobrien { 143260484Sobrien if (pe_def_file->is_dll) 143360484Sobrien fprintf (out, "LIBRARY "); 143460484Sobrien else 143560484Sobrien fprintf (out, "NAME "); 143689857Sobrien 143760484Sobrien quoteput (pe_def_file->name, out, 1); 143889857Sobrien 143960484Sobrien if (pe_data (output_bfd)->pe_opthdr.ImageBase) 144060484Sobrien fprintf (out, " BASE=0x%lx", 144160484Sobrien (unsigned long) pe_data (output_bfd)->pe_opthdr.ImageBase); 144260484Sobrien fprintf (out, "\n"); 144360484Sobrien } 144460484Sobrien 144560484Sobrien if (pe_def_file->description) 144660484Sobrien { 144760484Sobrien fprintf (out, "DESCRIPTION "); 144860484Sobrien quoteput (pe_def_file->description, out, 1); 144960484Sobrien fprintf (out, "\n"); 145060484Sobrien } 145160484Sobrien 145260484Sobrien if (pe_def_file->version_minor != -1) 145360484Sobrien fprintf (out, "VERSION %d.%d\n", pe_def_file->version_major, 145460484Sobrien pe_def_file->version_minor); 145560484Sobrien else if (pe_def_file->version_major != -1) 145660484Sobrien fprintf (out, "VERSION %d\n", pe_def_file->version_major); 145760484Sobrien 145860484Sobrien if (pe_def_file->stack_reserve != -1 || pe_def_file->heap_reserve != -1) 145960484Sobrien fprintf (out, "\n"); 146060484Sobrien 146160484Sobrien if (pe_def_file->stack_commit != -1) 146260484Sobrien fprintf (out, "STACKSIZE 0x%x,0x%x\n", 146360484Sobrien pe_def_file->stack_reserve, pe_def_file->stack_commit); 146460484Sobrien else if (pe_def_file->stack_reserve != -1) 146560484Sobrien fprintf (out, "STACKSIZE 0x%x\n", pe_def_file->stack_reserve); 146689857Sobrien 146760484Sobrien if (pe_def_file->heap_commit != -1) 146860484Sobrien fprintf (out, "HEAPSIZE 0x%x,0x%x\n", 146960484Sobrien pe_def_file->heap_reserve, pe_def_file->heap_commit); 147060484Sobrien else if (pe_def_file->heap_reserve != -1) 147160484Sobrien fprintf (out, "HEAPSIZE 0x%x\n", pe_def_file->heap_reserve); 147260484Sobrien 147360484Sobrien if (pe_def_file->num_section_defs > 0) 147460484Sobrien { 147560484Sobrien fprintf (out, "\nSECTIONS\n\n"); 147689857Sobrien 147760484Sobrien for (i = 0; i < pe_def_file->num_section_defs; i++) 147860484Sobrien { 147960484Sobrien fprintf (out, " "); 148060484Sobrien quoteput (pe_def_file->section_defs[i].name, out, 0); 148189857Sobrien 148260484Sobrien if (pe_def_file->section_defs[i].class) 148360484Sobrien { 148460484Sobrien fprintf (out, " CLASS "); 148560484Sobrien quoteput (pe_def_file->section_defs[i].class, out, 0); 148660484Sobrien } 148789857Sobrien 148860484Sobrien if (pe_def_file->section_defs[i].flag_read) 148960484Sobrien fprintf (out, " READ"); 149089857Sobrien 149160484Sobrien if (pe_def_file->section_defs[i].flag_write) 149260484Sobrien fprintf (out, " WRITE"); 149389857Sobrien 149460484Sobrien if (pe_def_file->section_defs[i].flag_execute) 149560484Sobrien fprintf (out, " EXECUTE"); 149689857Sobrien 149760484Sobrien if (pe_def_file->section_defs[i].flag_shared) 149860484Sobrien fprintf (out, " SHARED"); 149989857Sobrien 150060484Sobrien fprintf (out, "\n"); 150160484Sobrien } 150260484Sobrien } 150360484Sobrien 150460484Sobrien if (pe_def_file->num_exports > 0) 150560484Sobrien { 150689857Sobrien fprintf (out, "EXPORTS\n"); 150789857Sobrien 150860484Sobrien for (i = 0; i < pe_def_file->num_exports; i++) 150960484Sobrien { 151060484Sobrien def_file_export *e = pe_def_file->exports + i; 151160484Sobrien fprintf (out, " "); 151260484Sobrien quoteput (e->name, out, 0); 151389857Sobrien 151460484Sobrien if (e->internal_name && strcmp (e->internal_name, e->name)) 151560484Sobrien { 151660484Sobrien fprintf (out, " = "); 151760484Sobrien quoteput (e->internal_name, out, 0); 151860484Sobrien } 151989857Sobrien 152060484Sobrien if (e->ordinal != -1) 152160484Sobrien fprintf (out, " @%d", e->ordinal); 152289857Sobrien 152360484Sobrien if (e->flag_private) 152460484Sobrien fprintf (out, " PRIVATE"); 152589857Sobrien 152660484Sobrien if (e->flag_constant) 152760484Sobrien fprintf (out, " CONSTANT"); 152889857Sobrien 152960484Sobrien if (e->flag_noname) 153060484Sobrien fprintf (out, " NONAME"); 153189857Sobrien 153260484Sobrien if (e->flag_data) 153360484Sobrien fprintf (out, " DATA"); 153460484Sobrien 153560484Sobrien fprintf (out, "\n"); 153660484Sobrien } 153760484Sobrien } 153860484Sobrien 153960484Sobrien if (pe_def_file->num_imports > 0) 154060484Sobrien { 154160484Sobrien fprintf (out, "\nIMPORTS\n\n"); 154289857Sobrien 154360484Sobrien for (i = 0; i < pe_def_file->num_imports; i++) 154460484Sobrien { 154560484Sobrien def_file_import *im = pe_def_file->imports + i; 154660484Sobrien fprintf (out, " "); 154789857Sobrien 154860484Sobrien if (im->internal_name 154960484Sobrien && (!im->name || strcmp (im->internal_name, im->name))) 155060484Sobrien { 155160484Sobrien quoteput (im->internal_name, out, 0); 155260484Sobrien fprintf (out, " = "); 155360484Sobrien } 155489857Sobrien 155560484Sobrien quoteput (im->module->name, out, 0); 155660484Sobrien fprintf (out, "."); 155789857Sobrien 155860484Sobrien if (im->name) 155960484Sobrien quoteput (im->name, out, 0); 156060484Sobrien else 156160484Sobrien fprintf (out, "%d", im->ordinal); 156289857Sobrien 156360484Sobrien fprintf (out, "\n"); 156460484Sobrien } 156560484Sobrien } 156660484Sobrien } 156760484Sobrien else 156860484Sobrien fprintf (out, _("; no contents available\n")); 156960484Sobrien 157060484Sobrien if (fclose (out) == EOF) 157189857Sobrien /* xgettext:c-format */ 157289857Sobrien einfo (_("%P: Error closing file `%s'\n"), pe_out_def_filename); 157360484Sobrien} 157460484Sobrien 157589857Sobrien/* Generate the import library. */ 157660484Sobrien 157760484Sobrienstatic asymbol **symtab; 157860484Sobrienstatic int symptr; 157960484Sobrienstatic int tmp_seq; 158060484Sobrienstatic const char *dll_filename; 158160484Sobrienstatic char *dll_symname; 158260484Sobrien 158360484Sobrien#define UNDSEC (asection *) &bfd_und_section 158460484Sobrien 158560484Sobrienstatic asection * 1586130561Sobrienquick_section (bfd *abfd, const char *name, int flags, int align) 158760484Sobrien{ 158860484Sobrien asection *sec; 158960484Sobrien asymbol *sym; 159060484Sobrien 159160484Sobrien sec = bfd_make_section_old_way (abfd, name); 159277298Sobrien bfd_set_section_flags (abfd, sec, flags | SEC_ALLOC | SEC_LOAD | SEC_KEEP); 159360484Sobrien bfd_set_section_alignment (abfd, sec, align); 159477298Sobrien /* Remember to undo this before trying to link internally! */ 159560484Sobrien sec->output_section = sec; 159660484Sobrien 159760484Sobrien sym = bfd_make_empty_symbol (abfd); 159860484Sobrien symtab[symptr++] = sym; 159960484Sobrien sym->name = sec->name; 160060484Sobrien sym->section = sec; 160160484Sobrien sym->flags = BSF_LOCAL; 160260484Sobrien sym->value = 0; 160360484Sobrien 160460484Sobrien return sec; 160560484Sobrien} 160660484Sobrien 160760484Sobrienstatic void 1608130561Sobrienquick_symbol (bfd *abfd, 1609130561Sobrien const char *n1, 1610130561Sobrien const char *n2, 1611130561Sobrien const char *n3, 1612130561Sobrien asection *sec, 1613130561Sobrien int flags, 1614130561Sobrien int addr) 161560484Sobrien{ 161660484Sobrien asymbol *sym; 1617130561Sobrien char *name = xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); 161889857Sobrien 161960484Sobrien strcpy (name, n1); 162060484Sobrien strcat (name, n2); 162160484Sobrien strcat (name, n3); 162260484Sobrien sym = bfd_make_empty_symbol (abfd); 162360484Sobrien sym->name = name; 162460484Sobrien sym->section = sec; 162560484Sobrien sym->flags = flags; 162660484Sobrien sym->value = addr; 162760484Sobrien symtab[symptr++] = sym; 162860484Sobrien} 162960484Sobrien 163060484Sobrienstatic arelent *reltab = 0; 163160484Sobrienstatic int relcount = 0, relsize = 0; 163260484Sobrien 163360484Sobrienstatic void 1634130561Sobrienquick_reloc (bfd *abfd, int address, int which_howto, int symidx) 163560484Sobrien{ 1636130561Sobrien if (relcount >= relsize - 1) 163760484Sobrien { 163860484Sobrien relsize += 10; 163960484Sobrien if (reltab) 1640130561Sobrien reltab = xrealloc (reltab, relsize * sizeof (arelent)); 164160484Sobrien else 1642130561Sobrien reltab = xmalloc (relsize * sizeof (arelent)); 164360484Sobrien } 164460484Sobrien reltab[relcount].address = address; 164560484Sobrien reltab[relcount].addend = 0; 164660484Sobrien reltab[relcount].howto = bfd_reloc_type_lookup (abfd, which_howto); 164760484Sobrien reltab[relcount].sym_ptr_ptr = symtab + symidx; 164860484Sobrien relcount++; 164960484Sobrien} 165060484Sobrien 165160484Sobrienstatic void 165260484Sobriensave_relocs (asection *sec) 165360484Sobrien{ 165460484Sobrien int i; 165589857Sobrien 165660484Sobrien sec->relocation = reltab; 165760484Sobrien sec->reloc_count = relcount; 1658130561Sobrien sec->orelocation = xmalloc ((relcount + 1) * sizeof (arelent *)); 165977298Sobrien for (i = 0; i < relcount; i++) 166060484Sobrien sec->orelocation[i] = sec->relocation + i; 166160484Sobrien sec->orelocation[relcount] = 0; 166260484Sobrien sec->flags |= SEC_RELOC; 166360484Sobrien reltab = 0; 166460484Sobrien relcount = relsize = 0; 166560484Sobrien} 166660484Sobrien 166789857Sobrien/* .section .idata$2 166889857Sobrien .global __head_my_dll 166989857Sobrien __head_my_dll: 167089857Sobrien .rva hname 167189857Sobrien .long 0 167289857Sobrien .long 0 167389857Sobrien .rva __my_dll_iname 167489857Sobrien .rva fthunk 1675104834Sobrien 167689857Sobrien .section .idata$5 167789857Sobrien .long 0 167889857Sobrien fthunk: 1679104834Sobrien 168089857Sobrien .section .idata$4 168189857Sobrien .long 0 168289857Sobrien hname: */ 168360484Sobrien 168460484Sobrienstatic bfd * 1685130561Sobrienmake_head (bfd *parent) 168660484Sobrien{ 168760484Sobrien asection *id2, *id5, *id4; 168860484Sobrien unsigned char *d2, *d5, *d4; 168960484Sobrien char *oname; 169060484Sobrien bfd *abfd; 169160484Sobrien 1692130561Sobrien oname = xmalloc (20); 169360484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 169460484Sobrien tmp_seq++; 169560484Sobrien 169660484Sobrien abfd = bfd_create (oname, parent); 169760484Sobrien bfd_find_target (pe_details->object_target, abfd); 169860484Sobrien bfd_make_writable (abfd); 169960484Sobrien 170060484Sobrien bfd_set_format (abfd, bfd_object); 170160484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 170260484Sobrien 170360484Sobrien symptr = 0; 1704130561Sobrien symtab = xmalloc (6 * sizeof (asymbol *)); 170560484Sobrien id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); 170660484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 170760484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 170877298Sobrien quick_symbol (abfd, U ("_head_"), dll_symname, "", id2, BSF_GLOBAL, 0); 170977298Sobrien quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); 171060484Sobrien 171160484Sobrien /* OK, pay attention here. I got confused myself looking back at 171260484Sobrien it. We create a four-byte section to mark the beginning of the 171360484Sobrien list, and we include an offset of 4 in the section, so that the 171460484Sobrien pointer to the list points to the *end* of this section, which is 171577298Sobrien the start of the list of sections from other objects. */ 171660484Sobrien 171760484Sobrien bfd_set_section_size (abfd, id2, 20); 1718130561Sobrien d2 = xmalloc (20); 171960484Sobrien id2->contents = d2; 172060484Sobrien memset (d2, 0, 20); 172189857Sobrien d2[0] = d2[16] = 4; /* Reloc addend. */ 172260484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); 172360484Sobrien quick_reloc (abfd, 12, BFD_RELOC_RVA, 4); 172460484Sobrien quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); 172560484Sobrien save_relocs (id2); 172660484Sobrien 1727218822Sdim bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); 1728218822Sdim d5 = xmalloc (PE_IDATA5_SIZE); 172960484Sobrien id5->contents = d5; 1730218822Sdim memset (d5, 0, PE_IDATA5_SIZE); 173160484Sobrien 1732218822Sdim bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); 1733218822Sdim d4 = xmalloc (PE_IDATA4_SIZE); 173460484Sobrien id4->contents = d4; 1735218822Sdim memset (d4, 0, PE_IDATA4_SIZE); 173660484Sobrien 173760484Sobrien bfd_set_symtab (abfd, symtab, symptr); 173860484Sobrien 173960484Sobrien bfd_set_section_contents (abfd, id2, d2, 0, 20); 1740218822Sdim bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); 1741218822Sdim bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); 174277298Sobrien 174360484Sobrien bfd_make_readable (abfd); 174460484Sobrien return abfd; 174560484Sobrien} 174660484Sobrien 174789857Sobrien/* .section .idata$4 174889857Sobrien .long 0 1749218822Sdim [.long 0] for PE+ 175089857Sobrien .section .idata$5 175189857Sobrien .long 0 1752218822Sdim [.long 0] for PE+ 175389857Sobrien .section idata$7 175489857Sobrien .global __my_dll_iname 175589857Sobrien __my_dll_iname: 175689857Sobrien .asciz "my.dll" */ 175760484Sobrien 175860484Sobrienstatic bfd * 1759130561Sobrienmake_tail (bfd *parent) 176060484Sobrien{ 176160484Sobrien asection *id4, *id5, *id7; 176260484Sobrien unsigned char *d4, *d5, *d7; 176360484Sobrien int len; 176460484Sobrien char *oname; 176560484Sobrien bfd *abfd; 176660484Sobrien 1767130561Sobrien oname = xmalloc (20); 176860484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 176960484Sobrien tmp_seq++; 177060484Sobrien 177160484Sobrien abfd = bfd_create (oname, parent); 177260484Sobrien bfd_find_target (pe_details->object_target, abfd); 177360484Sobrien bfd_make_writable (abfd); 177460484Sobrien 177560484Sobrien bfd_set_format (abfd, bfd_object); 177660484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 177760484Sobrien 177860484Sobrien symptr = 0; 1779130561Sobrien symtab = xmalloc (5 * sizeof (asymbol *)); 178060484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 178160484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 178260484Sobrien id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); 178377298Sobrien quick_symbol (abfd, U (""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); 178460484Sobrien 1785218822Sdim bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); 1786218822Sdim d4 = xmalloc (PE_IDATA4_SIZE); 178760484Sobrien id4->contents = d4; 1788218822Sdim memset (d4, 0, PE_IDATA4_SIZE); 178960484Sobrien 1790218822Sdim bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); 1791218822Sdim d5 = xmalloc (PE_IDATA5_SIZE); 179260484Sobrien id5->contents = d5; 1793218822Sdim memset (d5, 0, PE_IDATA5_SIZE); 179460484Sobrien 179577298Sobrien len = strlen (dll_filename) + 1; 179660484Sobrien if (len & 1) 179777298Sobrien len++; 179860484Sobrien bfd_set_section_size (abfd, id7, len); 1799130561Sobrien d7 = xmalloc (len); 180060484Sobrien id7->contents = d7; 1801218822Sdim strcpy ((char *) d7, dll_filename); 1802218822Sdim /* If len was odd, the above 1803218822Sdim strcpy leaves behind an undefined byte. That is harmless, 1804218822Sdim but we set it to 0 just so the binary dumps are pretty. */ 1805218822Sdim d7[len - 1] = 0; 180660484Sobrien 180760484Sobrien bfd_set_symtab (abfd, symtab, symptr); 180860484Sobrien 1809218822Sdim bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); 1810218822Sdim bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); 181160484Sobrien bfd_set_section_contents (abfd, id7, d7, 0, len); 181260484Sobrien 181360484Sobrien bfd_make_readable (abfd); 181460484Sobrien return abfd; 181560484Sobrien} 181660484Sobrien 181789857Sobrien/* .text 181889857Sobrien .global _function 181989857Sobrien .global ___imp_function 182089857Sobrien .global __imp__function 182189857Sobrien _function: 182289857Sobrien jmp *__imp__function: 1823104834Sobrien 182489857Sobrien .section idata$7 182589857Sobrien .long __head_my_dll 1826104834Sobrien 182789857Sobrien .section .idata$5 182889857Sobrien ___imp_function: 182989857Sobrien __imp__function: 183089857Sobrien iat? 183189857Sobrien .section .idata$4 183289857Sobrien iat? 183389857Sobrien .section .idata$6 183489857Sobrien ID<ordinal>: 183589857Sobrien .short <hint> 183689857Sobrien .asciz "function" xlate? (add underscore, kill at) */ 183760484Sobrien 1838218822Sdimstatic const unsigned char jmp_ix86_bytes[] = 183989857Sobrien{ 184060484Sobrien 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 184160484Sobrien}; 184260484Sobrien 184389857Sobrien/* _function: 184489857Sobrien mov.l ip+8,r0 184589857Sobrien mov.l @r0,r0 184689857Sobrien jmp @r0 184789857Sobrien nop 184889857Sobrien .dw __imp_function */ 184960484Sobrien 1850218822Sdimstatic const unsigned char jmp_sh_bytes[] = 185189857Sobrien{ 185260484Sobrien 0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 185360484Sobrien}; 185460484Sobrien 185589857Sobrien/* _function: 185689857Sobrien lui $t0,<high:__imp_function> 185789857Sobrien lw $t0,<low:__imp_function> 185889857Sobrien jr $t0 185989857Sobrien nop */ 186060484Sobrien 1861218822Sdimstatic const unsigned char jmp_mips_bytes[] = 186289857Sobrien{ 186360484Sobrien 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d, 186460484Sobrien 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 186560484Sobrien}; 186660484Sobrien 1867218822Sdimstatic const unsigned char jmp_arm_bytes[] = 1868218822Sdim{ 1869218822Sdim 0x00, 0xc0, 0x9f, 0xe5, /* ldr ip, [pc] */ 1870218822Sdim 0x00, 0xf0, 0x9c, 0xe5, /* ldr pc, [ip] */ 1871218822Sdim 0, 0, 0, 0 1872218822Sdim}; 1873218822Sdim 1874218822Sdim 187560484Sobrienstatic bfd * 1876218822Sdimmake_one (def_file_export *exp, bfd *parent, bfd_boolean include_jmp_stub) 187760484Sobrien{ 187860484Sobrien asection *tx, *id7, *id5, *id4, *id6; 187977298Sobrien unsigned char *td = NULL, *d7, *d5, *d4, *d6 = NULL; 188060484Sobrien int len; 188160484Sobrien char *oname; 188260484Sobrien bfd *abfd; 1883218822Sdim const unsigned char *jmp_bytes = NULL; 188460484Sobrien int jmp_byte_count = 0; 188560484Sobrien 1886218822Sdim /* Include the jump stub section only if it is needed. A jump 1887218822Sdim stub is needed if the symbol being imported <sym> is a function 1888218822Sdim symbol and there is at least one undefined reference to that 1889218822Sdim symbol. In other words, if all the import references to <sym> are 1890218822Sdim explicitly through _declspec(dllimport) then the jump stub is not 1891218822Sdim needed. */ 1892218822Sdim if (include_jmp_stub) 189360484Sobrien { 1894218822Sdim switch (pe_details->pe_arch) 1895218822Sdim { 1896218822Sdim case PE_ARCH_i386: 1897218822Sdim jmp_bytes = jmp_ix86_bytes; 1898218822Sdim jmp_byte_count = sizeof (jmp_ix86_bytes); 1899218822Sdim break; 1900218822Sdim case PE_ARCH_sh: 1901218822Sdim jmp_bytes = jmp_sh_bytes; 1902218822Sdim jmp_byte_count = sizeof (jmp_sh_bytes); 1903218822Sdim break; 1904218822Sdim case PE_ARCH_mips: 1905218822Sdim jmp_bytes = jmp_mips_bytes; 1906218822Sdim jmp_byte_count = sizeof (jmp_mips_bytes); 1907218822Sdim break; 1908218822Sdim case PE_ARCH_arm: 1909218822Sdim case PE_ARCH_arm_epoc: 1910218822Sdim case PE_ARCH_arm_wince: 1911218822Sdim jmp_bytes = jmp_arm_bytes; 1912218822Sdim jmp_byte_count = sizeof (jmp_arm_bytes); 1913218822Sdim break; 1914218822Sdim default: 1915218822Sdim abort (); 1916218822Sdim } 191760484Sobrien } 191860484Sobrien 1919130561Sobrien oname = xmalloc (20); 192060484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 192160484Sobrien tmp_seq++; 192260484Sobrien 192360484Sobrien abfd = bfd_create (oname, parent); 192460484Sobrien bfd_find_target (pe_details->object_target, abfd); 192560484Sobrien bfd_make_writable (abfd); 192660484Sobrien 192760484Sobrien bfd_set_format (abfd, bfd_object); 192860484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 192960484Sobrien 193060484Sobrien symptr = 0; 1931130561Sobrien symtab = xmalloc (11 * sizeof (asymbol *)); 193260484Sobrien tx = quick_section (abfd, ".text", SEC_CODE|SEC_HAS_CONTENTS, 2); 193360484Sobrien id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); 193460484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 193560484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 193660484Sobrien id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); 1937130561Sobrien 1938130561Sobrien if (*exp->internal_name == '@') 1939130561Sobrien { 1940130561Sobrien quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, 1941130561Sobrien BSF_GLOBAL, 0); 1942218822Sdim if (include_jmp_stub) 1943130561Sobrien quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0); 1944218822Sdim quick_symbol (abfd, "__imp_", exp->internal_name, "", id5, 1945130561Sobrien BSF_GLOBAL, 0); 1946130561Sobrien /* Fastcall applies only to functions, 1947130561Sobrien so no need for auto-import symbol. */ 1948130561Sobrien } 1949130561Sobrien else 1950130561Sobrien { 1951130561Sobrien quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, 1952130561Sobrien BSF_GLOBAL, 0); 1953218822Sdim if (include_jmp_stub) 1954130561Sobrien quick_symbol (abfd, U (""), exp->internal_name, "", tx, 1955130561Sobrien BSF_GLOBAL, 0); 1956218822Sdim quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5, 1957130561Sobrien BSF_GLOBAL, 0); 1958130561Sobrien /* Symbol to reference ord/name of imported 1959130561Sobrien data symbol, used to implement auto-import. */ 1960130561Sobrien if (exp->flag_data) 1961218822Sdim quick_symbol (abfd, U ("_nm_"), U (""), exp->internal_name, id6, 1962130561Sobrien BSF_GLOBAL,0); 1963130561Sobrien } 196460484Sobrien if (pe_dll_compat_implib) 1965130561Sobrien quick_symbol (abfd, U ("__imp_"), exp->internal_name, "", id5, 1966130561Sobrien BSF_GLOBAL, 0); 196760484Sobrien 1968218822Sdim if (include_jmp_stub) 196989857Sobrien { 197089857Sobrien bfd_set_section_size (abfd, tx, jmp_byte_count); 1971130561Sobrien td = xmalloc (jmp_byte_count); 197289857Sobrien tx->contents = td; 197389857Sobrien memcpy (td, jmp_bytes, jmp_byte_count); 197460484Sobrien 197589857Sobrien switch (pe_details->pe_arch) 197689857Sobrien { 197789857Sobrien case PE_ARCH_i386: 1978218822Sdim#ifdef pe_use_x86_64 1979218822Sdim quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2); 1980218822Sdim#else 1981218822Sdim quick_reloc (abfd, 2, BFD_RELOC_32, 2); 1982218822Sdim#endif 198389857Sobrien break; 198489857Sobrien case PE_ARCH_sh: 198589857Sobrien quick_reloc (abfd, 8, BFD_RELOC_32, 2); 198689857Sobrien break; 198789857Sobrien case PE_ARCH_mips: 198889857Sobrien quick_reloc (abfd, 0, BFD_RELOC_HI16_S, 2); 198989857Sobrien quick_reloc (abfd, 0, BFD_RELOC_LO16, 0); /* MIPS_R_PAIR */ 199089857Sobrien quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); 199189857Sobrien break; 1992218822Sdim case PE_ARCH_arm: 1993218822Sdim case PE_ARCH_arm_epoc: 1994218822Sdim case PE_ARCH_arm_wince: 1995218822Sdim quick_reloc (abfd, 8, BFD_RELOC_32, 2); 1996218822Sdim break; 199789857Sobrien default: 199889857Sobrien abort (); 199989857Sobrien } 200089857Sobrien save_relocs (tx); 200189857Sobrien } 2002218822Sdim else 2003218822Sdim bfd_set_section_size (abfd, tx, 0); 200489857Sobrien 200560484Sobrien bfd_set_section_size (abfd, id7, 4); 2006130561Sobrien d7 = xmalloc (4); 200760484Sobrien id7->contents = d7; 200860484Sobrien memset (d7, 0, 4); 2009130561Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); 201060484Sobrien save_relocs (id7); 201160484Sobrien 2012218822Sdim bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); 2013218822Sdim d5 = xmalloc (PE_IDATA5_SIZE); 201460484Sobrien id5->contents = d5; 2015218822Sdim memset (d5, 0, PE_IDATA5_SIZE); 201689857Sobrien 201760484Sobrien if (exp->flag_noname) 201860484Sobrien { 201960484Sobrien d5[0] = exp->ordinal; 202060484Sobrien d5[1] = exp->ordinal >> 8; 2021218822Sdim d5[PE_IDATA5_SIZE - 1] = 0x80; 202260484Sobrien } 202360484Sobrien else 202460484Sobrien { 202560484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); 202660484Sobrien save_relocs (id5); 202760484Sobrien } 202860484Sobrien 2029218822Sdim bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); 2030218822Sdim d4 = xmalloc (PE_IDATA4_SIZE); 203160484Sobrien id4->contents = d4; 2032218822Sdim memset (d4, 0, PE_IDATA4_SIZE); 203389857Sobrien 203460484Sobrien if (exp->flag_noname) 203560484Sobrien { 203677298Sobrien d4[0] = exp->ordinal; 203777298Sobrien d4[1] = exp->ordinal >> 8; 2038218822Sdim d4[PE_IDATA4_SIZE - 1] = 0x80; 203960484Sobrien } 204060484Sobrien else 204160484Sobrien { 204260484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); 204360484Sobrien save_relocs (id4); 204460484Sobrien } 204560484Sobrien 204660484Sobrien if (exp->flag_noname) 204760484Sobrien { 204860484Sobrien len = 0; 204960484Sobrien bfd_set_section_size (abfd, id6, 0); 205060484Sobrien } 205160484Sobrien else 205260484Sobrien { 2053218822Sdim /* { short, asciz } */ 2054218822Sdim len = 2 + strlen (exp->name) + 1; 205560484Sobrien if (len & 1) 205660484Sobrien len++; 205760484Sobrien bfd_set_section_size (abfd, id6, len); 2058130561Sobrien d6 = xmalloc (len); 205960484Sobrien id6->contents = d6; 206060484Sobrien memset (d6, 0, len); 206160484Sobrien d6[0] = exp->hint & 0xff; 206260484Sobrien d6[1] = exp->hint >> 8; 2063218822Sdim strcpy ((char *) d6 + 2, exp->name); 206460484Sobrien } 206560484Sobrien 206660484Sobrien bfd_set_symtab (abfd, symtab, symptr); 206760484Sobrien 2068218822Sdim if (include_jmp_stub) 2069218822Sdim bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count); 207060484Sobrien bfd_set_section_contents (abfd, id7, d7, 0, 4); 2071218822Sdim bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); 2072218822Sdim bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); 207360484Sobrien if (!exp->flag_noname) 207460484Sobrien bfd_set_section_contents (abfd, id6, d6, 0, len); 207560484Sobrien 207660484Sobrien bfd_make_readable (abfd); 207760484Sobrien return abfd; 207860484Sobrien} 207960484Sobrien 208089857Sobrienstatic bfd * 2081130561Sobrienmake_singleton_name_thunk (const char *import, bfd *parent) 208289857Sobrien{ 208389857Sobrien /* Name thunks go to idata$4. */ 208489857Sobrien asection *id4; 208589857Sobrien unsigned char *d4; 208689857Sobrien char *oname; 208789857Sobrien bfd *abfd; 208889857Sobrien 2089130561Sobrien oname = xmalloc (20); 209089857Sobrien sprintf (oname, "nmth%06d.o", tmp_seq); 209189857Sobrien tmp_seq++; 209289857Sobrien 209389857Sobrien abfd = bfd_create (oname, parent); 209489857Sobrien bfd_find_target (pe_details->object_target, abfd); 209589857Sobrien bfd_make_writable (abfd); 209689857Sobrien 209789857Sobrien bfd_set_format (abfd, bfd_object); 209889857Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 209989857Sobrien 210089857Sobrien symptr = 0; 2101130561Sobrien symtab = xmalloc (3 * sizeof (asymbol *)); 210289857Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 210389857Sobrien quick_symbol (abfd, U ("_nm_thnk_"), import, "", id4, BSF_GLOBAL, 0); 210489857Sobrien quick_symbol (abfd, U ("_nm_"), import, "", UNDSEC, BSF_GLOBAL, 0); 210589857Sobrien 2106218822Sdim /* We need space for the real thunk and for the null terminator. */ 2107218822Sdim bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE * 2); 2108218822Sdim d4 = xmalloc (PE_IDATA4_SIZE * 2); 210989857Sobrien id4->contents = d4; 2110218822Sdim memset (d4, 0, PE_IDATA4_SIZE * 2); 211189857Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); 211289857Sobrien save_relocs (id4); 211389857Sobrien 211489857Sobrien bfd_set_symtab (abfd, symtab, symptr); 211589857Sobrien 2116218822Sdim bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE * 2); 211789857Sobrien 211889857Sobrien bfd_make_readable (abfd); 211989857Sobrien return abfd; 212089857Sobrien} 212189857Sobrien 212289857Sobrienstatic char * 2123130561Sobrienmake_import_fixup_mark (arelent *rel) 212489857Sobrien{ 212589857Sobrien /* We convert reloc to symbol, for later reference. */ 212689857Sobrien static int counter; 212789857Sobrien static char *fixup_name = NULL; 212889857Sobrien static size_t buffer_len = 0; 2129104834Sobrien 2130130561Sobrien struct bfd_symbol *sym = *rel->sym_ptr_ptr; 2131104834Sobrien 213289857Sobrien bfd *abfd = bfd_asymbol_bfd (sym); 2133107492Sobrien struct bfd_link_hash_entry *bh; 213489857Sobrien 213589857Sobrien if (!fixup_name) 213689857Sobrien { 2137130561Sobrien fixup_name = xmalloc (384); 213889857Sobrien buffer_len = 384; 213989857Sobrien } 214089857Sobrien 214189857Sobrien if (strlen (sym->name) + 25 > buffer_len) 2142104834Sobrien /* Assume 25 chars for "__fu" + counter + "_". If counter is 214389857Sobrien bigger than 20 digits long, we've got worse problems than 214489857Sobrien overflowing this buffer... */ 214589857Sobrien { 214689857Sobrien free (fixup_name); 2147130561Sobrien /* New buffer size is length of symbol, plus 25, but 2148130561Sobrien then rounded up to the nearest multiple of 128. */ 214989857Sobrien buffer_len = ((strlen (sym->name) + 25) + 127) & ~127; 2150130561Sobrien fixup_name = xmalloc (buffer_len); 215189857Sobrien } 2152104834Sobrien 215389857Sobrien sprintf (fixup_name, "__fu%d_%s", counter++, sym->name); 215489857Sobrien 2155107492Sobrien bh = NULL; 2156104834Sobrien bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, 215789857Sobrien current_sec, /* sym->section, */ 2158130561Sobrien rel->address, NULL, TRUE, FALSE, &bh); 215989857Sobrien 216089857Sobrien return fixup_name; 216189857Sobrien} 216289857Sobrien 2163218822Sdim/* .section .idata$2 216489857Sobrien .rva __nm_thnk_SYM (singleton thunk with name of func) 216589857Sobrien .long 0 216689857Sobrien .long 0 216789857Sobrien .rva __my_dll_iname (name of dll) 216889857Sobrien .rva __fuNN_SYM (pointer to reference (address) in text) */ 216989857Sobrien 217089857Sobrienstatic bfd * 2171130561Sobrienmake_import_fixup_entry (const char *name, 2172130561Sobrien const char *fixup_name, 2173130561Sobrien const char *dll_symname, 2174130561Sobrien bfd *parent) 217589857Sobrien{ 2176218822Sdim asection *id2; 2177218822Sdim unsigned char *d2; 217889857Sobrien char *oname; 217989857Sobrien bfd *abfd; 218089857Sobrien 2181130561Sobrien oname = xmalloc (20); 218289857Sobrien sprintf (oname, "fu%06d.o", tmp_seq); 218389857Sobrien tmp_seq++; 218489857Sobrien 218589857Sobrien abfd = bfd_create (oname, parent); 218689857Sobrien bfd_find_target (pe_details->object_target, abfd); 218789857Sobrien bfd_make_writable (abfd); 218889857Sobrien 218989857Sobrien bfd_set_format (abfd, bfd_object); 219089857Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 219189857Sobrien 219289857Sobrien symptr = 0; 2193130561Sobrien symtab = xmalloc (6 * sizeof (asymbol *)); 2194218822Sdim id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); 219589857Sobrien 219689857Sobrien quick_symbol (abfd, U ("_nm_thnk_"), name, "", UNDSEC, BSF_GLOBAL, 0); 219789857Sobrien quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); 219889857Sobrien quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); 219989857Sobrien 2200218822Sdim bfd_set_section_size (abfd, id2, 20); 2201218822Sdim d2 = xmalloc (20); 2202218822Sdim id2->contents = d2; 2203218822Sdim memset (d2, 0, 20); 220489857Sobrien 220589857Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); 220689857Sobrien quick_reloc (abfd, 12, BFD_RELOC_RVA, 2); 220789857Sobrien quick_reloc (abfd, 16, BFD_RELOC_RVA, 3); 2208218822Sdim save_relocs (id2); 220989857Sobrien 221089857Sobrien bfd_set_symtab (abfd, symtab, symptr); 221189857Sobrien 2212218822Sdim bfd_set_section_contents (abfd, id2, d2, 0, 20); 221389857Sobrien 221489857Sobrien bfd_make_readable (abfd); 221589857Sobrien return abfd; 221689857Sobrien} 221789857Sobrien 2218130561Sobrien/* .section .rdata_runtime_pseudo_reloc 2219130561Sobrien .long addend 2220130561Sobrien .rva __fuNN_SYM (pointer to reference (address) in text) */ 2221130561Sobrien 2222130561Sobrienstatic bfd * 2223130561Sobrienmake_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, 2224130561Sobrien const char *fixup_name, 2225130561Sobrien int addend, 2226130561Sobrien bfd *parent) 2227130561Sobrien{ 2228130561Sobrien asection *rt_rel; 2229130561Sobrien unsigned char *rt_rel_d; 2230130561Sobrien char *oname; 2231130561Sobrien bfd *abfd; 2232130561Sobrien 2233130561Sobrien oname = xmalloc (20); 2234130561Sobrien sprintf (oname, "rtr%06d.o", tmp_seq); 2235130561Sobrien tmp_seq++; 2236130561Sobrien 2237130561Sobrien abfd = bfd_create (oname, parent); 2238130561Sobrien bfd_find_target (pe_details->object_target, abfd); 2239130561Sobrien bfd_make_writable (abfd); 2240130561Sobrien 2241130561Sobrien bfd_set_format (abfd, bfd_object); 2242130561Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 2243130561Sobrien 2244130561Sobrien symptr = 0; 2245130561Sobrien symtab = xmalloc (2 * sizeof (asymbol *)); 2246130561Sobrien rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", 2247130561Sobrien SEC_HAS_CONTENTS, 2); 2248130561Sobrien 2249130561Sobrien quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); 2250130561Sobrien 2251130561Sobrien bfd_set_section_size (abfd, rt_rel, 8); 2252130561Sobrien rt_rel_d = xmalloc (8); 2253130561Sobrien rt_rel->contents = rt_rel_d; 2254130561Sobrien memset (rt_rel_d, 0, 8); 2255130561Sobrien bfd_put_32 (abfd, addend, rt_rel_d); 2256130561Sobrien 2257130561Sobrien quick_reloc (abfd, 4, BFD_RELOC_RVA, 1); 2258130561Sobrien save_relocs (rt_rel); 2259130561Sobrien 2260130561Sobrien bfd_set_symtab (abfd, symtab, symptr); 2261130561Sobrien 2262130561Sobrien bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8); 2263130561Sobrien 2264130561Sobrien bfd_make_readable (abfd); 2265130561Sobrien return abfd; 2266130561Sobrien} 2267130561Sobrien 2268130561Sobrien/* .section .rdata 2269130561Sobrien .rva __pei386_runtime_relocator */ 2270130561Sobrien 2271130561Sobrienstatic bfd * 2272130561Sobrienpe_create_runtime_relocator_reference (bfd *parent) 2273130561Sobrien{ 2274130561Sobrien asection *extern_rt_rel; 2275130561Sobrien unsigned char *extern_rt_rel_d; 2276130561Sobrien char *oname; 2277130561Sobrien bfd *abfd; 2278130561Sobrien 2279130561Sobrien oname = xmalloc (20); 2280130561Sobrien sprintf (oname, "ertr%06d.o", tmp_seq); 2281130561Sobrien tmp_seq++; 2282130561Sobrien 2283130561Sobrien abfd = bfd_create (oname, parent); 2284130561Sobrien bfd_find_target (pe_details->object_target, abfd); 2285130561Sobrien bfd_make_writable (abfd); 2286130561Sobrien 2287130561Sobrien bfd_set_format (abfd, bfd_object); 2288130561Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 2289130561Sobrien 2290130561Sobrien symptr = 0; 2291130561Sobrien symtab = xmalloc (2 * sizeof (asymbol *)); 2292130561Sobrien extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2); 2293130561Sobrien 2294218822Sdim quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC, 2295130561Sobrien BSF_NO_FLAGS, 0); 2296130561Sobrien 2297130561Sobrien bfd_set_section_size (abfd, extern_rt_rel, 4); 2298130561Sobrien extern_rt_rel_d = xmalloc (4); 2299130561Sobrien extern_rt_rel->contents = extern_rt_rel_d; 2300130561Sobrien 2301130561Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); 2302130561Sobrien save_relocs (extern_rt_rel); 2303130561Sobrien 2304130561Sobrien bfd_set_symtab (abfd, symtab, symptr); 2305130561Sobrien 2306130561Sobrien bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, 4); 2307130561Sobrien 2308130561Sobrien bfd_make_readable (abfd); 2309130561Sobrien return abfd; 2310130561Sobrien} 2311130561Sobrien 231260484Sobrienvoid 2313130561Sobrienpe_create_import_fixup (arelent *rel, asection *s, int addend) 231489857Sobrien{ 231589857Sobrien char buf[300]; 2316130561Sobrien struct bfd_symbol *sym = *rel->sym_ptr_ptr; 231789857Sobrien struct bfd_link_hash_entry *name_thunk_sym; 231889857Sobrien const char *name = sym->name; 231989857Sobrien char *fixup_name = make_import_fixup_mark (rel); 2320130561Sobrien bfd *b; 232189857Sobrien 232289857Sobrien sprintf (buf, U ("_nm_thnk_%s"), name); 232389857Sobrien 232489857Sobrien name_thunk_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); 232589857Sobrien 232689857Sobrien if (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined) 232789857Sobrien { 232889857Sobrien bfd *b = make_singleton_name_thunk (name, output_bfd); 232989857Sobrien add_bfd_to_link (b, b->filename, &link_info); 233089857Sobrien 233189857Sobrien /* If we ever use autoimport, we have to cast text section writable. */ 2332130561Sobrien config.text_read_only = FALSE; 2333130561Sobrien output_bfd->flags &= ~WP_TEXT; 233489857Sobrien } 233589857Sobrien 2336130561Sobrien if (addend == 0 || link_info.pei386_runtime_pseudo_reloc) 2337130561Sobrien { 2338130561Sobrien extern char * pe_data_import_dll; 2339130561Sobrien char * dll_symname = pe_data_import_dll ? pe_data_import_dll : "unknown"; 234089857Sobrien 2341130561Sobrien b = make_import_fixup_entry (name, fixup_name, dll_symname, output_bfd); 2342130561Sobrien add_bfd_to_link (b, b->filename, &link_info); 2343130561Sobrien } 2344130561Sobrien 2345130561Sobrien if (addend != 0) 2346130561Sobrien { 2347130561Sobrien if (link_info.pei386_runtime_pseudo_reloc) 2348130561Sobrien { 2349130561Sobrien if (pe_dll_extra_pe_debug) 2350130561Sobrien printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", 2351130561Sobrien fixup_name, addend); 2352130561Sobrien b = make_runtime_pseudo_reloc (name, fixup_name, addend, output_bfd); 2353130561Sobrien add_bfd_to_link (b, b->filename, &link_info); 2354130561Sobrien 2355130561Sobrien if (runtime_pseudo_relocs_created == 0) 2356130561Sobrien { 2357130561Sobrien b = pe_create_runtime_relocator_reference (output_bfd); 2358130561Sobrien add_bfd_to_link (b, b->filename, &link_info); 2359130561Sobrien } 2360130561Sobrien runtime_pseudo_relocs_created++; 2361130561Sobrien } 2362130561Sobrien else 2363130561Sobrien { 2364130561Sobrien einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), 2365130561Sobrien s->owner, s, rel->address, sym->name); 2366130561Sobrien einfo ("%X"); 2367130561Sobrien } 2368130561Sobrien } 236989857Sobrien} 237089857Sobrien 237189857Sobrien 237289857Sobrienvoid 2373130561Sobrienpe_dll_generate_implib (def_file *def, const char *impfilename) 237460484Sobrien{ 237560484Sobrien int i; 237660484Sobrien bfd *ar_head; 237760484Sobrien bfd *ar_tail; 237860484Sobrien bfd *outarch; 237960484Sobrien bfd *head = 0; 238060484Sobrien 238160484Sobrien dll_filename = (def->name) ? def->name : dll_name; 238260484Sobrien dll_symname = xstrdup (dll_filename); 238377298Sobrien for (i = 0; dll_symname[i]; i++) 238489857Sobrien if (!ISALNUM (dll_symname[i])) 238560484Sobrien dll_symname[i] = '_'; 238660484Sobrien 2387218822Sdim unlink_if_ordinary (impfilename); 238860484Sobrien 238960484Sobrien outarch = bfd_openw (impfilename, 0); 239060484Sobrien 239160484Sobrien if (!outarch) 239260484Sobrien { 239360484Sobrien /* xgettext:c-format */ 239460484Sobrien einfo (_("%XCan't open .lib file: %s\n"), impfilename); 239560484Sobrien return; 239660484Sobrien } 239760484Sobrien 239860484Sobrien /* xgettext:c-format */ 2399218822Sdim info_msg (_("Creating library file: %s\n"), impfilename); 2400218822Sdim 240160484Sobrien bfd_set_format (outarch, bfd_archive); 240260484Sobrien outarch->has_armap = 1; 240360484Sobrien 240477298Sobrien /* Work out a reasonable size of things to put onto one line. */ 240560484Sobrien ar_head = make_head (outarch); 240660484Sobrien 240777298Sobrien for (i = 0; i < def->num_exports; i++) 240860484Sobrien { 240977298Sobrien /* The import library doesn't know about the internal name. */ 241060484Sobrien char *internal = def->exports[i].internal_name; 241160484Sobrien bfd *n; 241289857Sobrien 2413130561Sobrien /* Don't add PRIVATE entries to import lib. */ 2414130561Sobrien if (pe_def_file->exports[i].flag_private) 2415130561Sobrien continue; 241660484Sobrien def->exports[i].internal_name = def->exports[i].name; 2417218822Sdim n = make_one (def->exports + i, outarch, 2418218822Sdim ! (def->exports + i)->flag_data); 2419218822Sdim n->archive_next = head; 242060484Sobrien head = n; 242160484Sobrien def->exports[i].internal_name = internal; 242260484Sobrien } 242360484Sobrien 242460484Sobrien ar_tail = make_tail (outarch); 242560484Sobrien 242660484Sobrien if (ar_head == NULL || ar_tail == NULL) 242760484Sobrien return; 242860484Sobrien 242977298Sobrien /* Now stick them all into the archive. */ 2430218822Sdim ar_head->archive_next = head; 2431218822Sdim ar_tail->archive_next = ar_head; 243260484Sobrien head = ar_tail; 243360484Sobrien 243460484Sobrien if (! bfd_set_archive_head (outarch, head)) 2435218822Sdim einfo ("%Xbfd_set_archive_head: %E\n"); 243677298Sobrien 243760484Sobrien if (! bfd_close (outarch)) 2438218822Sdim einfo ("%Xbfd_close %s: %E\n", impfilename); 243960484Sobrien 244060484Sobrien while (head != NULL) 244160484Sobrien { 2442218822Sdim bfd *n = head->archive_next; 244360484Sobrien bfd_close (head); 244460484Sobrien head = n; 244560484Sobrien } 244660484Sobrien} 244760484Sobrien 244860484Sobrienstatic void 2449130561Sobrienadd_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *link_info) 245060484Sobrien{ 245160484Sobrien lang_input_statement_type *fake_file; 245289857Sobrien 245360484Sobrien fake_file = lang_add_input_file (name, 245460484Sobrien lang_input_file_is_fake_enum, 245560484Sobrien NULL); 245660484Sobrien fake_file->the_bfd = abfd; 245760484Sobrien ldlang_add_file (fake_file); 245889857Sobrien 245960484Sobrien if (!bfd_link_add_symbols (abfd, link_info)) 2460218822Sdim einfo ("%Xaddsym %s: %E\n", name); 246160484Sobrien} 246260484Sobrien 246360484Sobrienvoid 2464130561Sobrienpe_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info) 246560484Sobrien{ 246660484Sobrien def_file_module *module; 246789857Sobrien 246877298Sobrien pe_dll_id_target (bfd_get_target (output_bfd)); 246960484Sobrien 247060484Sobrien if (!pe_def_file) 247160484Sobrien return; 247260484Sobrien 247360484Sobrien for (module = pe_def_file->modules; module; module = module->next) 247460484Sobrien { 247560484Sobrien int i, do_this_dll; 247660484Sobrien 247760484Sobrien dll_filename = module->name; 247860484Sobrien dll_symname = xstrdup (module->name); 247977298Sobrien for (i = 0; dll_symname[i]; i++) 248089857Sobrien if (!ISALNUM (dll_symname[i])) 248160484Sobrien dll_symname[i] = '_'; 248260484Sobrien 248360484Sobrien do_this_dll = 0; 248460484Sobrien 248577298Sobrien for (i = 0; i < pe_def_file->num_imports; i++) 248660484Sobrien if (pe_def_file->imports[i].module == module) 248760484Sobrien { 248860484Sobrien def_file_export exp; 248960484Sobrien struct bfd_link_hash_entry *blhe; 2490130561Sobrien int lead_at = (*pe_def_file->imports[i].internal_name == '@'); 2491130561Sobrien /* See if we need this import. */ 2492130561Sobrien size_t len = strlen (pe_def_file->imports[i].internal_name); 2493130561Sobrien char *name = xmalloc (len + 2 + 6); 2494218822Sdim bfd_boolean include_jmp_stub = FALSE; 249560484Sobrien 2496130561Sobrien if (lead_at) 2497218822Sdim sprintf (name, "%s", 2498130561Sobrien pe_def_file->imports[i].internal_name); 2499130561Sobrien else 2500130561Sobrien sprintf (name, "%s%s",U (""), 2501130561Sobrien pe_def_file->imports[i].internal_name); 2502130561Sobrien 250360484Sobrien blhe = bfd_link_hash_lookup (link_info->hash, name, 2504130561Sobrien FALSE, FALSE, FALSE); 2505130561Sobrien 2506218822Sdim /* Include the jump stub for <sym> only if the <sym> 2507218822Sdim is undefined. */ 250877298Sobrien if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)) 250977298Sobrien { 2510130561Sobrien if (lead_at) 2511218822Sdim sprintf (name, "%s%s", "__imp_", 2512130561Sobrien pe_def_file->imports[i].internal_name); 2513130561Sobrien else 2514218822Sdim sprintf (name, "%s%s%s", "__imp_", U (""), 2515130561Sobrien pe_def_file->imports[i].internal_name); 2516130561Sobrien 251777298Sobrien blhe = bfd_link_hash_lookup (link_info->hash, name, 2518130561Sobrien FALSE, FALSE, FALSE); 251977298Sobrien } 2520218822Sdim else 2521218822Sdim include_jmp_stub = TRUE; 2522218822Sdim 252360484Sobrien free (name); 2524130561Sobrien 252560484Sobrien if (blhe && blhe->type == bfd_link_hash_undefined) 252660484Sobrien { 252760484Sobrien bfd *one; 252877298Sobrien /* We do. */ 252960484Sobrien if (!do_this_dll) 253060484Sobrien { 253160484Sobrien bfd *ar_head = make_head (output_bfd); 253260484Sobrien add_bfd_to_link (ar_head, ar_head->filename, link_info); 253360484Sobrien do_this_dll = 1; 253460484Sobrien } 253560484Sobrien exp.internal_name = pe_def_file->imports[i].internal_name; 253660484Sobrien exp.name = pe_def_file->imports[i].name; 253760484Sobrien exp.ordinal = pe_def_file->imports[i].ordinal; 253860484Sobrien exp.hint = exp.ordinal >= 0 ? exp.ordinal : 0; 253960484Sobrien exp.flag_private = 0; 254060484Sobrien exp.flag_constant = 0; 2541130561Sobrien exp.flag_data = pe_def_file->imports[i].data; 254260484Sobrien exp.flag_noname = exp.name ? 0 : 1; 2543218822Sdim one = make_one (&exp, output_bfd, (! exp.flag_data) && include_jmp_stub); 254460484Sobrien add_bfd_to_link (one, one->filename, link_info); 254560484Sobrien } 254660484Sobrien } 254760484Sobrien if (do_this_dll) 254860484Sobrien { 254960484Sobrien bfd *ar_tail = make_tail (output_bfd); 255060484Sobrien add_bfd_to_link (ar_tail, ar_tail->filename, link_info); 255160484Sobrien } 255260484Sobrien 255360484Sobrien free (dll_symname); 255460484Sobrien } 255560484Sobrien} 255660484Sobrien 255789857Sobrien/* We were handed a *.DLL file. Parse it and turn it into a set of 2558130561Sobrien IMPORTS directives in the def file. Return TRUE if the file was 2559130561Sobrien handled, FALSE if not. */ 256060484Sobrien 256160484Sobrienstatic unsigned int 2562130561Sobrienpe_get16 (bfd *abfd, int where) 256360484Sobrien{ 256460484Sobrien unsigned char b[2]; 256589857Sobrien 256689857Sobrien bfd_seek (abfd, (file_ptr) where, SEEK_SET); 256789857Sobrien bfd_bread (b, (bfd_size_type) 2, abfd); 256877298Sobrien return b[0] + (b[1] << 8); 256960484Sobrien} 257060484Sobrien 257160484Sobrienstatic unsigned int 2572130561Sobrienpe_get32 (bfd *abfd, int where) 257360484Sobrien{ 257460484Sobrien unsigned char b[4]; 257589857Sobrien 257689857Sobrien bfd_seek (abfd, (file_ptr) where, SEEK_SET); 257789857Sobrien bfd_bread (b, (bfd_size_type) 4, abfd); 257877298Sobrien return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); 257960484Sobrien} 258060484Sobrien 258160484Sobrienstatic unsigned int 2582130561Sobrienpe_as32 (void *ptr) 258360484Sobrien{ 258460484Sobrien unsigned char *b = ptr; 258589857Sobrien 258677298Sobrien return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); 258760484Sobrien} 258860484Sobrien 2589130561Sobrienbfd_boolean 2590130561Sobrienpe_implied_import_dll (const char *filename) 259160484Sobrien{ 259260484Sobrien bfd *dll; 259360484Sobrien unsigned long pe_header_offset, opthdr_ofs, num_entries, i; 259460484Sobrien unsigned long export_rva, export_size, nsections, secptr, expptr; 2595130561Sobrien unsigned long exp_funcbase; 2596218822Sdim unsigned char *expdata; 2597218822Sdim char *erva; 259860484Sobrien unsigned long name_rvas, ordinals, nexp, ordbase; 259960484Sobrien const char *dll_name; 2600130561Sobrien /* Initialization with start > end guarantees that is_data 2601130561Sobrien will not be set by mistake, and avoids compiler warning. */ 2602130561Sobrien unsigned long data_start = 1; 2603130561Sobrien unsigned long data_end = 0; 2604130561Sobrien unsigned long rdata_start = 1; 2605130561Sobrien unsigned long rdata_end = 0; 2606130561Sobrien unsigned long bss_start = 1; 2607130561Sobrien unsigned long bss_end = 0; 260860484Sobrien 260960484Sobrien /* No, I can't use bfd here. kernel32.dll puts its export table in 261077298Sobrien the middle of the .rdata section. */ 261160484Sobrien dll = bfd_openr (filename, pe_details->target_name); 261260484Sobrien if (!dll) 261360484Sobrien { 2614218822Sdim einfo ("%Xopen %s: %E\n", filename); 2615130561Sobrien return FALSE; 261660484Sobrien } 261789857Sobrien 261877298Sobrien /* PEI dlls seem to be bfd_objects. */ 261960484Sobrien if (!bfd_check_format (dll, bfd_object)) 262060484Sobrien { 262160484Sobrien einfo ("%X%s: this doesn't appear to be a DLL\n", filename); 2622130561Sobrien return FALSE; 262360484Sobrien } 262460484Sobrien 2625130561Sobrien /* Get pe_header, optional header and numbers of export entries. */ 262660484Sobrien pe_header_offset = pe_get32 (dll, 0x3c); 262760484Sobrien opthdr_ofs = pe_header_offset + 4 + 20; 2628218822Sdim#ifdef pe_use_x86_64 2629218822Sdim num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /* & NumberOfRvaAndSizes. */ 2630218822Sdim#else 263160484Sobrien num_entries = pe_get32 (dll, opthdr_ofs + 92); 2632218822Sdim#endif 263389857Sobrien 263489857Sobrien if (num_entries < 1) /* No exports. */ 2635130561Sobrien return FALSE; 263689857Sobrien 2637218822Sdim#ifdef pe_use_x86_64 2638218822Sdim export_rva = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4); 2639218822Sdim export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4); 2640218822Sdim#else 264160484Sobrien export_rva = pe_get32 (dll, opthdr_ofs + 96); 264260484Sobrien export_size = pe_get32 (dll, opthdr_ofs + 100); 2643218822Sdim#endif 2644218822Sdim 264560484Sobrien nsections = pe_get16 (dll, pe_header_offset + 4 + 2); 264660484Sobrien secptr = (pe_header_offset + 4 + 20 + 264760484Sobrien pe_get16 (dll, pe_header_offset + 4 + 16)); 264860484Sobrien expptr = 0; 264989857Sobrien 2650130561Sobrien /* Get the rva and size of the export section. */ 265177298Sobrien for (i = 0; i < nsections; i++) 265260484Sobrien { 265360484Sobrien char sname[8]; 265460484Sobrien unsigned long secptr1 = secptr + 40 * i; 265560484Sobrien unsigned long vaddr = pe_get32 (dll, secptr1 + 12); 265660484Sobrien unsigned long vsize = pe_get32 (dll, secptr1 + 16); 265760484Sobrien unsigned long fptr = pe_get32 (dll, secptr1 + 20); 265889857Sobrien 265989857Sobrien bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); 266089857Sobrien bfd_bread (sname, (bfd_size_type) 8, dll); 266189857Sobrien 266277298Sobrien if (vaddr <= export_rva && vaddr + vsize > export_rva) 266360484Sobrien { 266460484Sobrien expptr = fptr + (export_rva - vaddr); 266560484Sobrien if (export_rva + export_size > vaddr + vsize) 266660484Sobrien export_size = vsize - (export_rva - vaddr); 266760484Sobrien break; 266860484Sobrien } 266960484Sobrien } 267060484Sobrien 2671130561Sobrien /* Scan sections and store the base and size of the 2672130561Sobrien data and bss segments in data/base_start/end. */ 2673130561Sobrien for (i = 0; i < nsections; i++) 2674130561Sobrien { 2675130561Sobrien unsigned long secptr1 = secptr + 40 * i; 2676130561Sobrien unsigned long vsize = pe_get32 (dll, secptr1 + 8); 2677130561Sobrien unsigned long vaddr = pe_get32 (dll, secptr1 + 12); 2678130561Sobrien unsigned long flags = pe_get32 (dll, secptr1 + 36); 2679130561Sobrien char sec_name[9]; 2680130561Sobrien 2681130561Sobrien sec_name[8] = '\0'; 2682130561Sobrien bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); 2683130561Sobrien bfd_bread (sec_name, (bfd_size_type) 8, dll); 2684130561Sobrien 2685130561Sobrien if (strcmp(sec_name,".data") == 0) 2686130561Sobrien { 2687130561Sobrien data_start = vaddr; 2688130561Sobrien data_end = vaddr + vsize; 2689130561Sobrien 2690130561Sobrien if (pe_dll_extra_pe_debug) 2691130561Sobrien printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", 2692130561Sobrien __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); 2693130561Sobrien } 2694130561Sobrien else if (strcmp(sec_name,".rdata") == 0) 2695130561Sobrien { 2696130561Sobrien rdata_start = vaddr; 2697130561Sobrien rdata_end = vaddr + vsize; 2698130561Sobrien 2699130561Sobrien if (pe_dll_extra_pe_debug) 2700130561Sobrien printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", 2701130561Sobrien __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); 2702130561Sobrien } 2703130561Sobrien else if (strcmp (sec_name,".bss") == 0) 2704130561Sobrien { 2705130561Sobrien bss_start = vaddr; 2706130561Sobrien bss_end = vaddr + vsize; 2707130561Sobrien 2708130561Sobrien if (pe_dll_extra_pe_debug) 2709130561Sobrien printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", 2710130561Sobrien __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); 2711130561Sobrien } 2712130561Sobrien } 2713130561Sobrien 2714130561Sobrien expdata = xmalloc (export_size); 271589857Sobrien bfd_seek (dll, (file_ptr) expptr, SEEK_SET); 271689857Sobrien bfd_bread (expdata, (bfd_size_type) export_size, dll); 2717218822Sdim erva = (char *) expdata - export_rva; 271860484Sobrien 271960484Sobrien if (pe_def_file == 0) 272077298Sobrien pe_def_file = def_file_empty (); 272160484Sobrien 272277298Sobrien nexp = pe_as32 (expdata + 24); 272377298Sobrien name_rvas = pe_as32 (expdata + 32); 272477298Sobrien ordinals = pe_as32 (expdata + 36); 272577298Sobrien ordbase = pe_as32 (expdata + 16); 2726130561Sobrien exp_funcbase = pe_as32 (expdata + 28); 272789857Sobrien 2728130561Sobrien /* Use internal dll name instead of filename 2729130561Sobrien to enable symbolic dll linking. */ 2730218822Sdim dll_name = erva + pe_as32 (expdata + 12); 2731130561Sobrien 2732130561Sobrien /* Check to see if the dll has already been added to 2733130561Sobrien the definition list and if so return without error. 2734130561Sobrien This avoids multiple symbol definitions. */ 2735130561Sobrien if (def_get_module (pe_def_file, dll_name)) 2736130561Sobrien { 2737130561Sobrien if (pe_dll_extra_pe_debug) 2738130561Sobrien printf ("%s is already loaded\n", dll_name); 2739130561Sobrien return TRUE; 2740130561Sobrien } 2741130561Sobrien 2742130561Sobrien /* Iterate through the list of symbols. */ 274377298Sobrien for (i = 0; i < nexp; i++) 274460484Sobrien { 2745130561Sobrien /* Pointer to the names vector. */ 274677298Sobrien unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); 274760484Sobrien def_file_import *imp; 2748130561Sobrien /* Pointer to the function address vector. */ 2749130561Sobrien unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4); 2750130561Sobrien int is_data = 0; 275189857Sobrien 2752130561Sobrien /* Skip unwanted symbols, which are 2753130561Sobrien exported in buggy auto-import releases. */ 2754218822Sdim if (! CONST_STRNEQ (erva + name_rva, "_nm_")) 2755130561Sobrien { 2756130561Sobrien /* is_data is true if the address is in the data, rdata or bss 2757130561Sobrien segment. */ 2758130561Sobrien is_data = 2759130561Sobrien (func_rva >= data_start && func_rva < data_end) 2760130561Sobrien || (func_rva >= rdata_start && func_rva < rdata_end) 2761130561Sobrien || (func_rva >= bss_start && func_rva < bss_end); 2762130561Sobrien 2763130561Sobrien imp = def_file_add_import (pe_def_file, erva + name_rva, 2764130561Sobrien dll_name, i, 0); 2765130561Sobrien /* Mark symbol type. */ 2766130561Sobrien imp->data = is_data; 2767130561Sobrien 2768130561Sobrien if (pe_dll_extra_pe_debug) 2769130561Sobrien printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", 2770130561Sobrien __FUNCTION__, dll_name, erva + name_rva, 2771130561Sobrien func_rva, is_data ? "(data)" : ""); 2772130561Sobrien } 277360484Sobrien } 277460484Sobrien 2775130561Sobrien return TRUE; 277660484Sobrien} 277760484Sobrien 277889857Sobrien/* These are the main functions, called from the emulation. The first 277989857Sobrien is called after the bfds are read, so we can guess at how much space 278089857Sobrien we need. The second is called after everything is placed, so we 278189857Sobrien can put the right values in place. */ 278260484Sobrien 278360484Sobrienvoid 2784130561Sobrienpe_dll_build_sections (bfd *abfd, struct bfd_link_info *info) 278560484Sobrien{ 278660484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 278760484Sobrien process_def_file (abfd, info); 278860484Sobrien 2789130561Sobrien if (pe_def_file->num_exports == 0 && !info->shared) 2790130561Sobrien return; 2791130561Sobrien 279260484Sobrien generate_edata (abfd, info); 279360484Sobrien build_filler_bfd (1); 279460484Sobrien} 279560484Sobrien 279660484Sobrienvoid 2797130561Sobrienpe_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) 279860484Sobrien{ 279960484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 280060484Sobrien build_filler_bfd (0); 280160484Sobrien} 280260484Sobrien 280360484Sobrienvoid 2804130561Sobrienpe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info) 280560484Sobrien{ 280660484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 280760484Sobrien image_base = pe_data (abfd)->pe_opthdr.ImageBase; 280860484Sobrien 280960484Sobrien generate_reloc (abfd, info); 281060484Sobrien if (reloc_sz > 0) 281160484Sobrien { 281260484Sobrien bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); 281360484Sobrien 281460484Sobrien /* Resize the sections. */ 2815218822Sdim lang_reset_memory_regions (); 2816218822Sdim lang_size_sections (NULL, TRUE); 281760484Sobrien 281860484Sobrien /* Redo special stuff. */ 281960484Sobrien ldemul_after_allocation (); 282060484Sobrien 282160484Sobrien /* Do the assignments again. */ 2822218822Sdim lang_do_assignments (); 282360484Sobrien } 282460484Sobrien 282560484Sobrien fill_edata (abfd, info); 282660484Sobrien 2827218822Sdim if (info->shared && !info->pie) 2828130561Sobrien pe_data (abfd)->dll = 1; 282960484Sobrien 283060484Sobrien edata_s->contents = edata_d; 283160484Sobrien reloc_s->contents = reloc_d; 283260484Sobrien} 283360484Sobrien 283460484Sobrienvoid 2835130561Sobrienpe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info) 283660484Sobrien{ 283760484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 283860484Sobrien image_base = pe_data (abfd)->pe_opthdr.ImageBase; 283960484Sobrien 284060484Sobrien generate_reloc (abfd, info); 284160484Sobrien if (reloc_sz > 0) 284260484Sobrien { 284360484Sobrien bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); 284460484Sobrien 284560484Sobrien /* Resize the sections. */ 2846218822Sdim lang_reset_memory_regions (); 2847218822Sdim lang_size_sections (NULL, TRUE); 284860484Sobrien 284960484Sobrien /* Redo special stuff. */ 285060484Sobrien ldemul_after_allocation (); 285160484Sobrien 285260484Sobrien /* Do the assignments again. */ 2853218822Sdim lang_do_assignments (); 285460484Sobrien } 285560484Sobrien reloc_s->contents = reloc_d; 285660484Sobrien} 2857218822Sdim 2858218822Sdimbfd_boolean 2859218822Sdimpe_bfd_is_dll (bfd *abfd) 2860218822Sdim{ 2861218822Sdim return (bfd_get_format (abfd) == bfd_object 2862218822Sdim && obj_pe (abfd) 2863218822Sdim && pe_data (abfd)->dll); 2864218822Sdim} 2865