objcopy: Add --update-section option.
authorAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 13 Feb 2015 17:04:42 +0000 (17:04 +0000)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Sat, 28 Feb 2015 21:25:51 +0000 (21:25 +0000)
New option for objcopy --update-section allows the contents of a section
to be updated while maintaining the section flags, and, for ELF files,
the section to segment mapping.

New test uses --dump-section and --update-section to check that a
section can be made larger and smaller with an update.

binutils/ChangeLog:

* objcopy.c (update_sections): New list.
(command_line_switch): Add OPTION_UPDATE_SECTION.
(copy_options): Add update-section.
(copy_usage): Document new option.
(is_update_section): New function.
(is_strip_section_1): Add check for attempt to update and remove
the same section.
(copy_object): Update size and content of requested sections.
(skip_section): Don't copy for updated sections.
(copy_main): Handle --update-section.
* doc/binutils.texi (objcopy): Add description of --update-section
option.
* NEWS: Mention --update-section option.

binutils/testsuite/ChangeLog:

* binutils-all/update-1.s: New file.
* binutils-all/update-2.s: New file.
* binutils-all/update-3.s: New file.
* binutils-all/update-4.s: New file.
* binutils-all/update-section.exp: New file.

binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/objcopy.c
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/update-1.s [new file with mode: 0644]
binutils/testsuite/binutils-all/update-2.s [new file with mode: 0644]
binutils/testsuite/binutils-all/update-3.s [new file with mode: 0644]
binutils/testsuite/binutils-all/update-4.s [new file with mode: 0644]
binutils/testsuite/binutils-all/update-section.exp [new file with mode: 0644]

index 81f19f17a522a5bac41acf8fe17c14a5cfb7c277..07729162946c0c9ddabfde631ff985a56a273966 100644 (file)
@@ -1,3 +1,19 @@
+2015-02-28  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * objcopy.c (update_sections): New list.
+       (command_line_switch): Add OPTION_UPDATE_SECTION.
+       (copy_options): Add update-section.
+       (copy_usage): Document new option.
+       (is_update_section): New function.
+       (is_strip_section_1): Add check for attempt to update and remove
+       the same section.
+       (copy_object): Update size and content of requested sections.
+       (skip_section): Don't copy for updated sections.
+       (copy_main): Handle --update-section.
+       * doc/binutils.texi (objcopy): Add description of --update-section
+       option.
+       * NEWS: Mention --update-section option.
+
 2015-02-26  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17512
 2015-02-26  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17512
index 32b95ae729421b6c899663447c4c36e8fc33a18f..41586387419bcf296d9840c6fddba0f87f5a5079 100644 (file)
@@ -1,5 +1,7 @@
 -*- text -*-
 
 -*- text -*-
 
+* Add --update-section option to objcopy.
+
 Changes in 2.25:
 
 * Add --data option to strings to only print strings in loadable, initialized
 Changes in 2.25:
 
 * Add --data option to strings to only print strings in loadable, initialized
index a5bfd4c0b44eb8368852d9ccdae127ec273a04dc..d63c04ca6c089b6dc2952aaff382e2382cf1f65b 100644 (file)
@@ -1091,6 +1091,7 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{--set-section-flags} @var{sectionpattern}=@var{flags}]
         [@option{--add-section} @var{sectionname}=@var{filename}]
         [@option{--dump-section} @var{sectionname}=@var{filename}]
         [@option{--set-section-flags} @var{sectionpattern}=@var{flags}]
         [@option{--add-section} @var{sectionname}=@var{filename}]
         [@option{--dump-section} @var{sectionname}=@var{filename}]
+        [@option{--update-section} @var{sectionname}=@var{filename}]
         [@option{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]]
         [@option{--long-section-names} @{enable,disable,keep@}]
         [@option{--change-leading-char}] [@option{--remove-leading-char}]
         [@option{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]]
         [@option{--long-section-names} @{enable,disable,keep@}]
         [@option{--change-leading-char}] [@option{--remove-leading-char}]
@@ -1489,6 +1490,21 @@ that it does not create a formatted file, it just dumps the contents
 as raw binary data, without applying any relocations.  The option can
 be specified more than once.
 
 as raw binary data, without applying any relocations.  The option can
 be specified more than once.
 
+@item --update-section @var{sectionname}=@var{filename}
+Replace the existing contents of a section named @var{sectionname}
+with the contents of file @var{filename}.  The size of the section
+will be adjusted to the size of the file.  The section flags for
+@var{sectionname} will be unchanged.  For ELF format files the section
+to segment mapping will also remain unchanged, something which is not
+possible using @option{--remove-section} followed by
+@option{--add-section}.  The option can be specified more than once.
+
+Note - it is possible to use @option{--rename-section} and
+@option{--update-section} to both update and rename a section from one
+command line.  In this case, pass the original section name to
+@option{--update-section}, and the original and new section names to
+@option{--rename-section}.
+
 @item --rename-section @var{oldname}=@var{newname}[,@var{flags}]
 Rename a section from @var{oldname} to @var{newname}, optionally
 changing the section's flags to @var{flags} in the process.  This has
 @item --rename-section @var{oldname}=@var{newname}[,@var{flags}]
 Rename a section from @var{oldname} to @var{newname}, optionally
 changing the section's flags to @var{flags} in the process.  This has
index 7f094d343ec9cc0dda841763c084fcdf407f7af6..f340c8acd70a88962f6aa1dd8d2b655f4fa7e309 100644 (file)
@@ -186,6 +186,9 @@ struct section_add
 /* List of sections to add to the output BFD.  */
 static struct section_add *add_sections;
 
 /* List of sections to add to the output BFD.  */
 static struct section_add *add_sections;
 
+/* List of sections to update in the output BFD.  */
+static struct section_add *update_sections;
+
 /* List of sections to dump from the output BFD.  */
 static struct section_add *dump_sections;
 
 /* List of sections to dump from the output BFD.  */
 static struct section_add *dump_sections;
 
@@ -262,6 +265,7 @@ static enum long_section_name_handling long_section_names = KEEP;
 enum command_line_switch
   {
     OPTION_ADD_SECTION=150,
 enum command_line_switch
   {
     OPTION_ADD_SECTION=150,
+    OPTION_UPDATE_SECTION,
     OPTION_DUMP_SECTION,
     OPTION_CHANGE_ADDRESSES,
     OPTION_CHANGE_LEADING_CHAR,
     OPTION_DUMP_SECTION,
     OPTION_CHANGE_ADDRESSES,
     OPTION_CHANGE_LEADING_CHAR,
@@ -361,6 +365,7 @@ static struct option copy_options[] =
 {
   {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
   {"add-section", required_argument, 0, OPTION_ADD_SECTION},
 {
   {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
   {"add-section", required_argument, 0, OPTION_ADD_SECTION},
+  {"update-section", required_argument, 0, OPTION_UPDATE_SECTION},
   {"adjust-start", required_argument, 0, OPTION_CHANGE_START},
   {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
   {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
   {"adjust-start", required_argument, 0, OPTION_CHANGE_START},
   {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
   {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
@@ -553,6 +558,9 @@ copy_usage (FILE *stream, int exit_status)
      --set-section-flags <name>=<flags>\n\
                                    Set section <name>'s properties to <flags>\n\
      --add-section <name>=<file>   Add section <name> found in <file> to output\n\
      --set-section-flags <name>=<flags>\n\
                                    Set section <name>'s properties to <flags>\n\
      --add-section <name>=<file>   Add section <name> found in <file> to output\n\
+     --update-section <name>=<file>\n\
+                                   Update contents of section <name> with\n\
+                                   contents found in <file>\n\
      --dump-section <name>=<file>  Dump the contents of section <name> into <file>\n\
      --rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
      --long-section-names {enable|disable|keep}\n\
      --dump-section <name>=<file>  Dump the contents of section <name> into <file>\n\
      --rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
      --long-section-names {enable|disable|keep}\n\
@@ -1044,6 +1052,27 @@ is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
   return strncmp (name + len - 4, ".dwo", 4) == 0;
 }
 
   return strncmp (name + len - 4, ".dwo", 4) == 0;
 }
 
+/* Return TRUE if section SEC is in the update list.  */
+
+static bfd_boolean
+is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+  if (update_sections != NULL)
+    {
+      struct section_add *pupdate;
+
+      for (pupdate = update_sections;
+           pupdate != NULL;
+           pupdate = pupdate->next)
+       {
+          if (strcmp (sec->name, pupdate->name) == 0)
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 /* See if a non-group section is being removed.  */
 
 static bfd_boolean
 /* See if a non-group section is being removed.  */
 
 static bfd_boolean
@@ -1062,6 +1091,9 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
       if (p && q)
        fatal (_("error: section %s matches both remove and copy options"),
               bfd_get_section_name (abfd, sec));
       if (p && q)
        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));
 
       if (p != NULL)
        return TRUE;
 
       if (p != NULL)
        return TRUE;
@@ -1865,6 +1897,29 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        }
     }
 
        }
     }
 
+  if (update_sections != NULL)
+    {
+      struct section_add *pupdate;
+
+      for (pupdate = update_sections;
+          pupdate != NULL;
+          pupdate = pupdate->next)
+       {
+         asection *osec;
+
+         pupdate->section = bfd_get_section_by_name (ibfd, pupdate->name);
+         if (pupdate->section == NULL)
+           fatal (_("error: %s not found, can't be updated"), pupdate->name);
+
+         osec = pupdate->section->output_section;
+         if (! bfd_set_section_size (obfd, osec, pupdate->size))
+           {
+             bfd_nonfatal_message (NULL, obfd, osec, NULL);
+             return FALSE;
+           }
+       }
+    }
+
   if (dump_sections != NULL)
     {
       struct section_add * pdump;
   if (dump_sections != NULL)
     {
       struct section_add * pdump;
@@ -2150,6 +2205,26 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        }
     }
 
        }
     }
 
+  if (update_sections != NULL)
+    {
+      struct section_add *pupdate;
+
+      for (pupdate = update_sections;
+           pupdate != NULL;
+           pupdate = pupdate->next)
+       {
+         asection *osec;
+
+         osec = pupdate->section->output_section;
+         if (! bfd_set_section_contents (obfd, osec, pupdate->contents,
+                                         0, pupdate->size))
+           {
+             bfd_nonfatal_message (NULL, obfd, osec, NULL);
+             return FALSE;
+           }
+       }
+    }
+
   if (gnu_debuglink_filename != NULL)
     {
       if (! bfd_fill_in_gnu_debuglink_section
   if (gnu_debuglink_filename != NULL)
     {
       if (! bfd_fill_in_gnu_debuglink_section
@@ -2881,6 +2956,9 @@ skip_section (bfd *ibfd, sec_ptr isection)
   if (is_strip_section (ibfd, isection))
     return TRUE;
 
   if (is_strip_section (ibfd, isection))
     return TRUE;
 
+  if (is_update_section (ibfd, isection))
+    return TRUE;
+
   flags = bfd_get_section_flags (ibfd, isection);
   if ((flags & SEC_GROUP) != 0)
     return TRUE;
   flags = bfd_get_section_flags (ibfd, isection);
   if ((flags & SEC_GROUP) != 0)
     return TRUE;
@@ -3795,6 +3873,12 @@ copy_main (int argc, char *argv[])
           section_add_load_file (add_sections);
          break;
 
           section_add_load_file (add_sections);
          break;
 
+       case OPTION_UPDATE_SECTION:
+         update_sections = init_section_add (optarg, update_sections,
+                                              "--update-section");
+         section_add_load_file (update_sections);
+         break;
+
        case OPTION_DUMP_SECTION:
           dump_sections = init_section_add (optarg, dump_sections,
                                             "--dump-section");
        case OPTION_DUMP_SECTION:
           dump_sections = init_section_add (optarg, dump_sections,
                                             "--dump-section");
index 8e784340ac1bd51824869d9533603f0cc6666167..ef8efa31d1f13d34f91b70a107a4b9fcadb49bb5 100644 (file)
@@ -1,3 +1,11 @@
+2015-02-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * binutils-all/update-1.s: New file.
+       * binutils-all/update-2.s: New file.
+       * binutils-all/update-3.s: New file.
+       * binutils-all/update-4.s: New file.
+       * binutils-all/update-section.exp: New file.
+
 2015-02-24  Nick Clifton  <nickc@redhat.com>
 
        * binutils-all/objcopy.exp: Skip the strip-10 test for the V850.
 2015-02-24  Nick Clifton  <nickc@redhat.com>
 
        * binutils-all/objcopy.exp: Skip the strip-10 test for the V850.
diff --git a/binutils/testsuite/binutils-all/update-1.s b/binutils/testsuite/binutils-all/update-1.s
new file mode 100644 (file)
index 0000000..8ef51a0
--- /dev/null
@@ -0,0 +1,2 @@
+        .section ".foo", "aw"
+        .word 1, 1, 1, 1
diff --git a/binutils/testsuite/binutils-all/update-2.s b/binutils/testsuite/binutils-all/update-2.s
new file mode 100644 (file)
index 0000000..b720812
--- /dev/null
@@ -0,0 +1,2 @@
+        .section ".foo", "aw"
+        .word 2, 2, 2, 2, 2, 2
diff --git a/binutils/testsuite/binutils-all/update-3.s b/binutils/testsuite/binutils-all/update-3.s
new file mode 100644 (file)
index 0000000..087986f
--- /dev/null
@@ -0,0 +1,3 @@
+        .section ".foo", "aw"
+        .word 3, 3
+
diff --git a/binutils/testsuite/binutils-all/update-4.s b/binutils/testsuite/binutils-all/update-4.s
new file mode 100644 (file)
index 0000000..ae8a844
--- /dev/null
@@ -0,0 +1,2 @@
+        .section ".bar", "aw"
+        .word 5
diff --git a/binutils/testsuite/binutils-all/update-section.exp b/binutils/testsuite/binutils-all/update-section.exp
new file mode 100644 (file)
index 0000000..6a74302
--- /dev/null
@@ -0,0 +1,114 @@
+# Copyright (C) 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+if { [is_remote host] } then {
+    return
+}
+
+send_user "Version [binutil_version $OBJCOPY]"
+
+proc do_assemble {srcfile} {
+    global srcdir
+    global subdir
+    set objfile [regsub -- "\.s$" $srcfile ".o"]
+    if {![binutils_assemble $srcdir/$subdir/${srcfile} tmpdir/${objfile}]} then {
+        return 0;
+    }
+    return 1;
+}
+
+proc do_objcopy {objfile extraflags {pattern ""}} {
+    global OBJCOPY
+    global OBJCOPYFLAGS
+
+    set testname "objcopy $extraflags ${objfile}"
+    set got [binutils_run $OBJCOPY \
+                 "$OBJCOPYFLAGS ${extraflags} tmpdir/${objfile}"]
+    if ![regexp $pattern $got] then {
+        fail "objcopy ($testname)"
+        return 0
+    }
+    if { $pattern != "" } then {
+        pass "objcopy ($testname)"
+    }
+    return 1
+}
+
+proc do_compare {file1 file2} {
+    set src1 "tmpdir/${file1}"
+    set src2 "tmpdir/${file2}"
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+
+    set testname "compare ${file1} ${file2}"
+    if [string match "" $exec_output] then {
+        pass "objcopy ($testname)"
+    } else {
+        send_log "$exec_output\n"
+        verbose "$exec_output" 1
+        fail "objcopy ($testname)"
+        return 0
+    }
+    return 1
+}
+
+#
+# Start Of Tests
+#
+
+foreach f [list update-1.s update-2.s update-3.s update-4.s] {
+    if { ![do_assemble $f] } then {
+        unsupported "update-section.exp"
+        return
+    }
+}
+
+if { ![do_objcopy update-1.o \
+           "--dump-section .foo=tmpdir/dumped-contents"]
+     || ![do_objcopy update-2.o \
+              "--update-section .foo=tmpdir/dumped-contents"]
+     || ![do_objcopy update-3.o \
+              "--update-section .foo=tmpdir/dumped-contents"]
+     || ![do_objcopy update-4.o \
+              "--update-section .bar=tmpdir/dumped-contents \
+               --rename-section .bar=.foo"] } then {
+    # If any of the above tests failed then a FAIL will already have
+    # been reported.
+    return
+}
+
+# Check that the updated object files are as expected.
+do_compare update-1.o update-2.o
+do_compare update-1.o update-3.o
+do_compare update-1.o update-4.o
+
+# Check that --update-section on an unknown section will fail.
+if { ![do_objcopy update-2.o \
+           "--update-section .bar=tmpdir/dumped-contents" \
+           "error: .bar not found, can't be updated"] } then {
+    return
+}
+
+# Check that --update-section and --remove-section on the same section
+# will fail.
+if { ![do_objcopy update-2.o \
+           "--update-section .foo=tmpdir/dumped-contents \
+            --remove-section .foo" \
+           "error: section .foo matches both update and remove options"] \
+     } then {
+    return
+}
This page took 0.042842 seconds and 4 git commands to generate.