*** empty log message ***
[deliverable/binutils-gdb.git] / ld / emultempl / pe.em
index a91caa848fdf61988e84a3787e1cdb62bb90fe86..6519eae6d30642cd91f1f9483649e2608fcb2b65 100644 (file)
@@ -1,10 +1,16 @@
 # This shell script emits a C file. -*- C -*-
 # It does some substitutions.
+if [ -z "$MACHINE" ]; then 
+  OUTPUT_ARCH=${ARCH}
+else
+  OUTPUT_ARCH=${ARCH}:${MACHINE}
+fi
 rm -f e${EMULATION_NAME}.c
 (echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-)
 cat >>e${EMULATION_NAME}.c <<EOF
 /* This file is part of GLD, the Gnu Linker.
-   Copyright 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -37,11 +43,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "ldgram.h"
 #include "ldexp.h"
 #include "ldlang.h"
+#include "ldfile.h"
 #include "ldemul.h"
 #include "ldlex.h"
 #include "ldmisc.h"
 #include "ldctor.h"
-#include "ldfile.h"
 #include "coff/internal.h"
 
 /* FIXME: This is a BFD internal header file, and we should not be
@@ -51,6 +57,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "deffile.h"
 #include "pe-dll.h"
 
+#include <ctype.h>
+
 #define TARGET_IS_${EMULATION_NAME}
 
 /* Permit the emulation parameters to override the default section
@@ -65,8 +73,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #if defined(TARGET_IS_i386pe)
 #define DLL_SUPPORT
 #endif
+#if defined(TARGET_IS_shpe) || defined(TARGET_IS_mipspe) || defined(TARGET_IS_armpe)
+#define DLL_SUPPORT
+#endif
 
+#if defined(TARGET_IS_i386pe) || ! defined(DLL_SUPPORT)
 #define        PE_DEF_SUBSYSTEM                3
+#else
+#undef NT_EXE_IMAGE_BASE
+#undef PE_DEF_SECTION_ALIGNMENT
+#undef PE_DEF_FILE_ALIGNMENT
+#define NT_EXE_IMAGE_BASE              0x00010000
+#ifdef TARGET_IS_armpe
+#define PE_DEF_SECTION_ALIGNMENT       0x00001000
+#define        PE_DEF_SUBSYSTEM                9
+#else
+#define PE_DEF_SECTION_ALIGNMENT       0x00000400
+#define        PE_DEF_SUBSYSTEM                2
+#endif
+#define PE_DEF_FILE_ALIGNMENT          0x00000200
+#endif
 
 #ifdef TARGET_IS_arm_epoc_pe
 #define bfd_arm_pe_allocate_interworking_sections \
@@ -84,11 +110,11 @@ static void gld_${EMULATION_NAME}_after_parse PARAMS ((void));
 static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void));
 static boolean gld_${EMULATION_NAME}_place_orphan
   PARAMS ((lang_input_statement_type *, asection *));
-static void gld${EMULATION_NAME}_place_section
-  PARAMS ((lang_statement_union_type *));
 static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *));
 static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **));
 static void gld_${EMULATION_NAME}_finish PARAMS ((void));
+static boolean gld_${EMULATION_NAME}_open_dynamic_archive 
+  PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
 
 static struct internal_extra_pe_aouthdr pe;
 static int dll;
@@ -96,19 +122,41 @@ static int support_old_code = 0;
 static char * thumb_entry_symbol = NULL;
 static lang_assignment_statement_type *image_base_statement = 0;
 
-static char *pe_out_def_filename = 0;
+#ifdef DLL_SUPPORT
 static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
-static char *pe_implib_filename = 0;
+static char *pe_out_def_filename = NULL;
+static char *pe_implib_filename = NULL;
+static int pe_enable_auto_image_base = 0;
+static char *pe_dll_search_prefix = NULL;
+#endif
 
 extern const char *output_filename;
 
 static void
 gld_${EMULATION_NAME}_before_parse()
 {
+  const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+  if (arch)
+    {
+      ldfile_output_architecture = arch->arch;
+      ldfile_output_machine = arch->mach;
+      ldfile_output_machine_name = arch->printable_name;
+    }
+  else
+    ldfile_output_architecture = bfd_arch_${ARCH};
   output_filename = "${EXECUTABLE_NAME:-a.exe}";
-  ldfile_output_architecture = bfd_arch_${ARCH};
 #ifdef DLL_SUPPORT
+  config.dynamic_link = true;
   config.has_shared = 1;
+/* link_info.pei386_auto_import = true; */
+
+#if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2)
+#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe
+  lang_add_entry ("WinMainCRTStartup", 1);
+#else
+  lang_add_entry ("_WinMainCRTStartup", 1);
+#endif
+#endif
 #endif
 }
 \f
@@ -141,9 +189,15 @@ gld_${EMULATION_NAME}_before_parse()
 #define OPTION_THUMB_ENTRY             (OPTION_IMPLIB_FILENAME + 1)
 #define OPTION_WARN_DUPLICATE_EXPORTS  (OPTION_THUMB_ENTRY + 1)
 #define OPTION_IMP_COMPAT              (OPTION_WARN_DUPLICATE_EXPORTS + 1)
-
-static struct option longopts[] =
-{
+#define OPTION_ENABLE_AUTO_IMAGE_BASE  (OPTION_IMP_COMPAT + 1)
+#define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1)
+#define OPTION_DLL_SEARCH_PREFIX       (OPTION_DISABLE_AUTO_IMAGE_BASE + 1)
+#define OPTION_NO_DEFAULT_EXCLUDES     (OPTION_DLL_SEARCH_PREFIX + 1)
+#define OPTION_DLL_ENABLE_AUTO_IMPORT  (OPTION_NO_DEFAULT_EXCLUDES + 1)
+#define OPTION_DLL_DISABLE_AUTO_IMPORT (OPTION_DLL_ENABLE_AUTO_IMPORT + 1)
+#define OPTION_ENABLE_EXTRA_PE_DEBUG   (OPTION_DLL_DISABLE_AUTO_IMPORT + 1)
+
+static struct option longopts[] = {
   /* PE options */
   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
   {"dll", no_argument, NULL, OPTION_DLL},
@@ -175,6 +229,13 @@ static struct option longopts[] =
   {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME},
   {"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS},
   {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT},
+  {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE},
+  {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE},
+  {"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX},
+  {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
+  {"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT},
+  {"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT},
+  {"enable-extra-pe-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG},
 #endif
   {NULL, no_argument, NULL, 0}
 };
@@ -207,10 +268,14 @@ static definfo init[] =
   D(MinorOperatingSystemVersion,"__minor_os_version__", 0),
   D(MajorImageVersion,"__major_image_version__", 1),
   D(MinorImageVersion,"__minor_image_version__", 0),
+#ifdef TARGET_IS_armpe
+  D(MajorSubsystemVersion,"__major_subsystem_version__", 2),
+#else
   D(MajorSubsystemVersion,"__major_subsystem_version__", 4),
+#endif
   D(MinorSubsystemVersion,"__minor_subsystem_version__", 0),
   D(Subsystem,"__subsystem__", ${SUBSYSTEM}),
-  D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x2000000),
+  D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x200000),
   D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000),
   D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000),
   D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000),
@@ -247,6 +312,20 @@ gld_${EMULATION_NAME}_list_options (file)
   fprintf (file, _("  --kill-at                          Remove @nn from exported symbols\n"));
   fprintf (file, _("  --out-implib <file>                Generate import library\n"));
   fprintf (file, _("  --output-def <file>                Generate a .DEF file for the built DLL\n"));
+  fprintf (file, _("  --warn-duplicate-exports           Warn about duplicate exports.\n"));
+  fprintf (file, _("  --compat-implib                    Create backward compatible import libs;\n"));
+  fprintf (file, _("                                       create __imp_<SYMBOL> as well.\n"));
+  fprintf (file, _("  --enable-auto-image-base           Automatically choose image base for DLLs\n"));
+  fprintf (file, _("                                       unless user specifies one\n"));
+  fprintf (file, _("  --disable-auto-image-base          Do not auto-choose image base. (default)\n"));
+  fprintf (file, _("  --dll-search-prefix=<string>       When linking dynamically to a dll witout an\n"));
+  fprintf (file, _("                                       importlib, use <string><basename>.dll \n"));
+  fprintf (file, _("                                       in preference to lib<basename>.dll \n"));
+  fprintf (file, _("  --enable-auto-import               Do sophistcated linking of _sym to \n"));
+  fprintf (file, _("                                       __imp_sym for DATA references\n"));
+  fprintf (file, _("  --disable-auto-import              Do not auto-import DATA items from DLLs\n"));
+  fprintf (file, _("  --enable-extra-pe-debug            Enable verbose debug output when building\n"));
+  fprintf (file, _("                                       or linking to DLLs (esp. auto-import)\n"));
 #endif
 }
 
@@ -285,13 +364,18 @@ set_pe_subsystem ()
   v[] =
     {
       { "native", 1, "NtProcessStartup" },
+#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe
+      { "windows", 2, "WinMainCRTStartup" },
+#else
       { "windows", 2, "WinMainCRTStartup" },
+#endif
       { "console", 3, "mainCRTStartup" },
 #if 0
       /* The Microsoft linker does not recognize this.  */
       { "os2", 5, "" },
 #endif
       { "posix", 7, "__PosixProcessStartup"},
+      { "wince", 9, "_WinMainCRTStartup" },
       { 0, 0, 0 }
     };
 
@@ -500,11 +584,66 @@ gld_${EMULATION_NAME}_parse_args(argc, argv)
     case OPTION_IMP_COMPAT:
       pe_dll_compat_implib = 1;
       break;
+    case OPTION_ENABLE_AUTO_IMAGE_BASE:
+      pe_enable_auto_image_base = 1;
+      break;
+    case OPTION_DISABLE_AUTO_IMAGE_BASE:
+      pe_enable_auto_image_base = 0;
+      break;
+    case OPTION_DLL_SEARCH_PREFIX:
+      pe_dll_search_prefix = xstrdup( optarg );
+      break;
+    case OPTION_NO_DEFAULT_EXCLUDES:
+      pe_dll_do_default_excludes = 0;
+      break;
+    case OPTION_DLL_ENABLE_AUTO_IMPORT:
+      link_info.pei386_auto_import = true;
+      break;
+    case OPTION_DLL_DISABLE_AUTO_IMPORT:
+      link_info.pei386_auto_import = false;
+      break;
+    case OPTION_ENABLE_EXTRA_PE_DEBUG:
+      pe_dll_extra_pe_debug = 1;
+      break;
 #endif
     }
   return 1;
 }
 \f
+
+#ifdef DLL_SUPPORT
+static unsigned long 
+strhash (const char *str)
+{
+  const unsigned char *s;
+  unsigned long hash;
+  unsigned int c;
+  unsigned int len;
+
+  hash = 0;
+  len = 0;
+  s = (const unsigned char *) str;
+  while ((c = *s++) != '\0')
+    {
+      hash += c + (c << 17);
+      hash ^= hash >> 2;
+      ++len;
+    }
+  hash += len + (len << 17);
+  hash ^= hash >> 2;
+
+  return hash;
+}
+
+/* Use the output file to create a image base for relocatable DLLs. */
+static unsigned long
+compute_dll_image_base (const char *ofile)
+{
+  unsigned long hash = strhash (ofile);
+  return 0x60000000 | ((hash << 16) & 0x0FFC0000);
+}
+#endif
+
 /* Assign values to the special symbols before the linker script is
    read.  */
 
@@ -521,7 +660,12 @@ gld_${EMULATION_NAME}_set_symbols ()
       if (link_info.relocateable)
        init[IMAGEBASEOFF].value = 0;
       else if (init[DLLOFF].value || link_info.shared)
+#ifdef DLL_SUPPORT
+       init[IMAGEBASEOFF].value = (pe_enable_auto_image_base) ?
+         compute_dll_image_base (output_filename) : NT_DLL_IMAGE_BASE;
+#else
        init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE;
+#endif
       else
        init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE;
     }
@@ -586,6 +730,7 @@ gld_${EMULATION_NAME}_after_parse ()
     ldlang_add_undef (entry_symbol);
 }
 
+#ifdef DLL_SUPPORT
 static struct bfd_link_hash_entry *pe_undef_found_sym;
 
 static boolean
@@ -593,14 +738,15 @@ pe_undef_cdecl_match (h, string)
   struct bfd_link_hash_entry *h;
   PTR string;
 {
-  int sl = strlen (string);
+  int sl;
+  sl = strlen (string); /* silence compiler warning */
   if (h->type == bfd_link_hash_defined
       && strncmp (h->root.string, string, sl) == 0
       && h->root.string[sl] == '@')
-  {
-    pe_undef_found_sym = h;
-    return false;
-  }
+    {
+      pe_undef_found_sym = h;
+      return false;
+    }
   return true;
 }
 
@@ -610,6 +756,11 @@ pe_fixup_stdcalls ()
   static int gave_warning_message = 0;
   struct bfd_link_hash_entry *undef, *sym;
   char *at;
+  if (pe_dll_extra_pe_debug) 
+    {
+      printf ("%s\n", __FUNCTION__);
+    }
+  
   for (undef = link_info.hash->undefs; undef; undef=undef->next)
     if (undef->type == bfd_link_hash_undefined)
     {
@@ -669,14 +820,126 @@ pe_fixup_stdcalls ()
     }
 }
 
+static int
+make_import_fixup (rel)
+  arelent *rel;
+{
+  struct symbol_cache_entry *sym = *rel->sym_ptr_ptr;
+/*
+  bfd *b; 
+*/
+
+  if (pe_dll_extra_pe_debug) 
+    {
+      printf ("arelent: %s@%#x: add=%li\n", sym->name, 
+              (int) rel->address, rel->addend);
+    }
+  pe_create_import_fixup (rel);
+  return 1;
+}
+
+char *pe_data_import_dll;
+
+static void
+pe_find_data_imports ()
+{
+  struct bfd_link_hash_entry *undef, *sym;
+  for (undef = link_info.hash->undefs; undef; undef=undef->next)
+    {
+      if (undef->type == bfd_link_hash_undefined)
+        {
+          /* C++ symbols are *long* */
+          char buf[4096];
+          if (pe_dll_extra_pe_debug) 
+            {
+              printf ("%s:%s\n", __FUNCTION__, undef->root.string);
+            }
+          sprintf (buf, "__imp_%s", undef->root.string);
+
+          sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1);
+          if (sym && sym->type == bfd_link_hash_defined)
+            {
+              einfo (_("Warning: resolving %s by linking to %s (auto-import)\n"),
+                     undef->root.string, buf);
+              {  
+                bfd *b = sym->u.def.section->owner;
+                asymbol **symbols;
+                int nsyms, symsize, i;
+     
+                symsize = bfd_get_symtab_upper_bound (b);
+                symbols = (asymbol **) xmalloc (symsize);
+                nsyms = bfd_canonicalize_symtab (b, symbols);
+
+                for (i = 0; i < nsyms; i++)
+                  {
+                    if (memcmp(symbols[i]->name, "__head_", 
+                             sizeof ("__head_") - 1))
+                      continue;
+                    if (pe_dll_extra_pe_debug)
+                      {
+                        printf ("->%s\n", symbols[i]->name);
+                      }
+                    pe_data_import_dll = (char*) (symbols[i]->name + 
+                                                  sizeof ("__head_") - 1);
+                    break;
+                  }
+              }
+
+              pe_walk_relocs_of_symbol (&link_info, undef->root.string, 
+                                        make_import_fixup);
+
+              /* let's differentiate it somehow from defined */
+              undef->type = bfd_link_hash_defweak;
+              /* we replace original name with __imp_ prefixed, this
+                 1) may trash memory 2) leads to duplicate symbol generation.
+                 Still, IMHO it's better than having name poluted. */
+              undef->root.string = sym->root.string;
+              undef->u.def.value = sym->u.def.value;
+              undef->u.def.section = sym->u.def.section;
+            }
+        }
+    }
+}
+#endif /* DLL_SUPPORT */
+
+static boolean
+pr_sym (h, string)
+  struct bfd_hash_entry *h;
+  PTR string;
+{
+  if (pe_dll_extra_pe_debug) 
+    {
+      printf("+%s\n",h->string);
+    }
+  return true;
+}
+
+
 static void
 gld_${EMULATION_NAME}_after_open ()
 {
+
+  if (pe_dll_extra_pe_debug) 
+    {
+      bfd *a;
+      struct bfd_link_hash_entry *sym;
+      printf ("%s()\n", __FUNCTION__);
+
+      for (sym = link_info.hash->undefs; sym; sym=sym->next)
+        printf ("-%s\n", sym->root.string);
+      bfd_hash_traverse (&link_info.hash->table, pr_sym,NULL);
+
+      for (a = link_info.input_bfds; a; a = a->link_next)
+        {
+          printf("*%s\n",a->filename);
+        }
+    }
+  
   /* Pass the wacky PE command line options into the output bfd.
      FIXME: This should be done via a function, rather than by
      including an internal BFD header.  */
   
-  if (!coff_data (output_bfd)->pe)
+  if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == NULL)
     einfo (_("%F%P: PE operations on non PE file.\n"));
 
   pe_data (output_bfd)->pe_opthdr = pe;
@@ -686,9 +949,18 @@ gld_${EMULATION_NAME}_after_open ()
   if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */
     pe_fixup_stdcalls ();
 
+  pe_find_data_imports (output_bfd, &link_info);
+
   pe_process_import_defs(output_bfd, &link_info);
   if (link_info.shared)
     pe_dll_build_sections (output_bfd, &link_info);
+
+#ifndef TARGET_IS_i386pe
+#ifndef TARGET_IS_armpe
+  else
+    pe_exe_build_sections (output_bfd, &link_info);
+#endif
+#endif
 #endif
 
 #if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe)
@@ -712,7 +984,117 @@ gld_${EMULATION_NAME}_after_open ()
 #endif
 
   {
-    int is_ms_arch;
+    /* This next chunk of code tries to detect the case where you have
+       two import libraries for the same DLL (specifically,
+       symbolically linking libm.a and libc.a in cygwin to
+       libcygwin.a).  In those cases, it's possible for function
+       thunks from the second implib to be used but without the
+       head/tail objects, causing an improper import table.  We detect
+       those cases and rename the "other" import libraries to match
+       the one the head/tail come from, so that the linker will sort
+       things nicely and produce a valid import table. */
+
+    LANG_FOR_EACH_INPUT_STATEMENT (is)
+      {
+       if (is->the_bfd->my_archive)
+         {
+           int idata2 = 0, reloc_count=0, is_imp = 0;
+           asection *sec;
+           
+           /* See if this is an import library thunk.  */
+           for (sec = is->the_bfd->sections; sec; sec = sec->next)
+             {
+               if (strcmp (sec->name, ".idata\$2") == 0)
+                 idata2 = 1;
+               if (strncmp (sec->name, ".idata\$", 7) == 0)
+                 is_imp = 1;
+               reloc_count += sec->reloc_count;
+             }
+           
+           if (is_imp && !idata2 && reloc_count)
+             {
+               /* It is, look for the reference to head and see if it's
+                  from our own library.  */
+               for (sec = is->the_bfd->sections; sec; sec = sec->next)
+                 {
+                   int i;
+                   long symsize;
+                   long relsize;
+                   asymbol **symbols;
+                   arelent **relocs;
+                   int nrelocs;
+                   
+                   symsize = bfd_get_symtab_upper_bound (is->the_bfd);
+                   if (symsize < 1)
+                     break;
+                   relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec);
+                   if (relsize < 1)
+                     break;
+                   
+                   symbols = (asymbol **) xmalloc (symsize);
+                   symsize = bfd_canonicalize_symtab (is->the_bfd, symbols);
+                   if (symsize < 0)
+                     {
+                       einfo ("%X%P: unable to process symbols: %E");
+                       return;
+                     }
+                   
+                   relocs = (arelent **) xmalloc ((size_t) relsize);
+                   nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec,
+                                                         relocs, symbols);
+                   if (nrelocs < 0)
+                     {
+                       free (relocs);
+                       einfo ("%X%P: unable to process relocs: %E");
+                       return;
+                     }
+                   
+                   for (i = 0; i < nrelocs; i++)
+                     {
+                       struct symbol_cache_entry *s;
+                       struct bfd_link_hash_entry * blhe;
+                       bfd *other_bfd;
+                       char *n;
+                       
+                       s = (relocs[i]->sym_ptr_ptr)[0];
+                       
+                       if (s->flags & BSF_LOCAL)
+                         continue;
+                       
+                       /* Thunk section with reloc to another bfd.  */
+                       blhe = bfd_link_hash_lookup (link_info.hash,
+                                                    s->name,
+                                                    false, false, true);
+                           
+                       if (blhe == NULL
+                           || blhe->type != bfd_link_hash_defined)
+                         continue;
+                       
+                       other_bfd = blhe->u.def.section->owner;
+                           
+                       if (strcmp (is->the_bfd->my_archive->filename,
+                                   other_bfd->my_archive->filename) == 0)
+                         continue;
+                       
+                       /* Rename this implib to match the other.  */
+                       n = (char *) xmalloc (strlen (other_bfd->my_archive->filename) + 1);
+                           
+                       strcpy (n, other_bfd->my_archive->filename);
+                           
+                       is->the_bfd->my_archive->filename = n;
+                     }
+
+                   free (relocs);
+                   /* Note - we do not free the symbols,
+                      they are now cached in the BFD.  */
+                 }
+             }
+         }
+      }
+  }
+
+  {
+    int is_ms_arch = 0;
     bfd *cur_arch = 0;
     lang_input_statement_type *is2;
 
@@ -767,7 +1149,7 @@ gld_${EMULATION_NAME}_after_open ()
                sprintf (new_name, "%s.%c", is->the_bfd->filename, seq);
                is->the_bfd->filename = new_name;
 
-               new_name = xmalloc (strlen(is->filename) + 3);
+               new_name = xmalloc (strlen (is->filename) + 3);
                sprintf (new_name, "%s.%c", is->filename, seq);
                is->filename = new_name;
              }
@@ -821,7 +1203,7 @@ gld_${EMULATION_NAME}_before_allocation()
 #endif /* TARGET_IS_armpe */
 }
 \f
-
+#ifdef DLL_SUPPORT
 /* This is called when an input file isn't recognized as a BFD.  We
    check here for .DEF files and pull them in automatically. */
 
@@ -834,10 +1216,11 @@ saw_option(char *option)
       return init[i].inited;
   return 0;
 }
+#endif /* DLL_SUPPORT */
 
 static boolean
 gld_${EMULATION_NAME}_unrecognized_file(entry)
-  lang_input_statement_type *entry;
+     lang_input_statement_type *entry ATTRIBUTE_UNUSED;
 {
 #ifdef DLL_SUPPORT
   const char *ext = entry->filename + strlen (entry->filename) - 4;
@@ -922,11 +1305,20 @@ gld_${EMULATION_NAME}_unrecognized_file(entry)
 
 static boolean
 gld_${EMULATION_NAME}_recognized_file(entry)
-  lang_input_statement_type *entry;
+  lang_input_statement_type *entry ATTRIBUTE_UNUSED;
 {
 #ifdef DLL_SUPPORT
 #ifdef TARGET_IS_i386pe
   pe_dll_id_target ("pei-i386");
+#endif
+#ifdef TARGET_IS_shpe
+  pe_dll_id_target ("pei-shl");
+#endif
+#ifdef TARGET_IS_mipspe
+  pe_dll_id_target ("pei-mips");
+#endif
+#ifdef TARGET_IS_armpe
+  pe_dll_id_target ("pei-arm-little");
 #endif
   if (bfd_get_format (entry->the_bfd) == bfd_object)
     {
@@ -989,9 +1381,27 @@ gld_${EMULATION_NAME}_finish ()
       if (pe_implib_filename)
        pe_dll_generate_implib (pe_def_file, pe_implib_filename);
     }
+#if defined(TARGET_IS_shpe) || defined(TARGET_IS_mipspe)
+  /* ARM doesn't need relocs.  */
+  else
+    {
+      pe_exe_fill_sections (output_bfd, &link_info);
+    }
+#endif
+  
   if (pe_out_def_filename)
     pe_dll_generate_def_file (pe_out_def_filename);
-#endif
+#endif /* DLL_SUPPORT */
+
+  /* I don't know where .idata gets set as code, but it shouldn't be */
+  {
+    asection *asec = bfd_get_section_by_name (output_bfd, ".idata");
+    if (asec)
+      {
+        asec->flags &= ~SEC_CODE;
+        asec->flags |= SEC_DATA;
+      }
+  }
 }
 
 \f
@@ -1008,16 +1418,12 @@ gld_${EMULATION_NAME}_finish ()
    default linker script using wildcards, and are sorted by
    sort_sections.  */
 
-static asection *hold_section;
-static char *hold_section_name;
-static lang_output_section_statement_type *hold_use;
-static lang_output_section_statement_type *hold_text;
-static lang_output_section_statement_type *hold_rdata;
-static lang_output_section_statement_type *hold_data;
-static lang_output_section_statement_type *hold_bss;
-
-/* Place an orphan section.  We use this to put random SHF_ALLOC
-   sections in the right segment.  */
+struct orphan_save
+{
+  lang_output_section_statement_type *os;
+  asection **section;
+  lang_statement_union_type **stmt;
+};
 
 /*ARGSUSED*/
 static boolean
@@ -1026,17 +1432,16 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
      asection *s;
 {
   const char *secname;
-  char *dollar;
-
-  if ((s->flags & SEC_ALLOC) == 0)
-    return false;
+  char *hold_section_name;
+  char *dollar = NULL;
+  const char *ps = NULL;
+  lang_output_section_statement_type *os;
+  lang_statement_list_type add_child;
 
   secname = bfd_get_section_name (s->owner, s);
 
   /* Look through the script to see where to place this section.  */
 
-  hold_section = s;
-
   hold_section_name = xstrdup (secname);
   if (!link_info.relocateable)
     {
@@ -1045,34 +1450,51 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
        *dollar = '\0';
     }
 
-  hold_use = NULL;
-  lang_for_each_statement (gld${EMULATION_NAME}_place_section);
+  os = lang_output_section_find (hold_section_name);
 
-  if (hold_use == NULL)
+  lang_list_init (&add_child);
+
+  if (os != NULL
+      && os->bfd_section != NULL
+      && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
     {
-      lang_output_section_statement_type *place;
+      lang_add_section (&add_child, s, os, file);
+    }
+  else
+    {
+      struct orphan_save *place;
+      static struct orphan_save hold_text;
+      static struct orphan_save hold_rdata;
+      static struct orphan_save hold_data;
+      static struct orphan_save hold_bss;
       char *outsecname;
-      asection *snew, **pps;
       lang_statement_list_type *old;
       lang_statement_list_type add;
       etree_type *address;
 
       /* Try to put the new output section in a reasonable place based
         on the section name and section flags.  */
+#define HAVE_SECTION(hold, name) \
+(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
+
       place = NULL;
-      if ((s->flags & SEC_HAS_CONTENTS) == 0
-         && hold_bss != NULL)
-       place = hold_bss;
+      if ((s->flags & SEC_ALLOC) == 0)
+       ;
+      else if ((s->flags & SEC_HAS_CONTENTS) == 0
+              && HAVE_SECTION (hold_bss, ".bss"))
+       place = &hold_bss;
       else if ((s->flags & SEC_READONLY) == 0
-              && hold_data != NULL)
-       place = hold_data;
+              && HAVE_SECTION (hold_data, ".data"))
+       place = &hold_data;
       else if ((s->flags & SEC_CODE) == 0
               && (s->flags & SEC_READONLY) != 0
-              && hold_rdata != NULL)
-       place = hold_rdata;
+              && HAVE_SECTION (hold_rdata, ".rdata"))
+       place = &hold_rdata;
       else if ((s->flags & SEC_READONLY) != 0
-              && hold_text != NULL)
-       place = hold_text;
+              && HAVE_SECTION (hold_text, ".text"))
+       place = &hold_text;
+
+#undef HAVE_SECTION
 
       /* Choose a unique name for the section.  This will be needed if
         the same section name appears in the input file with
@@ -1099,32 +1521,33 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
          outsecname = newname;
        }
 
-      /* We don't want to free OUTSECNAME, as it may get attached to
-        the output section statement.  */
-
-      /* Create the section in the output file, and put it in the
-        right place.  This shuffling is to make the output file look
-        neater.  */
-      snew = bfd_make_section (output_bfd, outsecname);
-      if (snew == NULL)
-       einfo ("%P%F: output format %s cannot represent section called %s\n",
-              output_bfd->xvec->name, outsecname);
-      if (place != NULL && place->bfd_section != NULL)
-       {
-         for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
-           ;
-         *pps = snew->next;
-         snew->next = place->bfd_section->next;
-         place->bfd_section->next = snew;
-       }
-
       /* Start building a list of statements for this section.  */
       old = stat_ptr;
       stat_ptr = &add;
       lang_list_init (stat_ptr);
 
-      if (link_info.relocateable)
-       address = NULL;
+      if (config.build_constructors)
+       {
+         /* If the name of the section is representable in C, then create
+            symbols to mark the start and the end of the section.  */
+         for (ps = outsecname; *ps != '\0'; ps++)
+           if (! isalnum ((unsigned char) *ps) && *ps != '_')
+             break;
+         if (*ps == '\0')
+           {
+             char *symname;
+             etree_type *e_align;
+             
+             symname = (char *) xmalloc (ps - outsecname + sizeof "___start_");
+             sprintf (symname, "___start_%s", outsecname);
+             e_align = exp_unop (ALIGN_K,
+                                 exp_intop ((bfd_vma) 1 << s->alignment_power));
+             lang_add_assignment (exp_assop ('=', symname, e_align));
+           }
+       }
+      
+      if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+       address = exp_intop ((bfd_vma) 0);
       else
        {
          /* All sections in an executable must be aligned to a page
@@ -1133,104 +1556,234 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
                              exp_nameop (NAME, "__section_alignment__"));
        }
 
-      lang_enter_output_section_statement (outsecname, address, 0,
-                                          (bfd_vma) 0,
-                                          (etree_type *) NULL,
-                                          (etree_type *) NULL,
-                                          (etree_type *) NULL);
+      os = lang_enter_output_section_statement (outsecname, address, 0,
+                                               (bfd_vma) 0,
+                                               (etree_type *) NULL,
+                                               (etree_type *) NULL,
+                                               (etree_type *) NULL);
 
-      hold_use = lang_output_section_statement_lookup (outsecname);
+      lang_add_section (&add_child, s, os, file);
 
       lang_leave_output_section_statement
        ((bfd_vma) 0, "*default*",
-        (struct lang_output_section_phdr_list *) NULL);
+        (struct lang_output_section_phdr_list *) NULL, "*default*");
 
-      /* Now stick the new statement list right after PLACE.  */
-      if (place != NULL)
-       {
-         *add.tail = place->header.next;
-         place->header.next = add.head;
+      if (config.build_constructors && *ps == '\0')
+        {
+         char *symname;
+
+         /* lang_leave_ouput_section_statement resets stat_ptr.  Put
+            stat_ptr back where we want it.  */
+         if (place != NULL)
+           stat_ptr = &add;
+         
+         symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_");
+         sprintf (symname, "___stop_%s", outsecname);
+         lang_add_assignment (exp_assop ('=', symname,
+                                         exp_nameop (NAME, ".")));
        }
 
       stat_ptr = old;
-    }
-
-  if (dollar == NULL)
-    wild_doit (&hold_use->children, s, hold_use, file);
-  else
-    {
-      lang_statement_union_type **pl;
-      boolean found_dollar;
-      lang_statement_list_type list;
-
-      /* The section name has a '$'.  Sort it with the other '$'
-         sections.  */
 
-      found_dollar = false;
-      for (pl = &hold_use->children.head; *pl != NULL; pl = &(*pl)->next)
+      if (place != NULL)
        {
-         lang_input_section_type *ls;
-         const char *lname;
+         asection *snew, **pps;
 
-         if ((*pl)->header.type != lang_input_section_enum)
-           continue;
+         snew = os->bfd_section;
+         if (place->os->bfd_section != NULL || place->section != NULL)
+           {
+             /* Shuffle the section to make the output file look neater.  */
+             if (place->section == NULL)
+               {
+#if 0
+                 /* Finding the end of the list is a little tricky.  We
+                    make a wild stab at it by comparing section flags.  */
+                 flagword first_flags = place->os->bfd_section->flags;
+                 for (pps = &place->os->bfd_section->next;
+                      *pps != NULL && (*pps)->flags == first_flags;
+                      pps = &(*pps)->next)
+                   ;
+                 place->section = pps;
+#else
+                 /* Put orphans after the first section on the list.  */
+                 place->section = &place->os->bfd_section->next;
+#endif
+               }
 
-         ls = &(*pl)->input_section;
+             /*  Unlink the section.  */
+             for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+               ;
+             *pps = snew->next;
 
-         lname = bfd_get_section_name (ls->ifile->the_bfd, ls->section);
-         if (strchr (lname, '$') == NULL)
+             /* Now tack it on to the "place->os" section list.  */
+             snew->next = *place->section;
+             *place->section = snew;
+           }
+         place->section = &snew->next; /* Save the end of this list.  */
+
+         if (place->stmt == NULL)
            {
-             if (found_dollar)
-               break;
+             /* Put the new statement list right at the head.  */
+             *add.tail = place->os->header.next;
+             place->os->header.next = add.head;
            }
          else
            {
-             found_dollar = true;
-             if (strcmp (secname, lname) < 0)
-               break;
+             /* Put it after the last orphan statement we added.  */
+             *add.tail = *place->stmt;
+             *place->stmt = add.head;
            }
-       }
-
-      lang_list_init (&list);
-      wild_doit (&list, s, hold_use, file);
-      if (list.head != NULL)
-       {
-         ASSERT (list.head->next == NULL);
-         list.head->next = *pl;
-         *pl = list.head;
+         place->stmt = add.tail;       /* Save the end of this list.  */
        }
     }
 
+  {
+    lang_statement_union_type **pl = &os->children.head;
+
+    if (dollar != NULL)
+      {
+       boolean found_dollar;
+
+       /* The section name has a '$'.  Sort it with the other '$'
+          sections.  */
+
+       found_dollar = false;
+       for ( ; *pl != NULL; pl = &(*pl)->next)
+         {
+           lang_input_section_type *ls;
+           const char *lname;
+
+           if ((*pl)->header.type != lang_input_section_enum)
+             continue;
+
+           ls = &(*pl)->input_section;
+
+           lname = bfd_get_section_name (ls->ifile->the_bfd, ls->section);
+           if (strchr (lname, '$') == NULL)
+             {
+               if (found_dollar)
+                 break;
+             }
+           else
+             {
+               found_dollar = true;
+               if (strcmp (secname, lname) < 0)
+                 break;
+             }
+         }
+      }
+
+    if (add_child.head != NULL)
+      {
+       add_child.head->next = *pl;
+       *pl = add_child.head;
+      }
+  }
+
   free (hold_section_name);
 
   return true;
 }
 
-static void
-gld${EMULATION_NAME}_place_section (s)
-     lang_statement_union_type *s;
+static boolean
+gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
+     const char * arch ATTRIBUTE_UNUSED;
+     search_dirs_type * search;
+     lang_input_statement_type * entry;
 {
-  lang_output_section_statement_type *os;
+  const char * filename;
+  char * string;
 
-  if (s->header.type != lang_output_section_statement_enum)
-    return;
+  if (! entry->is_archive)
+    return false;
 
-  os = &s->output_section_statement;
+  filename = entry->filename;
 
-  if (strcmp (os->name, hold_section_name) == 0
-      && os->bfd_section != NULL
-      && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC))
-         == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC))))
-    hold_use = os;
-
-  if (strcmp (os->name, ".text") == 0)
-    hold_text = os;
-  else if (strcmp (os->name, ".rdata") == 0)
-    hold_rdata = os;
-  else if (strcmp (os->name, ".data") == 0)
-    hold_data = os;
-  else if (strcmp (os->name, ".bss") == 0)
-    hold_bss = os;
+  string = (char *) xmalloc (strlen (search->name)
+                             + strlen (filename) 
+                             + sizeof "/lib.a.dll"
+#ifdef DLL_SUPPORT
+                             + (pe_dll_search_prefix ? strlen (pe_dll_search_prefix) : 0)
+#endif
+                             + 1);
+
+  /* Try "libfoo.dll.a" first (preferred explicit import library for dll's */
+  sprintf (string, "%s/lib%s.dll.a", search->name, filename);
+
+  if (! ldfile_try_open_bfd (string, entry))
+    {
+      /* Try "foo.dll.a" next (alternate explicit import library for dll's */
+      sprintf (string, "%s/%s.dll.a", search->name, filename);
+      if (! ldfile_try_open_bfd (string, entry))
+        {
+/*
+   Try libfoo.a next. Normally, this would be interpreted as a static
+   library, but it *could* be an import library. For backwards compatibility,
+   libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search,
+   or sometimes errors occur when building legacy packages.
+
+   Putting libfoo.a here means that in a failure case (i.e. the library
+   -lfoo is not found) we will search for libfoo.a twice before
+   giving up -- once here, and once when searching for a "static" lib.
+   for a "static" lib.
+*/
+          /* Try "libfoo.a" (import lib, or static lib, but must
+             take precedence over dll's) */
+          sprintf (string, "%s/lib%s.a", search->name, filename);
+          if (! ldfile_try_open_bfd (string, entry))
+            {
+#ifdef DLL_SUPPORT
+              if (pe_dll_search_prefix)
+                {  
+                  /* Try "<prefix>foo.dll" (preferred dll name, if specified) */
+                  sprintf (string, "%s/%s%s.dll", search->name, pe_dll_search_prefix, filename);
+                  if (! ldfile_try_open_bfd (string, entry))
+                    {
+                      /* Try "libfoo.dll" (default preferred dll name) */
+                      sprintf (string, "%s/lib%s.dll", search->name, filename);
+                      if (! ldfile_try_open_bfd (string, entry))
+                        {
+                          /* Finally, try "foo.dll" (alternate dll name) */
+                          sprintf (string, "%s/%s.dll", search->name, filename);
+                          if (! ldfile_try_open_bfd (string, entry))
+                            {
+                              free (string);
+                              return false;
+                            }
+                        }
+                    }
+                }
+              else /* pe_dll_search_prefix not specified */
+#endif         
+                {
+                  /* Try "libfoo.dll" (preferred dll name) */
+                  sprintf (string, "%s/lib%s.dll", search->name, filename);
+                  if (! ldfile_try_open_bfd (string, entry))
+                    {
+                      /* Finally, try "foo.dll" (alternate dll name) */
+                      sprintf (string, "%s/%s.dll", search->name, filename);
+                      if (! ldfile_try_open_bfd (string, entry))
+                        {
+                          free (string);
+                          return false;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+  entry->filename = string;
+
+  return true;
+}
+
+static int
+gld_${EMULATION_NAME}_find_potential_libraries (name, entry)
+     char * name;
+     lang_input_statement_type * entry;
+{
+  return ldfile_open_file_search (name, entry, "", ".lib");
 }
 \f
 static char *
@@ -1278,12 +1831,13 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   "${OUTPUT_FORMAT}",
   gld_${EMULATION_NAME}_finish, /* finish */
   NULL, /* create output section statements */
-  NULL, /* open dynamic archive */
+  gld_${EMULATION_NAME}_open_dynamic_archive,
   gld_${EMULATION_NAME}_place_orphan,
   gld_${EMULATION_NAME}_set_symbols,
   gld_${EMULATION_NAME}_parse_args,
   gld_${EMULATION_NAME}_unrecognized_file,
   gld_${EMULATION_NAME}_list_options,
-  gld_${EMULATION_NAME}_recognized_file
+  gld_${EMULATION_NAME}_recognized_file,
+  gld_${EMULATION_NAME}_find_potential_libraries
 };
 EOF
This page took 0.050819 seconds and 4 git commands to generate.