objcopy/strip: Add option --remove-relocations=SECTIONPATTERN
authorAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 21 Aug 2015 19:08:26 +0000 (20:08 +0100)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Thu, 14 Jul 2016 10:34:10 +0000 (11:34 +0100)
The objcopy and strip tools make use of the bfd library to manipulate
the state of the input file (to produce an output file).  Within the
input file (for ELF at least), relocations are held within a section,
and so, if the user wanted to remove the relocations, but keep the
section to which the relocations would have been applied, it is tempting
to think that specifying the name of a relocation section to objcopy's
--remove-section option might do what you want, for example:

   objcopy --remove-section=.rela.text input.elf output.elf

However, this does not work.  The reason is that when the input file is
loaded, relocations are not managed as sections, but are, instead,
loaded as data associated with the section to which the relocations
would be applied.  In our example above the relocations in '.rela.text'
are held as data on the section '.text' once 'input.elf' is loaded.

One task that objcopy and strip do is copy the relocations from the
input file to the output file if the section is also being copied from
the input file to the output file.

This commit adds a new command line option for objcopy and strip,
--remove-relocations, which can be used to remove the relocations, while
keeping the section that the relocations would have been applied to, for
example:

    objcopy --remove-relocations=.text input.elf output.elf

in this case the section '.text' will appear in both 'input.elf' and
'output.elf', but any relocations in 'input.elf' that apply to '.text'
will not be present in 'output.elf'.

I have also added a special case to the handling of --remove-section
that spots if a user tries to remove a relocation section (currently
this is done by spotting the '.rela.' or '.rel.' prefix) and forwards
the request to --remove-relocations.

As with --remove-section and --only-section the --remove-relocations
option supports the '!' prefix on the section-patterns it takes to allow
for sections to be specifically not matched.

There are tests for all the new functionality.

binutils/ChangeLog:

* doc/binutils.texi (objcopy): Document 'remove-relocations'.
(strip): Likewise.
* objcopy.c (SECTION_CONTEXT_REMOVE_RELOCS): Define.
(enum command_line_switch): Add 'OPTION_REMOVE_RELOCS'.
(struct option strip_options): Add 'remove-relocations'.
(struct option copy_options): Likewise.
(copy_usage): Likewise.
(strip_usage): Likewise.
(handle_remove_relocations_option): New function.
(discard_relocations): New function.
(handle_remove_section_option): New function.
(copy_relocations_in_section): Use discard_relocations.
(strip_main): Use handle_remove_section_option for
'remove-section', and handle 'remove-relocations' option.
(copy_main): Likewise.
* testsuite/binutils-all/objcopy.exp: Run new tests.
* testsuite/binutils-all/remove-relocs-01.d: New file.
* testsuite/binutils-all/remove-relocs-01.s: New file.
* testsuite/binutils-all/remove-relocs-02.d: New file.
* testsuite/binutils-all/remove-relocs-03.d: New file.
* testsuite/binutils-all/remove-relocs-04.d: New file.
* testsuite/binutils-all/remove-relocs-05.d: New file.
* testsuite/binutils-all/remove-relocs-06.d: New file.

12 files changed:
binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/objcopy.c
binutils/testsuite/binutils-all/objcopy.exp
binutils/testsuite/binutils-all/remove-relocs-01.d [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-01.s [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-02.d [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-03.d [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-04.d [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-05.d [new file with mode: 0644]
binutils/testsuite/binutils-all/remove-relocs-06.d [new file with mode: 0644]

index f5b45d8c86186c48db36c42d11d7c5d8c479942d..6b8f2260fd3ef7da1f67f0adcfb99c0fdaef7d62 100644 (file)
@@ -1,3 +1,30 @@
+2016-07-14  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * doc/binutils.texi (objcopy): Document 'remove-relocations'.
+       (strip): Likewise.
+       * objcopy.c (SECTION_CONTEXT_REMOVE_RELOCS): Define.
+       (enum command_line_switch): Add 'OPTION_REMOVE_RELOCS'.
+       (struct option strip_options): Add 'remove-relocations'.
+       (struct option copy_options): Likewise.
+       (copy_usage): Likewise.
+       (strip_usage): Likewise.
+       (handle_remove_relocations_option): New function.
+       (discard_relocations): New function.
+       (handle_remove_section_option): New function.
+       (copy_relocations_in_section): Use discard_relocations.
+       (strip_main): Use handle_remove_section_option for
+       'remove-section', and handle 'remove-relocations' option.
+       (copy_main): Likewise.
+       * testsuite/binutils-all/objcopy.exp: Run new tests.
+       * testsuite/binutils-all/remove-relocs-01.d: New file.
+       * testsuite/binutils-all/remove-relocs-01.s: New file.
+       * testsuite/binutils-all/remove-relocs-02.d: New file.
+       * testsuite/binutils-all/remove-relocs-03.d: New file.
+       * testsuite/binutils-all/remove-relocs-04.d: New file.
+       * testsuite/binutils-all/remove-relocs-05.d: New file.
+       * testsuite/binutils-all/remove-relocs-06.d: New file.
+       * NEWS: Mention new option.
+
 2016-07-14  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * objcopy.c (find_section_list): Handle section patterns starting
index 9625cf49e28e0921ff0aa54dad0e943ee6c0e5b1..56adfa2d9edbbd5e455c6697d0f3d55af7abd9bf 100644 (file)
   A non-matching section is removed from the set of sections matched by
   an earlier --only-section pattern.
 
+* New --remove-relocations=SECTIONPATTERN option for objcopy and strip.
+  This option can be used to remove sections containing relocations.
+  The SECTIONPATTERN is the section to which the relocations apply, not
+  the relocation section itself.
+
 Changes in 2.27:
 
 * Add a configure option, --enable-64-bit-archive, to force use of a
index d77bc86b0f431ea3524043457728e364138475ce..5a564efd665884d936d4685c3993c505b6a37eb4 100644 (file)
@@ -1075,6 +1075,7 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{--interleave-width=}@var{width}]
         [@option{-j} @var{sectionpattern}|@option{--only-section=}@var{sectionpattern}]
         [@option{-R} @var{sectionpattern}|@option{--remove-section=}@var{sectionpattern}]
+        [@option{--remove-relocations=}@var{sectionpattern}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
         [@option{-U}|@option{--disable-deterministic-archives}]
@@ -1254,6 +1255,34 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --remove-relocations=@var{sectionpattern}
+Remove relocations from the output file for any section matching
+@var{sectionpattern}.  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}.
+For example:
+
+@smallexample
+  --remove-relocations=.text.*
+@end smallexample
+
+will remove the relocations for all sections matching the patter
+'.text.*'.
+
+If the first character of @var{sectionpattern} is the exclamation
+point (!) then matching sections will not have their relocation
+removed even if an earlier use of @option{--remove-relocations} on the
+same command line would otherwise cause the relocations to be removed.
+For example:
+
+@smallexample
+  --remove-relocations=.text.* --remove-relocations=!.text.foo
+@end smallexample
+
+will remove all relocations for sections matching the pattern
+'.text.*', but will not remove relocations for the section
+'.text.foo'.
+
 @item -S
 @itemx --strip-all
 Do not copy relocation and symbol information from the source file.
@@ -2988,6 +3017,7 @@ strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname}]
       [@option{-w}|@option{--wildcard}]
       [@option{-x}|@option{--discard-all}] [@option{-X} |@option{--discard-locals}]
       [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname}]
+      [@option{--remove-relocations=}@var{sectionpattern}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
       [@option{-U}|@option{--disable-deterministic-archives}]
@@ -3057,6 +3087,34 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --remove-relocations=@var{sectionpattern}
+Remove relocations from the output file for any section matching
+@var{sectionpattern}.  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}.
+For example:
+
+@smallexample
+  --remove-relocations=.text.*
+@end smallexample
+
+will remove the relocations for all sections matching the patter
+'.text.*'.
+
+If the first character of @var{sectionpattern} is the exclamation
+point (!) then matching sections will not have their relocation
+removed even if an earlier use of @option{--remove-relocations} on the
+same command line would otherwise cause the relocations to be removed.
+For example:
+
+@smallexample
+  --remove-relocations=.text.* --remove-relocations=!.text.foo
+@end smallexample
+
+will remove all relocations for sections matching the pattern
+'.text.*', but will not remove relocations for the section
+'.text.foo'.
+
 @item -s
 @itemx --strip-all
 Remove all symbols.
index 41ccc761d538751efe1d65cebf3dfea87e86fecf..cf3f9832d37214dd43610f59d4a4f74d146caad5 100644 (file)
@@ -139,6 +139,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.  */
@@ -326,6 +327,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,
@@ -367,6 +369,7 @@ static struct option strip_options[] =
   {"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},
@@ -451,6 +454,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},
@@ -538,6 +542,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\
@@ -668,6 +673,7 @@ 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\
@@ -3207,6 +3213,46 @@ 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.  */
+
+static void
+handle_remove_section_option (const char *section_pattern)
+{
+  if (strncmp (section_pattern, ".rela.", 6) == 0)
+    handle_remove_relocations_option (section_pattern + 5);
+  else if (strncmp (section_pattern, ".rel.", 5) == 0)
+    handle_remove_relocations_option (section_pattern + 4);
+  else
+    {
+      find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
+      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.  */
@@ -3226,7 +3272,9 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   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
     {
@@ -3606,8 +3654,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;
@@ -4009,8 +4059,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':
index be8a7d2b5079c82008f7c18ace818ba337186756..76d0b672f78bc67a49407ed920eb7371688e09a0 100644 (file)
@@ -1121,6 +1121,14 @@ if [is_elf_format] {
 
     run_dump_test "only-section-01"
     run_dump_test "remove-section-01"
+
+    # Test the remove relocation functionality
+    set test_list [lsort [glob -nocomplain $srcdir/$subdir/remove-relocs-*.d]]
+    foreach t $test_list {
+        # We need to strip the ".d", but can leave the dirname.
+        verbose [file rootname $t]
+        run_dump_test [file rootname $t]
+    }
 }
 run_dump_test "localize-hidden-2"
 
diff --git a/binutils/testsuite/binutils-all/remove-relocs-01.d b/binutils/testsuite/binutils-all/remove-relocs-01.d
new file mode 100644 (file)
index 0000000..9cd0bfe
--- /dev/null
@@ -0,0 +1,16 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-relocations=.data.relocs.01
+#readelf: -r
+
+Relocation section '\.rela?\.data\.relocs\.02' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
+
+Relocation section '\.rela?\.data\.relocs\.03' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
diff --git a/binutils/testsuite/binutils-all/remove-relocs-01.s b/binutils/testsuite/binutils-all/remove-relocs-01.s
new file mode 100644 (file)
index 0000000..642d54f
--- /dev/null
@@ -0,0 +1,19 @@
+        .section ".data.relocs.01", "aw"
+        .word   rel_01_01
+        .word   rel_01_02
+        .word   rel_01_03
+
+        .section ".data.relocs.02", "aw"
+        .word   rel_02_01
+        .word   rel_02_02
+        .word   rel_02_03
+
+        .section ".data.relocs.03", "aw"
+        .word   rel_03_01
+        .word   rel_03_02
+        .word   rel_03_03
+
+        .section ".data.01", "aw"
+        .word   0x1
+        .word   0x2
+        .word   0x3
diff --git a/binutils/testsuite/binutils-all/remove-relocs-02.d b/binutils/testsuite/binutils-all/remove-relocs-02.d
new file mode 100644 (file)
index 0000000..c5fbacb
--- /dev/null
@@ -0,0 +1,6 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-relocations=*.relocs.*
+#readelf: -r
+
+There are no relocations in this file\.
diff --git a/binutils/testsuite/binutils-all/remove-relocs-03.d b/binutils/testsuite/binutils-all/remove-relocs-03.d
new file mode 100644 (file)
index 0000000..534d85e
--- /dev/null
@@ -0,0 +1,6 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-relocations=*
+#readelf: -r
+
+There are no relocations in this file\.
diff --git a/binutils/testsuite/binutils-all/remove-relocs-04.d b/binutils/testsuite/binutils-all/remove-relocs-04.d
new file mode 100644 (file)
index 0000000..99f5a61
--- /dev/null
@@ -0,0 +1,11 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-relocations=.data.relocs.0\[12\]
+#readelf: -r
+
+Relocation section '\.rela?\.data\.relocs\.03' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
+
diff --git a/binutils/testsuite/binutils-all/remove-relocs-05.d b/binutils/testsuite/binutils-all/remove-relocs-05.d
new file mode 100644 (file)
index 0000000..e2166c9
--- /dev/null
@@ -0,0 +1,17 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-section=.rela.data.relocs.01 --remove-section=.rel.data.relocs.01
+#readelf: -r
+
+Relocation section '\.rela?\.data\.relocs\.02' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
+
+Relocation section '\.rela?\.data\.relocs\.03' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
+
diff --git a/binutils/testsuite/binutils-all/remove-relocs-06.d b/binutils/testsuite/binutils-all/remove-relocs-06.d
new file mode 100644 (file)
index 0000000..09fed58
--- /dev/null
@@ -0,0 +1,11 @@
+#PROG: objcopy
+#source: remove-relocs-01.s
+#objcopy: --remove-relocations=.data.relocs.* --remove-relocations=!.data.relocs.02
+#readelf: -r
+
+Relocation section '\.rela?\.data\.relocs\.02' at offset 0x[0-9a-f]+ contains 3 entries:
+.*
+.*
+.*
+.*
+