Add some shell variables and shell code to elf32.em
[deliverable/binutils-gdb.git] / ld / emultempl / pe.em
index aeecb614109ba6c178b7e6265bf899df8a04afd0..0ffeffc061b4992cd6a2679e55e4194d1afc465c 100644 (file)
@@ -37,11 +37,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
@@ -102,11 +102,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;
@@ -114,10 +114,11 @@ static int support_old_code = 0;
 static char * thumb_entry_symbol = NULL;
 static lang_assignment_statement_type *image_base_statement = 0;
 
-static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
 #ifdef DLL_SUPPORT
-static char *pe_out_def_filename = 0;
-static char *pe_implib_filename = 0;
+static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
+static char *pe_out_def_filename = NULL;
+static char *pe_implib_filename = NULL;
+static int pe_enable_auto_image_base = 0;
 #endif
 
 extern const char *output_filename;
@@ -169,6 +170,8 @@ 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)
+#define OPTION_ENABLE_AUTO_IMAGE_BASE  (OPTION_IMP_COMPAT + 1)
+#define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1)
 
 static struct option longopts[] =
 {
@@ -203,6 +206,8 @@ 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},
 #endif
   {NULL, no_argument, NULL, 0}
 };
@@ -282,6 +287,9 @@ gld_${EMULATION_NAME}_list_options (file)
   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"));
 #endif
 }
 
@@ -540,11 +548,51 @@ 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;
 #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.  */
 
@@ -561,7 +609,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;
     }
@@ -626,6 +679,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
@@ -644,7 +698,6 @@ pe_undef_cdecl_match (h, string)
   return true;
 }
 
-#ifdef DLL_SUPPORT
 static void
 pe_fixup_stdcalls ()
 {
@@ -816,7 +869,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;
              }
@@ -870,10 +923,10 @@ 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. */
-#ifdef DLL_SUPPORT
+
 static int
 saw_option(char *option)
 {
@@ -883,7 +936,7 @@ saw_option(char *option)
       return init[i].inited;
   return 0;
 }
-#endif
+#endif /* DLL_SUPPORT */
 
 static boolean
 gld_${EMULATION_NAME}_unrecognized_file(entry)
@@ -1049,6 +1102,7 @@ gld_${EMULATION_NAME}_finish ()
        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);
@@ -1057,7 +1111,7 @@ gld_${EMULATION_NAME}_finish ()
   
   if (pe_out_def_filename)
     pe_dll_generate_def_file (pe_out_def_filename);
-#endif
+#endif /* DLL_SUPPORT */
 }
 
 \f
@@ -1074,23 +1128,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;
-
 struct orphan_save
 {
   lang_output_section_statement_type *os;
   asection **section;
   lang_statement_union_type **stmt;
 };
-static struct orphan_save hold_text;
-static struct orphan_save hold_rdata;
-static struct orphan_save hold_data;
-static struct orphan_save hold_bss;
-
-/* Place an orphan section.  We use this to put random SHF_ALLOC
-   sections in the right segment.  */
 
 /*ARGSUSED*/
 static boolean
@@ -1099,15 +1142,15 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
      asection *s;
 {
   const char *secname;
+  char *hold_section_name;
   char *dollar = 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)
     {
@@ -1116,18 +1159,23 @@ 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);
 
   lang_list_init (&add_child);
 
-  if (hold_use != NULL)
+  if (os != NULL
+      && os->bfd_section != NULL
+      && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
     {
-      wild_doit (&add_child, s, hold_use, file);
+      wild_doit (&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;
       lang_statement_list_type *old;
       lang_statement_list_type add;
@@ -1135,23 +1183,28 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
 
       /* 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_ALLOC) == 0)
        ;
       else if ((s->flags & SEC_HAS_CONTENTS) == 0
-              && hold_bss.os != NULL)
+              && HAVE_SECTION (hold_bss, ".bss"))
        place = &hold_bss;
       else if ((s->flags & SEC_READONLY) == 0
-              && hold_data.os != NULL)
+              && HAVE_SECTION (hold_data, ".data"))
        place = &hold_data;
       else if ((s->flags & SEC_CODE) == 0
               && (s->flags & SEC_READONLY) != 0
-              && hold_rdata.os != NULL)
+              && HAVE_SECTION (hold_rdata, ".rdata"))
        place = &hold_rdata;
       else if ((s->flags & SEC_READONLY) != 0
-              && hold_text.os != NULL)
+              && 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
         different loadable or allocateable characteristics.  */
@@ -1192,19 +1245,17 @@ 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);
-      wild_doit (&add_child, s, hold_use, file);
+      wild_doit (&add_child, s, os, file);
 
       lang_leave_output_section_statement
        ((bfd_vma) 0, "*default*",
-        (struct lang_output_section_phdr_list *) NULL,
-       "*default*");
+        (struct lang_output_section_phdr_list *) NULL, "*default*");
 
       stat_ptr = old;
 
@@ -1212,7 +1263,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
        {
          asection *snew, **pps;
 
-         snew = hold_use->bfd_section;
+         snew = os->bfd_section;
          if (place->os->bfd_section != NULL || place->section != NULL)
            {
              /* Shuffle the section to make the output file look neater.  */
@@ -1261,7 +1312,7 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
     }
 
   {
-    lang_statement_union_type **pl = &hold_use->children.head;
+    lang_statement_union_type **pl = &os->children.head;
 
     if (dollar != NULL)
       {
@@ -1308,31 +1359,69 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
   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 = os;
-  else if (strcmp (os->name, ".rdata") == 0)
-    hold_rdata.os = os;
-  else if (strcmp (os->name, ".data") == 0)
-    hold_data.os = os;
-  else if (strcmp (os->name, ".bss") == 0)
-    hold_bss.os = os;
+  string = (char *) xmalloc (strlen (search->name)
+                             + strlen (filename) 
+                             + sizeof "/lib.a.dll"
+                             + 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))
+           {
+              /* 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
@@ -1388,7 +1477,7 @@ 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,
This page took 0.028632 seconds and 4 git commands to generate.