objcopy: Add --update-section option.

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.
This commit is contained in:
Andrew Burgess
2015-02-13 17:04:42 +00:00
parent b7236fbee4
commit acf1419f9c
10 changed files with 249 additions and 0 deletions

View 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> 2015-02-26 Nick Clifton <nickc@redhat.com>
PR binutils/17512 PR binutils/17512

View File

@ -1,5 +1,7 @@
-*- text -*- -*- text -*-
* Add --update-section option to objcopy.
Changes in 2.25: Changes in 2.25:
* Add --data option to strings to only print strings in loadable, initialized * Add --data option to strings to only print strings in loadable, initialized

View File

@ -1091,6 +1091,7 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
[@option{--set-section-flags} @var{sectionpattern}=@var{flags}] [@option{--set-section-flags} @var{sectionpattern}=@var{flags}]
[@option{--add-section} @var{sectionname}=@var{filename}] [@option{--add-section} @var{sectionname}=@var{filename}]
[@option{--dump-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{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]]
[@option{--long-section-names} @{enable,disable,keep@}] [@option{--long-section-names} @{enable,disable,keep@}]
[@option{--change-leading-char}] [@option{--remove-leading-char}] [@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 as raw binary data, without applying any relocations. The option can
be specified more than once. 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}] @item --rename-section @var{oldname}=@var{newname}[,@var{flags}]
Rename a section from @var{oldname} to @var{newname}, optionally Rename a section from @var{oldname} to @var{newname}, optionally
changing the section's flags to @var{flags} in the process. This has changing the section's flags to @var{flags} in the process. This has

View File

@ -186,6 +186,9 @@ struct section_add
/* List of sections to add to the output BFD. */ /* List of sections to add to the output BFD. */
static struct section_add *add_sections; 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. */ /* List of sections to dump from the output BFD. */
static struct section_add *dump_sections; static struct section_add *dump_sections;
@ -262,6 +265,7 @@ static enum long_section_name_handling long_section_names = KEEP;
enum command_line_switch enum command_line_switch
{ {
OPTION_ADD_SECTION=150, OPTION_ADD_SECTION=150,
OPTION_UPDATE_SECTION,
OPTION_DUMP_SECTION, OPTION_DUMP_SECTION,
OPTION_CHANGE_ADDRESSES, OPTION_CHANGE_ADDRESSES,
OPTION_CHANGE_LEADING_CHAR, OPTION_CHANGE_LEADING_CHAR,
@ -361,6 +365,7 @@ static struct option copy_options[] =
{ {
{"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK}, {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
{"add-section", required_argument, 0, OPTION_ADD_SECTION}, {"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-start", required_argument, 0, OPTION_CHANGE_START},
{"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES}, {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
{"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, {"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-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\ Set section <name>'s properties to <flags>\n\
--add-section <name>=<file> Add section <name> found in <file> to output\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\ --dump-section <name>=<file> Dump the contents of section <name> into <file>\n\
--rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\ --rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
--long-section-names {enable|disable|keep}\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. */ /* See if a non-group section is being removed. */
static bfd_boolean static bfd_boolean
@ -1062,6 +1091,9 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
if (p && q) if (p && q)
fatal (_("error: section %s matches both remove and copy options"), fatal (_("error: section %s matches both remove and copy options"),
bfd_get_section_name (abfd, sec)); 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) if (p != NULL)
return TRUE; 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) if (dump_sections != NULL)
{ {
struct section_add * pdump; 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 (gnu_debuglink_filename != NULL)
{ {
if (! bfd_fill_in_gnu_debuglink_section if (! bfd_fill_in_gnu_debuglink_section
@ -2881,6 +2956,9 @@ skip_section (bfd *ibfd, sec_ptr isection)
if (is_strip_section (ibfd, isection)) if (is_strip_section (ibfd, isection))
return TRUE; return TRUE;
if (is_update_section (ibfd, isection))
return TRUE;
flags = bfd_get_section_flags (ibfd, isection); flags = bfd_get_section_flags (ibfd, isection);
if ((flags & SEC_GROUP) != 0) if ((flags & SEC_GROUP) != 0)
return TRUE; return TRUE;
@ -3795,6 +3873,12 @@ copy_main (int argc, char *argv[])
section_add_load_file (add_sections); section_add_load_file (add_sections);
break; 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: case OPTION_DUMP_SECTION:
dump_sections = init_section_add (optarg, dump_sections, dump_sections = init_section_add (optarg, dump_sections,
"--dump-section"); "--dump-section");

View 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> 2015-02-24 Nick Clifton <nickc@redhat.com>
* binutils-all/objcopy.exp: Skip the strip-10 test for the V850. * binutils-all/objcopy.exp: Skip the strip-10 test for the V850.

View File

@ -0,0 +1,2 @@
.section ".foo", "aw"
.word 1, 1, 1, 1

View File

@ -0,0 +1,2 @@
.section ".foo", "aw"
.word 2, 2, 2, 2, 2, 2

View File

@ -0,0 +1,3 @@
.section ".foo", "aw"
.word 3, 3

View File

@ -0,0 +1,2 @@
.section ".bar", "aw"
.word 5

View File

@ -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
}