]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/objcopy.c
[gdb/testsuite] Add cc-with-dwz.exp and cc-with-dwz-m.exp
[thirdparty/binutils-gdb.git] / binutils / objcopy.c
index 8185f2830c89e207c771029756a3a7555f6f5a95..330b93c1ad3f87a0f5777ac88dc4af1398959bbe 100644 (file)
@@ -1,5 +1,5 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
-   Copyright (C) 1991-2016 Free Software Foundation, Inc.
+   Copyright (C) 1991-2019 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -28,9 +28,9 @@
 #include "filenames.h"
 #include "fnmatch.h"
 #include "elf-bfd.h"
-#include "libbfd.h"
 #include "coff/internal.h"
 #include "libcoff.h"
+#include "safe-ctype.h"
 
 /* FIXME: See bfd/peXXigen.c for why we include an architecture specific
    header in generic PE code.  */
@@ -54,12 +54,11 @@ struct is_specified_symbol_predicate_data
   bfd_boolean  found;
 };
 
-/* A list to support redefine_sym.  */
+/* A node includes symbol name mapping to support redefine_sym.  */
 struct redefine_node
 {
   char *source;
   char *target;
-  struct redefine_node *next;
 };
 
 struct addsym_node
@@ -95,7 +94,11 @@ static int copy_width = 1;
 static bfd_boolean verbose;            /* Print file and target names.  */
 static bfd_boolean preserve_dates;     /* Preserve input file timestamp.  */
 static int deterministic = -1;         /* Enable deterministic archives.  */
-static int status = 0;         /* Exit status.  */
+static int status = 0;                 /* Exit status.  */
+
+static bfd_boolean    merge_notes = FALSE;     /* Merge note sections.  */
+static bfd_byte *     merged_notes = NULL;     /* Contents on note section undergoing a merge.  */
+static bfd_size_type  merged_size = 0;         /* New, smaller size of the merged note section.  */
 
 enum strip_action
 {
@@ -139,6 +142,7 @@ struct section_list
 #define SECTION_CONTEXT_SET_LMA   (1 << 4) /* Set the sections' LMA address.  */
 #define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address.  */
 #define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags.  */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section.  */
 
   bfd_vma              vma_val;   /* Amount to change by or set to.  */
   bfd_vma              lma_val;   /* Amount to change by or set to.  */
@@ -220,6 +224,9 @@ static enum
   decompress = 1 << 4
 } do_debug_sections = nothing;
 
+/* Whether to generate ELF common symbols with the STT_COMMON type.  */
+static enum bfd_link_elf_stt_common do_elf_stt_common = unchanged;
+
 /* Whether to change the leading character in symbol names.  */
 static bfd_boolean change_leading_char = FALSE;
 
@@ -241,10 +248,19 @@ static htab_t localize_specific_htab = NULL;
 static htab_t globalize_specific_htab = NULL;
 static htab_t keepglobal_specific_htab = NULL;
 static htab_t weaken_specific_htab = NULL;
-static struct redefine_node *redefine_sym_list = NULL;
+static htab_t redefine_specific_htab = NULL;
+static htab_t redefine_specific_reverse_htab = NULL;
 static struct addsym_node *add_sym_list = NULL, **add_sym_tail = &add_sym_list;
 static int add_symbols = 0;
 
+static char *strip_specific_buffer = NULL;
+static char *strip_unneeded_buffer = NULL;
+static char *keep_specific_buffer = NULL;
+static char *localize_specific_buffer = NULL;
+static char *globalize_specific_buffer = NULL;
+static char *keepglobal_specific_buffer = NULL;
+static char *weaken_specific_buffer = NULL;
+
 /* If this is TRUE, we weaken global symbols (set BSF_WEAK).  */
 static bfd_boolean weaken = FALSE;
 
@@ -294,6 +310,7 @@ enum command_line_switch
   OPTION_DEBUGGING,
   OPTION_DECOMPRESS_DEBUG_SECTIONS,
   OPTION_DUMP_SECTION,
+  OPTION_ELF_STT_COMMON,
   OPTION_EXTRACT_DWO,
   OPTION_EXTRACT_SYMBOL,
   OPTION_FILE_ALIGNMENT,
@@ -311,6 +328,8 @@ enum command_line_switch
   OPTION_LOCALIZE_HIDDEN,
   OPTION_LOCALIZE_SYMBOLS,
   OPTION_LONG_SECTION_NAMES,
+  OPTION_MERGE_NOTES,
+  OPTION_NO_MERGE_NOTES,
   OPTION_NO_CHANGE_WARNINGS,
   OPTION_ONLY_KEEP_DEBUG,
   OPTION_PAD_TO,
@@ -322,6 +341,7 @@ enum command_line_switch
   OPTION_REDEFINE_SYM,
   OPTION_REDEFINE_SYMS,
   OPTION_REMOVE_LEADING_CHAR,
+  OPTION_REMOVE_RELOCS,
   OPTION_RENAME_SECTION,
   OPTION_REVERSE_BYTES,
   OPTION_SECTION_ALIGNMENT,
@@ -357,12 +377,15 @@ static struct option strip_options[] =
   {"input-target", required_argument, 0, 'I'},
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
   {"keep-symbol", required_argument, 0, 'K'},
+  {"merge-notes", no_argument, 0, 'M'},
+  {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
   {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
   {"output-file", required_argument, 0, 'o'},
   {"output-format", required_argument, 0, 'O'},        /* Obsolete */
   {"output-target", required_argument, 0, 'O'},
   {"preserve-dates", no_argument, 0, 'p'},
   {"remove-section", required_argument, 0, 'R'},
+  {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
   {"strip-all", no_argument, 0, 's'},
   {"strip-debug", no_argument, 0, 'S'},
   {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
@@ -403,6 +426,7 @@ static struct option copy_options[] =
   {"discard-all", no_argument, 0, 'x'},
   {"discard-locals", no_argument, 0, 'X'},
   {"dump-section", required_argument, 0, OPTION_DUMP_SECTION},
+  {"elf-stt-common", required_argument, 0, OPTION_ELF_STT_COMMON},
   {"enable-deterministic-archives", no_argument, 0, 'D'},
   {"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO},
   {"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
@@ -429,6 +453,8 @@ static struct option copy_options[] =
   {"localize-symbol", required_argument, 0, 'L'},
   {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
   {"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
+  {"merge-notes", no_argument, 0, 'M'},
+  {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
   {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
   {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
   {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
@@ -446,6 +472,7 @@ static struct option copy_options[] =
   {"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
   {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
   {"remove-section", required_argument, 0, 'R'},
+  {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
   {"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
   {"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
   {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
@@ -483,14 +510,14 @@ extern char *program_name;
    -1 means if we should use argv[0] to decide.  */
 extern int is_strip;
 
-/* The maximum length of an S record.  This variable is declared in srec.c
+/* The maximum length of an S record.  This variable is defined in srec.c
    and can be modified by the --srec-len parameter.  */
-extern unsigned int Chunk;
+extern unsigned int _bfd_srec_len;
 
 /* Restrict the generation of Srecords to type S3 only.
-   This variable is declare in bfd/srec.c and can be toggled
+   This variable is defined in bfd/srec.c and can be toggled
    on by the --srec-forceS3 command line switch.  */
-extern bfd_boolean S3Forced;
+extern bfd_boolean _bfd_srec_forceS3;
 
 /* Forward declarations.  */
 static void setup_section (bfd *, asection *, void *);
@@ -502,8 +529,9 @@ static int compare_section_lma (const void *, const void *);
 static void mark_symbols_used_in_relocations (bfd *, asection *, void *);
 static bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***);
 static const char *lookup_sym_redefinition (const char *);
+static const char *find_section_rename (const char *, flagword *);
 \f
-static void
+ATTRIBUTE_NORETURN static void
 copy_usage (FILE *stream, int exit_status)
 {
   fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
@@ -532,6 +560,7 @@ copy_usage (FILE *stream, int exit_status)
   -j --only-section <name>         Only copy section <name> into the output\n\
      --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>\n\
   -R --remove-section <name>       Remove section <name> from the output\n\
+     --remove-relocations <name>   Remove relocations from section <name>\n\
   -S --strip-all                   Remove all symbol and relocation information\n\
   -g --strip-debug                 Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
@@ -622,6 +651,10 @@ copy_usage (FILE *stream, int exit_status)
      --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
                                    Compress DWARF debug sections using zlib\n\
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
+     --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
+                                     type\n\
+  -M  --merge-notes                Remove redundant entries in note sections\n\
+      --no-merge-notes             Do not attempt to remove redundant notes (default)\n\
   -v --verbose                     List all object files modified\n\
   @<file>                          Read options from <file>\n\
   -V --version                     Display this program's version number\n\
@@ -634,7 +667,7 @@ copy_usage (FILE *stream, int exit_status)
   exit (exit_status);
 }
 
-static void
+ATTRIBUTE_NORETURN static void
 strip_usage (FILE *stream, int exit_status)
 {
   fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
@@ -660,11 +693,14 @@ strip_usage (FILE *stream, int exit_status)
                                    Disable -D behavior (default)\n"));
   fprintf (stream, _("\
   -R --remove-section=<name>       Also remove section <name> from the output\n\
+     --remove-relocations <name>   Remove relocations from section <name>\n\
   -s --strip-all                   Remove all symbol and relocation information\n\
   -g -S -d --strip-debug           Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
      --strip-unneeded              Remove all symbols not needed by relocations\n\
      --only-keep-debug             Strip everything but the debug information\n\
+  -M  --merge-notes                Remove redundant entries in note sections (default)\n\
+      --no-merge-notes             Do not attempt to remove redundant notes\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
   -K --keep-symbol=<name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
@@ -708,8 +744,8 @@ parse_flags (const char *s)
        }
 
       if (0) ;
-#define PARSE_FLAG(fname,fval) \
-  else if (strncasecmp (fname, s, len) == 0) ret |= fval
+#define PARSE_FLAG(fname,fval)                                 \
+      else if (strncasecmp (fname, s, len) == 0) ret |= fval
       PARSE_FLAG ("alloc", SEC_ALLOC);
       PARSE_FLAG ("load", SEC_LOAD);
       PARSE_FLAG ("noload", SEC_NEVER_LOAD);
@@ -750,7 +786,7 @@ parse_symflags (const char *s, char **other)
 {
   flagword ret;
   const char *snext;
-  int len;
+  size_t len;
 
   ret = BSF_NO_FLAGS;
 
@@ -758,21 +794,23 @@ parse_symflags (const char *s, char **other)
     {
       snext = strchr (s, ',');
       if (snext == NULL)
-         len = strlen (s);
+       len = strlen (s);
       else
        {
          len = snext - s;
          ++snext;
        }
 
-#define PARSE_FLAG(fname,fval)                                                   \
-      else if (len == (int) sizeof fname - 1 && strncasecmp (fname, s, len) == 0) \
+#define PARSE_FLAG(fname, fval)                                                \
+      else if (len == sizeof fname - 1                                 \
+              && strncasecmp (fname, s, len) == 0)                     \
        ret |= fval
 
-#define PARSE_OTHER(fname,fval)                                                                   \
-      else if (len >= (int) sizeof fname && strncasecmp (fname, s, sizeof fname - 1) == 0) \
+#define PARSE_OTHER(fname, fval)                                       \
+      else if (len >= sizeof fname                                     \
+              && strncasecmp (fname, s, sizeof fname - 1) == 0)        \
        fval = xstrndup (s + sizeof fname - 1, len - sizeof fname + 1)
-      
+
       if (0) ;
       PARSE_FLAG ("local", BSF_LOCAL);
       PARSE_FLAG ("global", BSF_GLOBAL);
@@ -802,9 +840,9 @@ parse_symflags (const char *s, char **other)
          copy[len] = '\0';
          non_fatal (_("unrecognized symbol flag `%s'"), copy);
          fatal (_("supported flags: %s"),
-                 "local, global, export, debug, function, weak, section, "
-                 "constructor, warning, indirect, file, object, synthetic, "
-                 "indirect-function, unique-object, before=<othersym>");
+                "local, global, export, debug, function, weak, section, "
+                "constructor, warning, indirect, file, object, synthetic, "
+                "indirect-function, unique-object, before=<othersym>");
        }
 
       s = snext;
@@ -844,7 +882,7 @@ parse_symflags (const char *s, char **other)
 static struct section_list *
 find_section_list (const char *name, bfd_boolean add, unsigned int context)
 {
-  struct section_list *p;
+  struct section_list *p, *match = NULL;
 
   /* assert ((context & ((1 << 7) - 1)) != 0); */
 
@@ -880,19 +918,36 @@ find_section_list (const char *name, bfd_boolean add, unsigned int context)
        }
       /* If we are not adding a new name/pattern then
         only check for a match if the context applies.  */
-      else if ((p->context & context)
-              /* We could check for the presence of wildchar characters
-                 first and choose between calling strcmp and fnmatch,
-                 but is that really worth it ?  */
-              && fnmatch (p->pattern, name, 0) == 0)
-       {
-         p->used = TRUE;
-         return p;
-       }
+      else if (p->context & context)
+        {
+          /* We could check for the presence of wildchar characters
+             first and choose between calling strcmp and fnmatch,
+             but is that really worth it ?  */
+          if (p->pattern [0] == '!')
+            {
+              if (fnmatch (p->pattern + 1, name, 0) == 0)
+                {
+                  p->used = TRUE;
+                  return NULL;
+                }
+            }
+          else
+            {
+              if (fnmatch (p->pattern, name, 0) == 0)
+                {
+                  if (match == NULL)
+                    match = p;
+                }
+            }
+        }
     }
 
   if (! add)
-    return NULL;
+    {
+      if (match != NULL)
+        match->used = TRUE;
+      return match;
+    }
 
   p = (struct section_list *) xmalloc (sizeof (struct section_list));
   p->pattern = name;
@@ -907,6 +962,34 @@ find_section_list (const char *name, bfd_boolean add, unsigned int context)
   return p;
 }
 
+/* S1 is the entry node already in the table, S2 is the key node.  */
+
+static int
+eq_string_redefnode (const void *s1, const void *s2)
+{
+  struct redefine_node *node1 = (struct redefine_node *) s1;
+  struct redefine_node *node2 = (struct redefine_node *) s2;
+  return !strcmp ((const char *) node1->source, (const char *) node2->source);
+}
+
+/* P is redefine node.  Hash value is generated from its "source" filed.  */
+
+static hashval_t
+htab_hash_redefnode (const void *p)
+{
+  struct redefine_node *redefnode = (struct redefine_node *) p;
+  return htab_hash_string (redefnode->source);
+}
+
+/* Create hashtab used for redefine node.  */
+
+static htab_t
+create_symbol2redef_htab (void)
+{
+  return htab_create_alloc (16, htab_hash_redefnode, eq_string_redefnode, NULL,
+                           xcalloc, free);
+}
+
 /* There is htab_hash_string but no htab_eq_string. Makes sense.  */
 
 static int
@@ -931,6 +1014,10 @@ create_symbol_htabs (void)
   globalize_specific_htab = create_symbol_htab ();
   keepglobal_specific_htab = create_symbol_htab ();
   weaken_specific_htab = create_symbol_htab ();
+  redefine_specific_htab = create_symbol2redef_htab ();
+  /* As there is no bidirectional hash table in libiberty, need a reverse table
+     to check duplicated target string.  */
+  redefine_specific_reverse_htab = create_symbol_htab ();
 }
 
 /* Add a symbol to strip_specific_list.  */
@@ -941,13 +1028,21 @@ add_specific_symbol (const char *name, htab_t htab)
   *htab_find_slot (htab, name, INSERT) = (char *) name;
 }
 
+/* Like add_specific_symbol, but the element type is void *.  */
+
+static void
+add_specific_symbol_node (const void *node, htab_t htab)
+{
+  *htab_find_slot (htab, node, INSERT) = (void *) node;
+}
+
 /* Add symbols listed in `filename' to strip_specific_list.  */
 
 #define IS_WHITESPACE(c)      ((c) == ' ' || (c) == '\t')
 #define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
 
 static void
-add_specific_symbols (const char *filename, htab_t htab)
+add_specific_symbols (const char *filename, htab_t htab, char **buffer_p)
 {
   off_t  size;
   FILE * f;
@@ -1055,6 +1150,10 @@ add_specific_symbols (const char *filename, htab_t htab)
       line = eol;
       line_count ++;
     }
+
+  /* Do not free the buffer.  Parts of it will have been referenced
+     in the calls to add_specific_symbol.  */
+  *buffer_p = buffer;
 }
 
 /* See whether a symbol should be stripped or kept
@@ -1116,16 +1215,20 @@ group_signature (asection *group)
   bfd *abfd = group->owner;
   Elf_Internal_Shdr *ghdr;
 
+  /* PR 20089: An earlier error may have prevented us from loading the symbol table.  */
+  if (isympp == NULL)
+    return NULL;
+
   if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
     return NULL;
 
   ghdr = &elf_section_data (group)->this_hdr;
-  if (ghdr->sh_link < elf_numsections (abfd))
+  if (ghdr->sh_link == elf_onesymtab (abfd))
     {
       const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-      Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+      Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd);
 
-      if (symhdr->sh_type == SHT_SYMTAB
+      if (ghdr->sh_info > 0
          && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
        return isympp[ghdr->sh_info - 1];
     }
@@ -1153,17 +1256,35 @@ is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
       struct section_add *pupdate;
 
       for (pupdate = update_sections;
-           pupdate != NULL;
-           pupdate = pupdate->next)
+          pupdate != NULL;
+          pupdate = pupdate->next)
        {
-          if (strcmp (sec->name, pupdate->name) == 0)
-            return TRUE;
-        }
+         if (strcmp (sec->name, pupdate->name) == 0)
+           return TRUE;
+       }
     }
 
   return FALSE;
 }
 
+static bfd_boolean
+is_merged_note_section (bfd * abfd, asection * sec)
+{
+  if (merge_notes
+      && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && elf_section_data (sec)->this_hdr.sh_type == SHT_NOTE
+      /* FIXME: We currently only support merging GNU_BUILD_NOTEs.
+        We should add support for more note types.  */
+      && ((elf_section_data (sec)->this_hdr.sh_flags & SHF_GNU_BUILD_NOTE) != 0
+         /* Old versions of GAS (prior to 2.27) could not set the section
+            flags to OS-specific values, so we also accept sections with the
+            expected name.  */
+         || (strcmp (sec->name, GNU_BUILD_ATTRS_SECTION_NAME) == 0)))
+    return TRUE;
+
+  return FALSE;
+}
+
 /* See if a non-group section is being removed.  */
 
 static bfd_boolean
@@ -1183,8 +1304,8 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
        fatal (_("error: section %s matches both remove and copy options"),
               bfd_get_section_name (abfd, sec));
       if (p && is_update_section (abfd, sec))
-        fatal (_("error: section %s matches both update and remove options"),
-               bfd_get_section_name (abfd, sec));
+       fatal (_("error: section %s matches both update and remove options"),
+              bfd_get_section_name (abfd, sec));
 
       if (p != NULL)
        return TRUE;
@@ -1234,14 +1355,15 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
       const char *gname;
       asection *elt, *first;
 
+      gsym = group_signature (sec);
+      /* Strip groups without a valid signature.  */
+      if (gsym == NULL)
+       return TRUE;
+
       /* PR binutils/3181
         If we are going to strip the group signature symbol, then
         strip the group section too.  */
-      gsym = group_signature (sec);
-      if (gsym != NULL)
-       gname = gsym->name;
-      else
-       gname = sec->name;
+      gname = gsym->name;
       if ((strip_symbols == STRIP_ALL
           && !is_specified_symbol (gname, keep_specific_htab))
          || is_specified_symbol (gname, strip_specific_htab))
@@ -1326,9 +1448,9 @@ need_sym_before (struct addsym_node **node, const char *sym)
 static asymbol *
 create_new_symbol (struct addsym_node *ptr, bfd *obfd)
 {
-  asymbol *sym = bfd_make_empty_symbol(obfd);
+  asymbol *sym = bfd_make_empty_symbol (obfd);
 
-  bfd_asymbol_name(sym) = ptr->symdef;
+  bfd_asymbol_name (sym) = ptr->symdef;
   sym->value = ptr->symval;
   sym->flags = ptr->flags;
   if (ptr->section)
@@ -1338,8 +1460,8 @@ create_new_symbol (struct addsym_node *ptr, bfd *obfd)
        fatal (_("Section %s not found"), ptr->section);
       sym->section = sec;
     }
-  else 
-      sym->section = bfd_abs_section_ptr;
+  else
+    sym->section = bfd_abs_section_ptr;
   return sym;
 }
 
@@ -1376,12 +1498,14 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
            to[dst_count++] = create_new_symbol (ptr, obfd);
        }
 
-      if (redefine_sym_list)
+      if (htab_elements (redefine_specific_htab) || section_rename_list)
        {
-         char *old_name, *new_name;
+         char *new_name;
 
-         old_name = (char *) bfd_asymbol_name (sym);
-         new_name = (char *) lookup_sym_redefinition (old_name);
+         new_name = (char *) lookup_sym_redefinition (name);
+         if (new_name == name
+             && (flags & BSF_SECTION_SYM) != 0)
+           new_name = (char *) find_section_rename (name, NULL);
          bfd_asymbol_name (sym) = new_name;
          name = new_name;
        }
@@ -1404,12 +1528,12 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
       /* Short circuit for change_leading_char if we can do it in-place.  */
       if (rem_leading_char && add_leading_char && !prefix_symbols_string)
-        {
+       {
          name[0] = bfd_get_symbol_leading_char (obfd);
          bfd_asymbol_name (sym) = name;
          rem_leading_char = FALSE;
          add_leading_char = FALSE;
-        }
+       }
 
       /* Remove leading char.  */
       if (rem_leading_char)
@@ -1417,23 +1541,23 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
       /* Add new leading char and/or prefix.  */
       if (add_leading_char || prefix_symbols_string)
-        {
-          char *n, *ptr;
+       {
+         char *n, *ptr;
 
-          ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
-                                      + strlen (name) + 1);
-          if (add_leading_char)
+         ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
+                                     + strlen (name) + 1);
+         if (add_leading_char)
            *ptr++ = bfd_get_symbol_leading_char (obfd);
 
-          if (prefix_symbols_string)
-            {
-              strcpy (ptr, prefix_symbols_string);
-              ptr += strlen (prefix_symbols_string);
-           }
+         if (prefix_symbols_string)
+           {
+             strcpy (ptr, prefix_symbols_string);
+             ptr += strlen (prefix_symbols_string);
+           }
 
-          strcpy (ptr, name);
-          bfd_asymbol_name (sym) = n;
-          name = n;
+         strcpy (ptr, name);
+         bfd_asymbol_name (sym) = n;
+         name = n;
        }
 
       if (strip_symbols == STRIP_ALL)
@@ -1560,42 +1684,40 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 static const char *
 lookup_sym_redefinition (const char *source)
 {
-  struct redefine_node *list;
-
-  for (list = redefine_sym_list; list != NULL; list = list->next)
-    if (strcmp (source, list->source) == 0)
-      return list->target;
+  struct redefine_node key_node = {(char *) source, NULL};
+  struct redefine_node *redef_node
+    = (struct redefine_node *) htab_find (redefine_specific_htab, &key_node);
 
-  return source;
+  return redef_node == NULL ? source : redef_node->target;
 }
 
-/* Add a node to a symbol redefine list.  */
+/* Insert a node into symbol redefine hash tabel.  */
 
 static void
-redefine_list_append (const char *cause, const char *source, const char *target)
+add_redefine_and_check (const char *cause, const char *source,
+                       const char *target)
 {
-  struct redefine_node **p;
-  struct redefine_node *list;
-  struct redefine_node *new_node;
+  struct redefine_node *new_node
+    = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
 
-  for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
-    {
-      if (strcmp (source, list->source) == 0)
-       fatal (_("%s: Multiple redefinition of symbol \"%s\""),
-              cause, source);
+  new_node->source = strdup (source);
+  new_node->target = strdup (target);
 
-      if (strcmp (target, list->target) == 0)
-       fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
-              cause, target);
-    }
+  if (htab_find (redefine_specific_htab, new_node) != HTAB_EMPTY_ENTRY)
+    fatal (_("%s: Multiple redefinition of symbol \"%s\""),
+          cause, source);
 
-  new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
+  if (htab_find (redefine_specific_reverse_htab, target) != HTAB_EMPTY_ENTRY)
+    fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
+          cause, target);
 
-  new_node->source = strdup (source);
-  new_node->target = strdup (target);
-  new_node->next = NULL;
+  /* Insert the NEW_NODE into hash table for quick search.  */
+  add_specific_symbol_node (new_node, redefine_specific_htab);
+
+  /* Insert the target string into the reverse hash table, this is needed for
+     duplicated target string check.  */
+  add_specific_symbol (new_node->target, redefine_specific_reverse_htab);
 
-  *p = new_node;
 }
 
 /* Handle the --redefine-syms option.  Read lines containing "old new"
@@ -1677,10 +1799,10 @@ add_redefine_syms_file (const char *filename)
       if ((c == '\r' && (c = getc (file)) == '\n')
          || c == '\n' || c == EOF)
        {
- end_of_line:
      end_of_line:
          /* Append the redefinition to the list.  */
          if (buf[0] != '\0')
-           redefine_list_append (filename, &buf[0], &buf[outsym_off]);
+           add_redefine_and_check (filename, &buf[0], &buf[outsym_off]);
 
          lineno++;
          len = 0;
@@ -1692,7 +1814,7 @@ add_redefine_syms_file (const char *filename)
        }
       else
        fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
- comment:
   comment:
       if (len != 0 && (outsym_off == 0 || outsym_off == len))
        fatal (_("%s:%d: missing new symbol name"), filename, lineno);
       buf[len++] = '\0';
@@ -1707,9 +1829,10 @@ add_redefine_syms_file (const char *filename)
     fatal (_("%s:%d: premature end of file"), filename, lineno);
 
   free (buf);
+  fclose (file);
 }
 
-/* Copy unkown object file IBFD onto OBFD.
+/* Copy unknown object file IBFD onto OBFD.
    Returns TRUE upon success, FALSE otherwise.  */
 
 static bfd_boolean
@@ -1779,6 +1902,549 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
   return TRUE;
 }
 
+/* Returns the number of bytes needed to store VAL.  */
+
+static inline unsigned int
+num_bytes (unsigned long val)
+{
+  unsigned int count = 0;
+
+  /* FIXME: There must be a faster way to do this.  */
+  while (val)
+    {
+      count ++;
+      val >>= 8;
+    }
+  return count;
+}
+
+typedef struct objcopy_internal_note
+{
+  Elf_Internal_Note  note;
+  bfd_vma            start;
+  bfd_vma            end;
+  bfd_boolean        modified;
+} objcopy_internal_note;
+  
+/* Returns TRUE if a gap does, or could, exist between the address range
+   covered by PNOTE1 and PNOTE2.  */
+
+static bfd_boolean
+gap_exists (objcopy_internal_note * pnote1,
+           objcopy_internal_note * pnote2)
+{
+  /* Without range end notes, we assume that a gap might exist.  */
+  if (pnote1->end == 0 || pnote2->end == 0)
+    return TRUE;
+
+  /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+     Really we should extract the alignment of the section covered by the notes.  */
+  return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+}
+
+static bfd_boolean
+is_open_note (objcopy_internal_note * pnote)
+{
+  return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN);
+}
+
+static bfd_boolean
+is_func_note (objcopy_internal_note * pnote)
+{
+  return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC);
+}
+
+static bfd_boolean
+is_64bit (bfd * abfd)
+{
+  /* Should never happen, but let's be paranoid.  */
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return FALSE;
+
+  return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
+}
+
+/* Merge the notes on SEC, removing redundant entries.
+   Returns the new, smaller size of the section upon success.  */
+
+static bfd_size_type
+merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
+{
+  objcopy_internal_note *  pnotes_end;
+  objcopy_internal_note *  pnotes = NULL;
+  objcopy_internal_note *  pnote;
+  bfd_size_type       remain = size;
+  unsigned            version_1_seen = 0;
+  unsigned            version_2_seen = 0;
+  unsigned            version_3_seen = 0;
+  bfd_boolean         duplicate_found = FALSE;
+  const char *        err = NULL;
+  bfd_byte *          in = contents;
+  int                 attribute_type_byte;
+  int                 val_start;
+  unsigned long       previous_func_start = 0;
+  unsigned long       previous_open_start = 0;
+  unsigned long       previous_func_end = 0;
+  unsigned long       previous_open_end = 0;
+  long                relsize;
+
+
+  relsize = bfd_get_reloc_upper_bound (abfd, sec);
+  if (relsize > 0)
+    {
+      arelent **  relpp;
+      long        relcount;
+
+      /* If there are relocs associated with this section then we
+        cannot safely merge it.  */
+      relpp = (arelent **) xmalloc (relsize);
+      relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+      free (relpp);
+      if (relcount != 0)
+       goto done;
+    }
+  
+  /* Make a copy of the notes and convert to our internal format.
+     Minimum size of a note is 12 bytes.  */
+  pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
+  while (remain >= 12)
+    {
+      bfd_vma start, end;
+
+      pnote->note.namesz = (bfd_get_32 (abfd, in    ) + 3) & ~3;
+      pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
+      pnote->note.type   =  bfd_get_32 (abfd, in + 8);
+
+      if (pnote->note.type    != NT_GNU_BUILD_ATTRIBUTE_OPEN
+         && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+       {
+         err = _("corrupt GNU build attribute note: wrong note type");
+         goto done;
+       }
+
+      if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
+       {
+         err = _("corrupt GNU build attribute note: note too big");
+         goto done;
+       }
+
+      if (pnote->note.namesz < 2)
+       {
+         err = _("corrupt GNU build attribute note: name too small");
+         goto done;
+       }
+
+      pnote->note.namedata = (char *)(in + 12);
+      pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+
+      remain -= 12 + pnote->note.namesz + pnote->note.descsz;
+      in     += 12 + pnote->note.namesz + pnote->note.descsz;
+
+      if (pnote->note.namesz > 2
+         && pnote->note.namedata[0] == '$'
+         && pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
+         && pnote->note.namedata[2] == '1')
+       ++ version_1_seen;
+      else if (pnote->note.namesz > 4
+              && pnote->note.namedata[0] == 'G'
+              && pnote->note.namedata[1] == 'A'
+              && pnote->note.namedata[2] == '$'
+              && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION)
+       {
+         if (pnote->note.namedata[4] == '2')
+           ++ version_2_seen;
+         else if (pnote->note.namedata[4] == '3')
+           ++ version_3_seen;
+         else
+           {
+             err = _("corrupt GNU build attribute note: unsupported version");
+             goto done;
+           }
+       }
+
+      switch (pnote->note.descsz)
+       {
+       case 0:
+         start = end = 0;
+         break;
+
+       case 4:
+         start = bfd_get_32 (abfd, pnote->note.descdata);
+         /* FIXME: For version 1 and 2 notes we should try to
+            calculate the end address by finding a symbol whose
+            value is START, and then adding in its size.
+
+            For now though, since v1 and v2 was not intended to
+            handle gaps, we chose an artificially large end
+            address.  */
+         end = (bfd_vma) -1;
+         break;
+         
+       case 8:
+         if (! is_64bit (abfd))
+           {
+             start = bfd_get_32 (abfd, pnote->note.descdata);
+             end = bfd_get_32 (abfd, pnote->note.descdata + 4);
+           }
+         else
+           {
+             start = bfd_get_64 (abfd, pnote->note.descdata);
+             /* FIXME: For version 1 and 2 notes we should try to
+                calculate the end address by finding a symbol whose
+                value is START, and then adding in its size.
+
+                For now though, since v1 and v2 was not intended to
+                handle gaps, we chose an artificially large end
+                address.  */
+             end = (bfd_vma) -1;
+           }
+         break;
+
+       case 16:
+         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;
+       }
+
+      if (is_open_note (pnote))
+       {
+         if (start)
+           previous_open_start = start;
+
+         pnote->start = previous_open_start;
+
+         if (end)
+           previous_open_end = end;
+
+         pnote->end = previous_open_end;
+       }
+      else
+       {
+         if (start)
+           previous_func_start = start;
+
+         pnote->start = previous_func_start;
+
+         if (end)
+           previous_func_end = end;
+
+         pnote->end = previous_func_end;
+       }
+
+      if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
+       {
+         err = _("corrupt GNU build attribute note: name not NUL terminated");
+         goto done;
+       }
+
+      pnote ++;
+    }
+
+  pnotes_end = pnote;
+
+  /* Check that the notes are valid.  */
+  if (remain != 0)
+    {
+      err = _("corrupt GNU build attribute notes: excess data at end");
+      goto done;
+    }
+
+  if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
+    {
+      err = _("bad GNU build attribute notes: no known versions detected");
+      goto done;
+    }
+
+  if ((version_1_seen > 0 && version_2_seen > 0)
+      || (version_1_seen > 0 && version_3_seen > 0)
+      || (version_2_seen > 0 && version_3_seen > 0))
+    {
+      err = _("bad GNU build attribute notes: multiple different versions");
+      goto done;
+    }
+
+  /* Merging is only needed if there is more than one version note...  */
+  if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
+    goto done;
+
+  attribute_type_byte = version_1_seen ? 1 : 3;
+  val_start = attribute_type_byte + 1;
+
+  /* The first note should be the first version note.  */
+  if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
+    {
+      err = _("bad GNU build attribute notes: first note not version note");
+      goto done;
+    }
+
+  /* Now merge the notes.  The rules are:
+     1. Preserve the ordering of the notes.
+     2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
+     3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
+        full name field as the immediately preceeding note with the same type
+       of name and whose address ranges coincide.
+       IE - if there are gaps in the coverage of the notes, then these gaps
+       must be preserved.
+     4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
+        of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
+     5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
+        its description field is empty then the nearest preceeding OPEN note
+       with a non-empty description field must also be preserved *OR* the
+       description field of the note must be changed to contain the starting
+       address to which it refers.
+     6. Notes with the same start and end address can be deleted.  */
+  for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
+    {
+      int                      note_type;
+      objcopy_internal_note *  back;
+      objcopy_internal_note *  prev_open_with_range = NULL;
+
+      /* Rule 6 - delete 0-range notes.  */
+      if (pnote->start == pnote->end)
+       {
+         duplicate_found = TRUE;
+         pnote->note.type = 0;
+         continue;
+       }
+
+      /* Rule 2 - preserve function notes.  */
+      if (! is_open_note (pnote))
+       {
+         int iter;
+
+         /* Check to see if there is an identical previous function note.
+            This can happen with overlays for example.  */
+         for (iter = 0, back = pnote -1; back >= pnotes; back --)
+           {
+             if (back->start == pnote->start
+                 && back->end == pnote->end
+                 && back->note.namesz == pnote->note.namesz
+                 && memcmp (back->note.namedata, pnote->note.namedata, pnote->note.namesz) == 0)
+               {
+ fprintf (stderr, "DUP FUNXC\n");
+                 duplicate_found = TRUE;
+                 pnote->note.type = 0;
+                 break;
+               }
+
+             /* Don't scan too far back however.  */
+             if (iter ++ > 16)
+               break;
+           }
+         continue;
+       }
+
+      note_type = pnote->note.namedata[attribute_type_byte];
+
+      /* Scan backwards from pnote, looking for duplicates.
+        Clear the type field of any found - but do not delete them just yet.  */
+      for (back = pnote - 1; back >= pnotes; back --)
+       {
+         int back_type = back->note.namedata[attribute_type_byte];
+
+         /* If this is the first open note with an address
+            range that we have encountered then record it.  */
+         if (prev_open_with_range == NULL
+             && back->note.descsz > 0
+             && ! is_func_note (back))
+           prev_open_with_range = back;
+
+         if (! is_open_note (back))
+           continue;
+
+         /* If the two notes are different then keep on searching.  */
+         if (back_type != note_type)
+           continue;
+
+         /* Rule 4 - combine stack size notes.  */
+         if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+           {
+             unsigned char * name;
+             unsigned long   note_val;
+             unsigned long   back_val;
+             unsigned int    shift;
+             unsigned int    bytes;
+             unsigned long   byte;
+
+             for (shift = 0, note_val = 0,
+                    bytes = pnote->note.namesz - val_start,
+                    name = (unsigned char *) pnote->note.namedata + val_start;
+                  bytes--;)
+               {
+                 byte = (* name ++) & 0xff;
+                 note_val |= byte << shift;
+                 shift += 8;
+               }
+
+             for (shift = 0, back_val = 0,
+                    bytes = back->note.namesz - val_start,
+                    name = (unsigned char *) back->note.namedata + val_start;
+                  bytes--;)
+               {
+                 byte = (* name ++) & 0xff;
+                 back_val |= byte << shift;
+                 shift += 8;
+               }
+
+             back_val += note_val;
+             if (num_bytes (back_val) >= back->note.namesz - val_start)
+               {
+                 /* We have a problem - the new value requires more bytes of
+                    storage in the name field than are available.  Currently
+                    we have no way of fixing this, so we just preserve both
+                    notes.  */
+                 continue;
+               }
+
+             /* Write the new val into back.  */
+             name = (unsigned char *) back->note.namedata + val_start;
+             while (name < (unsigned char *) back->note.namedata
+                    + back->note.namesz)
+               {
+                 byte = back_val & 0xff;
+                 * name ++ = byte;
+                 if (back_val == 0)
+                   break;
+                 back_val >>= 8;
+               }
+
+             duplicate_found = TRUE;
+             pnote->note.type = 0;
+             break;
+           }
+
+         /* Rule 3 - combine identical open notes.  */
+         if (back->note.namesz == pnote->note.namesz
+             && memcmp (back->note.namedata,
+                        pnote->note.namedata, back->note.namesz) == 0
+             && ! gap_exists (back, pnote))
+           {
+             duplicate_found = TRUE;
+             pnote->note.type = 0;
+
+             if (pnote->end > back->end)
+               back->end = pnote->end;
+
+             if (version_3_seen)
+               back->modified = TRUE;
+             break;
+           }
+
+         /* Rule 5 - Since we are keeping this note we must check to see
+            if its description refers back to an earlier OPEN version
+            note that has been scheduled for deletion.  If so then we
+            must make sure that version note is also preserved.  */
+         if (version_3_seen)
+           {
+             /* As of version 3 we can just
+                move the range into the note.  */
+             pnote->modified = TRUE;
+             pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+             back->modified = TRUE;
+             back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+           }
+         else
+           {
+             if (pnote->note.descsz == 0
+                 && prev_open_with_range != NULL
+                 && prev_open_with_range->note.type == 0)
+               prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+           }
+
+         /* We have found a similar attribute but the details do not match.
+            Stop searching backwards.  */
+         break;
+       }
+    }
+
+  if (duplicate_found)
+    {
+      bfd_byte *     new_contents;
+      bfd_byte *     old;
+      bfd_byte *     new;
+      bfd_size_type  new_size;
+      bfd_vma        prev_start = 0;
+      bfd_vma        prev_end = 0;
+
+      /* Eliminate the duplicates.  */
+      new = new_contents = xmalloc (size);
+      for (pnote = pnotes, old = contents;
+          pnote < pnotes_end;
+          pnote ++)
+       {
+         bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
+
+         if (pnote->note.type != 0)
+           {
+             if (pnote->modified)
+               {
+                 /* If the note has been modified then we must copy it by
+                    hand, potentially adding in a new description field.  */
+                 if (pnote->start == prev_start && pnote->end == prev_end)
+                   {
+                     bfd_put_32 (abfd, pnote->note.namesz, new);
+                     bfd_put_32 (abfd, 0, new + 4);
+                     bfd_put_32 (abfd, pnote->note.type, new + 8);
+                     new += 12;
+                     memcpy (new, pnote->note.namedata, pnote->note.namesz);
+                     new += pnote->note.namesz;
+                   }
+                 else
+                   {
+                     bfd_put_32 (abfd, pnote->note.namesz, new);
+                     bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+                     bfd_put_32 (abfd, pnote->note.type, new + 8);
+                     new += 12;
+                     memcpy (new, pnote->note.namedata, pnote->note.namesz);
+                     new += pnote->note.namesz;
+                     if (is_64bit (abfd))
+                       {
+                         bfd_put_64 (abfd, pnote->start, new);
+                         bfd_put_64 (abfd, pnote->end, new + 8);
+                         new += 16;
+                       }
+                     else
+                       {
+                         bfd_put_32 (abfd, pnote->start, new);
+                         bfd_put_32 (abfd, pnote->end, new + 4);
+                         new += 8;
+                       }
+                   }
+               }
+             else
+               {
+                 memcpy (new, old, note_size);
+                 new += note_size;
+               }
+             prev_start = pnote->start;
+             prev_end = pnote->end;
+           }
+
+         old += note_size;
+       }
+
+      new_size = new - new_contents;
+      memcpy (contents, new_contents, new_size);
+      size = new_size;
+      free (new_contents);
+    }
+
+ done:
+  if (err)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      bfd_nonfatal_message (NULL, abfd, sec, err);
+      status = 1;
+    }
+
+  free (pnotes);
+  return size;
+}
+
 /* Copy object file IBFD onto OBFD.
    Returns TRUE upon success, FALSE otherwise.  */
 
@@ -1788,6 +2454,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
   bfd_vma start;
   long symcount;
   asection **osections = NULL;
+  asection *osec;
   asection *gnu_debuglink_section = NULL;
   bfd_size_type *gaps = NULL;
   bfd_size_type max_gap = 0;
@@ -1820,13 +2487,22 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       return FALSE;
     }
 
-  if ((do_debug_sections & compress) != 0
-      && do_debug_sections != compress
-      && ibfd->xvec->flavour != bfd_target_elf_flavour)
+  if (ibfd->xvec->flavour != bfd_target_elf_flavour)
     {
-      non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
-                bfd_get_archive_filename (ibfd));
-      return FALSE;
+      if ((do_debug_sections & compress) != 0
+         && do_debug_sections != compress)
+       {
+         non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+                    bfd_get_archive_filename (ibfd));
+         return FALSE;
+       }
+
+      if (do_elf_stt_common)
+       {
+         non_fatal (_("--elf-stt-common=[yes|no] is unsupported on `%s'"),
+                    bfd_get_archive_filename (ibfd));
+         return FALSE;
+       }
     }
 
   if (verbose)
@@ -2019,15 +2695,15 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
          if (bfd_get_section_by_name (obfd, padd->name))
            {
              bfd_nonfatal_message (NULL, obfd, NULL,
-                                _("can't add section '%s'"), padd->name);
+                                   _("can't add section '%s'"), padd->name);
              return FALSE;
            }
          else
            {
              /* We use LINKER_CREATED here so that the backend hooks
-                will create any special section type information,
-                instead of presuming we know what we're doing merely
-                because we set the flags.  */
+                will create any special section type information,
+                instead of presuming we know what we're doing merely
+                because we set the flags.  */
              padd->section = bfd_make_section_with_flags
                (obfd, padd->name, flags | SEC_LINKER_CREATED);
              if (padd->section == NULL)
@@ -2079,8 +2755,6 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
           pupdate != NULL;
           pupdate = pupdate->next)
        {
-         asection *osec;
-
          pupdate->section = bfd_get_section_by_name (ibfd, pupdate->name);
          if (pupdate->section == NULL)
            {
@@ -2097,16 +2771,63 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        }
     }
 
+  if (merge_notes)
+    {
+      /* This palaver is necessary because we must set the output
+        section size first, before its contents are ready.  */
+      osec = bfd_get_section_by_name (ibfd, GNU_BUILD_ATTRS_SECTION_NAME);
+      if (osec && is_merged_note_section (ibfd, osec))
+       {
+         bfd_size_type size;
+         
+         size = bfd_get_section_size (osec);
+         if (size == 0)
+           {
+             bfd_nonfatal_message (NULL, ibfd, osec, _("warning: note section is empty"));
+             merge_notes = FALSE;
+           }
+         else if (! bfd_get_full_section_contents (ibfd, osec, & merged_notes))
+           {
+             bfd_nonfatal_message (NULL, ibfd, osec, _("warning: could not load note section"));
+             free (merged_notes);
+             merged_notes = NULL;
+             merge_notes = FALSE;
+           }
+         else
+           {
+             merged_size = merge_gnu_build_notes (ibfd, osec, size, merged_notes);
+             if (merged_size == size)
+               {
+                 /* Merging achieves nothing.  */
+                 free (merged_notes);
+                 merged_notes = NULL;
+                 merge_notes = FALSE;
+                 merged_size = 0;
+               }
+             else
+               {
+                 if (osec->output_section == NULL
+                     || ! bfd_set_section_size (obfd, osec->output_section, merged_size))
+                   {
+                     bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size"));
+                     free (merged_notes);
+                     merged_notes = NULL;
+                     merge_notes = FALSE;
+                     merged_size = 0;
+                   }
+               }
+           }
+       }
+    }
+
   if (dump_sections != NULL)
     {
       struct section_add * pdump;
 
       for (pdump = dump_sections; pdump != NULL; pdump = pdump->next)
        {
-         asection * sec;
-
-         sec = bfd_get_section_by_name (ibfd, pdump->name);
-         if (sec == NULL)
+         osec = bfd_get_section_by_name (ibfd, pdump->name);
+         if (osec == NULL)
            {
              bfd_nonfatal_message (NULL, ibfd, NULL,
                                    _("can't dump section '%s' - it does not exist"),
@@ -2114,17 +2835,17 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
              continue;
            }
 
-         if ((bfd_get_section_flags (ibfd, sec) & SEC_HAS_CONTENTS) == 0)
+         if ((bfd_get_section_flags (ibfd, osec) & SEC_HAS_CONTENTS) == 0)
            {
-             bfd_nonfatal_message (NULL, ibfd, sec,
+             bfd_nonfatal_message (NULL, ibfd, osec,
                                    _("can't dump section - it has no contents"));
              continue;
            }
 
-         bfd_size_type size = bfd_get_section_size (sec);
+         bfd_size_type size = bfd_get_section_size (osec);
          if (size == 0)
            {
-             bfd_nonfatal_message (NULL, ibfd, sec,
+             bfd_nonfatal_message (NULL, ibfd, osec,
                                    _("can't dump section - it is empty"));
              continue;
            }
@@ -2138,19 +2859,21 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
              continue;
            }
 
-         bfd_byte * contents = xmalloc (size);
-         if (bfd_get_section_contents (ibfd, sec, contents, 0, size))
+         bfd_byte *contents;
+         if (bfd_malloc_and_get_section (ibfd, osec, &contents))
            {
              if (fwrite (contents, 1, size, f) != size)
                {
                  non_fatal (_("error writing section contents to %s (error: %s)"),
                             pdump->filename,
                             strerror (errno));
+                 free (contents);
+                 fclose (f);
                  return FALSE;
                }
            }
          else
-           bfd_nonfatal_message (NULL, ibfd, sec,
+           bfd_nonfatal_message (NULL, ibfd, osec,
                                  _("could not retrieve section contents"));
 
          fclose (f);
@@ -2188,7 +2911,6 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
            {
              bfd_vma debuglink_vma;
              asection * highest_section;
-             asection * sec;
 
              /* The PE spec requires that all sections be adjacent and sorted
                 in ascending order of VMA.  It also specifies that debug
@@ -2200,13 +2922,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                 VMA which makes it contiguous with other debug sections.  So
                 walk the current section list, find the section with the
                 highest VMA and start the debuglink section after that one.  */
-             for (sec = obfd->sections, highest_section = NULL;
-                  sec != NULL;
-                  sec = sec->next)
-               if (sec->vma > 0
+             for (osec = obfd->sections, highest_section = NULL;
+                  osec != NULL;
+                  osec = osec->next)
+               if (osec->vma > 0
                    && (highest_section == NULL
-                       || sec->vma > highest_section->vma))
-                 highest_section = sec;
+                       || osec->vma > highest_section->vma))
+                 highest_section = osec;
 
              if (highest_section)
                debuglink_vma = BFD_ALIGN (highest_section->vma
@@ -2327,13 +3049,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       || htab_elements (globalize_specific_htab) != 0
       || htab_elements (keepglobal_specific_htab) != 0
       || htab_elements (weaken_specific_htab) != 0
+      || htab_elements (redefine_specific_htab) != 0
       || prefix_symbols_string
       || sections_removed
       || sections_copied
       || convert_debugging
       || change_leading_char
       || remove_leading_char
-      || redefine_sym_list
+      || section_rename_list
       || weaken
       || add_symbols)
     {
@@ -2346,16 +3069,32 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
         ignore input sections which have no corresponding output
         section.  */
       if (strip_symbols != STRIP_ALL)
-       bfd_map_over_sections (ibfd,
-                              mark_symbols_used_in_relocations,
-                              isympp);
+       {
+         bfd_set_error (bfd_error_no_error);
+         bfd_map_over_sections (ibfd,
+                                mark_symbols_used_in_relocations,
+                                isympp);
+         if (bfd_get_error () != bfd_error_no_error)
+           {
+             status = 1;
+             return FALSE;
+           }
+       }
+
       osympp = (asymbol **) xmalloc ((symcount + add_symbols + 1) * sizeof (asymbol *));
       symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
     }
 
   if (convert_debugging && dhandle != NULL)
     {
-      if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
+      bfd_boolean res;
+
+      res = write_debugging_info (obfd, dhandle, &symcount, &osympp);
+
+      free (dhandle);
+      dhandle = NULL; /* Paranoia...  */
+
+      if (! res)
        {
          status = 1;
          return FALSE;
@@ -2390,14 +3129,12 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       struct section_add *pupdate;
 
       for (pupdate = update_sections;
-           pupdate != NULL;
-           pupdate = pupdate->next)
+          pupdate != NULL;
+          pupdate = pupdate->next)
        {
-         asection *osec;
-
          osec = pupdate->section->output_section;
          if (! bfd_set_section_contents (obfd, osec, pupdate->contents,
-                                         0, pupdate->size))
+                                         0, pupdate->size))
            {
              bfd_nonfatal_message (NULL, obfd, osec, NULL);
              return FALSE;
@@ -2405,6 +3142,24 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        }
     }
 
+  if (merge_notes)
+    {
+      osec = bfd_get_section_by_name (obfd, GNU_BUILD_ATTRS_SECTION_NAME);
+      if (osec && is_merged_note_section (obfd, osec))
+       {
+         if (! bfd_set_section_contents (obfd, osec, merged_notes, 0, merged_size))
+           {
+             bfd_nonfatal_message (NULL, obfd, osec, _("error: failed to copy merged notes into output"));
+             return FALSE;
+           }
+       }
+      else if (! is_strip)
+       bfd_nonfatal_message (NULL, obfd, osec, _("could not find any mergeable note sections"));
+      free (merged_notes);
+      merged_notes = NULL;
+      merge_notes = FALSE;
+    }
+
   if (gnu_debuglink_filename != NULL)
     {
       if (! bfd_fill_in_gnu_debuglink_section
@@ -2451,6 +3206,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                                                  off, now))
                    {
                      bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
+                     free (buf);
                      return FALSE;
                    }
 
@@ -2459,6 +3215,10 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                }
            }
        }
+
+      free (buf);
+      free (gaps);
+      gaps = NULL;
     }
 
   /* Allow the BFD backend to copy any private data it understands
@@ -2516,10 +3276,31 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
   char *dir;
   const char *filename;
 
+  /* PR 24281: It is not clear what should happen when copying a thin archive.
+     One part is straight forward - if the output archive is in a different
+     directory from the input archive then any relative paths in the library
+     should be adjusted to the new location.  But if any transformation
+     options are active (eg strip, rename, add, etc) then the implication is
+     that these should be applied to the files pointed to by the archive.
+     But since objcopy is not destructive, this means that new files must be
+     created, and there is no guidance for the names of the new files.  (Plus
+     this conflicts with one of the goals of thin libraries - only taking up
+     a  minimal amount of space in the file system).
+
+     So for now we fail if an attempt is made to copy such libraries.  */
+  if (ibfd->is_thin_archive)
+    {
+      status = 1;
+      bfd_set_error (bfd_error_invalid_operation);
+      bfd_nonfatal_message (NULL, ibfd, NULL,
+                           _("sorry: copying thin archives is not currently supported"));
+      return;
+    }
+
   /* Make a temp directory to hold the contents.  */
   dir = make_tempdir (bfd_get_filename (obfd));
   if (dir == NULL)
-      fatal (_("cannot create tempdir for archive copying (error: %s)"),
+    fatal (_("cannot create tempdir for archive copying (error: %s)"),
           strerror (errno));
 
   if (strip_symbols == STRIP_ALL)
@@ -2569,8 +3350,10 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
       /* If the file already exists, make another temp dir.  */
       if (stat (output_name, &buf) >= 0)
        {
-         output_name = make_tempdir (output_name);
-         if (output_name == NULL)
+         char * tmpdir = make_tempdir (output_name);
+
+         free (output_name);
+         if (tmpdir == NULL)
            {
              non_fatal (_("cannot create tempdir for archive copying (error: %s)"),
                         strerror (errno));
@@ -2579,11 +3362,11 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
            }
 
          l = (struct name_list *) xmalloc (sizeof (struct name_list));
-         l->name = output_name;
+         l->name = tmpdir;
          l->next = list;
          l->obfd = NULL;
          list = l;
-         output_name = concat (output_name, "/",
+         output_name = concat (tmpdir, "/",
                                bfd_get_filename (this_element), (char *) 0);
        }
 
@@ -2690,16 +3473,22 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
 
  cleanup_and_exit:
   /* Delete all the files that we opened.  */
-  for (l = list; l != NULL; l = l->next)
-    {
-      if (l->obfd == NULL)
-       rmdir (l->name);
-      else
-       {
-         bfd_close (l->obfd);
-         unlink (l->name);
-       }
-    }
+  {
+    struct name_list * next;
+
+    for (l = list; l != NULL; l = next)
+      {
+       if (l->obfd == NULL)
+         rmdir (l->name);
+       else
+         {
+           bfd_close (l->obfd);
+           unlink (l->name);
+         }
+       next = l->next;
+       free (l);
+      }
+  }
 
   rmdir (dir);
 }
@@ -2767,13 +3556,26 @@ copy_file (const char *input_filename, const char *output_filename,
       break;
     }
 
+  switch (do_elf_stt_common)
+    {
+    case elf_stt_common:
+      ibfd->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON;
+      break;
+      break;
+    case no_elf_stt_common:
+      ibfd->flags |= BFD_CONVERT_ELF_COMMON;
+      break;
+    default:
+      break;
+    }
+
   if (bfd_check_format (ibfd, bfd_archive))
     {
       bfd_boolean force_output_target;
       bfd *obfd;
 
       /* bfd_get_target does not return the correct value until
-         bfd_check_format succeeds.  */
+        bfd_check_format succeeds.  */
       if (output_target == NULL)
        {
          output_target = bfd_get_target (ibfd);
@@ -2800,7 +3602,7 @@ copy_file (const char *input_filename, const char *output_filename,
     do_copy:
 
       /* bfd_get_target does not return the correct value until
-         bfd_check_format succeeds.  */
+        bfd_check_format succeeds.  */
       if (output_target == NULL)
        output_target = bfd_get_target (ibfd);
 
@@ -2901,24 +3703,19 @@ add_section_rename (const char * old_name, const char * new_name,
 }
 
 /* Check the section rename list for a new name of the input section
-   ISECTION.  Return the new name if one is found.
-   Also set RETURNED_FLAGS to the flags to be used for this section.  */
+   called OLD_NAME.  Returns the new name if one is found and sets
+   RETURNED_FLAGS if non-NULL to the flags to be used for this section.  */
 
 static const char *
-find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
-                    flagword * returned_flags)
+find_section_rename (const char *old_name, flagword *returned_flags)
 {
-  const char * old_name = bfd_section_name (ibfd, isection);
-  section_rename * srename;
-
-  /* Default to using the flags of the input section.  */
-  * returned_flags = bfd_get_section_flags (ibfd, isection);
+  const section_rename *srename;
 
   for (srename = section_rename_list; srename != NULL; srename = srename->next)
     if (strcmp (srename->old_name, old_name) == 0)
       {
-       if (srename->flags != (flagword) -1)
-         * returned_flags = srename->flags;
+       if (returned_flags != NULL && srename->flags != (flagword) -1)
+         *returned_flags = srename->flags;
 
        return srename->new_name;
       }
@@ -2968,7 +3765,9 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     return;
 
   /* Get the, possibly new, name of the output section.  */
-  name = find_section_rename (ibfd, isection, & flags);
+  name = bfd_section_name (ibfd, isection);
+  flags = bfd_get_section_flags (ibfd, isection);
+  name = find_section_rename (name, &flags);
 
   /* Prefix sections.  */
   if ((prefix_alloc_sections_string)
@@ -2995,7 +3794,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
   else if (strip_symbols == STRIP_NONDEBUG
           && (flags & (SEC_ALLOC | SEC_GROUP)) != 0
-           && !is_nondebug_keep_contents_section (ibfd, isection))
+          && !is_nondebug_keep_contents_section (ibfd, isection))
     {
       flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
       if (obfd->xvec->flavour == bfd_target_elf_flavour)
@@ -3112,7 +3911,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   /* All went well.  */
   return;
 
-loser:
+ loser:
   status = 1;
   bfd_nonfatal_message (NULL, obfd, osection, err);
 }
@@ -3120,7 +3919,7 @@ loser:
 /* Return TRUE if input section ISECTION should be skipped.  */
 
 static bfd_boolean
-skip_section (bfd *ibfd, sec_ptr isection)
+skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy)
 {
   sec_ptr osection;
   bfd_size_type size;
@@ -3140,6 +3939,11 @@ skip_section (bfd *ibfd, sec_ptr isection)
   if (is_update_section (ibfd, isection))
     return TRUE;
 
+  /* When merging a note section we skip the copying of the contents,
+     but not the copying of the relocs associated with the contents.  */
+  if (skip_copy && is_merged_note_section (ibfd, isection))
+    return TRUE;
+
   flags = bfd_get_section_flags (ibfd, isection);
   if ((flags & SEC_GROUP) != 0)
     return TRUE;
@@ -3153,6 +3957,47 @@ skip_section (bfd *ibfd, sec_ptr isection)
   return FALSE;
 }
 
+/* Add section SECTION_PATTERN to the list of sections that will have their
+   relocations removed.  */
+
+static void
+handle_remove_relocations_option (const char *section_pattern)
+{
+  find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE_RELOCS);
+}
+
+/* Return TRUE if ISECTION from IBFD should have its relocations removed,
+   otherwise return FALSE.  If the user has requested that relocations be
+   removed from a section that does not have relocations then this
+   function will still return TRUE.  */
+
+static bfd_boolean
+discard_relocations (bfd *ibfd ATTRIBUTE_UNUSED, asection *isection)
+{
+  return (find_section_list (bfd_section_name (ibfd, isection), FALSE,
+                            SECTION_CONTEXT_REMOVE_RELOCS) != NULL);
+}
+
+/* Wrapper for dealing with --remove-section (-R) command line arguments.
+   A special case is detected here, if the user asks to remove a relocation
+   section (one starting with ".rela" or ".rel") then this removal must
+   be done using a different technique in a relocatable object.  */
+
+static void
+handle_remove_section_option (const char *section_pattern)
+{
+  find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
+  if (strncmp (section_pattern, ".rel", 4) == 0)
+    {
+      section_pattern += 4;
+      if (*section_pattern == 'a')
+       section_pattern++;
+      if (*section_pattern)
+       handle_remove_relocations_option (section_pattern);
+    }
+  sections_removed = TRUE;
+}
+
 /* Copy relocations in input section ISECTION of IBFD to an output
    section with the same name in OBFDARG.  If stripping then don't
    copy any relocation info.  */
@@ -3166,13 +4011,15 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   long relcount;
   sec_ptr osection;
 
 if (skip_section (ibfd, isection))
if (skip_section (ibfd, isection, FALSE))
     return;
 
   osection = isection->output_section;
 
   /* Core files and DWO files do not need to be relocated.  */
-  if (bfd_get_format (obfd) == bfd_core || strip_symbols == STRIP_NONDWO)
+  if (bfd_get_format (obfd) == bfd_core
+      || strip_symbols == STRIP_NONDWO
+      || discard_relocations (ibfd, isection))
     relsize = 0;
   else
     {
@@ -3199,14 +4046,24 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     }
   else
     {
-      relpp = (arelent **) xmalloc (relsize);
-      relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
-      if (relcount < 0)
+      if (isection->orelocation != NULL)
        {
-         status = 1;
-         bfd_nonfatal_message (NULL, ibfd, isection,
-                               _("relocation count is negative"));
-         return;
+         /* Some other function has already set up the output relocs
+            for us, so scan those instead of the default relocs.  */
+         relcount = isection->reloc_count;
+         relpp = isection->orelocation;
+       }
+      else
+       {
+         relpp = (arelent **) xmalloc (relsize);
+         relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
+         if (relcount < 0)
+           {
+             status = 1;
+             bfd_nonfatal_message (NULL, ibfd, isection,
+                                   _("relocation count is negative"));
+             return;
+           }
        }
 
       if (strip_symbols == STRIP_ALL)
@@ -3221,13 +4078,16 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
          for (i = 0; i < relcount; i++)
            {
              /* PR 17512: file: 9e907e0c.  */
-             if (relpp[i]->sym_ptr_ptr)
+             if (relpp[i]->sym_ptr_ptr
+                 /* PR 20096 */
+                 && * relpp[i]->sym_ptr_ptr)
                if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
                                         keep_specific_htab))
                  temp_relpp [temp_relcount++] = relpp [i];
            }
          relcount = temp_relcount;
-         free (relpp);
+         if (isection->orelocation == NULL)
+           free (relpp);
          relpp = temp_relpp;
        }
 
@@ -3251,7 +4111,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   sec_ptr osection;
   bfd_size_type size;
 
-  if (skip_section (ibfd, isection))
+  if (skip_section (ibfd, isection, TRUE))
     return;
 
   osection = isection->output_section;
@@ -3272,6 +4132,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        {
          status = 1;
          bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+         free (memhunk);
          return;
        }
 
@@ -3309,6 +4170,15 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
          char *end = (char *) memhunk + size;
          int i;
 
+         /* If the section address is not exactly divisible by the interleave,
+            then we must bias the from address.  If the copy_byte is less than
+            the bias, then we must skip forward one interleave, and increment
+            the final lma.  */
+         int extra = isection->lma % interleave;
+         from -= extra;
+         if (copy_byte < extra)
+           from += interleave;
+
          for (; from < end; from += interleave)
            for (i = 0; i < copy_width; i++)
              {
@@ -3319,12 +4189,15 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
 
          size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
          osection->lma /= interleave;
+         if (copy_byte < extra)
+           osection->lma++;
        }
 
       if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
        {
          status = 1;
          bfd_nonfatal_message (NULL, obfd, osection, NULL);
+         free (memhunk);
          return;
        }
       free (memhunk);
@@ -3346,6 +4219,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        {
          status = 1;
          bfd_nonfatal_message (NULL, obfd, osection, NULL);
+         free (memhunk);
          return;
        }
       free (memhunk);
@@ -3445,7 +4319,10 @@ mark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg)
      special bfd section symbols, then mark it with BSF_KEEP.  */
   for (i = 0; i < relcount; i++)
     {
-      if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
+      /* See PRs 20923 and 20930 for reproducers for the NULL tests.  */
+      if (relpp[i]->sym_ptr_ptr != NULL
+         && * relpp[i]->sym_ptr_ptr != NULL
+         && *relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
          && *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
          && *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
        (*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
@@ -3462,13 +4339,10 @@ write_debugging_info (bfd *obfd, void *dhandle,
                      long *symcountp ATTRIBUTE_UNUSED,
                      asymbol ***symppp ATTRIBUTE_UNUSED)
 {
-  if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
-    return write_ieee_debugging_info (obfd, dhandle);
-
   if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
       || bfd_get_flavour (obfd) == bfd_target_elf_flavour)
     {
-      bfd_byte *syms, *strings;
+      bfd_byte *syms, *strings = NULL;
       bfd_size_type symsize, stringsize;
       asection *stabsec, *stabstrsec;
       flagword flags;
@@ -3490,19 +4364,21 @@ write_debugging_info (bfd *obfd, void *dhandle,
        {
          bfd_nonfatal_message (NULL, obfd, NULL,
                                _("can't create debugging section"));
+         free (strings);
          return FALSE;
        }
 
       /* We can get away with setting the section contents now because
-         the next thing the caller is going to do is copy over the
-         real sections.  We may someday have to split the contents
-         setting out of this function.  */
+        the next thing the caller is going to do is copy over the
+        real sections.  We may someday have to split the contents
+        setting out of this function.  */
       if (! bfd_set_section_contents (obfd, stabsec, syms, 0, symsize)
          || ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
                                         stringsize))
        {
          bfd_nonfatal_message (NULL, obfd, NULL,
                                _("can't set debugging section contents"));
+         free (strings);
          return FALSE;
        }
 
@@ -3511,7 +4387,7 @@ write_debugging_info (bfd *obfd, void *dhandle,
 
   bfd_nonfatal_message (NULL, obfd, NULL,
                        _("don't know how to write debugging information for %s"),
-            bfd_get_target (obfd));
+                       bfd_get_target (obfd));
   return FALSE;
 }
 
@@ -3535,7 +4411,9 @@ strip_main (int argc, char *argv[])
   int i;
   char *output_file = NULL;
 
-  while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvwDU",
+  merge_notes = TRUE;
+
+  while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
                           strip_options, (int *) 0)) != EOF)
     {
       switch (c)
@@ -3550,8 +4428,10 @@ strip_main (int argc, char *argv[])
          input_target = output_target = optarg;
          break;
        case 'R':
-         find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
-         sections_removed = TRUE;
+         handle_remove_section_option (optarg);
+         break;
+       case OPTION_REMOVE_RELOCS:
+         handle_remove_relocations_option (optarg);
          break;
        case 's':
          strip_symbols = STRIP_ALL;
@@ -3570,6 +4450,12 @@ strip_main (int argc, char *argv[])
        case 'K':
          add_specific_symbol (optarg, keep_specific_htab);
          break;
+       case 'M':
+         merge_notes = TRUE;
+         break;
+       case OPTION_NO_MERGE_NOTES:
+         merge_notes = FALSE;
+         break;
        case 'N':
          add_specific_symbol (optarg, strip_specific_htab);
          break;
@@ -3819,8 +4705,8 @@ convert_efi_target (char *efi)
 
 static struct section_add *
 init_section_add (const char *arg,
-                  struct section_add *next,
-                  const char *option)
+                 struct section_add *next,
+                 const char *option)
 {
   struct section_add *pa;
   const char *s;
@@ -3857,7 +4743,7 @@ section_add_load_file (struct section_add *pa)
   f = fopen (pa->filename, FOPEN_RB);
   if (f == NULL)
     fatal (_("cannot open: %s: %s"),
-           pa->filename, strerror (errno));
+          pa->filename, strerror (errno));
 
   off = 0;
   alloc = 4096;
@@ -3867,14 +4753,14 @@ section_add_load_file (struct section_add *pa)
       off_t got;
 
       if (off == alloc)
-        {
-          alloc <<= 1;
-          pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
-        }
+       {
+         alloc <<= 1;
+         pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
+       }
 
       got = fread (pa->contents + off, 1, alloc - off, f);
       if (ferror (f))
-        fatal (_("%s: fread failed"), pa->filename);
+       fatal (_("%s: fread failed"), pa->filename);
 
       off += got;
     }
@@ -3895,11 +4781,13 @@ copy_main (int argc, char *argv[])
   bfd_boolean show_version = FALSE;
   bfd_boolean change_warn = TRUE;
   bfd_boolean formats_info = FALSE;
+  bfd_boolean use_globalize = FALSE;
+  bfd_boolean use_keep_global = FALSE;
   int c;
   struct stat statbuf;
   const bfd_arch_info_type *input_arch = NULL;
 
-  while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
+  while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:MN:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
                           copy_options, (int *) 0)) != EOF)
     {
       switch (c)
@@ -3953,8 +4841,11 @@ copy_main (int argc, char *argv[])
          break;
 
        case 'R':
-         find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
-         sections_removed = TRUE;
+         handle_remove_section_option (optarg);
+         break;
+
+        case OPTION_REMOVE_RELOCS:
+         handle_remove_relocations_option (optarg);
          break;
 
        case 'S':
@@ -3990,6 +4881,13 @@ copy_main (int argc, char *argv[])
          add_specific_symbol (optarg, keep_specific_htab);
          break;
 
+       case 'M':
+         merge_notes = TRUE;
+         break;
+       case OPTION_NO_MERGE_NOTES:
+         merge_notes = FALSE;
+         break;
+
        case 'N':
          add_specific_symbol (optarg, strip_specific_htab);
          break;
@@ -4003,10 +4901,12 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_GLOBALIZE_SYMBOL:
+         use_globalize = TRUE;
          add_specific_symbol (optarg, globalize_specific_htab);
          break;
 
        case 'G':
+         use_keep_global = TRUE;
          add_specific_symbol (optarg, keepglobal_specific_htab);
          break;
 
@@ -4055,20 +4955,20 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_ADD_SECTION:
-          add_sections = init_section_add (optarg, add_sections,
-                                           "--add-section");
-          section_add_load_file (add_sections);
+         add_sections = init_section_add (optarg, add_sections,
+                                          "--add-section");
+         section_add_load_file (add_sections);
          break;
 
        case OPTION_UPDATE_SECTION:
          update_sections = init_section_add (optarg, update_sections,
-                                              "--update-section");
+                                             "--update-section");
          section_add_load_file (update_sections);
          break;
 
        case OPTION_DUMP_SECTION:
-          dump_sections = init_section_add (optarg, dump_sections,
-                                            "--dump-section");
+         dump_sections = init_section_add (optarg, dump_sections,
+                                           "--dump-section");
          break;
 
        case OPTION_ADD_SYMBOL:
@@ -4096,6 +4996,7 @@ copy_main (int argc, char *argv[])
              }
 
            t = strchr (t + 1, ',');
+           newsym->othersym = NULL;
            if (t)
              newsym->flags = parse_symflags (t+1, &newsym->othersym);
            else
@@ -4193,7 +5094,7 @@ copy_main (int argc, char *argv[])
              {
              case OPTION_CHANGE_SECTION_ADDRESS:
                p->vma_val = val;
-               /* Drop through.  */
+               /* Fall through.  */
 
              case OPTION_CHANGE_SECTION_LMA:
                p->lma_val = val;
@@ -4246,6 +5147,16 @@ copy_main (int argc, char *argv[])
          do_debug_sections = decompress;
          break;
 
+       case OPTION_ELF_STT_COMMON:
+         if (strcasecmp (optarg, "yes") == 0)
+           do_elf_stt_common = elf_stt_common;
+         else if (strcasecmp (optarg, "no") == 0)
+           do_elf_stt_common = no_elf_stt_common;
+         else
+           fatal (_("unrecognized --elf-stt-common= option `%s'"),
+                  optarg);
+         break;
+
        case OPTION_GAP_FILL:
          {
            bfd_vma gap_fill_vma;
@@ -4280,7 +5191,7 @@ copy_main (int argc, char *argv[])
 
        case OPTION_REDEFINE_SYM:
          {
-           /* Push this redefinition onto redefine_symbol_list.  */
+           /* Insert this redefinition onto redefine_specific_htab.  */
 
            int len;
            const char *s;
@@ -4301,7 +5212,7 @@ copy_main (int argc, char *argv[])
            target = (char *) xmalloc (len + 1);
            strcpy (target, nextarg);
 
-           redefine_list_append ("--redefine-sym", source, target);
+           add_redefine_and_check ("--redefine-sym", source, target);
 
            free (source);
            free (target);
@@ -4384,23 +5295,26 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_SREC_LEN:
-         Chunk = parse_vma (optarg, "--srec-len");
+         _bfd_srec_len = parse_vma (optarg, "--srec-len");
          break;
 
        case OPTION_SREC_FORCES3:
-         S3Forced = TRUE;
+         _bfd_srec_forceS3 = TRUE;
          break;
 
        case OPTION_STRIP_SYMBOLS:
-         add_specific_symbols (optarg, strip_specific_htab);
+         add_specific_symbols (optarg, strip_specific_htab,
+                               &strip_specific_buffer);
          break;
 
        case OPTION_STRIP_UNNEEDED_SYMBOLS:
-         add_specific_symbols (optarg, strip_unneeded_htab);
+         add_specific_symbols (optarg, strip_unneeded_htab,
+                               &strip_unneeded_buffer);
          break;
 
        case OPTION_KEEP_SYMBOLS:
-         add_specific_symbols (optarg, keep_specific_htab);
+         add_specific_symbols (optarg, keep_specific_htab,
+                               &keep_specific_buffer);
          break;
 
        case OPTION_LOCALIZE_HIDDEN:
@@ -4408,7 +5322,8 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_LOCALIZE_SYMBOLS:
-         add_specific_symbols (optarg, localize_specific_htab);
+         add_specific_symbols (optarg, localize_specific_htab,
+                               &localize_specific_buffer);
          break;
 
        case OPTION_LONG_SECTION_NAMES:
@@ -4423,15 +5338,20 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_GLOBALIZE_SYMBOLS:
-         add_specific_symbols (optarg, globalize_specific_htab);
+         use_globalize = TRUE;
+         add_specific_symbols (optarg, globalize_specific_htab,
+                               &globalize_specific_buffer);
          break;
 
        case OPTION_KEEPGLOBAL_SYMBOLS:
-         add_specific_symbols (optarg, keepglobal_specific_htab);
+         use_keep_global = TRUE;
+         add_specific_symbols (optarg, keepglobal_specific_htab,
+                               &keepglobal_specific_buffer);
          break;
 
        case OPTION_WEAKEN_SYMBOLS:
-         add_specific_symbols (optarg, weaken_specific_htab);
+         add_specific_symbols (optarg, weaken_specific_htab,
+                               &weaken_specific_buffer);
          break;
 
        case OPTION_ALT_MACH_CODE:
@@ -4481,39 +5401,39 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_REVERSE_BYTES:
-          {
-            int prev = reverse_bytes;
+         {
+           int prev = reverse_bytes;
 
-            reverse_bytes = atoi (optarg);
-            if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
-              fatal (_("number of bytes to reverse must be positive and even"));
+           reverse_bytes = atoi (optarg);
+           if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
+             fatal (_("number of bytes to reverse must be positive and even"));
 
-            if (prev && prev != reverse_bytes)
-              non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
-                         prev);
-            break;
-          }
+           if (prev && prev != reverse_bytes)
+             non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
+                        prev);
+           break;
+         }
 
        case OPTION_FILE_ALIGNMENT:
          pe_file_alignment = parse_vma (optarg, "--file-alignment");
          break;
 
        case OPTION_HEAP:
-           {
-             char *end;
-             pe_heap_reserve = strtoul (optarg, &end, 0);
-             if (end == optarg
-                 || (*end != '.' && *end != '\0'))
-               non_fatal (_("%s: invalid reserve value for --heap"),
-                          optarg);
-             else if (*end != '\0')
-               {
-                 pe_heap_commit = strtoul (end + 1, &end, 0);
-                 if (*end != '\0')
-                   non_fatal (_("%s: invalid commit value for --heap"),
-                              optarg);
-               }
-           }
+         {
+           char *end;
+           pe_heap_reserve = strtoul (optarg, &end, 0);
+           if (end == optarg
+               || (*end != '.' && *end != '\0'))
+             non_fatal (_("%s: invalid reserve value for --heap"),
+                        optarg);
+           else if (*end != '\0')
+             {
+               pe_heap_commit = strtoul (end + 1, &end, 0);
+               if (*end != '\0')
+                 non_fatal (_("%s: invalid commit value for --heap"),
+                            optarg);
+             }
+         }
          break;
 
        case OPTION_IMAGE_BASE:
@@ -4530,21 +5450,21 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_STACK:
-           {
-             char *end;
-             pe_stack_reserve = strtoul (optarg, &end, 0);
-             if (end == optarg
-                 || (*end != '.' && *end != '\0'))
-               non_fatal (_("%s: invalid reserve value for --stack"),
-                          optarg);
-             else if (*end != '\0')
-               {
-                 pe_stack_commit = strtoul (end + 1, &end, 0);
-                 if (*end != '\0')
-                   non_fatal (_("%s: invalid commit value for --stack"),
-                              optarg);
-               }
-           }
+         {
+           char *end;
+           pe_stack_reserve = strtoul (optarg, &end, 0);
+           if (end == optarg
+               || (*end != '.' && *end != '\0'))
+             non_fatal (_("%s: invalid reserve value for --stack"),
+                        optarg);
+           else if (*end != '\0')
+             {
+               pe_stack_commit = strtoul (end + 1, &end, 0);
+               if (*end != '\0')
+                 non_fatal (_("%s: invalid commit value for --stack"),
+                            optarg);
+             }
+         }
          break;
 
        case 0:
@@ -4560,6 +5480,9 @@ copy_main (int argc, char *argv[])
        }
     }
 
+  if (use_globalize && use_keep_global)
+    fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)"));
+
   if (formats_info)
     {
       display_info ();
@@ -4676,6 +5599,9 @@ copy_main (int argc, char *argv[])
   else
     unlink_if_ordinary (tmpname);
 
+  if (tmpname != output_filename)
+    free (tmpname);
+
   if (change_warn)
     {
       struct section_list *p;
@@ -4715,6 +5641,27 @@ copy_main (int argc, char *argv[])
        }
     }
 
+  if (strip_specific_buffer)
+    free (strip_specific_buffer);
+
+  if (strip_unneeded_buffer)
+    free (strip_unneeded_buffer);
+
+  if (keep_specific_buffer)
+    free (keep_specific_buffer);
+
+  if (localize_specific_buffer)
+    free (globalize_specific_buffer);
+
+  if (globalize_specific_buffer)
+    free (globalize_specific_buffer);
+
+  if (keepglobal_specific_buffer)
+    free (keepglobal_specific_buffer);
+
+  if (weaken_specific_buffer)
+    free (weaken_specific_buffer);
+
   return 0;
 }
 
@@ -4740,7 +5687,8 @@ main (int argc, char *argv[])
   strip_symbols = STRIP_UNDEF;
   discard_locals = LOCALS_UNDEF;
 
-  bfd_init ();
+  if (bfd_init () != BFD_INIT_MAGIC)
+    fatal (_("fatal error: libbfd ABI mismatch"));
   set_default_bfd_target ();
 
   if (is_strip < 0)