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