pe-dll.c revision 60484
160484Sobrien/* Routines to help build PEI-format DLLs (Win32 etc) 260484Sobrien Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. 360484Sobrien Written by DJ Delorie <dj@cygnus.com> 460484Sobrien 560484Sobrien This file is part of GLD, the Gnu Linker. 660484Sobrien 760484Sobrien GLD is free software; you can redistribute it and/or modify 860484Sobrien it under the terms of the GNU General Public License as published by 960484Sobrien the Free Software Foundation; either version 2, or (at your option) 1060484Sobrien any later version. 1160484Sobrien 1260484Sobrien GLD is distributed in the hope that it will be useful, 1360484Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1460484Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1560484Sobrien GNU General Public License for more details. 1660484Sobrien 1760484Sobrien You should have received a copy of the GNU General Public License 1860484Sobrien along with GLD; see the file COPYING. If not, write to the Free 1960484Sobrien Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2060484Sobrien 02111-1307, USA. */ 2160484Sobrien 2260484Sobrien#include "bfd.h" 2360484Sobrien#include "sysdep.h" 2460484Sobrien#include "bfdlink.h" 2560484Sobrien#include "libiberty.h" 2660484Sobrien 2760484Sobrien#include <time.h> 2860484Sobrien#include <ctype.h> 2960484Sobrien 3060484Sobrien#include "ld.h" 3160484Sobrien#include "ldexp.h" 3260484Sobrien#include "ldlang.h" 3360484Sobrien#include "ldwrite.h" 3460484Sobrien#include "ldmisc.h" 3560484Sobrien#include "ldgram.h" 3660484Sobrien#include "ldmain.h" 3760484Sobrien#include "ldemul.h" 3860484Sobrien#include "coff/internal.h" 3960484Sobrien#include "../bfd/libcoff.h" 4060484Sobrien#include "deffile.h" 4160484Sobrien#include "pe-dll.h" 4260484Sobrien 4360484Sobrien/************************************************************************ 4460484Sobrien 4560484Sobrien This file turns a regular Windows PE image into a DLL. Because of 4660484Sobrien the complexity of this operation, it has been broken down into a 4760484Sobrien number of separate modules which are all called by the main function 4860484Sobrien at the end of this file. This function is not re-entrant and is 4960484Sobrien normally only called once, so static variables are used to reduce 5060484Sobrien the number of parameters and return values required. 5160484Sobrien 5260484Sobrien See also: ld/emultempl/pe.em 5360484Sobrien 5460484Sobrien ************************************************************************/ 5560484Sobrien 5660484Sobrien/* for emultempl/pe.em */ 5760484Sobrien 5860484Sobriendef_file *pe_def_file = 0; 5960484Sobrienint pe_dll_export_everything = 0; 6060484Sobrienint pe_dll_do_default_excludes = 1; 6160484Sobrienint pe_dll_kill_ats = 0; 6260484Sobrienint pe_dll_stdcall_aliases = 0; 6360484Sobrienint pe_dll_warn_dup_exports = 0; 6460484Sobrienint pe_dll_compat_implib = 0; 6560484Sobrien 6660484Sobrien/************************************************************************ 6760484Sobrien 6860484Sobrien static variables and types 6960484Sobrien 7060484Sobrien ************************************************************************/ 7160484Sobrien 7260484Sobrienstatic bfd_vma image_base; 7360484Sobrien 7460484Sobrienstatic bfd *filler_bfd; 7560484Sobrienstatic struct sec *edata_s, *reloc_s; 7660484Sobrienstatic unsigned char *edata_d, *reloc_d; 7760484Sobrienstatic size_t edata_sz, reloc_sz; 7860484Sobrien 7960484Sobrientypedef struct { 8060484Sobrien char *target_name; 8160484Sobrien char *object_target; 8260484Sobrien unsigned int imagebase_reloc; 8360484Sobrien int pe_arch; 8460484Sobrien int bfd_arch; 8560484Sobrien int underscored; 8660484Sobrien} pe_details_type; 8760484Sobrien 8860484Sobrien#define PE_ARCH_i386 1 8960484Sobrien#define PE_ARCH_sh 2 9060484Sobrien#define PE_ARCH_mips 3 9160484Sobrien#define PE_ARCH_arm 4 9260484Sobrien 9360484Sobrienstatic pe_details_type pe_detail_list[] = { 9460484Sobrien { 9560484Sobrien "pei-i386", 9660484Sobrien "pe-i386", 9760484Sobrien 7 /* R_IMAGEBASE */, 9860484Sobrien PE_ARCH_i386, 9960484Sobrien bfd_arch_i386, 10060484Sobrien 1 10160484Sobrien }, 10260484Sobrien { 10360484Sobrien "pei-shl", 10460484Sobrien "pe-shl", 10560484Sobrien 16 /* R_SH_IMAGEBASE */, 10660484Sobrien PE_ARCH_sh, 10760484Sobrien bfd_arch_sh, 10860484Sobrien 1 10960484Sobrien }, 11060484Sobrien { 11160484Sobrien "pei-mips", 11260484Sobrien "pe-mips", 11360484Sobrien 34 /* MIPS_R_RVA */, 11460484Sobrien PE_ARCH_mips, 11560484Sobrien bfd_arch_mips, 11660484Sobrien 0 11760484Sobrien }, 11860484Sobrien { 11960484Sobrien "pei-arm-little", 12060484Sobrien "pe-arm-little", 12160484Sobrien 11 /* ARM_RVA32 */, 12260484Sobrien PE_ARCH_arm, 12360484Sobrien bfd_arch_arm, 12460484Sobrien 0 12560484Sobrien }, 12660484Sobrien { NULL, NULL, 0, 0, 0, 0 } 12760484Sobrien}; 12860484Sobrien 12960484Sobrienstatic pe_details_type *pe_details; 13060484Sobrien 13160484Sobrien#define U(str) (pe_details->underscored ? "_" str : str) 13260484Sobrien 13360484Sobrienvoid 13460484Sobrienpe_dll_id_target (target) 13560484Sobrien const char *target; 13660484Sobrien{ 13760484Sobrien int i; 13860484Sobrien for (i=0; pe_detail_list[i].target_name; i++) 13960484Sobrien if (strcmp (pe_detail_list[i].target_name, target) == 0) 14060484Sobrien { 14160484Sobrien pe_details = pe_detail_list+i; 14260484Sobrien return; 14360484Sobrien } 14460484Sobrien einfo (_("%XUnsupported PEI architecture: %s\n"), target); 14560484Sobrien exit (1); 14660484Sobrien} 14760484Sobrien 14860484Sobrien/************************************************************************ 14960484Sobrien 15060484Sobrien Helper functions for qsort. Relocs must be sorted so that we can write 15160484Sobrien them out by pages. 15260484Sobrien 15360484Sobrien ************************************************************************/ 15460484Sobrien 15560484Sobrientypedef struct { 15660484Sobrien bfd_vma vma; 15760484Sobrien char type; 15860484Sobrien short extra; 15960484Sobrien} reloc_data_type; 16060484Sobrien 16160484Sobrienstatic int 16260484Sobrienreloc_sort (va, vb) 16360484Sobrien const void *va, *vb; 16460484Sobrien{ 16560484Sobrien bfd_vma a = ((reloc_data_type *) va)->vma; 16660484Sobrien bfd_vma b = ((reloc_data_type *) vb)->vma; 16760484Sobrien return (a > b) ? 1 : ((a < b) ? -1 : 0); 16860484Sobrien} 16960484Sobrien 17060484Sobrienstatic int 17160484Sobrienpe_export_sort (va, vb) 17260484Sobrien const void *va, *vb; 17360484Sobrien{ 17460484Sobrien def_file_export *a = (def_file_export *) va; 17560484Sobrien def_file_export *b = (def_file_export *) vb; 17660484Sobrien return strcmp (a->name, b->name); 17760484Sobrien} 17860484Sobrien 17960484Sobrien/************************************************************************ 18060484Sobrien 18160484Sobrien Read and process the .DEF file 18260484Sobrien 18360484Sobrien ************************************************************************/ 18460484Sobrien 18560484Sobrien/* These correspond to the entries in pe_def_file->exports[]. I use 18660484Sobrien exported_symbol_sections[i] to tag whether or not the symbol was 18760484Sobrien defined, since we can't export symbols we don't have. */ 18860484Sobrien 18960484Sobrienstatic bfd_vma *exported_symbol_offsets; 19060484Sobrienstatic struct sec **exported_symbol_sections; 19160484Sobrien 19260484Sobrienstatic int export_table_size; 19360484Sobrienstatic int count_exported; 19460484Sobrienstatic int count_exported_byname; 19560484Sobrienstatic int count_with_ordinals; 19660484Sobrienstatic const char *dll_name; 19760484Sobrienstatic int min_ordinal, max_ordinal; 19860484Sobrienstatic int *exported_symbols; 19960484Sobrien 20060484Sobrientypedef struct exclude_list_struct 20160484Sobrien { 20260484Sobrien char *string; 20360484Sobrien struct exclude_list_struct *next; 20460484Sobrien } 20560484Sobrienexclude_list_struct; 20660484Sobrienstatic struct exclude_list_struct *excludes = 0; 20760484Sobrien 20860484Sobrienvoid 20960484Sobrienpe_dll_add_excludes (new_excludes) 21060484Sobrien const char *new_excludes; 21160484Sobrien{ 21260484Sobrien char *local_copy; 21360484Sobrien char *exclude_string; 21460484Sobrien 21560484Sobrien local_copy = xstrdup (new_excludes); 21660484Sobrien 21760484Sobrien exclude_string = strtok (local_copy, ",:"); 21860484Sobrien for (; exclude_string; exclude_string = strtok (NULL, ",:")) 21960484Sobrien { 22060484Sobrien struct exclude_list_struct *new_exclude; 22160484Sobrien 22260484Sobrien new_exclude = ((struct exclude_list_struct *) 22360484Sobrien xmalloc (sizeof (struct exclude_list_struct))); 22460484Sobrien new_exclude->string = (char *) xmalloc (strlen (exclude_string) + 1); 22560484Sobrien strcpy (new_exclude->string, exclude_string); 22660484Sobrien new_exclude->next = excludes; 22760484Sobrien excludes = new_exclude; 22860484Sobrien } 22960484Sobrien 23060484Sobrien free (local_copy); 23160484Sobrien} 23260484Sobrien 23360484Sobrienstatic int 23460484Sobrienauto_export (d, n) 23560484Sobrien def_file *d; 23660484Sobrien const char *n; 23760484Sobrien{ 23860484Sobrien int i; 23960484Sobrien struct exclude_list_struct *ex; 24060484Sobrien for (i = 0; i < d->num_exports; i++) 24160484Sobrien if (strcmp (d->exports[i].name, n) == 0) 24260484Sobrien return 0; 24360484Sobrien if (pe_dll_do_default_excludes) 24460484Sobrien { 24560484Sobrien if (strcmp (n, "DllMain@12") == 0) 24660484Sobrien return 0; 24760484Sobrien if (strcmp (n, "DllEntryPoint@0") == 0) 24860484Sobrien return 0; 24960484Sobrien if (strcmp (n, "impure_ptr") == 0) 25060484Sobrien return 0; 25160484Sobrien } 25260484Sobrien for (ex = excludes; ex; ex = ex->next) 25360484Sobrien if (strcmp (n, ex->string) == 0) 25460484Sobrien return 0; 25560484Sobrien return 1; 25660484Sobrien} 25760484Sobrien 25860484Sobrienstatic void 25960484Sobrienprocess_def_file (abfd, info) 26060484Sobrien bfd *abfd ATTRIBUTE_UNUSED; 26160484Sobrien struct bfd_link_info *info; 26260484Sobrien{ 26360484Sobrien int i, j; 26460484Sobrien struct bfd_link_hash_entry *blhe; 26560484Sobrien bfd *b; 26660484Sobrien struct sec *s; 26760484Sobrien def_file_export *e=0; 26860484Sobrien 26960484Sobrien if (!pe_def_file) 27060484Sobrien pe_def_file = def_file_empty (); 27160484Sobrien 27260484Sobrien /* First, run around to all the objects looking for the .drectve 27360484Sobrien sections, and push those into the def file too */ 27460484Sobrien 27560484Sobrien for (b = info->input_bfds; b; b = b->link_next) 27660484Sobrien { 27760484Sobrien s = bfd_get_section_by_name (b, ".drectve"); 27860484Sobrien if (s) 27960484Sobrien { 28060484Sobrien int size = bfd_get_section_size_before_reloc (s); 28160484Sobrien char *buf = xmalloc (size); 28260484Sobrien bfd_get_section_contents (b, s, buf, 0, size); 28360484Sobrien def_file_add_directive (pe_def_file, buf, size); 28460484Sobrien free (buf); 28560484Sobrien } 28660484Sobrien } 28760484Sobrien 28860484Sobrien /* Now, maybe export everything else the default way */ 28960484Sobrien 29060484Sobrien if (pe_dll_export_everything || pe_def_file->num_exports == 0) 29160484Sobrien { 29260484Sobrien for (b = info->input_bfds; b; b = b->link_next) 29360484Sobrien { 29460484Sobrien asymbol **symbols; 29560484Sobrien int nsyms, symsize; 29660484Sobrien 29760484Sobrien symsize = bfd_get_symtab_upper_bound (b); 29860484Sobrien symbols = (asymbol **) xmalloc (symsize); 29960484Sobrien nsyms = bfd_canonicalize_symtab (b, symbols); 30060484Sobrien 30160484Sobrien for (j = 0; j < nsyms; j++) 30260484Sobrien { 30360484Sobrien if ((symbols[j]->flags & (BSF_FUNCTION | BSF_GLOBAL)) 30460484Sobrien == (BSF_FUNCTION | BSF_GLOBAL)) 30560484Sobrien { 30660484Sobrien const char *sn = symbols[j]->name; 30760484Sobrien if (*sn == '_') 30860484Sobrien sn++; 30960484Sobrien if (auto_export (pe_def_file, sn)) 31060484Sobrien def_file_add_export (pe_def_file, sn, 0, -1); 31160484Sobrien } 31260484Sobrien } 31360484Sobrien } 31460484Sobrien } 31560484Sobrien 31660484Sobrien#undef NE 31760484Sobrien#define NE pe_def_file->num_exports 31860484Sobrien 31960484Sobrien /* Canonicalize the export list */ 32060484Sobrien 32160484Sobrien if (pe_dll_kill_ats) 32260484Sobrien { 32360484Sobrien for (i = 0; i < NE; i++) 32460484Sobrien { 32560484Sobrien if (strchr (pe_def_file->exports[i].name, '@')) 32660484Sobrien { 32760484Sobrien /* This will preserve internal_name, which may have been pointing 32860484Sobrien to the same memory as name, or might not have */ 32960484Sobrien char *tmp = xstrdup (pe_def_file->exports[i].name); 33060484Sobrien *(strchr (tmp, '@')) = 0; 33160484Sobrien pe_def_file->exports[i].name = tmp; 33260484Sobrien } 33360484Sobrien } 33460484Sobrien } 33560484Sobrien 33660484Sobrien if (pe_dll_stdcall_aliases) 33760484Sobrien { 33860484Sobrien for (i = 0; i < NE; i++) 33960484Sobrien { 34060484Sobrien if (strchr (pe_def_file->exports[i].name, '@')) 34160484Sobrien { 34260484Sobrien char *tmp = xstrdup (pe_def_file->exports[i].name); 34360484Sobrien *(strchr (tmp, '@')) = 0; 34460484Sobrien if (auto_export (pe_def_file, tmp)) 34560484Sobrien def_file_add_export (pe_def_file, tmp, 34660484Sobrien pe_def_file->exports[i].internal_name, -1); 34760484Sobrien else 34860484Sobrien free (tmp); 34960484Sobrien } 35060484Sobrien } 35160484Sobrien } 35260484Sobrien 35360484Sobrien e = pe_def_file->exports; /* convenience, but watch out for it changing */ 35460484Sobrien 35560484Sobrien exported_symbol_offsets = (bfd_vma *) xmalloc (NE * sizeof (bfd_vma)); 35660484Sobrien exported_symbol_sections = (struct sec **) xmalloc (NE * sizeof (struct sec *)); 35760484Sobrien 35860484Sobrien memset (exported_symbol_sections, 0, NE * sizeof (struct sec *)); 35960484Sobrien max_ordinal = 0; 36060484Sobrien min_ordinal = 65536; 36160484Sobrien count_exported = 0; 36260484Sobrien count_exported_byname = 0; 36360484Sobrien count_with_ordinals = 0; 36460484Sobrien 36560484Sobrien qsort (pe_def_file->exports, NE, sizeof (pe_def_file->exports[0]), pe_export_sort); 36660484Sobrien for (i = 0, j = 0; i < NE; i++) 36760484Sobrien { 36860484Sobrien if (i > 0 && strcmp (e[i].name, e[i - 1].name) == 0) 36960484Sobrien { 37060484Sobrien /* This is a duplicate. */ 37160484Sobrien if (e[j - 1].ordinal != -1 37260484Sobrien && e[i].ordinal != -1 37360484Sobrien && e[j - 1].ordinal != e[i].ordinal) 37460484Sobrien { 37560484Sobrien if (pe_dll_warn_dup_exports) 37660484Sobrien /* xgettext:c-format */ 37760484Sobrien einfo (_("%XError, duplicate EXPORT with oridinals: %s (%d vs %d)\n"), 37860484Sobrien e[j - 1].name, e[j - 1].ordinal, e[i].ordinal); 37960484Sobrien } 38060484Sobrien else 38160484Sobrien { 38260484Sobrien if (pe_dll_warn_dup_exports) 38360484Sobrien /* xgettext:c-format */ 38460484Sobrien einfo (_("Warning, duplicate EXPORT: %s\n"), 38560484Sobrien e[j - 1].name); 38660484Sobrien } 38760484Sobrien if (e[i].ordinal) 38860484Sobrien e[j - 1].ordinal = e[i].ordinal; 38960484Sobrien e[j - 1].flag_private |= e[i].flag_private; 39060484Sobrien e[j - 1].flag_constant |= e[i].flag_constant; 39160484Sobrien e[j - 1].flag_noname |= e[i].flag_noname; 39260484Sobrien e[j - 1].flag_data |= e[i].flag_data; 39360484Sobrien } 39460484Sobrien else 39560484Sobrien { 39660484Sobrien if (i != j) 39760484Sobrien e[j] = e[i]; 39860484Sobrien j++; 39960484Sobrien } 40060484Sobrien } 40160484Sobrien pe_def_file->num_exports = j; /* == NE */ 40260484Sobrien 40360484Sobrien for (i = 0; i < NE; i++) 40460484Sobrien { 40560484Sobrien char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); 40660484Sobrien if (pe_details->underscored) 40760484Sobrien { 40860484Sobrien *name = '_'; 40960484Sobrien strcpy (name + 1, pe_def_file->exports[i].internal_name); 41060484Sobrien } 41160484Sobrien else 41260484Sobrien strcpy (name, pe_def_file->exports[i].internal_name); 41360484Sobrien 41460484Sobrien blhe = bfd_link_hash_lookup (info->hash, 41560484Sobrien name, 41660484Sobrien false, false, true); 41760484Sobrien 41860484Sobrien if (blhe 41960484Sobrien && (blhe->type == bfd_link_hash_defined 42060484Sobrien || (blhe->type == bfd_link_hash_common))) 42160484Sobrien { 42260484Sobrien count_exported++; 42360484Sobrien if (!pe_def_file->exports[i].flag_noname) 42460484Sobrien count_exported_byname++; 42560484Sobrien 42660484Sobrien /* Only fill in the sections. The actual offsets are computed 42760484Sobrien in fill_exported_offsets() after common symbols are laid 42860484Sobrien out. */ 42960484Sobrien if (blhe->type == bfd_link_hash_defined) 43060484Sobrien exported_symbol_sections[i] = blhe->u.def.section; 43160484Sobrien else 43260484Sobrien exported_symbol_sections[i] = blhe->u.c.p->section; 43360484Sobrien 43460484Sobrien if (pe_def_file->exports[i].ordinal != -1) 43560484Sobrien { 43660484Sobrien if (max_ordinal < pe_def_file->exports[i].ordinal) 43760484Sobrien max_ordinal = pe_def_file->exports[i].ordinal; 43860484Sobrien if (min_ordinal > pe_def_file->exports[i].ordinal) 43960484Sobrien min_ordinal = pe_def_file->exports[i].ordinal; 44060484Sobrien count_with_ordinals++; 44160484Sobrien } 44260484Sobrien } 44360484Sobrien else if (blhe && blhe->type == bfd_link_hash_undefined) 44460484Sobrien { 44560484Sobrien /* xgettext:c-format */ 44660484Sobrien einfo (_("%XCannot export %s: symbol not defined\n"), 44760484Sobrien pe_def_file->exports[i].internal_name); 44860484Sobrien } 44960484Sobrien else if (blhe) 45060484Sobrien { 45160484Sobrien /* xgettext:c-format */ 45260484Sobrien einfo (_("%XCannot export %s: symbol wrong type (%d vs %d)\n"), 45360484Sobrien pe_def_file->exports[i].internal_name, 45460484Sobrien blhe->type, bfd_link_hash_defined); 45560484Sobrien } 45660484Sobrien else 45760484Sobrien { 45860484Sobrien /* xgettext:c-format */ 45960484Sobrien einfo (_("%XCannot export %s: symbol not found\n"), 46060484Sobrien pe_def_file->exports[i].internal_name); 46160484Sobrien } 46260484Sobrien free (name); 46360484Sobrien } 46460484Sobrien} 46560484Sobrien 46660484Sobrien/************************************************************************ 46760484Sobrien 46860484Sobrien Build the bfd that will contain .edata and .reloc sections 46960484Sobrien 47060484Sobrien ************************************************************************/ 47160484Sobrien 47260484Sobrienstatic void 47360484Sobrienbuild_filler_bfd (include_edata) 47460484Sobrien int include_edata; 47560484Sobrien{ 47660484Sobrien lang_input_statement_type *filler_file; 47760484Sobrien filler_file = lang_add_input_file ("dll stuff", 47860484Sobrien lang_input_file_is_fake_enum, 47960484Sobrien NULL); 48060484Sobrien filler_file->the_bfd = filler_bfd = bfd_create ("dll stuff", output_bfd); 48160484Sobrien if (filler_bfd == NULL 48260484Sobrien || !bfd_set_arch_mach (filler_bfd, 48360484Sobrien bfd_get_arch (output_bfd), 48460484Sobrien bfd_get_mach (output_bfd))) 48560484Sobrien { 48660484Sobrien einfo ("%X%P: can not create BFD %E\n"); 48760484Sobrien return; 48860484Sobrien } 48960484Sobrien 49060484Sobrien if (include_edata) 49160484Sobrien { 49260484Sobrien edata_s = bfd_make_section_old_way (filler_bfd, ".edata"); 49360484Sobrien if (edata_s == NULL 49460484Sobrien || !bfd_set_section_flags (filler_bfd, edata_s, 49560484Sobrien (SEC_HAS_CONTENTS 49660484Sobrien | SEC_ALLOC 49760484Sobrien | SEC_LOAD 49860484Sobrien | SEC_KEEP 49960484Sobrien | SEC_IN_MEMORY))) 50060484Sobrien { 50160484Sobrien einfo ("%X%P: can not create .edata section: %E\n"); 50260484Sobrien return; 50360484Sobrien } 50460484Sobrien bfd_set_section_size (filler_bfd, edata_s, edata_sz); 50560484Sobrien } 50660484Sobrien 50760484Sobrien reloc_s = bfd_make_section_old_way (filler_bfd, ".reloc"); 50860484Sobrien if (reloc_s == NULL 50960484Sobrien || !bfd_set_section_flags (filler_bfd, reloc_s, 51060484Sobrien (SEC_HAS_CONTENTS 51160484Sobrien | SEC_ALLOC 51260484Sobrien | SEC_LOAD 51360484Sobrien | SEC_KEEP 51460484Sobrien | SEC_IN_MEMORY))) 51560484Sobrien { 51660484Sobrien einfo ("%X%P: can not create .reloc section: %E\n"); 51760484Sobrien return; 51860484Sobrien } 51960484Sobrien bfd_set_section_size (filler_bfd, reloc_s, 0); 52060484Sobrien 52160484Sobrien ldlang_add_file (filler_file); 52260484Sobrien} 52360484Sobrien 52460484Sobrien/************************************************************************ 52560484Sobrien 52660484Sobrien Gather all the exported symbols and build the .edata section 52760484Sobrien 52860484Sobrien ************************************************************************/ 52960484Sobrien 53060484Sobrienstatic void 53160484Sobriengenerate_edata (abfd, info) 53260484Sobrien bfd *abfd; 53360484Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 53460484Sobrien{ 53560484Sobrien int i, next_ordinal; 53660484Sobrien int name_table_size = 0; 53760484Sobrien const char *dlnp; 53860484Sobrien 53960484Sobrien /* First, we need to know how many exported symbols there are, 54060484Sobrien and what the range of ordinals is. */ 54160484Sobrien 54260484Sobrien if (pe_def_file->name) 54360484Sobrien { 54460484Sobrien dll_name = pe_def_file->name; 54560484Sobrien } 54660484Sobrien else 54760484Sobrien { 54860484Sobrien dll_name = abfd->filename; 54960484Sobrien for (dlnp = dll_name; *dlnp; dlnp++) 55060484Sobrien { 55160484Sobrien if (*dlnp == '\\' || *dlnp == '/' || *dlnp == ':') 55260484Sobrien dll_name = dlnp + 1; 55360484Sobrien } 55460484Sobrien } 55560484Sobrien 55660484Sobrien if (count_with_ordinals && max_ordinal > count_exported) 55760484Sobrien { 55860484Sobrien if (min_ordinal > max_ordinal - count_exported + 1) 55960484Sobrien min_ordinal = max_ordinal - count_exported + 1; 56060484Sobrien } 56160484Sobrien else 56260484Sobrien { 56360484Sobrien min_ordinal = 1; 56460484Sobrien max_ordinal = count_exported; 56560484Sobrien } 56660484Sobrien export_table_size = max_ordinal - min_ordinal + 1; 56760484Sobrien 56860484Sobrien exported_symbols = (int *) xmalloc (export_table_size * sizeof (int)); 56960484Sobrien for (i = 0; i < export_table_size; i++) 57060484Sobrien exported_symbols[i] = -1; 57160484Sobrien 57260484Sobrien /* Now we need to assign ordinals to those that don't have them */ 57360484Sobrien for (i = 0; i < NE; i++) 57460484Sobrien { 57560484Sobrien if (exported_symbol_sections[i]) 57660484Sobrien { 57760484Sobrien if (pe_def_file->exports[i].ordinal != -1) 57860484Sobrien { 57960484Sobrien int ei = pe_def_file->exports[i].ordinal - min_ordinal; 58060484Sobrien int pi = exported_symbols[ei]; 58160484Sobrien if (pi != -1) 58260484Sobrien { 58360484Sobrien /* xgettext:c-format */ 58460484Sobrien einfo (_("%XError, oridinal used twice: %d (%s vs %s)\n"), 58560484Sobrien pe_def_file->exports[i].ordinal, 58660484Sobrien pe_def_file->exports[i].name, 58760484Sobrien pe_def_file->exports[pi].name); 58860484Sobrien } 58960484Sobrien exported_symbols[ei] = i; 59060484Sobrien } 59160484Sobrien name_table_size += strlen (pe_def_file->exports[i].name) + 1; 59260484Sobrien } 59360484Sobrien } 59460484Sobrien 59560484Sobrien next_ordinal = min_ordinal; 59660484Sobrien for (i = 0; i < NE; i++) 59760484Sobrien if (exported_symbol_sections[i]) 59860484Sobrien if (pe_def_file->exports[i].ordinal == -1) 59960484Sobrien { 60060484Sobrien while (exported_symbols[next_ordinal - min_ordinal] != -1) 60160484Sobrien next_ordinal++; 60260484Sobrien exported_symbols[next_ordinal - min_ordinal] = i; 60360484Sobrien pe_def_file->exports[i].ordinal = next_ordinal; 60460484Sobrien } 60560484Sobrien 60660484Sobrien /* OK, now we can allocate some memory */ 60760484Sobrien 60860484Sobrien edata_sz = (40 /* directory */ 60960484Sobrien + 4 * export_table_size /* addresses */ 61060484Sobrien + 4 * count_exported_byname /* name ptrs */ 61160484Sobrien + 2 * count_exported_byname /* ordinals */ 61260484Sobrien + name_table_size + strlen (dll_name) + 1); 61360484Sobrien} 61460484Sobrien 61560484Sobrien/* Fill the exported symbol offsets. The preliminary work has already 61660484Sobrien been done in process_def_file(). */ 61760484Sobrien 61860484Sobrienstatic void 61960484Sobrienfill_exported_offsets (abfd, info) 62060484Sobrien bfd *abfd ATTRIBUTE_UNUSED; 62160484Sobrien struct bfd_link_info *info; 62260484Sobrien{ 62360484Sobrien int i; 62460484Sobrien struct bfd_link_hash_entry *blhe; 62560484Sobrien 62660484Sobrien for (i = 0; i < pe_def_file->num_exports; i++) 62760484Sobrien { 62860484Sobrien char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); 62960484Sobrien if (pe_details->underscored) 63060484Sobrien { 63160484Sobrien *name = '_'; 63260484Sobrien strcpy (name + 1, pe_def_file->exports[i].internal_name); 63360484Sobrien } 63460484Sobrien else 63560484Sobrien strcpy (name, pe_def_file->exports[i].internal_name); 63660484Sobrien 63760484Sobrien blhe = bfd_link_hash_lookup (info->hash, 63860484Sobrien name, 63960484Sobrien false, false, true); 64060484Sobrien 64160484Sobrien if (blhe && (blhe->type == bfd_link_hash_defined)) 64260484Sobrien { 64360484Sobrien exported_symbol_offsets[i] = blhe->u.def.value; 64460484Sobrien } 64560484Sobrien free (name); 64660484Sobrien } 64760484Sobrien} 64860484Sobrien 64960484Sobrienstatic void 65060484Sobrienfill_edata (abfd, info) 65160484Sobrien bfd *abfd; 65260484Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 65360484Sobrien{ 65460484Sobrien int i, hint; 65560484Sobrien unsigned char *edirectory; 65660484Sobrien unsigned long *eaddresses; 65760484Sobrien unsigned long *enameptrs; 65860484Sobrien unsigned short *eordinals; 65960484Sobrien unsigned char *enamestr; 66060484Sobrien time_t now; 66160484Sobrien 66260484Sobrien time (&now); 66360484Sobrien 66460484Sobrien edata_d = (unsigned char *) xmalloc (edata_sz); 66560484Sobrien 66660484Sobrien /* Note use of array pointer math here */ 66760484Sobrien edirectory = edata_d; 66860484Sobrien eaddresses = (unsigned long *) (edata_d + 40); 66960484Sobrien enameptrs = eaddresses + export_table_size; 67060484Sobrien eordinals = (unsigned short *) (enameptrs + count_exported_byname); 67160484Sobrien enamestr = (char *) (eordinals + count_exported_byname); 67260484Sobrien 67360484Sobrien#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) + edata_s->output_section->vma - image_base) 67460484Sobrien 67560484Sobrien memset (edata_d, 0, 40); 67660484Sobrien bfd_put_32 (abfd, now, edata_d + 4); 67760484Sobrien if (pe_def_file->version_major != -1) 67860484Sobrien { 67960484Sobrien bfd_put_16 (abfd, pe_def_file->version_major, edata_d + 8); 68060484Sobrien bfd_put_16 (abfd, pe_def_file->version_minor, edata_d + 10); 68160484Sobrien } 68260484Sobrien bfd_put_32 (abfd, ERVA (enamestr), edata_d + 12); 68360484Sobrien strcpy (enamestr, dll_name); 68460484Sobrien enamestr += strlen (enamestr) + 1; 68560484Sobrien bfd_put_32 (abfd, min_ordinal, edata_d + 16); 68660484Sobrien bfd_put_32 (abfd, export_table_size, edata_d + 20); 68760484Sobrien bfd_put_32 (abfd, count_exported_byname, edata_d + 24); 68860484Sobrien bfd_put_32 (abfd, ERVA (eaddresses), edata_d + 28); 68960484Sobrien bfd_put_32 (abfd, ERVA (enameptrs), edata_d + 32); 69060484Sobrien bfd_put_32 (abfd, ERVA (eordinals), edata_d + 36); 69160484Sobrien 69260484Sobrien fill_exported_offsets (abfd, info); 69360484Sobrien 69460484Sobrien /* Ok, now for the filling in part */ 69560484Sobrien hint = 0; 69660484Sobrien for (i = 0; i < export_table_size; i++) 69760484Sobrien { 69860484Sobrien int s = exported_symbols[i]; 69960484Sobrien if (s != -1) 70060484Sobrien { 70160484Sobrien struct sec *ssec = exported_symbol_sections[s]; 70260484Sobrien unsigned long srva = (exported_symbol_offsets[s] 70360484Sobrien + ssec->output_section->vma 70460484Sobrien + ssec->output_offset); 70560484Sobrien 70660484Sobrien bfd_put_32 (abfd, srva - image_base, (void *) (eaddresses + i)); 70760484Sobrien if (!pe_def_file->exports[s].flag_noname) 70860484Sobrien { 70960484Sobrien char *ename = pe_def_file->exports[s].name; 71060484Sobrien bfd_put_32 (abfd, ERVA (enamestr), (void *) enameptrs); 71160484Sobrien strcpy (enamestr, ename); 71260484Sobrien enamestr += strlen (enamestr) + 1; 71360484Sobrien bfd_put_16 (abfd, i, (void *) eordinals); 71460484Sobrien enameptrs++; 71560484Sobrien pe_def_file->exports[s].hint = hint++; 71660484Sobrien } 71760484Sobrien eordinals++; 71860484Sobrien } 71960484Sobrien } 72060484Sobrien} 72160484Sobrien 72260484Sobrien/************************************************************************ 72360484Sobrien 72460484Sobrien Gather all the relocations and build the .reloc section 72560484Sobrien 72660484Sobrien ************************************************************************/ 72760484Sobrien 72860484Sobrienstatic void 72960484Sobriengenerate_reloc (abfd, info) 73060484Sobrien bfd *abfd; 73160484Sobrien struct bfd_link_info *info; 73260484Sobrien{ 73360484Sobrien 73460484Sobrien /* for .reloc stuff */ 73560484Sobrien reloc_data_type *reloc_data; 73660484Sobrien int total_relocs = 0; 73760484Sobrien int i; 73860484Sobrien unsigned long sec_page = (unsigned long) (-1); 73960484Sobrien unsigned long page_ptr, page_count; 74060484Sobrien int bi; 74160484Sobrien bfd *b; 74260484Sobrien struct sec *s; 74360484Sobrien 74460484Sobrien total_relocs = 0; 74560484Sobrien for (b = info->input_bfds; b; b = b->link_next) 74660484Sobrien for (s = b->sections; s; s = s->next) 74760484Sobrien total_relocs += s->reloc_count; 74860484Sobrien 74960484Sobrien reloc_data = (reloc_data_type *) xmalloc (total_relocs * sizeof (reloc_data_type)); 75060484Sobrien 75160484Sobrien total_relocs = 0; 75260484Sobrien bi = 0; 75360484Sobrien for (bi = 0, b = info->input_bfds; b; bi++, b = b->link_next) 75460484Sobrien { 75560484Sobrien arelent **relocs; 75660484Sobrien int relsize, nrelocs, i; 75760484Sobrien 75860484Sobrien for (s = b->sections; s; s = s->next) 75960484Sobrien { 76060484Sobrien unsigned long sec_vma = s->output_section->vma + s->output_offset; 76160484Sobrien asymbol **symbols; 76260484Sobrien int nsyms, symsize; 76360484Sobrien 76460484Sobrien /* if it's not loaded, we don't need to relocate it this way */ 76560484Sobrien if (!(s->output_section->flags & SEC_LOAD)) 76660484Sobrien continue; 76760484Sobrien 76860484Sobrien /* I don't know why there would be a reloc for these, but I've 76960484Sobrien seen it happen - DJ */ 77060484Sobrien if (s->output_section == &bfd_abs_section) 77160484Sobrien continue; 77260484Sobrien 77360484Sobrien if (s->output_section->vma == 0) 77460484Sobrien { 77560484Sobrien /* Huh? Shouldn't happen, but punt if it does */ 77660484Sobrien einfo ("DJ: zero vma section reloc detected: `%s' #%d f=%d\n", 77760484Sobrien s->output_section->name, s->output_section->index, 77860484Sobrien s->output_section->flags); 77960484Sobrien continue; 78060484Sobrien } 78160484Sobrien 78260484Sobrien symsize = bfd_get_symtab_upper_bound (b); 78360484Sobrien symbols = (asymbol **) xmalloc (symsize); 78460484Sobrien nsyms = bfd_canonicalize_symtab (b, symbols); 78560484Sobrien 78660484Sobrien relsize = bfd_get_reloc_upper_bound (b, s); 78760484Sobrien relocs = (arelent **) xmalloc ((size_t) relsize); 78860484Sobrien nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); 78960484Sobrien 79060484Sobrien for (i = 0; i < nrelocs; i++) 79160484Sobrien { 79260484Sobrien if (!relocs[i]->howto->pc_relative 79360484Sobrien && relocs[i]->howto->type != pe_details->imagebase_reloc) 79460484Sobrien { 79560484Sobrien bfd_vma sym_vma; 79660484Sobrien struct symbol_cache_entry *sym = *relocs[i]->sym_ptr_ptr; 79760484Sobrien sym_vma = (relocs[i]->addend 79860484Sobrien + sym->value 79960484Sobrien + sym->section->vma 80060484Sobrien + sym->section->output_offset 80160484Sobrien + sym->section->output_section->vma); 80260484Sobrien reloc_data[total_relocs].vma = sec_vma + relocs[i]->address; 80360484Sobrien 80460484Sobrien#define BITS_AND_SHIFT(bits, shift) (bits * 1000 | shift) 80560484Sobrien 80660484Sobrien switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, 80760484Sobrien relocs[i]->howto->rightshift) 80860484Sobrien { 80960484Sobrien case BITS_AND_SHIFT (32, 0): 81060484Sobrien reloc_data[total_relocs].type = 3; 81160484Sobrien total_relocs++; 81260484Sobrien break; 81360484Sobrien case BITS_AND_SHIFT (16, 0): 81460484Sobrien reloc_data[total_relocs].type = 2; 81560484Sobrien total_relocs++; 81660484Sobrien break; 81760484Sobrien case BITS_AND_SHIFT (16, 16): 81860484Sobrien reloc_data[total_relocs].type = 4; 81960484Sobrien /* FIXME: we can't know the symbol's right value yet, 82060484Sobrien but we probably can safely assume that CE will relocate 82160484Sobrien us in 64k blocks, so leaving it zero is safe. */ 82260484Sobrien reloc_data[total_relocs].extra = 0; 82360484Sobrien total_relocs++; 82460484Sobrien break; 82560484Sobrien case BITS_AND_SHIFT (26, 2): 82660484Sobrien reloc_data[total_relocs].type = 5; 82760484Sobrien total_relocs++; 82860484Sobrien break; 82960484Sobrien default: 83060484Sobrien /* xgettext:c-format */ 83160484Sobrien einfo (_("%XError: %d-bit reloc in dll\n"), 83260484Sobrien relocs[i]->howto->bitsize); 83360484Sobrien break; 83460484Sobrien } 83560484Sobrien } 83660484Sobrien } 83760484Sobrien free (relocs); 83860484Sobrien /* Warning: the allocated symbols are remembered in BFD and reused 83960484Sobrien later, so don't free them! */ 84060484Sobrien /* free (symbols); */ 84160484Sobrien } 84260484Sobrien } 84360484Sobrien 84460484Sobrien /* At this point, we have total_relocs relocation addresses in 84560484Sobrien reloc_addresses, which are all suitable for the .reloc section. 84660484Sobrien We must now create the new sections. */ 84760484Sobrien 84860484Sobrien qsort (reloc_data, total_relocs, sizeof (*reloc_data), reloc_sort); 84960484Sobrien 85060484Sobrien for (i = 0; i < total_relocs; i++) 85160484Sobrien { 85260484Sobrien unsigned long this_page = (reloc_data[i].vma >> 12); 85360484Sobrien 85460484Sobrien if (this_page != sec_page) 85560484Sobrien { 85660484Sobrien reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align */ 85760484Sobrien reloc_sz += 8; 85860484Sobrien sec_page = this_page; 85960484Sobrien } 86060484Sobrien 86160484Sobrien reloc_sz += 2; 86260484Sobrien 86360484Sobrien if (reloc_data[i].type == 4) 86460484Sobrien reloc_sz += 2; 86560484Sobrien } 86660484Sobrien reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align */ 86760484Sobrien 86860484Sobrien reloc_d = (unsigned char *) xmalloc (reloc_sz); 86960484Sobrien 87060484Sobrien sec_page = (unsigned long) (-1); 87160484Sobrien reloc_sz = 0; 87260484Sobrien page_ptr = (unsigned long) (-1); 87360484Sobrien page_count = 0; 87460484Sobrien for (i = 0; i < total_relocs; i++) 87560484Sobrien { 87660484Sobrien unsigned long rva = reloc_data[i].vma - image_base; 87760484Sobrien unsigned long this_page = (rva & ~0xfff); 87860484Sobrien if (this_page != sec_page) 87960484Sobrien { 88060484Sobrien while (reloc_sz & 3) 88160484Sobrien reloc_d[reloc_sz++] = 0; 88260484Sobrien if (page_ptr != (unsigned long) (-1)) 88360484Sobrien bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); 88460484Sobrien bfd_put_32 (abfd, this_page, reloc_d + reloc_sz); 88560484Sobrien page_ptr = reloc_sz; 88660484Sobrien reloc_sz += 8; 88760484Sobrien sec_page = this_page; 88860484Sobrien page_count = 0; 88960484Sobrien } 89060484Sobrien bfd_put_16 (abfd, (rva & 0xfff) + (reloc_data[i].type<<12), 89160484Sobrien reloc_d + reloc_sz); 89260484Sobrien reloc_sz += 2; 89360484Sobrien if (reloc_data[i].type == 4) 89460484Sobrien { 89560484Sobrien bfd_put_16 (abfd, reloc_data[i].extra, reloc_d + reloc_sz); 89660484Sobrien reloc_sz += 2; 89760484Sobrien } 89860484Sobrien page_count++; 89960484Sobrien } 90060484Sobrien while (reloc_sz & 3) 90160484Sobrien reloc_d[reloc_sz++] = 0; 90260484Sobrien if (page_ptr != (unsigned long) (-1)) 90360484Sobrien bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); 90460484Sobrien while (reloc_sz < reloc_s->_raw_size) 90560484Sobrien reloc_d[reloc_sz++] = 0; 90660484Sobrien} 90760484Sobrien 90860484Sobrien/************************************************************************ 90960484Sobrien 91060484Sobrien Given the exiting def_file structure, print out a .DEF file that 91160484Sobrien corresponds to it. 91260484Sobrien 91360484Sobrien ************************************************************************/ 91460484Sobrien 91560484Sobrienstatic void 91660484Sobrienquoteput (s, f, needs_quotes) 91760484Sobrien char *s; 91860484Sobrien FILE * f; 91960484Sobrien int needs_quotes; 92060484Sobrien{ 92160484Sobrien char *cp; 92260484Sobrien for (cp = s; *cp; cp++) 92360484Sobrien if (*cp == '\'' 92460484Sobrien || *cp == '"' 92560484Sobrien || *cp == '\\' 92660484Sobrien || isspace ((unsigned char) *cp) 92760484Sobrien || *cp == ',' 92860484Sobrien || *cp == ';') 92960484Sobrien needs_quotes = 1; 93060484Sobrien if (needs_quotes) 93160484Sobrien { 93260484Sobrien putc ('"', f); 93360484Sobrien while (*s) 93460484Sobrien { 93560484Sobrien if (*s == '"' || *s == '\\') 93660484Sobrien putc ('\\', f); 93760484Sobrien putc (*s, f); 93860484Sobrien s++; 93960484Sobrien } 94060484Sobrien putc ('"', f); 94160484Sobrien } 94260484Sobrien else 94360484Sobrien fputs (s, f); 94460484Sobrien} 94560484Sobrien 94660484Sobrienvoid 94760484Sobrienpe_dll_generate_def_file (pe_out_def_filename) 94860484Sobrien const char *pe_out_def_filename; 94960484Sobrien{ 95060484Sobrien int i; 95160484Sobrien FILE *out = fopen (pe_out_def_filename, "w"); 95260484Sobrien if (out == NULL) 95360484Sobrien { 95460484Sobrien /* xgettext:c-format */ 95560484Sobrien einfo (_("%s: Can't open output def file %s\n"), 95660484Sobrien program_name, pe_out_def_filename); 95760484Sobrien } 95860484Sobrien 95960484Sobrien if (pe_def_file) 96060484Sobrien { 96160484Sobrien if (pe_def_file->name) 96260484Sobrien { 96360484Sobrien if (pe_def_file->is_dll) 96460484Sobrien fprintf (out, "LIBRARY "); 96560484Sobrien else 96660484Sobrien fprintf (out, "NAME "); 96760484Sobrien quoteput (pe_def_file->name, out, 1); 96860484Sobrien if (pe_data (output_bfd)->pe_opthdr.ImageBase) 96960484Sobrien fprintf (out, " BASE=0x%lx", 97060484Sobrien (unsigned long) pe_data (output_bfd)->pe_opthdr.ImageBase); 97160484Sobrien fprintf (out, "\n"); 97260484Sobrien } 97360484Sobrien 97460484Sobrien if (pe_def_file->description) 97560484Sobrien { 97660484Sobrien fprintf (out, "DESCRIPTION "); 97760484Sobrien quoteput (pe_def_file->description, out, 1); 97860484Sobrien fprintf (out, "\n"); 97960484Sobrien } 98060484Sobrien 98160484Sobrien if (pe_def_file->version_minor != -1) 98260484Sobrien fprintf (out, "VERSION %d.%d\n", pe_def_file->version_major, 98360484Sobrien pe_def_file->version_minor); 98460484Sobrien else if (pe_def_file->version_major != -1) 98560484Sobrien fprintf (out, "VERSION %d\n", pe_def_file->version_major); 98660484Sobrien 98760484Sobrien if (pe_def_file->stack_reserve != -1 || pe_def_file->heap_reserve != -1) 98860484Sobrien fprintf (out, "\n"); 98960484Sobrien 99060484Sobrien if (pe_def_file->stack_commit != -1) 99160484Sobrien fprintf (out, "STACKSIZE 0x%x,0x%x\n", 99260484Sobrien pe_def_file->stack_reserve, pe_def_file->stack_commit); 99360484Sobrien else if (pe_def_file->stack_reserve != -1) 99460484Sobrien fprintf (out, "STACKSIZE 0x%x\n", pe_def_file->stack_reserve); 99560484Sobrien if (pe_def_file->heap_commit != -1) 99660484Sobrien fprintf (out, "HEAPSIZE 0x%x,0x%x\n", 99760484Sobrien pe_def_file->heap_reserve, pe_def_file->heap_commit); 99860484Sobrien else if (pe_def_file->heap_reserve != -1) 99960484Sobrien fprintf (out, "HEAPSIZE 0x%x\n", pe_def_file->heap_reserve); 100060484Sobrien 100160484Sobrien if (pe_def_file->num_section_defs > 0) 100260484Sobrien { 100360484Sobrien fprintf (out, "\nSECTIONS\n\n"); 100460484Sobrien for (i = 0; i < pe_def_file->num_section_defs; i++) 100560484Sobrien { 100660484Sobrien fprintf (out, " "); 100760484Sobrien quoteput (pe_def_file->section_defs[i].name, out, 0); 100860484Sobrien if (pe_def_file->section_defs[i].class) 100960484Sobrien { 101060484Sobrien fprintf (out, " CLASS "); 101160484Sobrien quoteput (pe_def_file->section_defs[i].class, out, 0); 101260484Sobrien } 101360484Sobrien if (pe_def_file->section_defs[i].flag_read) 101460484Sobrien fprintf (out, " READ"); 101560484Sobrien if (pe_def_file->section_defs[i].flag_write) 101660484Sobrien fprintf (out, " WRITE"); 101760484Sobrien if (pe_def_file->section_defs[i].flag_execute) 101860484Sobrien fprintf (out, " EXECUTE"); 101960484Sobrien if (pe_def_file->section_defs[i].flag_shared) 102060484Sobrien fprintf (out, " SHARED"); 102160484Sobrien fprintf (out, "\n"); 102260484Sobrien } 102360484Sobrien } 102460484Sobrien 102560484Sobrien if (pe_def_file->num_exports > 0) 102660484Sobrien { 102760484Sobrien fprintf (out, "\nEXPORTS\n\n"); 102860484Sobrien for (i = 0; i < pe_def_file->num_exports; i++) 102960484Sobrien { 103060484Sobrien def_file_export *e = pe_def_file->exports + i; 103160484Sobrien fprintf (out, " "); 103260484Sobrien quoteput (e->name, out, 0); 103360484Sobrien if (e->internal_name && strcmp (e->internal_name, e->name)) 103460484Sobrien { 103560484Sobrien fprintf (out, " = "); 103660484Sobrien quoteput (e->internal_name, out, 0); 103760484Sobrien } 103860484Sobrien if (e->ordinal != -1) 103960484Sobrien fprintf (out, " @%d", e->ordinal); 104060484Sobrien if (e->flag_private) 104160484Sobrien fprintf (out, " PRIVATE"); 104260484Sobrien if (e->flag_constant) 104360484Sobrien fprintf (out, " CONSTANT"); 104460484Sobrien if (e->flag_noname) 104560484Sobrien fprintf (out, " NONAME"); 104660484Sobrien if (e->flag_data) 104760484Sobrien fprintf (out, " DATA"); 104860484Sobrien 104960484Sobrien fprintf (out, "\n"); 105060484Sobrien } 105160484Sobrien } 105260484Sobrien 105360484Sobrien if (pe_def_file->num_imports > 0) 105460484Sobrien { 105560484Sobrien fprintf (out, "\nIMPORTS\n\n"); 105660484Sobrien for (i = 0; i < pe_def_file->num_imports; i++) 105760484Sobrien { 105860484Sobrien def_file_import *im = pe_def_file->imports + i; 105960484Sobrien fprintf (out, " "); 106060484Sobrien if (im->internal_name 106160484Sobrien && (!im->name || strcmp (im->internal_name, im->name))) 106260484Sobrien { 106360484Sobrien quoteput (im->internal_name, out, 0); 106460484Sobrien fprintf (out, " = "); 106560484Sobrien } 106660484Sobrien quoteput (im->module->name, out, 0); 106760484Sobrien fprintf (out, "."); 106860484Sobrien if (im->name) 106960484Sobrien quoteput (im->name, out, 0); 107060484Sobrien else 107160484Sobrien fprintf (out, "%d", im->ordinal); 107260484Sobrien fprintf (out, "\n"); 107360484Sobrien } 107460484Sobrien } 107560484Sobrien } 107660484Sobrien else 107760484Sobrien fprintf (out, _("; no contents available\n")); 107860484Sobrien 107960484Sobrien if (fclose (out) == EOF) 108060484Sobrien { 108160484Sobrien /* xgettext:c-format */ 108260484Sobrien einfo (_("%P: Error closing file `%s'\n"), pe_out_def_filename); 108360484Sobrien } 108460484Sobrien} 108560484Sobrien 108660484Sobrien/************************************************************************ 108760484Sobrien 108860484Sobrien Generate the import library 108960484Sobrien 109060484Sobrien ************************************************************************/ 109160484Sobrien 109260484Sobrienstatic asymbol **symtab; 109360484Sobrienstatic int symptr; 109460484Sobrienstatic int tmp_seq; 109560484Sobrienstatic const char *dll_filename; 109660484Sobrienstatic char *dll_symname; 109760484Sobrien 109860484Sobrien#define UNDSEC (asection *) &bfd_und_section 109960484Sobrien 110060484Sobrienstatic asection * 110160484Sobrienquick_section(abfd, name, flags, align) 110260484Sobrien bfd *abfd; 110360484Sobrien const char *name; 110460484Sobrien int flags; 110560484Sobrien int align; 110660484Sobrien{ 110760484Sobrien asection *sec; 110860484Sobrien asymbol *sym; 110960484Sobrien 111060484Sobrien sec = bfd_make_section_old_way (abfd, name); 111160484Sobrien bfd_set_section_flags (abfd, sec, flags 111260484Sobrien | SEC_ALLOC 111360484Sobrien | SEC_LOAD 111460484Sobrien | SEC_KEEP 111560484Sobrien ); 111660484Sobrien bfd_set_section_alignment (abfd, sec, align); 111760484Sobrien /* remember to undo this before trying to link internally! */ 111860484Sobrien sec->output_section = sec; 111960484Sobrien 112060484Sobrien sym = bfd_make_empty_symbol (abfd); 112160484Sobrien symtab[symptr++] = sym; 112260484Sobrien sym->name = sec->name; 112360484Sobrien sym->section = sec; 112460484Sobrien sym->flags = BSF_LOCAL; 112560484Sobrien sym->value = 0; 112660484Sobrien 112760484Sobrien return sec; 112860484Sobrien} 112960484Sobrien 113060484Sobrienstatic void 113160484Sobrienquick_symbol (abfd, n1, n2, n3, sec, flags, addr) 113260484Sobrien bfd *abfd; 113360484Sobrien char *n1; 113460484Sobrien char *n2; 113560484Sobrien char *n3; 113660484Sobrien asection *sec; 113760484Sobrien int flags; 113860484Sobrien int addr; 113960484Sobrien{ 114060484Sobrien asymbol *sym; 114160484Sobrien char *name = (char *) xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); 114260484Sobrien strcpy (name, n1); 114360484Sobrien strcat (name, n2); 114460484Sobrien strcat (name, n3); 114560484Sobrien sym = bfd_make_empty_symbol (abfd); 114660484Sobrien sym->name = name; 114760484Sobrien sym->section = sec; 114860484Sobrien sym->flags = flags; 114960484Sobrien sym->value = addr; 115060484Sobrien symtab[symptr++] = sym; 115160484Sobrien} 115260484Sobrien 115360484Sobrienstatic arelent *reltab = 0; 115460484Sobrienstatic int relcount = 0, relsize = 0; 115560484Sobrien 115660484Sobrienstatic void 115760484Sobrienquick_reloc (abfd, address, which_howto, symidx) 115860484Sobrien bfd *abfd; 115960484Sobrien int address; 116060484Sobrien int which_howto; 116160484Sobrien int symidx; 116260484Sobrien{ 116360484Sobrien if (relcount >= (relsize-1)) 116460484Sobrien { 116560484Sobrien relsize += 10; 116660484Sobrien if (reltab) 116760484Sobrien reltab = (arelent *) xrealloc (reltab, relsize * sizeof (arelent)); 116860484Sobrien else 116960484Sobrien reltab = (arelent *) xmalloc (relsize * sizeof (arelent)); 117060484Sobrien } 117160484Sobrien reltab[relcount].address = address; 117260484Sobrien reltab[relcount].addend = 0; 117360484Sobrien reltab[relcount].howto = bfd_reloc_type_lookup (abfd, which_howto); 117460484Sobrien reltab[relcount].sym_ptr_ptr = symtab + symidx; 117560484Sobrien relcount++; 117660484Sobrien} 117760484Sobrien 117860484Sobrienstatic void 117960484Sobriensave_relocs (asection *sec) 118060484Sobrien{ 118160484Sobrien int i; 118260484Sobrien sec->relocation = reltab; 118360484Sobrien sec->reloc_count = relcount; 118460484Sobrien sec->orelocation = (arelent **) xmalloc ((relcount+1) * sizeof (arelent *)); 118560484Sobrien for (i=0; i<relcount; i++) 118660484Sobrien sec->orelocation[i] = sec->relocation + i; 118760484Sobrien sec->orelocation[relcount] = 0; 118860484Sobrien sec->flags |= SEC_RELOC; 118960484Sobrien reltab = 0; 119060484Sobrien relcount = relsize = 0; 119160484Sobrien} 119260484Sobrien 119360484Sobrien/* 119460484Sobrien * .section .idata$2 119560484Sobrien * .global __head_my_dll 119660484Sobrien * __head_my_dll: 119760484Sobrien * .rva hname 119860484Sobrien * .long 0 119960484Sobrien * .long 0 120060484Sobrien * .rva __my_dll_iname 120160484Sobrien * .rva fthunk 120260484Sobrien * 120360484Sobrien * .section .idata$5 120460484Sobrien * .long 0 120560484Sobrien * fthunk: 120660484Sobrien * 120760484Sobrien * .section .idata$4 120860484Sobrien * .long 0 120960484Sobrien * hname: 121060484Sobrien */ 121160484Sobrien 121260484Sobrienstatic bfd * 121360484Sobrienmake_head (parent) 121460484Sobrien bfd *parent; 121560484Sobrien{ 121660484Sobrien asection *id2, *id5, *id4; 121760484Sobrien unsigned char *d2, *d5, *d4; 121860484Sobrien char *oname; 121960484Sobrien bfd *abfd; 122060484Sobrien 122160484Sobrien oname = (char *) xmalloc (20); 122260484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 122360484Sobrien tmp_seq++; 122460484Sobrien 122560484Sobrien abfd = bfd_create (oname, parent); 122660484Sobrien bfd_find_target (pe_details->object_target, abfd); 122760484Sobrien bfd_make_writable (abfd); 122860484Sobrien 122960484Sobrien bfd_set_format (abfd, bfd_object); 123060484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 123160484Sobrien 123260484Sobrien symptr = 0; 123360484Sobrien symtab = (asymbol **) xmalloc (6 * sizeof (asymbol *)); 123460484Sobrien id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); 123560484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 123660484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 123760484Sobrien quick_symbol (abfd, U("_head_"), dll_symname, "", id2, BSF_GLOBAL, 0); 123860484Sobrien quick_symbol (abfd, U(""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); 123960484Sobrien 124060484Sobrien /* OK, pay attention here. I got confused myself looking back at 124160484Sobrien it. We create a four-byte section to mark the beginning of the 124260484Sobrien list, and we include an offset of 4 in the section, so that the 124360484Sobrien pointer to the list points to the *end* of this section, which is 124460484Sobrien the start of the list of sections from other objects. */ 124560484Sobrien 124660484Sobrien bfd_set_section_size (abfd, id2, 20); 124760484Sobrien d2 = (unsigned char *) xmalloc (20); 124860484Sobrien id2->contents = d2; 124960484Sobrien memset (d2, 0, 20); 125060484Sobrien d2[0] = d2[16] = 4; /* reloc addend */ 125160484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); 125260484Sobrien quick_reloc (abfd, 12, BFD_RELOC_RVA, 4); 125360484Sobrien quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); 125460484Sobrien save_relocs (id2); 125560484Sobrien 125660484Sobrien bfd_set_section_size (abfd, id5, 4); 125760484Sobrien d5 = (unsigned char *) xmalloc (4); 125860484Sobrien id5->contents = d5; 125960484Sobrien memset (d5, 0, 4); 126060484Sobrien 126160484Sobrien bfd_set_section_size (abfd, id4, 4); 126260484Sobrien d4 = (unsigned char *) xmalloc (4); 126360484Sobrien id4->contents = d4; 126460484Sobrien memset (d4, 0, 4); 126560484Sobrien 126660484Sobrien bfd_set_symtab (abfd, symtab, symptr); 126760484Sobrien 126860484Sobrien bfd_set_section_contents (abfd, id2, d2, 0, 20); 126960484Sobrien bfd_set_section_contents (abfd, id5, d5, 0, 4); 127060484Sobrien bfd_set_section_contents (abfd, id4, d4, 0, 4); 127160484Sobrien 127260484Sobrien bfd_make_readable (abfd); 127360484Sobrien return abfd; 127460484Sobrien} 127560484Sobrien 127660484Sobrien/* 127760484Sobrien * .section .idata$4 127860484Sobrien * .long 0 127960484Sobrien * .section .idata$5 128060484Sobrien * .long 0 128160484Sobrien * .section idata$7 128260484Sobrien * .global __my_dll_iname 128360484Sobrien *__my_dll_iname: 128460484Sobrien * .asciz "my.dll" 128560484Sobrien */ 128660484Sobrien 128760484Sobrienstatic bfd * 128860484Sobrienmake_tail (parent) 128960484Sobrien bfd *parent; 129060484Sobrien{ 129160484Sobrien asection *id4, *id5, *id7; 129260484Sobrien unsigned char *d4, *d5, *d7; 129360484Sobrien int len; 129460484Sobrien char *oname; 129560484Sobrien bfd *abfd; 129660484Sobrien 129760484Sobrien oname = (char *) xmalloc (20); 129860484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 129960484Sobrien tmp_seq++; 130060484Sobrien 130160484Sobrien abfd = bfd_create (oname, parent); 130260484Sobrien bfd_find_target (pe_details->object_target, abfd); 130360484Sobrien bfd_make_writable (abfd); 130460484Sobrien 130560484Sobrien bfd_set_format (abfd, bfd_object); 130660484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 130760484Sobrien 130860484Sobrien symptr = 0; 130960484Sobrien symtab = (asymbol **) xmalloc (5 * sizeof (asymbol *)); 131060484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 131160484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 131260484Sobrien id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); 131360484Sobrien quick_symbol (abfd, U(""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); 131460484Sobrien 131560484Sobrien bfd_set_section_size (abfd, id4, 4); 131660484Sobrien d4 = (unsigned char *) xmalloc (4); 131760484Sobrien id4->contents = d4; 131860484Sobrien memset (d4, 0, 4); 131960484Sobrien 132060484Sobrien bfd_set_section_size (abfd, id5, 4); 132160484Sobrien d5 = (unsigned char *) xmalloc (4); 132260484Sobrien id5->contents = d5; 132360484Sobrien memset (d5, 0, 4); 132460484Sobrien 132560484Sobrien len = strlen (dll_filename)+1; 132660484Sobrien if (len & 1) 132760484Sobrien len ++; 132860484Sobrien bfd_set_section_size (abfd, id7, len); 132960484Sobrien d7 = (unsigned char *) xmalloc (len); 133060484Sobrien id7->contents = d7; 133160484Sobrien strcpy (d7, dll_filename); 133260484Sobrien 133360484Sobrien bfd_set_symtab (abfd, symtab, symptr); 133460484Sobrien 133560484Sobrien bfd_set_section_contents (abfd, id4, d4, 0, 4); 133660484Sobrien bfd_set_section_contents (abfd, id5, d5, 0, 4); 133760484Sobrien bfd_set_section_contents (abfd, id7, d7, 0, len); 133860484Sobrien 133960484Sobrien bfd_make_readable (abfd); 134060484Sobrien return abfd; 134160484Sobrien} 134260484Sobrien 134360484Sobrien/* 134460484Sobrien * .text 134560484Sobrien * .global _function 134660484Sobrien * .global ___imp_function 134760484Sobrien * .global __imp__function 134860484Sobrien *_function: 134960484Sobrien * jmp *__imp__function: 135060484Sobrien * 135160484Sobrien * .section idata$7 135260484Sobrien * .long __head_my_dll 135360484Sobrien * 135460484Sobrien * .section .idata$5 135560484Sobrien *___imp_function: 135660484Sobrien *__imp__function: 135760484Sobrien *iat? 135860484Sobrien * .section .idata$4 135960484Sobrien *iat? 136060484Sobrien * .section .idata$6 136160484Sobrien *ID<ordinal>: 136260484Sobrien * .short <hint> 136360484Sobrien * .asciz "function" xlate? (add underscore, kill at) 136460484Sobrien */ 136560484Sobrien 136660484Sobrienstatic unsigned char jmp_ix86_bytes[] = { 136760484Sobrien 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 136860484Sobrien}; 136960484Sobrien 137060484Sobrien/* 137160484Sobrien *_function: 137260484Sobrien * mov.l ip+8,r0 137360484Sobrien * mov.l @r0,r0 137460484Sobrien * jmp @r0 137560484Sobrien * nop 137660484Sobrien * .dw __imp_function 137760484Sobrien */ 137860484Sobrien 137960484Sobrienstatic unsigned char jmp_sh_bytes[] = { 138060484Sobrien 0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 138160484Sobrien}; 138260484Sobrien 138360484Sobrien/* 138460484Sobrien *_function: 138560484Sobrien * lui $t0,<high:__imp_function> 138660484Sobrien * lw $t0,<low:__imp_function> 138760484Sobrien * jr $t0 138860484Sobrien * nop 138960484Sobrien */ 139060484Sobrien 139160484Sobrienstatic unsigned char jmp_mips_bytes[] = { 139260484Sobrien 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d, 139360484Sobrien 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 139460484Sobrien}; 139560484Sobrien 139660484Sobrienstatic bfd * 139760484Sobrienmake_one (exp, parent) 139860484Sobrien def_file_export *exp; 139960484Sobrien bfd *parent; 140060484Sobrien{ 140160484Sobrien asection *tx, *id7, *id5, *id4, *id6; 140260484Sobrien unsigned char *td, *d7, *d5, *d4, *d6 = NULL; 140360484Sobrien int len; 140460484Sobrien char *oname; 140560484Sobrien bfd *abfd; 140660484Sobrien unsigned char *jmp_bytes = NULL; 140760484Sobrien int jmp_byte_count = 0; 140860484Sobrien 140960484Sobrien switch (pe_details->pe_arch) 141060484Sobrien { 141160484Sobrien case PE_ARCH_i386: 141260484Sobrien jmp_bytes = jmp_ix86_bytes; 141360484Sobrien jmp_byte_count = sizeof (jmp_ix86_bytes); 141460484Sobrien break; 141560484Sobrien case PE_ARCH_sh: 141660484Sobrien jmp_bytes = jmp_sh_bytes; 141760484Sobrien jmp_byte_count = sizeof (jmp_sh_bytes); 141860484Sobrien break; 141960484Sobrien case PE_ARCH_mips: 142060484Sobrien jmp_bytes = jmp_mips_bytes; 142160484Sobrien jmp_byte_count = sizeof (jmp_mips_bytes); 142260484Sobrien break; 142360484Sobrien } 142460484Sobrien 142560484Sobrien oname = (char *) xmalloc (20); 142660484Sobrien sprintf (oname, "d%06d.o", tmp_seq); 142760484Sobrien tmp_seq++; 142860484Sobrien 142960484Sobrien abfd = bfd_create (oname, parent); 143060484Sobrien bfd_find_target (pe_details->object_target, abfd); 143160484Sobrien bfd_make_writable (abfd); 143260484Sobrien 143360484Sobrien bfd_set_format (abfd, bfd_object); 143460484Sobrien bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0); 143560484Sobrien 143660484Sobrien symptr = 0; 143760484Sobrien symtab = (asymbol **) xmalloc (10 * sizeof (asymbol *)); 143860484Sobrien tx = quick_section (abfd, ".text", SEC_CODE|SEC_HAS_CONTENTS, 2); 143960484Sobrien id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); 144060484Sobrien id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); 144160484Sobrien id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); 144260484Sobrien id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); 144360484Sobrien if (! exp->flag_data) 144460484Sobrien quick_symbol (abfd, U(""), exp->internal_name, "", tx, BSF_GLOBAL, 0); 144560484Sobrien quick_symbol (abfd, U("_head_"), dll_symname, "", UNDSEC, BSF_GLOBAL, 0); 144660484Sobrien quick_symbol (abfd, U("__imp_"), exp->internal_name, "", id5, BSF_GLOBAL, 0); 144760484Sobrien if (pe_dll_compat_implib) 144860484Sobrien quick_symbol (abfd, U("__imp_"), exp->internal_name, "", 144960484Sobrien id5, BSF_GLOBAL, 0); 145060484Sobrien 145160484Sobrien bfd_set_section_size (abfd, tx, jmp_byte_count); 145260484Sobrien td = (unsigned char *) xmalloc (jmp_byte_count); 145360484Sobrien tx->contents = td; 145460484Sobrien memcpy (td, jmp_bytes, jmp_byte_count); 145560484Sobrien switch (pe_details->pe_arch) 145660484Sobrien { 145760484Sobrien case PE_ARCH_i386: 145860484Sobrien quick_reloc (abfd, 2, BFD_RELOC_32, 2); 145960484Sobrien break; 146060484Sobrien case PE_ARCH_sh: 146160484Sobrien quick_reloc (abfd, 8, BFD_RELOC_32, 2); 146260484Sobrien break; 146360484Sobrien case PE_ARCH_mips: 146460484Sobrien quick_reloc (abfd, 0, BFD_RELOC_HI16_S, 2); 146560484Sobrien quick_reloc (abfd, 0, BFD_RELOC_LO16, 0); /* MIPS_R_PAIR */ 146660484Sobrien quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); 146760484Sobrien break; 146860484Sobrien } 146960484Sobrien save_relocs (tx); 147060484Sobrien 147160484Sobrien bfd_set_section_size (abfd, id7, 4); 147260484Sobrien d7 = (unsigned char *) xmalloc (4); 147360484Sobrien id7->contents = d7; 147460484Sobrien memset (d7, 0, 4); 147560484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 6); 147660484Sobrien save_relocs (id7); 147760484Sobrien 147860484Sobrien bfd_set_section_size (abfd, id5, 4); 147960484Sobrien d5 = (unsigned char *) xmalloc (4); 148060484Sobrien id5->contents = d5; 148160484Sobrien memset (d5, 0, 4); 148260484Sobrien if (exp->flag_noname) 148360484Sobrien { 148460484Sobrien d5[0] = exp->ordinal; 148560484Sobrien d5[1] = exp->ordinal >> 8; 148660484Sobrien d5[3] = 0x80; 148760484Sobrien } 148860484Sobrien else 148960484Sobrien { 149060484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); 149160484Sobrien save_relocs (id5); 149260484Sobrien } 149360484Sobrien 149460484Sobrien bfd_set_section_size (abfd, id4, 4); 149560484Sobrien d4 = (unsigned char *) xmalloc (4); 149660484Sobrien id4->contents = d4; 149760484Sobrien memset (d4, 0, 4); 149860484Sobrien if (exp->flag_noname) 149960484Sobrien { 150060484Sobrien d5[0] = exp->ordinal; 150160484Sobrien d5[1] = exp->ordinal >> 8; 150260484Sobrien d5[3] = 0x80; 150360484Sobrien } 150460484Sobrien else 150560484Sobrien { 150660484Sobrien quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); 150760484Sobrien save_relocs (id4); 150860484Sobrien } 150960484Sobrien 151060484Sobrien if (exp->flag_noname) 151160484Sobrien { 151260484Sobrien len = 0; 151360484Sobrien bfd_set_section_size (abfd, id6, 0); 151460484Sobrien } 151560484Sobrien else 151660484Sobrien { 151760484Sobrien len = strlen (exp->name) + 3; 151860484Sobrien if (len & 1) 151960484Sobrien len++; 152060484Sobrien bfd_set_section_size (abfd, id6, len); 152160484Sobrien d6 = (unsigned char *) xmalloc (len); 152260484Sobrien id6->contents = d6; 152360484Sobrien memset (d6, 0, len); 152460484Sobrien d6[0] = exp->hint & 0xff; 152560484Sobrien d6[1] = exp->hint >> 8; 152660484Sobrien strcpy (d6+2, exp->name); 152760484Sobrien } 152860484Sobrien 152960484Sobrien bfd_set_symtab (abfd, symtab, symptr); 153060484Sobrien 153160484Sobrien bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count); 153260484Sobrien bfd_set_section_contents (abfd, id7, d7, 0, 4); 153360484Sobrien bfd_set_section_contents (abfd, id5, d5, 0, 4); 153460484Sobrien bfd_set_section_contents (abfd, id4, d4, 0, 4); 153560484Sobrien if (!exp->flag_noname) 153660484Sobrien bfd_set_section_contents (abfd, id6, d6, 0, len); 153760484Sobrien 153860484Sobrien bfd_make_readable (abfd); 153960484Sobrien return abfd; 154060484Sobrien} 154160484Sobrien 154260484Sobrienvoid 154360484Sobrienpe_dll_generate_implib (def, impfilename) 154460484Sobrien def_file *def; 154560484Sobrien const char *impfilename; 154660484Sobrien{ 154760484Sobrien int i; 154860484Sobrien bfd *ar_head; 154960484Sobrien bfd *ar_tail; 155060484Sobrien bfd *outarch; 155160484Sobrien bfd *head = 0; 155260484Sobrien 155360484Sobrien dll_filename = (def->name) ? def->name : dll_name; 155460484Sobrien dll_symname = xstrdup (dll_filename); 155560484Sobrien for (i=0; dll_symname[i]; i++) 155660484Sobrien if (!isalnum ((unsigned char) dll_symname[i])) 155760484Sobrien dll_symname[i] = '_'; 155860484Sobrien 155960484Sobrien unlink (impfilename); 156060484Sobrien 156160484Sobrien outarch = bfd_openw (impfilename, 0); 156260484Sobrien 156360484Sobrien if (!outarch) 156460484Sobrien { 156560484Sobrien /* xgettext:c-format */ 156660484Sobrien einfo (_("%XCan't open .lib file: %s\n"), impfilename); 156760484Sobrien return; 156860484Sobrien } 156960484Sobrien 157060484Sobrien /* xgettext:c-format */ 157160484Sobrien einfo (_("Creating library file: %s\n"), impfilename); 157260484Sobrien 157360484Sobrien bfd_set_format (outarch, bfd_archive); 157460484Sobrien outarch->has_armap = 1; 157560484Sobrien 157660484Sobrien /* Work out a reasonable size of things to put onto one line. */ 157760484Sobrien 157860484Sobrien ar_head = make_head (outarch); 157960484Sobrien 158060484Sobrien for (i = 0; i<def->num_exports; i++) 158160484Sobrien { 158260484Sobrien /* The import library doesn't know about the internal name */ 158360484Sobrien char *internal = def->exports[i].internal_name; 158460484Sobrien bfd *n; 158560484Sobrien def->exports[i].internal_name = def->exports[i].name; 158660484Sobrien n = make_one (def->exports+i, outarch); 158760484Sobrien n->next = head; 158860484Sobrien head = n; 158960484Sobrien def->exports[i].internal_name = internal; 159060484Sobrien } 159160484Sobrien 159260484Sobrien ar_tail = make_tail (outarch); 159360484Sobrien 159460484Sobrien if (ar_head == NULL || ar_tail == NULL) 159560484Sobrien return; 159660484Sobrien 159760484Sobrien /* Now stick them all into the archive */ 159860484Sobrien 159960484Sobrien ar_head->next = head; 160060484Sobrien ar_tail->next = ar_head; 160160484Sobrien head = ar_tail; 160260484Sobrien 160360484Sobrien if (! bfd_set_archive_head (outarch, head)) 160460484Sobrien einfo ("%Xbfd_set_archive_head: %s\n", bfd_errmsg (bfd_get_error ())); 160560484Sobrien 160660484Sobrien if (! bfd_close (outarch)) 160760484Sobrien einfo ("%Xbfd_close %s: %s\n", impfilename, bfd_errmsg (bfd_get_error ())); 160860484Sobrien 160960484Sobrien while (head != NULL) 161060484Sobrien { 161160484Sobrien bfd *n = head->next; 161260484Sobrien bfd_close (head); 161360484Sobrien head = n; 161460484Sobrien } 161560484Sobrien} 161660484Sobrien 161760484Sobrienstatic void 161860484Sobrienadd_bfd_to_link (abfd, name, link_info) 161960484Sobrien bfd *abfd; 162060484Sobrien char *name; 162160484Sobrien struct bfd_link_info *link_info; 162260484Sobrien{ 162360484Sobrien lang_input_statement_type *fake_file; 162460484Sobrien fake_file = lang_add_input_file (name, 162560484Sobrien lang_input_file_is_fake_enum, 162660484Sobrien NULL); 162760484Sobrien fake_file->the_bfd = abfd; 162860484Sobrien ldlang_add_file (fake_file); 162960484Sobrien if (!bfd_link_add_symbols (abfd, link_info)) 163060484Sobrien einfo ("%Xaddsym %s: %s\n", name, bfd_errmsg (bfd_get_error ())); 163160484Sobrien} 163260484Sobrien 163360484Sobrienvoid 163460484Sobrienpe_process_import_defs (output_bfd, link_info) 163560484Sobrien bfd *output_bfd; 163660484Sobrien struct bfd_link_info *link_info; 163760484Sobrien{ 163860484Sobrien def_file_module *module; 163960484Sobrien pe_dll_id_target(bfd_get_target (output_bfd)); 164060484Sobrien 164160484Sobrien if (!pe_def_file) 164260484Sobrien return; 164360484Sobrien 164460484Sobrien for (module = pe_def_file->modules; module; module = module->next) 164560484Sobrien { 164660484Sobrien int i, do_this_dll; 164760484Sobrien 164860484Sobrien dll_filename = module->name; 164960484Sobrien dll_symname = xstrdup (module->name); 165060484Sobrien for (i=0; dll_symname[i]; i++) 165160484Sobrien if (!isalnum (dll_symname[i])) 165260484Sobrien dll_symname[i] = '_'; 165360484Sobrien 165460484Sobrien do_this_dll = 0; 165560484Sobrien 165660484Sobrien for (i=0; i<pe_def_file->num_imports; i++) 165760484Sobrien if (pe_def_file->imports[i].module == module) 165860484Sobrien { 165960484Sobrien def_file_export exp; 166060484Sobrien struct bfd_link_hash_entry *blhe; 166160484Sobrien 166260484Sobrien /* see if we need this import */ 166360484Sobrien char *name = (char *) xmalloc (strlen (pe_def_file->imports[i].internal_name) + 2); 166460484Sobrien sprintf (name, "%s%s", U(""), pe_def_file->imports[i].internal_name); 166560484Sobrien blhe = bfd_link_hash_lookup (link_info->hash, name, 166660484Sobrien false, false, false); 166760484Sobrien free (name); 166860484Sobrien if (blhe && blhe->type == bfd_link_hash_undefined) 166960484Sobrien { 167060484Sobrien bfd *one; 167160484Sobrien /* we do */ 167260484Sobrien if (!do_this_dll) 167360484Sobrien { 167460484Sobrien bfd *ar_head = make_head (output_bfd); 167560484Sobrien add_bfd_to_link (ar_head, ar_head->filename, link_info); 167660484Sobrien do_this_dll = 1; 167760484Sobrien } 167860484Sobrien exp.internal_name = pe_def_file->imports[i].internal_name; 167960484Sobrien exp.name = pe_def_file->imports[i].name; 168060484Sobrien exp.ordinal = pe_def_file->imports[i].ordinal; 168160484Sobrien exp.hint = exp.ordinal >= 0 ? exp.ordinal : 0; 168260484Sobrien exp.flag_private = 0; 168360484Sobrien exp.flag_constant = 0; 168460484Sobrien exp.flag_data = 0; 168560484Sobrien exp.flag_noname = exp.name ? 0 : 1; 168660484Sobrien one = make_one (&exp, output_bfd); 168760484Sobrien add_bfd_to_link (one, one->filename, link_info); 168860484Sobrien } 168960484Sobrien } 169060484Sobrien if (do_this_dll) 169160484Sobrien { 169260484Sobrien bfd *ar_tail = make_tail (output_bfd); 169360484Sobrien add_bfd_to_link (ar_tail, ar_tail->filename, link_info); 169460484Sobrien } 169560484Sobrien 169660484Sobrien free (dll_symname); 169760484Sobrien } 169860484Sobrien} 169960484Sobrien 170060484Sobrien/************************************************************************ 170160484Sobrien 170260484Sobrien We were handed a *.DLL file. Parse it and turn it into a set of 170360484Sobrien IMPORTS directives in the def file. Return true if the file was 170460484Sobrien handled, false if not. 170560484Sobrien 170660484Sobrien ************************************************************************/ 170760484Sobrien 170860484Sobrienstatic unsigned int 170960484Sobrienpe_get16 (abfd, where) 171060484Sobrien bfd *abfd; 171160484Sobrien int where; 171260484Sobrien{ 171360484Sobrien unsigned char b[2]; 171460484Sobrien bfd_seek (abfd, where, SEEK_SET); 171560484Sobrien bfd_read (b, 1, 2, abfd); 171660484Sobrien return b[0] + (b[1]<<8); 171760484Sobrien} 171860484Sobrien 171960484Sobrienstatic unsigned int 172060484Sobrienpe_get32 (abfd, where) 172160484Sobrien bfd *abfd; 172260484Sobrien int where; 172360484Sobrien{ 172460484Sobrien unsigned char b[4]; 172560484Sobrien bfd_seek (abfd, where, SEEK_SET); 172660484Sobrien bfd_read (b, 1, 4, abfd); 172760484Sobrien return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); 172860484Sobrien} 172960484Sobrien 173060484Sobrien#if 0 /* This is not currently used. */ 173160484Sobrien 173260484Sobrienstatic unsigned int 173360484Sobrienpe_as16 (ptr) 173460484Sobrien void *ptr; 173560484Sobrien{ 173660484Sobrien unsigned char *b = ptr; 173760484Sobrien return b[0] + (b[1]<<8); 173860484Sobrien} 173960484Sobrien 174060484Sobrien#endif 174160484Sobrien 174260484Sobrienstatic unsigned int 174360484Sobrienpe_as32 (ptr) 174460484Sobrien void *ptr; 174560484Sobrien{ 174660484Sobrien unsigned char *b = ptr; 174760484Sobrien return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); 174860484Sobrien} 174960484Sobrien 175060484Sobrienboolean 175160484Sobrienpe_implied_import_dll (filename) 175260484Sobrien const char *filename; 175360484Sobrien{ 175460484Sobrien bfd *dll; 175560484Sobrien unsigned long pe_header_offset, opthdr_ofs, num_entries, i; 175660484Sobrien unsigned long export_rva, export_size, nsections, secptr, expptr; 175760484Sobrien unsigned char *expdata, *erva; 175860484Sobrien unsigned long name_rvas, ordinals, nexp, ordbase; 175960484Sobrien const char *dll_name; 176060484Sobrien 176160484Sobrien /* No, I can't use bfd here. kernel32.dll puts its export table in 176260484Sobrien the middle of the .rdata section. */ 176360484Sobrien 176460484Sobrien dll = bfd_openr (filename, pe_details->target_name); 176560484Sobrien if (!dll) 176660484Sobrien { 176760484Sobrien einfo ("%Xopen %s: %s\n", filename, bfd_errmsg (bfd_get_error ())); 176860484Sobrien return false; 176960484Sobrien } 177060484Sobrien /* PEI dlls seem to be bfd_objects */ 177160484Sobrien if (!bfd_check_format (dll, bfd_object)) 177260484Sobrien { 177360484Sobrien einfo ("%X%s: this doesn't appear to be a DLL\n", filename); 177460484Sobrien return false; 177560484Sobrien } 177660484Sobrien 177760484Sobrien dll_name = filename; 177860484Sobrien for (i=0; filename[i]; i++) 177960484Sobrien if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') 178060484Sobrien dll_name = filename + i + 1; 178160484Sobrien 178260484Sobrien pe_header_offset = pe_get32 (dll, 0x3c); 178360484Sobrien opthdr_ofs = pe_header_offset + 4 + 20; 178460484Sobrien num_entries = pe_get32 (dll, opthdr_ofs + 92); 178560484Sobrien if (num_entries < 1) /* no exports */ 178660484Sobrien return false; 178760484Sobrien export_rva = pe_get32 (dll, opthdr_ofs + 96); 178860484Sobrien export_size = pe_get32 (dll, opthdr_ofs + 100); 178960484Sobrien nsections = pe_get16 (dll, pe_header_offset + 4 + 2); 179060484Sobrien secptr = (pe_header_offset + 4 + 20 + 179160484Sobrien pe_get16 (dll, pe_header_offset + 4 + 16)); 179260484Sobrien expptr = 0; 179360484Sobrien for (i=0; i<nsections; i++) 179460484Sobrien { 179560484Sobrien char sname[8]; 179660484Sobrien unsigned long secptr1 = secptr + 40 * i; 179760484Sobrien unsigned long vaddr = pe_get32 (dll, secptr1 + 12); 179860484Sobrien unsigned long vsize = pe_get32 (dll, secptr1 + 16); 179960484Sobrien unsigned long fptr = pe_get32 (dll, secptr1 + 20); 180060484Sobrien bfd_seek(dll, secptr1, SEEK_SET); 180160484Sobrien bfd_read(sname, 1, 8, dll); 180260484Sobrien if (vaddr <= export_rva && vaddr+vsize > export_rva) 180360484Sobrien { 180460484Sobrien expptr = fptr + (export_rva - vaddr); 180560484Sobrien if (export_rva + export_size > vaddr + vsize) 180660484Sobrien export_size = vsize - (export_rva - vaddr); 180760484Sobrien break; 180860484Sobrien } 180960484Sobrien } 181060484Sobrien 181160484Sobrien expdata = (unsigned char *) xmalloc (export_size); 181260484Sobrien bfd_seek (dll, expptr, SEEK_SET); 181360484Sobrien bfd_read (expdata, 1, export_size, dll); 181460484Sobrien erva = expdata - export_rva; 181560484Sobrien 181660484Sobrien if (pe_def_file == 0) 181760484Sobrien pe_def_file = def_file_empty(); 181860484Sobrien 181960484Sobrien nexp = pe_as32 (expdata+24); 182060484Sobrien name_rvas = pe_as32 (expdata+32); 182160484Sobrien ordinals = pe_as32 (expdata+36); 182260484Sobrien ordbase = pe_as32 (expdata+16); 182360484Sobrien for (i=0; i<nexp; i++) 182460484Sobrien { 182560484Sobrien unsigned long name_rva = pe_as32 (erva+name_rvas+i*4); 182660484Sobrien def_file_import *imp; 182760484Sobrien imp = def_file_add_import (pe_def_file, erva+name_rva, dll_name, 182860484Sobrien i, 0); 182960484Sobrien } 183060484Sobrien 183160484Sobrien return true; 183260484Sobrien} 183360484Sobrien 183460484Sobrien/************************************************************************ 183560484Sobrien 183660484Sobrien These are the main functions, called from the emulation. The first 183760484Sobrien is called after the bfds are read, so we can guess at how much space 183860484Sobrien we need. The second is called after everything is placed, so we 183960484Sobrien can put the right values in place. 184060484Sobrien 184160484Sobrien ************************************************************************/ 184260484Sobrien 184360484Sobrienvoid 184460484Sobrienpe_dll_build_sections (abfd, info) 184560484Sobrien bfd *abfd; 184660484Sobrien struct bfd_link_info *info; 184760484Sobrien{ 184860484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 184960484Sobrien process_def_file (abfd, info); 185060484Sobrien 185160484Sobrien generate_edata (abfd, info); 185260484Sobrien build_filler_bfd (1); 185360484Sobrien} 185460484Sobrien 185560484Sobrienvoid 185660484Sobrienpe_exe_build_sections (abfd, info) 185760484Sobrien bfd *abfd; 185860484Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 185960484Sobrien{ 186060484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 186160484Sobrien build_filler_bfd (0); 186260484Sobrien} 186360484Sobrien 186460484Sobrienvoid 186560484Sobrienpe_dll_fill_sections (abfd, info) 186660484Sobrien bfd *abfd; 186760484Sobrien struct bfd_link_info *info; 186860484Sobrien{ 186960484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 187060484Sobrien image_base = pe_data (abfd)->pe_opthdr.ImageBase; 187160484Sobrien 187260484Sobrien generate_reloc (abfd, info); 187360484Sobrien if (reloc_sz > 0) 187460484Sobrien { 187560484Sobrien bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); 187660484Sobrien 187760484Sobrien /* Resize the sections. */ 187860484Sobrien lang_size_sections (stat_ptr->head, abs_output_section, 187960484Sobrien &stat_ptr->head, 0, (bfd_vma) 0, false); 188060484Sobrien 188160484Sobrien /* Redo special stuff. */ 188260484Sobrien ldemul_after_allocation (); 188360484Sobrien 188460484Sobrien /* Do the assignments again. */ 188560484Sobrien lang_do_assignments (stat_ptr->head, 188660484Sobrien abs_output_section, 188760484Sobrien (fill_type) 0, (bfd_vma) 0); 188860484Sobrien } 188960484Sobrien 189060484Sobrien fill_edata (abfd, info); 189160484Sobrien 189260484Sobrien pe_data (abfd)->dll = 1; 189360484Sobrien 189460484Sobrien edata_s->contents = edata_d; 189560484Sobrien reloc_s->contents = reloc_d; 189660484Sobrien} 189760484Sobrien 189860484Sobrienvoid 189960484Sobrienpe_exe_fill_sections (abfd, info) 190060484Sobrien bfd *abfd; 190160484Sobrien struct bfd_link_info *info; 190260484Sobrien{ 190360484Sobrien pe_dll_id_target (bfd_get_target (abfd)); 190460484Sobrien image_base = pe_data (abfd)->pe_opthdr.ImageBase; 190560484Sobrien 190660484Sobrien generate_reloc (abfd, info); 190760484Sobrien if (reloc_sz > 0) 190860484Sobrien { 190960484Sobrien bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); 191060484Sobrien 191160484Sobrien /* Resize the sections. */ 191260484Sobrien lang_size_sections (stat_ptr->head, abs_output_section, 191360484Sobrien &stat_ptr->head, 0, (bfd_vma) 0, false); 191460484Sobrien 191560484Sobrien /* Redo special stuff. */ 191660484Sobrien ldemul_after_allocation (); 191760484Sobrien 191860484Sobrien /* Do the assignments again. */ 191960484Sobrien lang_do_assignments (stat_ptr->head, 192060484Sobrien abs_output_section, 192160484Sobrien (fill_type) 0, (bfd_vma) 0); 192260484Sobrien } 192360484Sobrien reloc_s->contents = reloc_d; 192460484Sobrien} 1925