Add ability to change linker warning messages into errors when reporting executable...
[binutils-gdb.git] / bfd / elflink.c
index 5a070a26e35509784c6c7615b7f9c477251c2234..49ea222ec77e3fe4305a5ff08344987050f5d9ab 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2022 Free Software Foundation, Inc.
+   Copyright (C) 1995-2023 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -2651,7 +2651,7 @@ elf_link_read_relocs_from_section (bfd *abfd,
     return false;
 
   /* Read the relocations.  */
-  if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
+  if (bfd_read (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
     return false;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -3586,10 +3586,19 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
       abfd = abfd->plugin_dummy_bfd;
       hdr = &elf_tdata (abfd)->symtab_hdr;
     }
-  else if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
-    hdr = &elf_tdata (abfd)->symtab_hdr;
   else
-    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    {
+      if (elf_use_dt_symtab_p (abfd))
+       {
+         bfd_set_error (bfd_error_wrong_format);
+         return false;
+       }
+
+      if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+       hdr = &elf_tdata (abfd)->symtab_hdr;
+      else
+       hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    }
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
 
@@ -4233,6 +4242,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   htab = elf_hash_table (info);
   bed = get_elf_backend_data (abfd);
 
+  if (elf_use_dt_symtab_p (abfd))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return false;
+    }
+
   if ((abfd->flags & DYNAMIC) == 0)
     dynamic = false;
   else
@@ -4386,7 +4401,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                       | DYN_NO_NEEDED)) == 0;
 
       s = bfd_get_section_by_name (abfd, ".dynamic");
-      if (s != NULL && s->size != 0)
+      if (s != NULL && s->size != 0 && (s->flags & SEC_HAS_CONTENTS) != 0)
        {
          bfd_byte *dynbuf;
          bfd_byte *extdyn;
@@ -4406,7 +4421,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
          for (extdyn = dynbuf;
-              extdyn <= dynbuf + s->size - bed->s->sizeof_dyn;
+              (size_t) (dynbuf + s->size - extdyn) >= bed->s->sizeof_dyn;
               extdyn += bed->s->sizeof_dyn)
            {
              Elf_Internal_Dyn dyn;
@@ -5302,10 +5317,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  else
                    _bfd_error_handler
                      /* xgettext:c-format */
-                     (_("warning: alignment %u of symbol `%s' in %pB"
-                        " is smaller than %u in %pB"),
+                     (_("warning: alignment %u of normal symbol `%s' in %pB"
+                        " is smaller than %u used by the common definition in %pB"),
                       1 << normal_align, name, normal_bfd,
                       1 << common_align, common_bfd);
+
+                 /* PR 30499: make sure that users understand that this warning is serious.  */
+                 _bfd_error_handler
+                   (_("warning: NOTE: alignment discrepancies can cause real problems.  Investigation is advised."));
                }
            }
 
@@ -5317,12 +5336,18 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              if (h->size != 0
                  && h->size != isym->st_size
                  && ! size_change_ok)
-               _bfd_error_handler
-                 /* xgettext:c-format */
-                 (_("warning: size of symbol `%s' changed"
-                    " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
-                  name, (uint64_t) h->size, old_bfd,
-                  (uint64_t) isym->st_size, abfd);
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("warning: size of symbol `%s' changed"
+                      " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
+                    name, (uint64_t) h->size, old_bfd,
+                    (uint64_t) isym->st_size, abfd);
+
+                 /* PR 30499: make sure that users understand that this warning is serious.  */
+                 _bfd_error_handler
+                   (_("warning: NOTE: size discrepancies can cause real problems.  Investigation is advised."));
+               }
 
              h->size = isym->st_size;
            }
@@ -5382,7 +5407,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
            }
 
-         if (definition && !dynamic)
+         /* Don't add indirect symbols for .symver x, x@FOO aliases
+            in IR.  Since all data or text symbols in IR have the
+            same type, value and section, we can't tell if a symbol
+            is an alias of another symbol by their types, values and
+            sections.  */
+         if (definition
+             && !dynamic
+             && (abfd->flags & BFD_PLUGIN) == 0)
            {
              char *p = strchr (name, ELF_VER_CHR);
              if (p != NULL && p[1] != ELF_VER_CHR)
@@ -6354,15 +6386,11 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   size_t best_size = 0;
   unsigned long int i;
 
-  /* We have a problem here.  The following code to optimize the table
-     size requires an integer type with more the 32 bits.  If
-     BFD_HOST_U_64_BIT is set we know about such a type.  */
-#ifdef BFD_HOST_U_64_BIT
   if (info->optimize)
     {
       size_t minsize;
       size_t maxsize;
-      BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
+      uint64_t best_chlen = ~((uint64_t) 0);
       bfd *dynobj = elf_hash_table (info)->dynobj;
       size_t dynsymcount = elf_hash_table (info)->dynsymcount;
       const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
@@ -6399,7 +6427,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
       for (i = minsize; i < maxsize; ++i)
        {
          /* Walk through the array of hashcodes and count the collisions.  */
-         BFD_HOST_U_64_BIT max;
+         uint64_t max;
          unsigned long int j;
          unsigned long int fact;
 
@@ -6464,11 +6492,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
       free (counts);
     }
   else
-#endif /* defined (BFD_HOST_U_64_BIT) */
     {
-      /* This is the fallback solution if no 64bit type is available or if we
-        are not supposed to spend much time on optimizations.  We select the
-        bucket count using a fixed set of numbers.  */
       for (i = 0; elf_buckets[i] != 0; i++)
        {
          best_size = elf_buckets[i];
@@ -7124,13 +7148,34 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   /* Determine any GNU_STACK segment requirements, after the backend
      has had a chance to set a default segment size.  */
   if (info->execstack)
-    elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+    {
+      /* If the user has explicitly requested warnings, then generate one even
+        though the choice is the result of another command line option.  */
+      if (info->warn_execstack == 1)
+       {
+         if (info->error_execstack)
+           {
+             _bfd_error_handler
+               (_("\
+error: creating an executable stack because of -z execstack command line option"));
+             return false;
+           }
+
+         _bfd_error_handler
+           (_("\
+warning: enabling an executable stack because of -z execstack command line option"));
+       }
+
+      elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+    }
   else if (info->noexecstack)
     elf_stack_flags (output_bfd) = PF_R | PF_W;
   else
     {
       bfd *inputobj;
       asection *notesec = NULL;
+      bfd *noteobj = NULL;
+      bfd *emptyobj = NULL;
       int exec = 0;
 
       for (inputobj = info->input_bfds;
@@ -7149,15 +7194,67 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
          if (s)
            {
-             if (s->flags & SEC_CODE)
-               exec = PF_X;
              notesec = s;
+             if (s->flags & SEC_CODE)
+               {
+                 noteobj = inputobj;
+                 exec = PF_X;
+                 /* There is no point in scanning the remaining bfds.  */
+                 break;
+               }
+           }
+         else if (bed->default_execstack && info->default_execstack)
+           {
+             exec = PF_X;
+             emptyobj = inputobj;
            }
-         else if (bed->default_execstack)
-           exec = PF_X;
        }
+
       if (notesec || info->stacksize > 0)
-       elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+       {
+         if (exec)
+           {
+             if (info->warn_execstack != 0)
+               {
+                 /* PR 29072: Because an executable stack is a serious
+                    security risk, make sure that the user knows that it is
+                    being enabled despite the fact that it was not requested
+                    on the command line.  */
+                 if (noteobj)
+                   {
+                     if (info->error_execstack)
+                       {
+                         _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack (because it has an executable .note.GNU-stack section)"),
+                                             bfd_get_filename (noteobj));
+                         return false;
+                       }
+
+                     _bfd_error_handler (_("\
+warning: %s: requires executable stack (because the .note.GNU-stack section is executable)"),
+                      bfd_get_filename (noteobj));
+                   }
+                 else if (emptyobj)
+                   {
+                     if (info->error_execstack)
+                       {
+                         _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack because it does not have a .note.GNU-stack section"),
+                                             bfd_get_filename (emptyobj));
+                         return false;
+                       }
+
+                     _bfd_error_handler (_("\
+warning: %s: missing .note.GNU-stack section implies executable stack"),
+                                         bfd_get_filename (emptyobj));
+                     _bfd_error_handler (_("\
+NOTE: This behaviour is deprecated and will be removed in a future version of the linker"));
+                   }
+               }
+           }
+         elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+       }
+
       if (notesec && exec && bfd_link_relocatable (info)
          && notesec->output_section != bfd_abs_section_ptr)
        notesec->output_section->flags |= SEC_CODE;
@@ -8168,7 +8265,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
     return true;
 
   s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s == NULL || s->size == 0)
+  if (s == NULL || s->size == 0 || (s->flags & SEC_HAS_CONTENTS) == 0)
     return true;
 
   if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
@@ -8183,9 +8280,9 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
   extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
   swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
-  extdyn = dynbuf;
-  extdynend = extdyn + s->size;
-  for (; extdyn < extdynend; extdyn += extdynsize)
+  for (extdyn = dynbuf, extdynend = dynbuf + s->size;
+       (size_t) (extdynend - extdyn) >= extdynsize;
+       extdyn += extdynsize)
     {
       Elf_Internal_Dyn dyn;
 
@@ -8336,8 +8433,7 @@ elf_create_symbuf (size_t symcount, Elf_Internal_Sym *isymbuf)
       ssymhead->count++;
     }
   BFD_ASSERT ((size_t) (ssymhead - ssymbuf) == shndx_count
-             && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
-                 == total_size));
+             && (uintptr_t) ssym - (uintptr_t) ssymbuf == total_size);
 
   free (indbuf);
   return ssymbuf;
@@ -9310,7 +9406,6 @@ ext32b_r_offset (const void *p)
   return aval;
 }
 
-#ifdef BFD_HOST_64_BIT
 static bfd_vma
 ext64l_r_offset (const void *p)
 {
@@ -9354,7 +9449,6 @@ ext64b_r_offset (const void *p)
                   | (uint64_t) a->c[7]);
   return aval;
 }
-#endif
 
 /* When performing a relocatable link, the input relocations are
    preserved.  But, if they reference global symbols, the indices
@@ -9458,13 +9552,11 @@ elf_link_adjust_relocs (bfd *abfd,
        }
       else
        {
-#ifdef BFD_HOST_64_BIT
          if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
            ext_r_off = ext64l_r_offset;
          else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
            ext_r_off = ext64b_r_offset;
          else
-#endif
            abort ();
        }
 
@@ -9517,12 +9609,20 @@ elf_link_adjust_relocs (bfd *abfd,
              size_t sortlen = p - loc;
              bfd_vma r_off2 = (*ext_r_off) (loc);
              size_t runlen = elt_size;
+             bfd_vma r_off_runend = r_off;
+             bfd_vma r_off_runend_next;
              size_t buf_size = 96 * 1024;
              while (p + runlen < end
                     && (sortlen <= buf_size
                         || runlen + elt_size <= buf_size)
-                    && r_off2 > (*ext_r_off) (p + runlen))
-               runlen += elt_size;
+                    /* run must not break the ordering of base..loc+1 */
+                    && r_off2 > (r_off_runend_next = (*ext_r_off) (p + runlen))
+                    /* run must be already sorted */
+                    && r_off_runend_next >= r_off_runend)
+               {
+                 runlen += elt_size;
+                 r_off_runend = r_off_runend_next;
+               }
              if (buf == NULL)
                {
                  buf = bfd_malloc (buf_size);
@@ -9956,9 +10056,7 @@ elf_link_output_symstrtab (void *finf,
   if (ELF_ST_BIND (elfsym->st_info) == STB_GNU_UNIQUE)
     elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_unique;
 
-  if (name == NULL
-      || *name == '\0'
-      || (input_sec->flags & SEC_EXCLUDE))
+  if (name == NULL || *name == '\0')
     elfsym->st_name = (unsigned long) -1;
   else
     {
@@ -10122,7 +10220,7 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
   pos = hdr->sh_offset + hdr->sh_size;
   amt = bed->s->sizeof_sym * flinfo->output_bfd->symcount;
   if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0
-      && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt)
+      && bfd_write (symbuf, amt, flinfo->output_bfd) == amt)
     {
       hdr->sh_size += amt;
       ret = true;
@@ -10860,6 +10958,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
     case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+    case SEC_INFO_TYPE_SFRAME:
       return true;
     default:
       break;
@@ -10885,12 +10984,22 @@ elf_section_ignore_discarded_relocs (asection *sec)
 unsigned int
 _bfd_elf_default_action_discarded (asection *sec)
 {
+  const struct elf_backend_data *bed;
+  bed = get_elf_backend_data (sec->owner);
+
   if (sec->flags & SEC_DEBUGGING)
     return PRETEND;
 
   if (strcmp (".eh_frame", sec->name) == 0)
     return 0;
 
+  if (bed->elf_backend_can_make_multiple_eh_frame
+      && strncmp (sec->name, ".eh_frame.", 10) == 0)
+    return 0;
+
+  if (strcmp (".sframe", sec->name) == 0)
+    return 0;
+
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
@@ -11103,22 +11212,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
       /* If this symbol is defined in a section which we are
         discarding, we don't need to keep it.  */
-      if (isym->st_shndx != SHN_UNDEF
-         && isym->st_shndx < SHN_LORESERVE
-         && isec->output_section == NULL
-         && flinfo->info->non_contiguous_regions
-         && flinfo->info->non_contiguous_regions_warnings)
-       {
-         _bfd_error_handler (_("warning: --enable-non-contiguous-regions "
-                               "discards section `%s' from '%s'\n"),
-                             isec->name, bfd_get_filename (isec->owner));
-         continue;
-       }
-
-      if (isym->st_shndx != SHN_UNDEF
-         && isym->st_shndx < SHN_LORESERVE
-         && bfd_section_removed_from_list (output_bfd,
-                                           isec->output_section))
+      if (isym->st_shndx < SHN_LORESERVE
+         && (isec->output_section == NULL
+             || bfd_section_removed_from_list (output_bfd,
+                                               isec->output_section)))
        continue;
 
       /* Get the name of the symbol.  */
@@ -11325,6 +11422,13 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              contents = flinfo->contents;
            }
        }
+      else if (!(o->flags & SEC_RELOC)
+              && !bed->elf_backend_write_section
+              && o->sec_info_type == SEC_INFO_TYPE_MERGE)
+       /* A MERGE section that has no relocations doesn't need the
+          contents anymore, they have been recorded earlier.  Except
+          if the backend has special provisions for writing sections.  */
+       contents = NULL;
       else
        {
          contents = flinfo->contents;
@@ -11824,6 +11928,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              return false;
          }
          break;
+       case SEC_INFO_TYPE_SFRAME:
+           {
+             /* Merge .sframe sections into the ctf frame encoder
+                context of the output_bfd's section.  The final .sframe
+                output section will be written out later.  */
+             if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info,
+                                                 o, contents))
+               return false;
+           }
+           break;
        default:
          {
            if (! (o->flags & SEC_EXCLUDE))
@@ -12374,8 +12488,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                      && elf_symtab_shndx_list (sec->owner) != NULL)
                    max_sym_shndx_count = sym_count;
 
-                 if (esdo->this_hdr.sh_type == SHT_REL
-                     || esdo->this_hdr.sh_type == SHT_RELA)
+                 esdi = elf_section_data (sec);
+
+                 if (esdi->this_hdr.sh_type == SHT_REL
+                     || esdi->this_hdr.sh_type == SHT_RELA)
                    /* Some backends use reloc_count in relocation sections
                       to count particular types of relocs.  Of course,
                       reloc sections themselves can't have relocations.  */
@@ -12393,8 +12509,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  else if (bed->elf_backend_count_relocs)
                    reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
 
-                 esdi = elf_section_data (sec);
-
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
                      size_t ext_size = 0;
@@ -12501,7 +12615,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
             later.  Use bfd_malloc since it will be freed by
             bfd_compress_section_contents.  */
          unsigned char *contents = esdo->this_hdr.contents;
-         if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL)
+         if (contents != NULL)
            abort ();
          contents
            = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size);
@@ -12816,8 +12930,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
-  if (bed->elf_backend_output_arch_local_syms
-      && (info->strip != strip_all || emit_relocs))
+  if (bed->elf_backend_output_arch_local_syms)
     {
       if (! ((*bed->elf_backend_output_arch_local_syms)
             (abfd, info, &flinfo, elf_link_output_symstrtab)))
@@ -12990,7 +13103,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                                                               off, true);
 
              if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
-                 || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
+                 || (bfd_write (flinfo.symshndxbuf, amt, abfd) != amt))
                {
                  ret = false;
                  goto return_local_hash_table;
@@ -13407,6 +13520,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
     goto error_return;
 
+  if (! _bfd_elf_write_section_sframe (abfd, info))
+    goto error_return;
+
   if (info->callbacks->emit_ctf)
       info->callbacks->emit_ctf ();
 
@@ -13623,7 +13739,7 @@ elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED,
       /* Return the local debug definition section.  */
       asection *isec = bfd_section_from_elf_index (sec->owner,
                                                   sym->st_shndx);
-      if ((isec->flags & SEC_DEBUGGING) != 0)
+      if (isec != NULL && (isec->flags & SEC_DEBUGGING) != 0)
        return isec;
     }
 
@@ -14862,6 +14978,41 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                _bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
+  o = bfd_get_section_by_name (output_bfd, ".sframe");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+       {
+         if (i->size == 0)
+           continue;
+
+         abfd = i->owner;
+         if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+           continue;
+
+         if (!init_reloc_cookie_for_section (&cookie, info, i))
+           return -1;
+
+         if (_bfd_elf_parse_sframe (abfd, info, i, &cookie))
+           {
+             if (_bfd_elf_discard_section_sframe (i,
+                                                  bfd_elf_reloc_symbol_deleted_p,
+                                                  &cookie))
+               {
+                 if (i->size != i->rawsize)
+                   changed = 1;
+               }
+           }
+         fini_reloc_cookie_for_section (&cookie, i);
+       }
+      /* Update the reference to the output .sframe section.  Used to
+        determine later if PT_GNU_SFRAME segment is to be generated.  */
+      if (!_bfd_elf_set_section_sframe (output_bfd, info))
+       return -1;
+    }
+
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     {
       const struct elf_backend_data *bed;