MIPS/BFD: Don't stop processing on `bfd_reloc_outofrange'
[deliverable/binutils-gdb.git] / ld / pe-dll.c
index d8b4e5e342692cbdae07710ad3699b42842dc648..1f176ecb46aaf67c6b1da99d57a37a935680a3a6 100644 (file)
@@ -1,6 +1,5 @@
 /* Routines to help build PEI-format DLLs (Win32 etc)
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1998-2016 Free Software Foundation, Inc.
    Written by DJ Delorie <dj@cygnus.com>
 
    This file is part of the GNU Binutils.
@@ -236,6 +235,7 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
   { STRING_COMMA_LEN ("_impure_ptr") },
   { STRING_COMMA_LEN ("_fmode") },
   { STRING_COMMA_LEN ("environ") },
+  { STRING_COMMA_LEN ("__dso_handle") },
   { NULL, 0 }
 };
 
@@ -655,7 +655,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
 
   /* First, run around to all the objects looking for the .drectve
      sections, and push those into the def file too.  */
-  for (b = info->input_bfds; b; b = b->link_next)
+  for (b = info->input_bfds; b; b = b->link.next)
     {
       s = bfd_get_section_by_name (b, ".drectve");
       if (s)
@@ -693,7 +693,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
 
   /* If we are building an executable and there is nothing
      to export, we do not build an export table at all.  */
-  if (info->executable && pe_def_file->num_exports == 0
+  if (bfd_link_executable (info) && pe_def_file->num_exports == 0
       && (!pe_dll_export_everything || pe_dll_exclude_all_symbols))
     return;
 
@@ -701,7 +701,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
   if ((pe_dll_export_everything || pe_def_file->num_exports == 0)
       && !pe_dll_exclude_all_symbols)
     {
-      for (b = info->input_bfds; b; b = b->link_next)
+      for (b = info->input_bfds; b; b = b->link.next)
        {
          asymbol **symbols;
          int nsyms;
@@ -720,9 +720,10 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
              /* We should export symbols which are either global or not
                 anything at all.  (.bss data is the latter)
                 We should not export undefined symbols.  */
-             bfd_boolean would_export = symbols[j]->section != &bfd_und_section
-                     && ((symbols[j]->flags & BSF_GLOBAL)
-                         || (symbols[j]->flags == 0));
+             bfd_boolean would_export
+               = (symbols[j]->section != bfd_und_section_ptr
+                  && ((symbols[j]->flags & BSF_GLOBAL)
+                      || (symbols[j]->flags == 0)));
              if (link_info.version_info && would_export)
                  would_export
                    = !bfd_hide_sym_by_version (link_info.version_info,
@@ -781,14 +782,17 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
     {
       for (i = 0; i < NE; i++)
        {
-         if (strchr (pe_def_file->exports[i].name, '@'))
+         /* Check for fastcall/stdcall-decoration, but ignore
+            C++ mangled names.  */
+         if (pe_def_file->exports[i].name[0] != '?'
+             && strchr (pe_def_file->exports[i].name, '@'))
            {
              /* This will preserve internal_name, which may have been
                 pointing to the same memory as name, or might not
                 have.  */
              int lead_at = (*pe_def_file->exports[i].name == '@');
              char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at);
-             char *tmp_at = strchr (tmp, '@');
+             char *tmp_at = strrchr (tmp, '@');
 
              if (tmp_at)
                *tmp_at = 0;
@@ -890,16 +894,23 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
 
   for (i = 0; i < NE; i++)
     {
+      char *int_name = pe_def_file->exports[i].internal_name;
       char *name;
-      name = xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2);
-      if (pe_details->underscored
-         && (*pe_def_file->exports[i].internal_name != '@'))
+
+      /* PR 19803: Make sure that any exported symbol does not get garbage collected.  */
+      lang_add_gc_name (int_name);
+
+      name = xmalloc (strlen (int_name) + 2);
+      if (pe_details->underscored && int_name[0] != '@')
        {
          *name = '_';
-         strcpy (name + 1, pe_def_file->exports[i].internal_name);
+         strcpy (name + 1, int_name);
+
+         /* PR 19803: The alias must be preserved as well.  */
+         lang_add_gc_name (xstrdup (name));
        }
       else
-       strcpy (name, pe_def_file->exports[i].internal_name);
+       strcpy (name, int_name);
 
       blhe = bfd_link_hash_lookup (info->hash,
                                   name,
@@ -935,7 +946,7 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
         but we must take care not to be fooled when the user wants to export
         a symbol that actually really has a dot in it, so we only check
         for them here, after real defined symbols have already been matched.  */
-      else if (strchr (pe_def_file->exports[i].internal_name, '.'))
+      else if (strchr (int_name, '.'))
        {
          count_exported++;
          if (!pe_def_file->exports[i].flag_noname)
@@ -956,20 +967,20 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
        {
          /* xgettext:c-format */
          einfo (_("%XCannot export %s: symbol not defined\n"),
-                pe_def_file->exports[i].internal_name);
+                int_name);
        }
       else if (blhe)
        {
          /* xgettext:c-format */
          einfo (_("%XCannot export %s: symbol wrong type (%d vs %d)\n"),
-                pe_def_file->exports[i].internal_name,
+                int_name,
                 blhe->type, bfd_link_hash_defined);
        }
       else
        {
          /* xgettext:c-format */
          einfo (_("%XCannot export %s: symbol not found\n"),
-                pe_def_file->exports[i].internal_name);
+                int_name);
        }
       free (name);
     }
@@ -1166,9 +1177,6 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
   unsigned char *enameptrs;
   unsigned char *eordinals;
   char *enamestr;
-  time_t now;
-
-  time (&now);
 
   edata_d = xmalloc (edata_sz);
 
@@ -1183,7 +1191,10 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
                   + edata_s->output_section->vma - image_base)
 
   memset (edata_d, 0, edata_sz);
-  bfd_put_32 (abfd, now, edata_d + 4);
+
+  if (pe_data (abfd)->insert_timestamp)
+    H_PUT_32 (abfd, time (0), edata_d + 4);
+
   if (pe_def_file->version_major != -1)
     {
       bfd_put_16 (abfd, pe_def_file->version_major, edata_d + 8);
@@ -1264,7 +1275,7 @@ pe_walk_relocs_of_symbol (struct bfd_link_info *info,
   bfd *b;
   asection *s;
 
-  for (b = info->input_bfds; b; b = b->link_next)
+  for (b = info->input_bfds; b; b = b->link.next)
     {
       asymbol **symbols;
 
@@ -1327,7 +1338,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
   struct bfd_section *s;
 
   total_relocs = 0;
-  for (b = info->input_bfds; b; b = b->link_next)
+  for (b = info->input_bfds; b; b = b->link.next)
     for (s = b->sections; s; s = s->next)
       total_relocs += s->reloc_count;
 
@@ -1335,7 +1346,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
 
   total_relocs = 0;
   bi = 0;
-  for (bi = 0, b = info->input_bfds; b; bi++, b = b->link_next)
+  for (bi = 0, b = info->input_bfds; b; bi++, b = b->link.next)
     {
       arelent **relocs;
       int relsize, nrelocs;
@@ -1351,7 +1362,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
 
          /* I don't know why there would be a reloc for these, but I've
             seen it happen - DJ  */
-         if (s->output_section == &bfd_abs_section)
+         if (s->output_section == bfd_abs_section_ptr)
            continue;
 
          if (s->output_section->vma == 0)
@@ -1408,7 +1419,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
                             no reason we'd want a reference to any absolute
                             address to get relocated during rebasing).  */
                          if (!h2 || h2->root.type == bfd_link_hash_undefined
-                               || h2->root.u.def.section == &bfd_abs_section)
+                               || h2->root.u.def.section == bfd_abs_section_ptr)
                            continue;
                        }
                      else if (!blhe || blhe->type != bfd_link_hash_defined)
@@ -1767,7 +1778,7 @@ static int tmp_seq2;
 static const char *dll_filename;
 static char *dll_symname;
 
-#define UNDSEC (asection *) &bfd_und_section
+#define UNDSEC bfd_und_section_ptr
 
 static asection *
 quick_section (bfd *abfd, const char *name, int flags, int align)
@@ -2587,7 +2598,7 @@ pe_create_runtime_relocator_reference (bfd *parent)
                BSF_NO_FLAGS, 0);
 
   bfd_set_section_size (abfd, extern_rt_rel, PE_IDATA5_SIZE);
-  extern_rt_rel_d = xmalloc (PE_IDATA5_SIZE);
+  extern_rt_rel_d = xcalloc (1, PE_IDATA5_SIZE);
   extern_rt_rel->contents = extern_rt_rel_d;
 
   quick_reloc (abfd, 0, BFD_RELOC_RVA, 1);
@@ -2712,8 +2723,9 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
       return;
     }
 
-  /* xgettext:c-format */
-  info_msg (_("Creating library file: %s\n"), impfilename);
+  if (verbose)
+    /* xgettext:c-format */
+    info_msg (_("Creating library file: %s\n"), impfilename);
 
   bfd_set_format (outarch, bfd_archive);
   outarch->has_armap = 1;
@@ -2722,7 +2734,7 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
   ar_head = make_head (outarch);
 
   /* Iterate the input BFDs, looking for exclude-modules-for-implib.  */
-  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       /* Iterate the exclude list.  */
       struct exclude_list_struct *ex;
@@ -2785,7 +2797,44 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
       /* Don't add PRIVATE entries to import lib.  */
       if (pe_def_file->exports[i].flag_private)
        continue;
+
       def->exports[i].internal_name = def->exports[i].name;
+
+      /* PR 19803: If a symbol has been discard due to garbage
+        collection then do not create any exports for it.  */
+      {
+       struct coff_link_hash_entry *h;
+
+       h = coff_link_hash_lookup (coff_hash_table (info), internal,
+                                  FALSE, FALSE, FALSE);
+       if (h != NULL
+           /* If the symbol is hidden and undefined then it
+              has been swept up by garbage collection.  */
+           && h->symbol_class == C_HIDDEN
+           && h->root.u.def.section == bfd_und_section_ptr)
+         continue;
+
+       /* If necessary, check with an underscore prefix as well.  */
+       if (pe_details->underscored && internal[0] != '@')
+         {
+           char *name;
+
+           name = xmalloc (strlen (internal) + 2);
+           sprintf (name, "_%s", internal);
+
+           h = coff_link_hash_lookup (coff_hash_table (info), name,
+                                      FALSE, FALSE, FALSE);
+           free (name);
+
+           if (h != NULL
+               /* If the symbol is hidden and undefined then it
+                  has been swept up by garbage collection.  */
+               && h->symbol_class == C_HIDDEN
+               && h->root.u.def.section == bfd_und_section_ptr)
+             continue;
+         }
+      }
+
       n = make_one (def->exports + i, outarch,
                    ! (def->exports + i)->flag_data);
       n->archive_next = head;
@@ -2817,36 +2866,166 @@ pe_dll_generate_implib (def_file *def, const char *impfilename, struct bfd_link_
     }
 }
 
-static struct bfd_link_hash_entry *found_sym;
+static int undef_count = 0;
+
+struct key_value
+{
+  char *key;
+  const char *oname;
+};
+
+static struct key_value *udef_table;
+
+static int undef_sort_cmp (const void *l1, const void *r1)
+{
+  const struct key_value *l = l1;
+  const struct key_value *r = r1;
+
+  return strcmp (l->key, r->key);
+}
+
+static struct bfd_link_hash_entry *
+pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name)
+{
+  struct bfd_link_hash_entry *h = NULL;
+  struct key_value *kv;
+  struct key_value key;
+  char *at, *lname = xmalloc (strlen (name) + 3);
+
+  strcpy (lname, name);
+
+  at = strchr (lname + (lname[0] == '@'), '@');
+  if (at)
+    at[1] = 0;
+
+  key.key = lname;
+  kv = bsearch (&key, udef_table, undef_count, sizeof (struct key_value),
+               undef_sort_cmp);
+
+  if (kv)
+    {
+      h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+      if (h->type == bfd_link_hash_undefined)
+        goto return_h;
+    }
+
+  if (lname[0] == '?')
+    goto return_NULL;
+
+  if (at || lname[0] == '@')
+    {
+      if (lname[0] == '@')
+        {
+         if (pe_details->underscored)
+           lname[0] = '_';
+         else
+           strcpy (lname, lname + 1);
+         key.key = lname;
+         kv = bsearch (&key, udef_table, undef_count,
+                       sizeof (struct key_value), undef_sort_cmp);
+         if (kv)
+           {
+             h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+             if (h->type == bfd_link_hash_undefined)
+               goto return_h;
+           }
+       }
+      if (at)
+        *strchr (lname, '@') = 0;
+      key.key = lname;
+      kv = bsearch (&key, udef_table, undef_count,
+                   sizeof (struct key_value), undef_sort_cmp);
+      if (kv)
+       {
+         h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+         if (h->type == bfd_link_hash_undefined)
+           goto return_h;
+       }
+      goto return_NULL;
+    }
+
+  strcat (lname, "@");
+  key.key = lname;
+  kv = bsearch (&key, udef_table, undef_count,
+               sizeof (struct key_value), undef_sort_cmp);
+
+  if (kv)
+    {
+      h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+      if (h->type == bfd_link_hash_undefined)
+       goto return_h;
+    }
+
+  if (lname[0] == '_' && pe_details->underscored)
+    lname[0] = '@';
+  else
+    {
+      memmove (lname + 1, lname, strlen (lname) + 1);
+      lname[0] = '@';
+    }
+  key.key = lname;
+
+  kv = bsearch (&key, udef_table, undef_count,
+               sizeof (struct key_value), undef_sort_cmp);
+
+  if (kv)
+    {
+      h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+      if (h->type == bfd_link_hash_undefined)
+        goto return_h;
+    }
+
+ return_NULL:
+  h = NULL;
+ return_h:
+  free (lname);
+  return h;
+}
+
+static bfd_boolean
+pe_undef_count (struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
+                void *inf ATTRIBUTE_UNUSED)
+{
+  if (h->type == bfd_link_hash_undefined)
+    undef_count++;
+  return TRUE;
+}
 
 static bfd_boolean
-pe_undef_alias_cdecl_match (struct bfd_link_hash_entry *h, void *inf)
+pe_undef_fill (struct bfd_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
 {
-  int sl;
-  char *string = inf;
-  const char *hs = h->root.string;
-
-  sl = strlen (string);
-  if (h->type == bfd_link_hash_undefined
-      && ((*hs == '@' && (!pe_details->underscored || *string == '_')
-          && strncmp (hs + 1, string + (pe_details->underscored != 0),
-                      sl - (pe_details->underscored != 0)) == 0)
-         || strncmp (hs, string, sl) == 0)
-      && h->root.string[sl] == '@')
-    {
-      found_sym = h;
-      return FALSE;
+  if (h->type == bfd_link_hash_undefined)
+    {
+      char *at;
+
+      udef_table[undef_count].key = xstrdup (h->root.string);
+      at = strchr (udef_table[undef_count].key
+                  + (udef_table[undef_count].key[0] == '@'), '@');
+      if (at)
+        at[1] = 0;
+      udef_table[undef_count].oname = h->root.string;
+      undef_count++;
     }
   return TRUE;
 }
 
-static struct bfd_link_hash_entry *
-pe_find_cdecl_alias_match (char *name)
+static void
+pe_create_undef_table (void)
 {
-  found_sym = 0;
-  bfd_link_hash_traverse (link_info.hash, pe_undef_alias_cdecl_match,
-                         (char *) name);
-  return found_sym;
+  undef_count = 0;
+
+  /* count undefined symbols */
+
+  bfd_link_hash_traverse (link_info.hash, pe_undef_count, "");
+
+  /* create and fill the corresponding table */
+  udef_table = xmalloc (undef_count * sizeof (struct key_value));
+
+  undef_count = 0;
+  bfd_link_hash_traverse (link_info.hash, pe_undef_fill, "");
+
+  /* sort items */
+  qsort (udef_table, undef_count, sizeof (struct key_value), undef_sort_cmp);
 }
 
 static void
@@ -2878,6 +3057,8 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
 
   imp = pe_def_file->imports;
 
+  pe_create_undef_table ();
+
   for (module = pe_def_file->modules; module; module = module->next)
     {
       int do_this_dll = 0;
@@ -2903,6 +3084,8 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
          char *name = xmalloc (len + 2 + 6);
          bfd_boolean include_jmp_stub = FALSE;
          bfd_boolean is_cdecl = FALSE;
+         bfd_boolean is_undef = FALSE;
+
          if (!lead_at && strchr (imp[i].internal_name, '@') == NULL)
              is_cdecl = TRUE;
 
@@ -2926,20 +3109,27 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
 
              blhe = bfd_link_hash_lookup (linfo->hash, name,
                                           FALSE, FALSE, FALSE);
+             if (blhe)
+               is_undef = (blhe->type == bfd_link_hash_undefined);
            }
          else
-           include_jmp_stub = TRUE;
+           {
+             include_jmp_stub = TRUE;
+             is_undef = (blhe->type == bfd_link_hash_undefined);
+           }
 
-         if (is_cdecl && !blhe)
+         if (is_cdecl && (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)))
            {
              sprintf (name, "%s%s",U (""), imp[i].internal_name);
-             blhe = pe_find_cdecl_alias_match (name);
+             blhe = pe_find_cdecl_alias_match (linfo, name);
              include_jmp_stub = TRUE;
+             if (blhe)
+               is_undef = (blhe->type == bfd_link_hash_undefined);
            }
 
          free (name);
 
-         if (blhe && blhe->type == bfd_link_hash_undefined)
+         if (is_undef)
            {
              bfd *one;
              /* We do.  */
@@ -2970,6 +3160,13 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
 
       free (dll_symname);
     }
+
+  while (undef_count)
+    {
+      --undef_count;
+      free (udef_table[undef_count].key);
+    }
+  free (udef_table);
 }
 
 /* We were handed a *.DLL file.  Parse it and turn it into a set of
@@ -3222,7 +3419,7 @@ pe_dll_build_sections (bfd *abfd, struct bfd_link_info *info)
   pe_output_file_set_long_section_names (abfd);
   process_def_file_and_drectve (abfd, info);
 
-  if (pe_def_file->num_exports == 0 && !info->shared)
+  if (pe_def_file->num_exports == 0 && !bfd_link_pic (info))
     return;
 
   generate_edata (abfd, info);
@@ -3264,7 +3461,7 @@ pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info)
 
   fill_edata (abfd, info);
 
-  if (info->shared && !info->pie)
+  if (bfd_link_dll (info))
     pe_data (abfd)->dll = 1;
 
   edata_s->contents = edata_d;
This page took 0.037353 seconds and 4 git commands to generate.