ld: microblaze: ignore rwx segments
[binutils-gdb.git] / ld / pe-dll.c
index 0248f4b2cf9e602c54985feb47682e9b4d9eae27..fc83f5208d6e5e71cd1d3183e55a3e2824d5c430 100644 (file)
@@ -168,7 +168,8 @@ static bfd_vma image_base;
 static bfd *filler_bfd;
 static struct bfd_section *edata_s, *reloc_s;
 static unsigned char *edata_d, *reloc_d;
-static size_t edata_sz, reloc_sz;
+static unsigned char *reloc_d = NULL;
+static size_t edata_sz, reloc_sz = 0;
 static int runtime_pseudo_relocs_created = 0;
 static bool runtime_pseudp_reloc_v2_init = false;
 
@@ -1033,9 +1034,10 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *
 /* Build the bfd that will contain .edata and .reloc sections.  */
 
 static void
-build_filler_bfd (int include_edata)
+build_filler_bfd (bool include_edata)
 {
   lang_input_statement_type *filler_file;
+
   filler_file = lang_add_input_file ("dll stuff",
                                     lang_input_file_is_fake_enum,
                                     NULL);
@@ -1229,7 +1231,10 @@ fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
   memset (edata_d, 0, edata_sz);
 
   if (pe_data (abfd)->timestamp == -1)
-    H_PUT_32 (abfd, time (0), edata_d + 4);
+    {
+      time_t now = bfd_get_current_time (0);
+      H_PUT_32 (abfd, now, edata_d + 4);
+    }
   else
     H_PUT_32 (abfd, pe_data (abfd)->timestamp, edata_d + 4);
 
@@ -1526,6 +1531,8 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
 
   if (reloc_s == NULL || reloc_s->output_section == bfd_abs_section_ptr)
     return;
+
+  /* Set an upper bound for the total number of relocations we will have to generate.  */
   total_relocs = 0;
   for (b = info->input_bfds; b; b = b->link.next)
     for (s = b->sections; s; s = s->next)
@@ -1538,39 +1545,45 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
     {
       arelent **relocs;
       int relsize, nrelocs;
+      asymbol **symbols;
+
+      if (!bfd_generic_link_read_symbols (b))
+       {
+         einfo (_("%F%P: %pB: could not read symbols: %E\n"), b);
+         return;
+       }
+
+      symbols = bfd_get_outsymbols (b);
 
       for (s = b->sections; s; s = s->next)
        {
-         bfd_vma sec_vma = s->output_section->vma + s->output_offset;
-         asymbol **symbols;
+         bfd_vma sec_vma;
 
-         /* If it's not loaded, we don't need to relocate it this way.  */
-         if (!(s->output_section->flags & SEC_LOAD))
-           continue;
+         /* If the section is not going to be output, then ignore it.  */
+         if (s->output_section == NULL)
+           {
+             /* FIXME: This should not happen.  Convert to the correct
+                form here, but really, this should be investigated.  */
+             s->output_section = bfd_abs_section_ptr;
+             continue;
+           }
 
          /* 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_ptr)
            continue;
 
+         /* If it's not loaded, we don't need to relocate it this way.  */
+         if (!(s->output_section->flags & SEC_LOAD))
+           continue;
+
+         /* This happens when linking with --just-symbols=<file>
+            so do not generate an error.  */
          if (s->output_section->vma == 0)
-           {
-             /* Huh?  Shouldn't happen, but punt if it does.  */
-#if 0 /* This happens when linking with --just-symbols=<file>, so do not generate an error.  */
-             einfo (_("%P: zero vma section reloc detected: `%s' #%d f=%d\n"),
-                    s->output_section->name, s->output_section->index,
-                    s->output_section->flags);
-#endif
-             continue;
-           }
+           continue;
 
-         if (!bfd_generic_link_read_symbols (b))
-           {
-             einfo (_("%F%P: %pB: could not read symbols: %E\n"), b);
-             return;
-           }
+         sec_vma = s->output_section->vma + s->output_offset;
 
-         symbols = bfd_get_outsymbols (b);
          relsize = bfd_get_reloc_upper_bound (b, s);
          relocs = xmalloc (relsize);
          nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols);
@@ -1601,7 +1614,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
                          if (h->symbol_class != C_NT_WEAK || h->numaux != 1)
                            continue;
                          h2 = h->auxbfd->tdata.coff_obj_data->sym_hashes
-                                               [h->aux->x_sym.x_tagndx.l];
+                                               [h->aux->x_sym.x_tagndx.u32];
                          /* We don't want a base reloc if the aux sym is not
                             found, undefined, or if it is the constant ABS
                             zero default value.  (We broaden that slightly by
@@ -1696,12 +1709,17 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
                    }
                }
            }
+
          free (relocs);
          /* Warning: the allocated symbols are remembered in BFD and
             reused later, so don't free them!  */
        }
     }
 
+  /* This can happen for example when LTO has eliminated all code.  */
+  if (total_relocs == 0)
+    return;
+  
   /* At this point, we have total_relocs relocation addresses in
      reloc_addresses, which are all suitable for the .reloc section.
      We must now create the new sections.  */
@@ -1726,9 +1744,9 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
 
   reloc_sz = (reloc_sz + 3) & ~3;      /* 4-byte align.  */
   reloc_d = xmalloc (reloc_sz);
-  sec_page = (bfd_vma) -1;
+
+  page_ptr = sec_page = (bfd_vma) -1;
   reloc_sz = 0;
-  page_ptr = (bfd_vma) -1;
 
   for (i = 0; i < total_relocs; i++)
     {
@@ -1758,7 +1776,6 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
          bfd_put_16 (abfd, reloc_data[i].extra, reloc_d + reloc_sz);
          reloc_sz += 2;
        }
-
     }
 
   while (reloc_sz & 3)
@@ -2093,6 +2110,7 @@ make_head (bfd *parent)
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2186,6 +2204,7 @@ make_tail (bfd *parent)
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2307,6 +2326,31 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
   bfd *abfd;
   const unsigned char *jmp_bytes = NULL;
   int jmp_byte_count = 0;
+  const char *internal_name = exp->internal_name;
+
+  if (!exp->flag_noname)
+    {
+      /* Check for a decorated symbol name */
+      struct decoration_hash_entry *entry;
+
+      entry = (struct decoration_hash_entry *)
+             bfd_hash_lookup (&(coff_hash_table (&link_info)->decoration_hash),
+                              internal_name, false, false);
+      if (entry)
+       {
+         if (entry->decorated_link)
+           {
+             internal_name = entry->decorated_link->root.string;
+
+             if (pe_details->underscored && internal_name[0] == '_')
+               internal_name++;
+           }
+         else
+           {
+             einfo (_("%P: error: NULL decorated name for %s\n"), internal_name);
+           }
+       }
+    }
 
   /* Include the jump stub section only if it is needed. A jump
      stub is needed if the symbol being imported <sym> is a function
@@ -2353,6 +2397,7 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2368,13 +2413,13 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
   id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2);
   id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2);
 
-  if  (*exp->internal_name == '@')
+  if  (*internal_name == '@')
     {
       quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
                    BSF_GLOBAL, 0);
       if (include_jmp_stub)
-       quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0);
-      quick_symbol (abfd, "__imp_", exp->internal_name, "", id5,
+       quick_symbol (abfd, "", internal_name, "", tx, BSF_GLOBAL, 0);
+      quick_symbol (abfd, "__imp_", internal_name, "", id5,
                    BSF_GLOBAL, 0);
       /* Fastcall applies only to functions,
         so no need for auto-import symbol.  */
@@ -2384,18 +2429,18 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
       quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC,
                    BSF_GLOBAL, 0);
       if (include_jmp_stub)
-       quick_symbol (abfd, U (""), exp->internal_name, "", tx,
+       quick_symbol (abfd, U (""), internal_name, "", tx,
                      BSF_GLOBAL, 0);
-      quick_symbol (abfd, "__imp_", U (""), exp->internal_name, id5,
+      quick_symbol (abfd, "__imp_", U (""), internal_name, id5,
                    BSF_GLOBAL, 0);
       /* Symbol to reference ord/name of imported
         data symbol, used to implement auto-import.  */
       if (exp->flag_data)
-       quick_symbol (abfd, "__nm_", U (""), exp->internal_name, id6,
+       quick_symbol (abfd, "__nm_", U (""), internal_name, id6,
                      BSF_GLOBAL,0);
     }
   if (pe_dll_compat_implib)
-    quick_symbol (abfd, "___imp_", exp->internal_name, "", id5,
+    quick_symbol (abfd, "___imp_", internal_name, "", id5,
                  BSF_GLOBAL, 0);
 
   if (include_jmp_stub)
@@ -2547,6 +2592,7 @@ make_singleton_name_thunk (const char *import, bfd *parent)
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2627,6 +2673,7 @@ make_import_fixup_entry (const char *name,
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2685,6 +2732,7 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED,
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2706,6 +2754,7 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED,
 
   rt_rel
     = quick_section (abfd, ".rdata_runtime_pseudo_reloc", SEC_HAS_CONTENTS, 2);
+  bfd_coff_set_long_section_names (abfd, true);
 
   quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0);
 
@@ -2776,6 +2825,7 @@ pe_create_runtime_relocator_reference (bfd *parent)
   tmp_seq++;
 
   abfd = bfd_create (oname, parent);
+  free (oname);
   bfd_find_target (pe_details->object_target, abfd);
   bfd_make_writable (abfd);
 
@@ -2864,7 +2914,7 @@ pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
     }
 
   else if (addend != 0)
-    einfo (_("%X%P: %C: variable '%pT' can't be auto-imported; please read the documentation for ld's --enable-auto-import for details\n"),
+    einfo (_("%X%P: %H: variable '%pT' can't be auto-imported; please read the documentation for ld's --enable-auto-import for details\n"),
           s->owner, s, rel->address, (*rel->sym_ptr_ptr)->name);
 }
 
@@ -3282,6 +3332,14 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
                                               false, false, false);
                  if (blhe)
                    is_undef = (blhe->type == bfd_link_hash_undefined);
+
+                 if (is_cdecl && (!blhe || !is_undef))
+                   {
+                     blhe = pe_find_cdecl_alias_match (linfo, name + 6);
+                     include_jmp_stub = true;
+                     if (blhe)
+                       is_undef = (blhe->type == bfd_link_hash_undefined);
+                   }
                }
              else
                {
@@ -3289,16 +3347,6 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
                  is_undef = (blhe->type == bfd_link_hash_undefined);
                }
 
-             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 (linfo, name);
-                 include_jmp_stub = true;
-                 if (blhe)
-                   is_undef = (blhe->type == bfd_link_hash_undefined);
-               }
-
              free (name);
 
              if (is_undef)
@@ -3363,22 +3411,30 @@ pe_process_import_defs (bfd *output_bfd, struct bfd_link_info *linfo)
    handled, FALSE if not.  */
 
 static unsigned int
-pe_get16 (bfd *abfd, int where)
+pe_get16 (bfd *abfd, int where, bool *fail)
 {
   unsigned char b[2];
 
-  bfd_seek (abfd, (file_ptr) where, SEEK_SET);
-  bfd_bread (b, (bfd_size_type) 2, abfd);
+  if (bfd_seek (abfd, where, SEEK_SET) != 0
+      || bfd_read (b, 2, abfd) != 2)
+    {
+      *fail = true;
+      return 0;
+    }
   return b[0] + (b[1] << 8);
 }
 
 static unsigned int
-pe_get32 (bfd *abfd, int where)
+pe_get32 (bfd *abfd, int where, bool *fail)
 {
   unsigned char b[4];
 
-  bfd_seek (abfd, (file_ptr) where, SEEK_SET);
-  bfd_bread (b, (bfd_size_type) 4, abfd);
+  if (bfd_seek (abfd, where, SEEK_SET) != 0
+      || bfd_read (b, 4, abfd) != 4)
+    {
+      *fail = true;
+      return 0;
+    }
   return b[0] + (b[1] << 8) + (b[2] << 16) + ((unsigned) b[3] << 24);
 }
 
@@ -3425,38 +3481,49 @@ pe_implied_import_dll (const char *filename)
   /* PEI dlls seem to be bfd_objects.  */
   if (!bfd_check_format (dll, bfd_object))
     {
+    notdll:
       einfo (_("%X%P: %s: this doesn't appear to be a DLL\n"), filename);
       return false;
     }
 
   /* Get pe_header, optional header and numbers of directory entries.  */
-  pe_header_offset = pe_get32 (dll, 0x3c);
+  bool fail = false;
+  pe_header_offset = pe_get32 (dll, 0x3c, &fail);
+  if (fail)
+    goto notdll;
   opthdr_ofs = pe_header_offset + 4 + 20;
 #ifdef pe_use_plus
-  num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /*  & NumberOfRvaAndSizes.  */
+  /* NumberOfRvaAndSizes.  */
+  num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4, &fail);
 #else
-  num_entries = pe_get32 (dll, opthdr_ofs + 92);
+  num_entries = pe_get32 (dll, opthdr_ofs + 92, &fail);
 #endif
+  if (fail)
+    goto notdll;
 
   /* No import or export directory entry.  */
   if (num_entries < 1)
     return false;
 
 #ifdef pe_use_plus
-  export_rva  = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4);
-  export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4);
+  export_rva  = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4, &fail);
+  export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4, &fail);
 #else
-  export_rva = pe_get32 (dll, opthdr_ofs + 96);
-  export_size = pe_get32 (dll, opthdr_ofs + 100);
+  export_rva = pe_get32 (dll, opthdr_ofs + 96, &fail);
+  export_size = pe_get32 (dll, opthdr_ofs + 100, &fail);
 #endif
+  if (fail)
+    goto notdll;
 
   /* No export table - nothing to export.  */
   if (export_size == 0)
     return false;
 
-  nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
+  nsections = pe_get16 (dll, pe_header_offset + 4 + 2, &fail);
   secptr = (pe_header_offset + 4 + 20 +
-           pe_get16 (dll, pe_header_offset + 4 + 16));
+           pe_get16 (dll, pe_header_offset + 4 + 16, &fail));
+  if (fail)
+    goto notdll;
   expptr = 0;
 
   /* Get the rva and size of the export section.  */
@@ -3464,12 +3531,14 @@ pe_implied_import_dll (const char *filename)
     {
       char sname[8];
       bfd_vma secptr1 = secptr + 40 * i;
-      bfd_vma vaddr = pe_get32 (dll, secptr1 + 12);
-      bfd_vma vsize = pe_get32 (dll, secptr1 + 16);
-      bfd_vma fptr = pe_get32 (dll, secptr1 + 20);
+      bfd_vma vaddr = pe_get32 (dll, secptr1 + 12, &fail);
+      bfd_vma vsize = pe_get32 (dll, secptr1 + 16, &fail);
+      bfd_vma fptr = pe_get32 (dll, secptr1 + 20, &fail);
 
-      bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
-      bfd_bread (sname, (bfd_size_type) 8, dll);
+      if (fail
+         || bfd_seek (dll, secptr1, SEEK_SET) != 0
+         || bfd_read (sname, 8, dll) != 8)
+       goto notdll;
 
       if (vaddr <= export_rva && vaddr + vsize > export_rva)
        {
@@ -3485,14 +3554,16 @@ pe_implied_import_dll (const char *filename)
   for (i = 0; i < nsections; i++)
     {
       bfd_vma secptr1 = secptr + 40 * i;
-      bfd_vma vsize = pe_get32 (dll, secptr1 + 8);
-      bfd_vma vaddr = pe_get32 (dll, secptr1 + 12);
-      bfd_vma flags = pe_get32 (dll, secptr1 + 36);
+      bfd_vma vsize = pe_get32 (dll, secptr1 + 8, &fail);
+      bfd_vma vaddr = pe_get32 (dll, secptr1 + 12, &fail);
+      bfd_vma flags = pe_get32 (dll, secptr1 + 36, &fail);
       char sec_name[9];
 
       sec_name[8] = '\0';
-      bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
-      bfd_bread (sec_name, (bfd_size_type) 8, dll);
+      if (fail
+         || bfd_seek (dll, secptr1 + 0, SEEK_SET) != 0
+         || bfd_read (sec_name, 8, dll) != 8)
+       goto notdll;
 
       if (strcmp(sec_name,".data") == 0)
        {
@@ -3527,8 +3598,9 @@ pe_implied_import_dll (const char *filename)
     }
 
   expdata = xmalloc (export_size);
-  bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
-  bfd_bread (expdata, (bfd_size_type) export_size, dll);
+  if (bfd_seek (dll, expptr, SEEK_SET) != 0
+      || bfd_read (expdata, export_size, dll) != export_size)
+    goto notdll;
   erva = (char *) expdata - export_rva;
 
   if (pe_def_file == 0)
@@ -3645,18 +3717,19 @@ 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 && !bfd_link_pic (info))
+  if (pe_def_file->num_exports == 0
+      && (!bfd_link_pic (info) || pe_dll_exclude_all_symbols))
     {
       if (pe_dll_enable_reloc_section)
        {
-         build_filler_bfd (0);
+         build_filler_bfd (false /* edata not needed.  */);
          pe_output_file_set_long_section_names (filler_bfd);
        }
       return;
     }
 
   generate_edata ();
-  build_filler_bfd (1);
+  build_filler_bfd (true /* edata is needed.  */);
   pe_output_file_set_long_section_names (filler_bfd);
 }
 
@@ -3692,6 +3765,7 @@ pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info)
   image_base = pe_data (abfd)->pe_opthdr.ImageBase;
 
   generate_reloc (abfd, info);
+
   if (reloc_sz > 0)
     {
       bfd_set_section_size (reloc_s, reloc_sz);
@@ -3705,9 +3779,15 @@ pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info)
 
       /* Do the assignments again.  */
       lang_do_assignments (lang_final_phase_enum);
+
+      reloc_s->contents = reloc_d;
+    }
+  else if (reloc_s)
+    {
+      /* Do not emit an empty reloc section.  */
+      bfd_set_section_flags (reloc_s, SEC_IN_MEMORY | SEC_EXCLUDE);
+      reloc_s->output_section = bfd_abs_section_ptr;
     }
-  if (reloc_s)
-    reloc_s->contents = reloc_d;
 }
 
 bool