[RFC] objcopy: Add --update-section option.

Andrew Burgess andrew.burgess@embecosm.com
Fri Feb 13 20:18:00 GMT 2015


Having linked an executable in ELF format, I would like to extract the
contents of a section, pass the contents through some filter, then
replace the original section contents with the new filtered contents.

The problem I'm having is trying to get the modified section contents
back into the original ELF file.  The best I've got so far is:

    objcopy -j .text -O binary input sec.contents
    # filter sec.contents
    objcopy -R .text input intput.tmp
    objcopy --add-section .text=sec.contents input.tmp output

This leaves the replacement .text section with the wrong LMA/VMA,
which can be solved using --change-section-lma, --change-section-vma.
The problem I'm having is that the new .text is not within any
segment, and I don't believe there's any way to fix this currently.

As an experiment I created the patch below that adds a new option to
objcopy, --update-section, that allows me to do this:

    objcopy -j .text -O binary input sec.contents
    # filter sec.contents
    objcopy --update-section .text=sec.contents input output

Is there a better way to solve this problem?

If there's no better way, then how does the patch below look?  Is
there anything else that needs expanding for it to be ready to commit?

Thanks,
Andrew


---
New option for objcopy --update-section allows the contents of a section
to be updated.

ChangeLog:

	* objcopy.c (update_sections): New list.
	(command_line_switch): Add OPTION_UPDATE_SECTION.
	(copy_options): Add update-section.
	(copy_usage): Document new option.
	(copy_object): Update size and content of requested sections.
	(is_update_section): New function.
	(skip_section): Don't copy for updated sections.
	(copy_main): Handle --update-section.
---
 binutils/objcopy.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 8320793..95c44b1 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -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 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;
 
@@ -262,6 +265,7 @@ static enum long_section_name_handling long_section_names = KEEP;
 enum command_line_switch
   {
     OPTION_ADD_SECTION=150,
+    OPTION_UPDATE_SECTION,
     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},
+  {"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},
@@ -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\
+     --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\
@@ -1865,6 +1873,31 @@ 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)
+	{
+	  pupdate->section = bfd_get_section_by_name (obfd, pupdate->name);
+	  if (pupdate->section == NULL)
+	    {
+	      bfd_nonfatal_message (NULL, obfd, NULL,
+				    _("can't update section '%s'"),
+				    pupdate->name);
+	      return FALSE;
+	    }
+
+	  if (! bfd_set_section_size (obfd, pupdate->section, pupdate->size))
+	    {
+	      bfd_nonfatal_message (NULL, obfd, pupdate->section, NULL);
+	      return FALSE;
+	    }
+	}
+    }
+
   if (dump_sections != NULL)
     {
       struct section_add * pdump;
@@ -2150,6 +2183,24 @@ 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)
+	{
+          if (! bfd_set_section_contents (obfd, pupdate->section,
+                                          pupdate->contents,
+					  0, pupdate->size))
+	    {
+	      bfd_nonfatal_message (NULL, obfd, pupdate->section, NULL);
+	      return FALSE;
+	    }
+	}
+    }
+
   if (gnu_debuglink_filename != NULL)
     {
       if (! bfd_fill_in_gnu_debuglink_section
@@ -2861,6 +2912,25 @@ loser:
   bfd_nonfatal_message (NULL, obfd, osection, err);
 }
 
+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;
+}
+
 /* Return TRUE if input section ISECTION should be skipped.  */
 
 static bfd_boolean
@@ -2881,6 +2951,9 @@ skip_section (bfd *ibfd, sec_ptr isection)
   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;
@@ -3770,6 +3843,60 @@ copy_main (int argc, char *argv[])
 	  }
 	  break;
 
+	case OPTION_UPDATE_SECTION:
+	  {
+	    const char *s;
+	    size_t off, alloc;
+	    struct section_add *pa;
+	    FILE *f;
+
+	    s = strchr (optarg, '=');
+
+	    if (s == NULL)
+	      fatal (_("bad format for %s"), "--update-section");
+
+	    pa = (struct section_add *) xmalloc (sizeof (struct section_add));
+	    pa->name = xstrndup (optarg, s - optarg);
+	    pa->filename = s + 1;
+
+	    /* We don't use get_file_size so that we can do
+		 --add-section .note.GNU_stack=/dev/null
+	       get_file_size doesn't work on /dev/null.	 */
+
+	    f = fopen (pa->filename, FOPEN_RB);
+	    if (f == NULL)
+	      fatal (_("cannot open: %s: %s"),
+		     pa->filename, strerror (errno));
+
+	    off = 0;
+	    alloc = 4096;
+	    pa->contents = (bfd_byte *) xmalloc (alloc);
+	    while (!feof (f))
+	      {
+		off_t got;
+
+		if (off == 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);
+
+		off += got;
+	      }
+
+	    pa->size = off;
+
+	    fclose (f);
+
+	    pa->next = update_sections;
+	    update_sections = pa;
+	  }
+	  break;
+
 	case OPTION_DUMP_SECTION:
 	  {
 	    const char *s;
-- 
2.2.2



More information about the Binutils mailing list