]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/objcopy.c
Fix an abort triggered when objcopy is used to set the "share" section flag on an...
[thirdparty/binutils-gdb.git] / binutils / objcopy.c
index 551378da399c8a793a951bb21b9af1b31bd65f99..09facf0061ea28865eabe83e6feb36c38bd35dad 100644 (file)
@@ -1,5 +1,5 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
-   Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   Copyright (C) 1991-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -68,7 +68,7 @@ struct addsym_node
   long      symval;
   flagword  flags;
   char *    section;
-  char *    othersym;
+  const char *  othersym;
 };
 
 typedef struct section_rename
@@ -780,6 +780,7 @@ parse_flags (const char *s)
       PARSE_FLAG ("code", SEC_CODE);
       PARSE_FLAG ("data", SEC_DATA);
       PARSE_FLAG ("rom", SEC_ROM);
+      PARSE_FLAG ("exclude", SEC_EXCLUDE);
       PARSE_FLAG ("share", SEC_COFF_SHARED);
       PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
       PARSE_FLAG ("merge", SEC_MERGE);
@@ -794,7 +795,7 @@ parse_flags (const char *s)
          copy[len] = '\0';
          non_fatal (_("unrecognized section flag `%s'"), copy);
          fatal (_("supported flags: %s"),
-                "alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings");
+                "alloc, load, noload, readonly, debug, code, data, rom, exclude, share, contents, merge, strings");
        }
 
       s = snext;
@@ -808,7 +809,7 @@ parse_flags (const char *s)
    string can't be parsed.  */
 
 static flagword
-parse_symflags (const char *s, char **other)
+parse_symflags (const char *s, const char **other)
 {
   flagword ret;
   const char *snext;
@@ -1453,6 +1454,9 @@ is_hidden_symbol (asymbol *sym)
   return FALSE;
 }
 
+/* Empty name is hopefully never a valid symbol name.  */
+static const char * empty_name = "";
+
 static bfd_boolean
 need_sym_before (struct addsym_node **node, const char *sym)
 {
@@ -1464,10 +1468,12 @@ need_sym_before (struct addsym_node **node, const char *sym)
     {
       if (!ptr->othersym)
        break;
+      if (ptr->othersym == empty_name)
+       continue;
       else if (strcmp (ptr->othersym, sym) == 0)
        {
-         free (ptr->othersym);
-         ptr->othersym = ""; /* Empty name is hopefully never a valid symbol name.  */
+         free ((char *) ptr->othersym);
+         ptr->othersym = empty_name;
          *node = ptr;
          return TRUE;
        }
@@ -1543,12 +1549,13 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
       /* Check if we will remove the current leading character.  */
       rem_leading_char =
-       (name[0] == bfd_get_symbol_leading_char (abfd))
-       && (change_leading_char
-           || (remove_leading_char
-               && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
-                   || undefined
-                   || bfd_is_com_section (bfd_asymbol_section (sym)))));
+       (name[0] != '\0'
+        && name[0] == bfd_get_symbol_leading_char (abfd)
+        && (change_leading_char
+            || (remove_leading_char
+                && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+                    || undefined
+                    || bfd_is_com_section (bfd_asymbol_section (sym))))));
 
       /* Check if we will add a new leading character.  */
       add_leading_char =
@@ -1574,9 +1581,14 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
       if (add_leading_char || prefix_symbols_string)
        {
          char *n, *ptr;
+         size_t len = strlen (name) + 1;
+
+         if (add_leading_char)
+           len++;
+         if (prefix_symbols_string)
+           len += strlen (prefix_symbols_string);
 
-         ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
-                                     + strlen (name) + 1);
+         ptr = n = (char *) xmalloc (len);
          if (add_leading_char)
            *ptr++ = bfd_get_symbol_leading_char (obfd);
 
@@ -1695,7 +1707,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
        {
          if (ptr->othersym)
            {
-             if (strcmp (ptr->othersym, ""))
+             if (ptr->othersym != empty_name)
                fatal (_("'before=%s' not found"), ptr->othersym);
            }
          else
@@ -1940,7 +1952,7 @@ typedef struct objcopy_internal_note
   bfd_vma            start;
   bfd_vma            end;
 } objcopy_internal_note;
-  
+
 #define DEBUG_MERGE 0
 
 #if DEBUG_MERGE
@@ -2036,7 +2048,7 @@ compare_gnu_build_notes (const void * data1, const void * data2)
                    pnote1->note.namesz - 3 : pnote2->note.namesz - 3);
   if (cmp)
     return cmp;
-  
+
   if (pnote1->end < pnote2->start)
     return -1;
   if (pnote1->start > pnote2->end)
@@ -2047,13 +2059,15 @@ compare_gnu_build_notes (const void * data1, const void * data2)
     return -1;
   if (pnote1->end > pnote2->end)
     return 1;
-  
+  if (pnote1->end < pnote2->end)
+    return -1;
+
   /* Put OPEN notes before function notes.  */
   if (is_open_note (pnote1) && ! is_open_note (pnote2))
     return -1;
   if (! is_open_note (pnote1) && is_open_note (pnote2))
     return 1;
-  
+
   return 0;
 }
 
@@ -2081,7 +2095,7 @@ sort_gnu_build_notes (const void * data1, const void * data2)
 
       return 1;                                /* 1: F   2: O   */
     }
-  
+
   /* Sort by starting address.  */
   if (pnote1->start < pnote2->start)
     return -1;
@@ -2099,7 +2113,7 @@ sort_gnu_build_notes (const void * data1, const void * data2)
       && pnote2->note.namesz > 4
       && pnote1->note.namedata[3] != pnote2->note.namedata[3])
     return pnote1->note.namedata[3] - pnote2->note.namedata[3];
-  
+
   return 0;
 }
 
@@ -2146,7 +2160,7 @@ merge_gnu_build_notes (bfd *          abfd,
          goto done;
        }
     }
-  
+
   /* Make a copy of the notes and convert to our internal format.
      Minimum size of a note is 12 bytes.  Also locate the version
      notes and check them.  */
@@ -2227,7 +2241,7 @@ merge_gnu_build_notes (bfd *          abfd,
             address.  */
          end = (bfd_vma) -1;
          break;
-         
+
        case 8:
          if (! is_64bit (abfd))
            {
@@ -2252,7 +2266,7 @@ merge_gnu_build_notes (bfd *          abfd,
          start = bfd_get_64 (abfd, pnote->note.descdata);
          end = bfd_get_64 (abfd, pnote->note.descdata + 8);
          break;
-         
+
        default:
          err = _("corrupt GNU build attribute note: bad description size");
          goto done;
@@ -2391,7 +2405,7 @@ merge_gnu_build_notes (bfd *          abfd,
              || memcmp (back->note.namedata,
                         pnote->note.namedata, pnote->note.namesz) != 0)
            break;
-         
+
          if (back->start == pnote->start
              && back->end == pnote->end)
            {
@@ -2445,7 +2459,7 @@ merge_gnu_build_notes (bfd *          abfd,
       if (! is_deleted_note (pnote))
        merge_debug ("Unable to do anything with note at %#08lx\n",
                     (pnote->note.namedata - (char *) contents) - 12);
-#endif              
+#endif
     }
 
   /* Resort the notes.  */
@@ -2460,7 +2474,9 @@ merge_gnu_build_notes (bfd *          abfd,
   bfd_vma        prev_start = 0;
   bfd_vma        prev_end = 0;
 
-  new = new_contents = xmalloc (size);
+  /* Not sure how, but the notes might grow in size.
+     (eg see PR 1774507).  Allow for this here.  */
+  new = new_contents = xmalloc (size * 2);
   for (pnote = pnotes, old = contents;
        pnote < pnotes_end;
        pnote ++)
@@ -2525,10 +2541,13 @@ merge_gnu_build_notes (bfd *          abfd,
                   pnote->note.namesz
                   );
 #endif
-  
+
   new_size = new - new_contents;
-  memcpy (contents, new_contents, new_size);
-  size = new_size;
+  if (new_size < size)
+    {
+      memcpy (contents, new_contents, new_size);
+      size = new_size;
+    }
   free (new_contents);
 
  done:
@@ -2543,6 +2562,23 @@ merge_gnu_build_notes (bfd *          abfd,
   return size;
 }
 
+static flagword
+check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
+{
+  /* Only set the SEC_COFF_SHARED flag on COFF files.
+     The same bit value is used by ELF targets to indicate
+     compressed sections, and setting that flag here breaks
+     things.  */
+  if ((flags & SEC_COFF_SHARED)
+      && bfd_get_flavour (abfd) != bfd_target_coff_flavour)
+    {
+      non_fatal (_("%s[%s]: Note - dropping 'share' flag as output format is not COFF"),
+                bfd_get_filename (abfd), secname);
+      flags &= ~ SEC_COFF_SHARED;
+    }
+  return flags;
+}
+
 /* Copy object file IBFD onto OBFD.
    Returns TRUE upon success, FALSE otherwise.  */
 
@@ -2646,8 +2682,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
   imach = bfd_get_mach (ibfd);
   if (input_arch)
     {
-      if (bfd_get_arch_info (ibfd) == NULL
-         || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
+      if (iarch == bfd_arch_unknown)
        {
          iarch = input_arch->arch;
          imach = input_arch->mach;
@@ -2656,6 +2691,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        non_fatal (_("Input file `%s' ignores binary architecture parameter."),
                   bfd_get_archive_filename (ibfd));
     }
+  if (iarch == bfd_arch_unknown
+      && bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      && bfd_get_flavour (obfd) == bfd_target_elf_flavour)
+    {
+      const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+      iarch = bed->arch;
+      imach = 0;
+    }
   if (!bfd_set_arch_mach (obfd, iarch, imach)
       && (ibfd->target_defaulted
          || bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
@@ -2784,7 +2827,10 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
          pset = find_section_list (padd->name, FALSE,
                                    SECTION_CONTEXT_SET_FLAGS);
          if (pset != NULL)
-           flags = pset->flags | SEC_HAS_CONTENTS;
+           {         
+             flags = pset->flags | SEC_HAS_CONTENTS;
+             flags = check_new_section_flags (flags, obfd, padd->name);
+           }
          else
            flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
 
@@ -3081,8 +3127,10 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
          for (i = 0; i < c - 1; i++)
            {
              flagword flags;
-             bfd_size_type size;
-             bfd_vma gap_start, gap_stop;
+             bfd_size_type size;           /* Octets.  */
+             bfd_vma gap_start, gap_stop;  /* Octets.  */
+             unsigned int opb1 = bfd_octets_per_byte (obfd, osections[i]);
+             unsigned int opb2 = bfd_octets_per_byte (obfd, osections[i+1]);
 
              flags = bfd_section_flags (osections[i]);
              if ((flags & SEC_HAS_CONTENTS) == 0
@@ -3090,8 +3138,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                continue;
 
              size = bfd_section_size (osections[i]);
-             gap_start = bfd_section_lma (osections[i]) + size;
-             gap_stop = bfd_section_lma (osections[i + 1]);
+             gap_start = bfd_section_lma (osections[i]) * opb1 + size;
+             gap_stop = bfd_section_lma (osections[i + 1]) * opb2;
              if (gap_start < gap_stop)
                {
                  if (!bfd_set_section_size (osections[i],
@@ -3111,14 +3159,16 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 
       if (pad_to_set)
        {
-         bfd_vma lma;
-         bfd_size_type size;
+         bfd_vma lma;         /* Octets.  */
+         bfd_size_type size;  /* Octets.  */
+         unsigned int opb = bfd_octets_per_byte (obfd, osections[c - 1]);
+         bfd_vma _pad_to = pad_to * opb;
 
-         lma = bfd_section_lma (osections[c - 1]);
+         lma = bfd_section_lma (osections[c - 1]) * opb;
          size = bfd_section_size (osections[c - 1]);
-         if (lma + size < pad_to)
+         if (lma + size < _pad_to)
            {
-             if (!bfd_set_section_size (osections[c - 1], pad_to - lma))
+             if (!bfd_set_section_size (osections[c - 1], _pad_to - lma))
                {
                  bfd_nonfatal_message (NULL, obfd, osections[c - 1],
                                        _("can't add padding"));
@@ -3126,9 +3176,9 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                }
              else
                {
-                 gaps[c - 1] = pad_to - (lma + size);
-                 if (max_gap < pad_to - (lma + size))
-                   max_gap = pad_to - (lma + size);
+                 gaps[c - 1] = _pad_to - (lma + size);
+                 if (max_gap < _pad_to - (lma + size))
+                   max_gap = _pad_to - (lma + size);
                }
            }
        }
@@ -3745,6 +3795,14 @@ copy_file (const char *input_filename, const char *output_filename,
          status = 1;
          return;
        }
+
+      if (gnu_debuglink_filename != NULL)
+       {
+         non_fatal (_("--add-gnu-debuglink ignored for archive %s"),
+                    bfd_get_filename (ibfd));
+         gnu_debuglink_filename = NULL;
+       }
+
       /* This is a no-op on non-Coff targets.  */
       set_long_section_mode (obfd, ibfd, long_section_names);
 
@@ -3912,6 +3970,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   flagword flags;
   const char *err;
   const char * name;
+  const char * new_name;
   char *prefix = NULL;
   bfd_boolean make_nobits;
   unsigned int alignment;
@@ -3927,7 +3986,12 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
       flags &= bfd_applicable_section_flags (ibfd);
       flags &= bfd_applicable_section_flags (obfd);
     }
-  name = find_section_rename (name, &flags);
+  new_name = find_section_rename (name, &flags);
+  if (new_name != name)
+    {
+      name = new_name;
+      flags = check_new_section_flags (flags, obfd, name);
+    }
 
   /* Prefix sections.  */
   if (prefix_alloc_sections_string
@@ -3951,7 +4015,10 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   p = find_section_list (bfd_section_name (isection), FALSE,
                         SECTION_CONTEXT_SET_FLAGS);
   if (p != NULL)
-    flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
+    {
+      flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
+      flags = check_new_section_flags (flags, obfd, bfd_section_name (isection));
+    }
   else if (strip_symbols == STRIP_NONDEBUG
           && (flags & (SEC_ALLOC | SEC_GROUP)) != 0
           && !is_nondebug_keep_contents_section (ibfd, isection))
@@ -4032,7 +4099,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     alignment = p->alignment;
   else
     alignment = bfd_section_alignment (isection);
-  
+
   /* FIXME: This is probably not enough.  If we change the LMA we
      may have to recompute the header for the file as well.  */
   if (!bfd_set_section_alignment (osection, alignment))
@@ -5443,7 +5510,7 @@ copy_main (int argc, char *argv[])
            s = strchr (optarg, '=');
            if (s == NULL)
              fatal (_("bad format for --set-section-alignment: argument needed"));
-           
+
            align = atoi (s + 1);
            if (align <= 0)
              fatal (_("bad format for --set-section-alignment: numeric argument needed"));
@@ -5455,7 +5522,7 @@ copy_main (int argc, char *argv[])
                align >>= 1;
                ++palign;
              }
-           
+
            if (align != 1)
              /* Number has more than on 1, i.e. wasn't a power of 2.  */
              fatal (_("bad format for --set-section-alignment: alignment is not a power of two"));
@@ -5471,7 +5538,7 @@ copy_main (int argc, char *argv[])
              p->alignment = palign;
          }
          break;
-         
+
        case OPTION_RENAME_SECTION:
          {
            flagword flags;