PR binutils/15033
authorNick Clifton <nickc@redhat.com>
Fri, 15 Feb 2013 09:32:31 +0000 (09:32 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 15 Feb 2013 09:32:31 +0000 (09:32 +0000)
* objcopy.c (enum change_action): Delete.
(struct section_list): Delete remove, copy, change_vma, change_lma
and set_flags fields.  Add context field.
(find_section_list): Add a context parameter.  Add support for
wildcard characters in section names.
(is_strip_section): Check for sections being both  copied and
removed.
(copy_object): Pass context to find_section_list.
(setup_section): Likewise.
(copy_section): Likewise.
(copy_main): Likewise.
* doc/binutils: Document the new behaviour.
* NEWS: Mention the new feature

binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/objcopy.c

index e9d030e..54d4dab 100644 (file)
@@ -1,3 +1,20 @@
+2013-02-15  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/15033
+       * objcopy.c (enum change_action): Delete.
+       (struct section_list): Delete remove, copy, change_vma, change_lma
+       and set_flags fields.  Add context field.
+       (find_section_list): Add a context parameter.  Add support for
+       wildcard characters in section names.
+       (is_strip_section): Check for sections being both  copied and
+       removed.
+       (copy_object): Pass context to find_section_list.
+       (setup_section): Likewise.
+       (copy_section): Likewise.
+       (copy_main): Likewise.
+       * doc/binutils: Document the new behaviour.
+       * NEWS: Mention the new feature
+
 2013-02-14  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/15125
index 9140043..3853275 100644 (file)
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Objcopy now supports wildcard characters in command line options that take
+  section names.
+
 * Add support for Altera Nios II.
 
 Changes in 2.23:
index fbe1f06..d733fdb 100644 (file)
@@ -1065,8 +1065,8 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{-b} @var{byte}|@option{--byte=}@var{byte}]
         [@option{-i} [@var{breadth}]|@option{--interleave}[=@var{breadth}]]
         [@option{--interleave-width=}@var{width}]
-        [@option{-j} @var{sectionname}|@option{--only-section=}@var{sectionname}]
-        [@option{-R} @var{sectionname}|@option{--remove-section=}@var{sectionname}]
+        [@option{-j} @var{sectionpattern}|@option{--only-section=}@var{sectionpattern}]
+        [@option{-R} @var{sectionpattern}|@option{--remove-section=}@var{sectionpattern}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
         [@option{-U}|@option{--disable-deterministic-archives}]
@@ -1076,11 +1076,11 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{--set-start=}@var{val}]
         [@option{--adjust-start=}@var{incr}]
         [@option{--change-addresses=}@var{incr}]
-        [@option{--change-section-address} @var{section}@{=,+,-@}@var{val}]
-        [@option{--change-section-lma} @var{section}@{=,+,-@}@var{val}]
-        [@option{--change-section-vma} @var{section}@{=,+,-@}@var{val}]
+        [@option{--change-section-address} @var{sectionpattern}@{=,+,-@}@var{val}]
+        [@option{--change-section-lma} @var{sectionpattern}@{=,+,-@}@var{val}]
+        [@option{--change-section-vma} @var{sectionpattern}@{=,+,-@}@var{val}]
         [@option{--change-warnings}] [@option{--no-change-warnings}]
-        [@option{--set-section-flags} @var{section}=@var{flags}]
+        [@option{--set-section-flags} @var{sectionpattern}=@var{flags}]
         [@option{--add-section} @var{sectionname}=@var{filename}]
         [@option{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]]
         [@option{--long-section-names} @{enable,disable,keep@}]
@@ -1204,17 +1204,21 @@ called _binary_@var{objfile}_start, _binary_@var{objfile}_end and
 _binary_@var{objfile}_size.  e.g. you can transform a picture file into
 an object file and then access it in your code using these symbols.
 
-@item -j @var{sectionname}
-@itemx --only-section=@var{sectionname}
-Copy only the named section from the input file to the output file.
+@item -j @var{sectionpattern}
+@itemx --only-section=@var{sectionpattern}
+Copy only the indicated sections from the input file to the output file.
 This option may be given more than once.  Note that using this option
-inappropriately may make the output file unusable.
+inappropriately may make the output file unusable.  Wildcard
+characters are accepted in @var{sectionpattern}.
 
-@item -R @var{sectionname}
-@itemx --remove-section=@var{sectionname}
-Remove any section named @var{sectionname} from the output file.  This
-option may be given more than once.  Note that using this option
-inappropriately may make the output file unusable.
+@item -R @var{sectionpattern}
+@itemx --remove-section=@var{sectionpattern}
+Remove any section matching @var{sectionpattern} from the output file.
+This option may be given more than once.  Note that using this option
+inappropriately may make the output file unusable.  Wildcard
+characters are accepted in @var{sectionpattern}.  Using both the
+@option{-j} and @option{-R} options together results in undefined
+behaviour.
 
 @item -S
 @itemx --strip-all
@@ -1396,65 +1400,68 @@ relocate the sections; if the program expects sections to be loaded at a
 certain address, and this option is used to change the sections such
 that they are loaded at a different address, the program may fail.
 
-@item --change-section-address @var{section}@{=,+,-@}@var{val}
-@itemx --adjust-section-vma @var{section}@{=,+,-@}@var{val}
+@item --change-section-address @var{sectionpattern}@{=,+,-@}@var{val}
+@itemx --adjust-section-vma @var{sectionpattern}@{=,+,-@}@var{val}
 @cindex changing section address
-Set or change both the VMA address and the LMA address of the named
-@var{section}.  If @samp{=} is used, the section address is set to
-@var{val}.  Otherwise, @var{val} is added to or subtracted from the
-section address.  See the comments under @option{--change-addresses},
-above. If @var{section} does not exist in the input file, a warning will
-be issued, unless @option{--no-change-warnings} is used.
+Set or change both the VMA address and the LMA address of any section
+matching @var{sectionpattern}.  If @samp{=} is used, the section
+address is set to @var{val}.  Otherwise, @var{val} is added to or
+subtracted from the section address.  See the comments under
+@option{--change-addresses}, above. If @var{sectionpattern} does not
+match any sections in the input file, a warning will be issued, unless
+@option{--no-change-warnings} is used.
 
-@item --change-section-lma @var{section}@{=,+,-@}@var{val}
+@item --change-section-lma @var{sectionpattern}@{=,+,-@}@var{val}
 @cindex changing section LMA
-Set or change the LMA address of the named @var{section}.  The LMA
-address is the address where the section will be loaded into memory at
-program load time.  Normally this is the same as the VMA address, which
-is the address of the section at program run time, but on some systems,
+Set or change the LMA address of any sections matching
+@var{sectionpattern}.  The LMA address is the address where the
+section will be loaded into memory at program load time.  Normally
+this is the same as the VMA address, which is the address of the
+section at program run time, but on some systems, especially those
+where a program is held in ROM, the two can be different.  If @samp{=}
+is used, the section address is set to @var{val}.  Otherwise,
+@var{val} is added to or subtracted from the section address.  See the
+comments under @option{--change-addresses}, above.  If
+@var{sectionpattern} does not match any sections in the input file, a
+warning will be issued, unless @option{--no-change-warnings} is used.
+
+@item --change-section-vma @var{sectionpattern}@{=,+,-@}@var{val}
+@cindex changing section VMA
+Set or change the VMA address of any section matching
+@var{sectionpattern}.  The VMA address is the address where the
+section will be located once the program has started executing.
+Normally this is the same as the LMA address, which is the address
+where the section will be loaded into memory, but on some systems,
 especially those where a program is held in ROM, the two can be
 different.  If @samp{=} is used, the section address is set to
 @var{val}.  Otherwise, @var{val} is added to or subtracted from the
 section address.  See the comments under @option{--change-addresses},
-above.  If @var{section} does not exist in the input file, a warning
-will be issued, unless @option{--no-change-warnings} is used.
-
-@item --change-section-vma @var{section}@{=,+,-@}@var{val}
-@cindex changing section VMA
-Set or change the VMA address of the named @var{section}.  The VMA
-address is the address where the section will be located once the
-program has started executing.  Normally this is the same as the LMA
-address, which is the address where the section will be loaded into
-memory, but on some systems, especially those where a program is held in
-ROM, the two can be different.  If @samp{=} is used, the section address
-is set to @var{val}.  Otherwise, @var{val} is added to or subtracted
-from the section address.  See the comments under
-@option{--change-addresses}, above.  If @var{section} does not exist in
-the input file, a warning will be issued, unless
+above.  If @var{sectionpattern} does not match any sections in the
+input file, a warning will be issued, unless
 @option{--no-change-warnings} is used.
 
 @item --change-warnings
 @itemx --adjust-warnings
 If @option{--change-section-address} or @option{--change-section-lma} or
-@option{--change-section-vma} is used, and the named section does not
-exist, issue a warning.  This is the default.
+@option{--change-section-vma} is used, and the section pattern does not
+match any sections, issue a warning.  This is the default.
 
 @item --no-change-warnings
 @itemx --no-adjust-warnings
 Do not issue a warning if @option{--change-section-address} or
 @option{--adjust-section-lma} or @option{--adjust-section-vma} is used, even
-if the named section does not exist.
-
-@item --set-section-flags @var{section}=@var{flags}
-Set the flags for the named section.  The @var{flags} argument is a
-comma separated string of flag names.  The recognized names are
-@samp{alloc}, @samp{contents}, @samp{load}, @samp{noload},
-@samp{readonly}, @samp{code}, @samp{data}, @samp{rom}, @samp{share}, and
-@samp{debug}.  You can set the @samp{contents} flag for a section which
-does not have contents, but it is not meaningful to clear the
-@samp{contents} flag of a section which does have contents--just remove
-the section instead.  Not all flags are meaningful for all object file
-formats.
+if the section pattern does not match any sections.
+
+@item --set-section-flags @var{sectionpattern}=@var{flags}
+Set the flags for any sections matching @var{sectionpattern}.  The
+@var{flags} argument is a comma separated string of flag names.  The
+recognized names are @samp{alloc}, @samp{contents}, @samp{load},
+@samp{noload}, @samp{readonly}, @samp{code}, @samp{data}, @samp{rom},
+@samp{share}, and @samp{debug}.  You can set the @samp{contents} flag
+for a section which does not have contents, but it is not meaningful
+to clear the @samp{contents} flag of a section which does have
+contents--just remove the section instead.  Not all flags are
+meaningful for all object file formats.
 
 @item --add-section @var{sectionname}=@var{filename}
 Add a new section named @var{sectionname} while copying the file.  The
@@ -2787,7 +2794,9 @@ Replace @var{objfile} with a file in the output format @var{bfdname}.
 @itemx --remove-section=@var{sectionname}
 Remove any section named @var{sectionname} from the output file.  This
 option may be given more than once.  Note that using this option
-inappropriately may make the output file unusable.
+inappropriately may make the output file unusable.  The wildcard
+character @samp{*} may be given at the end of @var{sectionname}.  If
+so, then any section starting with @var{sectionname} will be removed.
 
 @item -s
 @itemx --strip-all
index ca37288..288aa52 100644 (file)
@@ -1,7 +1,5 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright 1991-2013 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -114,27 +112,26 @@ enum locals_action
 /* Which local symbols to remove.  Overrides STRIP_ALL.  */
 static enum locals_action discard_locals;
 
-/* What kind of change to perform.  */
-enum change_action
-{
-  CHANGE_IGNORE,
-  CHANGE_MODIFY,
-  CHANGE_SET
-};
-
 /* Structure used to hold lists of sections and actions to take.  */
 struct section_list
 {
   struct section_list * next;     /* Next section to change.  */
-  const char *         name;      /* Section name.  */
+  const char *         pattern;   /* Section name pattern.  */
   bfd_boolean          used;      /* Whether this entry was used.  */
-  bfd_boolean          remove;    /* Whether to remove this section.  */
-  bfd_boolean          copy;      /* Whether to copy this section.  */
-  enum change_action   change_vma;/* Whether to change or set VMA.  */
+
+  unsigned int          context;   /* What to do with matching sections.  */
+  /* Flag bits used in the context field.
+     COPY and REMOVE are mutually exlusive.  SET and ALTER are mutually exclusive.  */
+#define SECTION_CONTEXT_REMOVE    (1 << 0) /* Remove this section.  */
+#define SECTION_CONTEXT_COPY      (1 << 1) /* Copy this section, delete all non-copied section.  */
+#define SECTION_CONTEXT_SET_VMA   (1 << 2) /* Set the sections' VMA address.  */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address.  */
+#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.  */
+
   bfd_vma              vma_val;   /* Amount to change by or set to.  */
-  enum change_action   change_lma;/* Whether to change or set LMA.  */
   bfd_vma              lma_val;   /* Amount to change by or set to.  */
-  bfd_boolean          set_flags; /* Whether to set the section flags.  */
   flagword             flags;     /* What to set the section flags to.  */
 };
 
@@ -712,32 +709,93 @@ parse_flags (const char *s)
   return ret;
 }
 
-/* Find and optionally add an entry in the change_sections list.  */
+/* Find and optionally add an entry in the change_sections list.
+
+   We need to be careful in how we match section names because of the support
+   for wildcard characters.  For example suppose that the user has invoked
+   objcopy like this:
+         
+       --set-section-flags .debug_*=debug
+       --set-section-flags .debug_str=readonly,debug
+       --change-section-address .debug_*ranges=0x1000
+
+   With the idea that all debug sections will receive the DEBUG flag, the
+   .debug_str section will also receive the READONLY flag and the
+   .debug_ranges and .debug_aranges sections will have their address set to
+   0x1000.  (This may not make much sense, but it is just an example).
+
+   When adding the section name patterns to the section list we need to make
+   sure that previous entries do not match with the new entry, unless the
+   match is exact.  (In which case we assume that the user is overriding
+   the previous entry with the new context).
+
+   When matching real section names to the section list we make use of the
+   wildcard characters, but we must do so in context.  Eg if we are setting
+   section addresses then we match for .debug_ranges but not for .debug_info.
+
+   Finally, if ADD is false and we do find a match, we mark the section list
+   entry as used.  */
 
 static struct section_list *
-find_section_list (const char *name, bfd_boolean add)
+find_section_list (const char *name, bfd_boolean add, unsigned int context)
 {
   struct section_list *p;
 
+  /* assert ((context & ((1 << 7) - 1)) != 0); */
+  
   for (p = change_sections; p != NULL; p = p->next)
-    if (strcmp (p->name, name) == 0)
-      return p;
+    {
+      if (add)
+       {
+         if (strcmp (p->pattern, name) == 0)
+           {
+             /* Check for context conflicts.  */
+             if (((p->context & SECTION_CONTEXT_REMOVE)
+                  && (context & SECTION_CONTEXT_COPY))
+                 || ((context & SECTION_CONTEXT_REMOVE)
+                     && (p->context & SECTION_CONTEXT_COPY)))
+               fatal (_("error: %s both copied and removed"), name);
+
+             if (((p->context & SECTION_CONTEXT_SET_VMA)
+                 && (context & SECTION_CONTEXT_ALTER_VMA))
+                 || ((context & SECTION_CONTEXT_SET_VMA)
+                     && (context & SECTION_CONTEXT_ALTER_VMA)))
+               fatal (_("error: %s both sets and alters VMA"), name);
+
+             if (((p->context & SECTION_CONTEXT_SET_LMA)
+                 && (context & SECTION_CONTEXT_ALTER_LMA))
+                 || ((context & SECTION_CONTEXT_SET_LMA)
+                     && (context & SECTION_CONTEXT_ALTER_LMA)))
+               fatal (_("error: %s both sets and alters LMA"), name);
+
+             /* Extend the context.  */
+             p->context |= context;
+             return p;
+           }
+       }
+      /* 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;
+       }
+    }
 
   if (! add)
     return NULL;
 
   p = (struct section_list *) xmalloc (sizeof (struct section_list));
-  p->name = name;
+  p->pattern = name;
   p->used = FALSE;
-  p->remove = FALSE;
-  p->copy = FALSE;
-  p->change_vma = CHANGE_IGNORE;
-  p->change_lma = CHANGE_IGNORE;
+  p->context = context;
   p->vma_val = 0;
   p->lma_val = 0;
-  p->set_flags = FALSE;
   p->flags = 0;
-
   p->next = change_sections;
   change_sections = p;
 
@@ -988,12 +1046,20 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
   if (sections_removed || sections_copied)
     {
       struct section_list *p;
+      struct section_list *q;
 
-      p = find_section_list (bfd_get_section_name (abfd, sec), FALSE);
+      p = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+                            SECTION_CONTEXT_REMOVE);
+      q = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+                            SECTION_CONTEXT_COPY);
 
-      if (sections_removed && p != NULL && p->remove)
+      if (p && q)
+       fatal (_("error: section %s matches both remove and copy options"),
+              bfd_get_section_name (abfd, sec));
+
+      if (p != NULL)
        return TRUE;
-      if (sections_copied && (p == NULL || ! p->copy))
+      if (sections_copied && q == NULL)
        return TRUE;
     }
 
@@ -1696,13 +1762,12 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        {
          flagword flags;
 
-         pset = find_section_list (padd->name, FALSE);
+         pset = find_section_list (padd->name, FALSE,
+                                   SECTION_CONTEXT_SET_FLAGS);
          if (pset != NULL)
-           pset->used = TRUE;
-
-         flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
-         if (pset != NULL && pset->set_flags)
            flags = pset->flags | SEC_HAS_CONTENTS;
+         else
+           flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
 
          /* bfd_make_section_with_flags() does not return very helpful
             error codes, so check for the most likely user error first.  */
@@ -1735,27 +1800,27 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
              return FALSE;
            }
 
+         pset = find_section_list (padd->name, FALSE,
+                                   SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA);
+         if (pset != NULL
+             && ! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
+           {
+             bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
+             return FALSE;
+           }
+
+         pset = find_section_list (padd->name, FALSE,
+                                   SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA);
          if (pset != NULL)
            {
-             if (pset->change_vma != CHANGE_IGNORE)
-               if (! bfd_set_section_vma (obfd, padd->section,
-                                          pset->vma_val))
-                 {
-                   bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
-                   return FALSE;
-                 }
+             padd->section->lma = pset->lma_val;
 
-             if (pset->change_lma != CHANGE_IGNORE)
+             if (! bfd_set_section_alignment
+                 (obfd, padd->section,
+                  bfd_section_alignment (obfd, padd->section)))
                {
-                 padd->section->lma = pset->lma_val;
-
-                 if (! bfd_set_section_alignment
-                     (obfd, padd->section,
-                      bfd_section_alignment (obfd, padd->section)))
-                   {
-                     bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
-                     return FALSE;
-                   }
+                 bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
+                 return FALSE;
                }
            }
        }
@@ -2531,10 +2596,6 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   if (is_strip_section (ibfd, isection))
     return;
 
-  p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
-  if (p != NULL)
-    p->used = TRUE;
-
   /* Get the, possibly new, name of the output section.  */
   name = find_section_rename (ibfd, isection, & flags);
 
@@ -2556,7 +2617,10 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     }
 
   make_nobits = FALSE;
-  if (p != NULL && p->set_flags)
+
+  p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+                        SECTION_CONTEXT_SET_FLAGS);
+  if (p != NULL)
     flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
   else if (strip_symbols == STRIP_NONDEBUG
           && (flags & (SEC_ALLOC | SEC_GROUP)) != 0
@@ -2599,10 +2663,15 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     }
 
   vma = bfd_section_vma (ibfd, isection);
-  if (p != NULL && p->change_vma == CHANGE_MODIFY)
-    vma += p->vma_val;
-  else if (p != NULL && p->change_vma == CHANGE_SET)
-    vma = p->vma_val;
+  p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+                        SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
+  if (p != NULL)
+    {
+      if (p->context & SECTION_CONTEXT_SET_VMA)
+       vma = p->vma_val;
+      else
+       vma += p->vma_val;
+    }
   else
     vma += change_section_address;
 
@@ -2613,14 +2682,14 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     }
 
   lma = isection->lma;
-  if ((p != NULL) && p->change_lma != CHANGE_IGNORE)
+  p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+                        SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
+  if (p != NULL)
     {
-      if (p->change_lma == CHANGE_MODIFY)
+      if (p->context & SECTION_CONTEXT_ALTER_LMA)
        lma += p->lma_val;
-      else if (p->change_lma == CHANGE_SET)
-       lma = p->lma_val;
       else
-       abort ();
+       lma = p->lma_val;
     }
   else
     lma += change_section_address;
@@ -2812,8 +2881,6 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   osection = isection->output_section;
   size = bfd_get_section_size (isection);
 
-  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
-
   if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
       && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
     {
@@ -2880,7 +2947,9 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        }
       free (memhunk);
     }
-  else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0)
+  else if ((p = find_section_list (bfd_get_section_name (ibfd, isection),
+                                  FALSE, SECTION_CONTEXT_SET_FLAGS)) != NULL
+          && (p->flags & SEC_HAS_CONTENTS) != 0)
     {
       void *memhunk = xmalloc (size);
 
@@ -3082,7 +3151,6 @@ strip_main (int argc, char *argv[])
   bfd_boolean formats_info = FALSE;
   int c;
   int i;
-  struct section_list *p;
   char *output_file = NULL;
 
   while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
@@ -3100,8 +3168,7 @@ strip_main (int argc, char *argv[])
          input_target = output_target = optarg;
          break;
        case 'R':
-         p = find_section_list (optarg, TRUE);
-         p->remove = TRUE;
+         find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
          sections_removed = TRUE;
          break;
        case 's':
@@ -3374,7 +3441,6 @@ copy_main (int argc, char *argv[])
   bfd_boolean change_warn = TRUE;
   bfd_boolean formats_info = FALSE;
   int c;
-  struct section_list *p;
   struct stat statbuf;
   const bfd_arch_info_type *input_arch = NULL;
 
@@ -3427,18 +3493,12 @@ copy_main (int argc, char *argv[])
          break;
 
        case 'j':
-         p = find_section_list (optarg, TRUE);
-         if (p->remove)
-           fatal (_("%s both copied and removed"), optarg);
-         p->copy = TRUE;
+         find_section_list (optarg, TRUE, SECTION_CONTEXT_COPY);
          sections_copied = TRUE;
          break;
 
        case 'R':
-         p = find_section_list (optarg, TRUE);
-         if (p->copy)
-           fatal (_("%s both copied and removed"), optarg);
-         p->remove = TRUE;
+         find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
          sections_removed = TRUE;
          break;
 
@@ -3601,23 +3661,27 @@ copy_main (int argc, char *argv[])
        case OPTION_CHANGE_SECTION_LMA:
        case OPTION_CHANGE_SECTION_VMA:
          {
+           struct section_list * p;
+           unsigned int context;
            const char *s;
            int len;
            char *name;
            char *option = NULL;
            bfd_vma val;
-           enum change_action what = CHANGE_IGNORE;
 
            switch (c)
              {
              case OPTION_CHANGE_SECTION_ADDRESS:
                option = "--change-section-address";
+               context = SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_ALTER_VMA;
                break;
              case OPTION_CHANGE_SECTION_LMA:
                option = "--change-section-lma";
+               context = SECTION_CONTEXT_ALTER_LMA;
                break;
              case OPTION_CHANGE_SECTION_VMA:
                option = "--change-section-vma";
+               context = SECTION_CONTEXT_ALTER_VMA;
                break;
              }
 
@@ -3632,38 +3696,46 @@ copy_main (int argc, char *argv[])
                      fatal (_("bad format for %s"), option);
                  }
              }
+           else
+             {
+               /* Correct the context.  */
+               switch (c)
+                 {
+                 case OPTION_CHANGE_SECTION_ADDRESS:
+                   context = SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_SET_VMA;
+                   break;
+                 case OPTION_CHANGE_SECTION_LMA:
+                   context = SECTION_CONTEXT_SET_LMA;
+                   break;
+                 case OPTION_CHANGE_SECTION_VMA:
+                   context = SECTION_CONTEXT_SET_VMA;
+                   break;
+                 }
+             }
 
            len = s - optarg;
            name = (char *) xmalloc (len + 1);
            strncpy (name, optarg, len);
            name[len] = '\0';
 
-           p = find_section_list (name, TRUE);
+           p = find_section_list (name, TRUE, context);
 
            val = parse_vma (s + 1, option);
-
-           switch (*s)
-             {
-             case '=': what = CHANGE_SET; break;
-             case '-': val  = - val; /* Drop through.  */
-             case '+': what = CHANGE_MODIFY; break;
-             }
+           if (*s == '-')
+             val = - val;
 
            switch (c)
              {
              case OPTION_CHANGE_SECTION_ADDRESS:
-               p->change_vma = what;
-               p->vma_val    = val;
+               p->vma_val = val;
                /* Drop through.  */
 
              case OPTION_CHANGE_SECTION_LMA:
-               p->change_lma = what;
-               p->lma_val    = val;
+               p->lma_val = val;
                break;
 
              case OPTION_CHANGE_SECTION_VMA:
-               p->change_vma = what;
-               p->vma_val    = val;
+               p->vma_val = val;
                break;
              }
          }
@@ -3762,6 +3834,7 @@ copy_main (int argc, char *argv[])
 
        case OPTION_SET_SECTION_FLAGS:
          {
+           struct section_list *p;
            const char *s;
            int len;
            char *name;
@@ -3775,9 +3848,8 @@ copy_main (int argc, char *argv[])
            strncpy (name, optarg, len);
            name[len] = '\0';
 
-           p = find_section_list (name, TRUE);
+           p = find_section_list (name, TRUE, SECTION_CONTEXT_SET_FLAGS);
 
-           p->set_flags = TRUE;
            p->flags = parse_flags (s + 1);
          }
          break;
@@ -4126,11 +4198,13 @@ copy_main (int argc, char *argv[])
 
   if (change_warn)
     {
+      struct section_list *p;
+
       for (p = change_sections; p != NULL; p = p->next)
        {
          if (! p->used)
            {
-             if (p->change_vma != CHANGE_IGNORE)
+             if (p->context & (SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA))
                {
                  char buff [20];
 
@@ -4139,12 +4213,12 @@ copy_main (int argc, char *argv[])
                  /* xgettext:c-format */
                  non_fatal (_("%s %s%c0x%s never used"),
                             "--change-section-vma",
-                            p->name,
-                            p->change_vma == CHANGE_SET ? '=' : '+',
+                            p->pattern,
+                            p->context & SECTION_CONTEXT_SET_VMA ? '=' : '+',
                             buff);
                }
 
-             if (p->change_lma != CHANGE_IGNORE)
+             if (p->context & (SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA))
                {
                  char buff [20];
 
@@ -4153,8 +4227,8 @@ copy_main (int argc, char *argv[])
                  /* xgettext:c-format */
                  non_fatal (_("%s %s%c0x%s never used"),
                             "--change-section-lma",
-                            p->name,
-                            p->change_lma == CHANGE_SET ? '=' : '+',
+                            p->pattern,
+                            p->context & SECTION_CONTEXT_SET_LMA ? '=' : '+',
                             buff);
                }
            }