Implement objcopy/strip --keep-section=<sectionpattern>

Message ID CAFP8O3KYkhb=5qbsfh86Pd_8yd1J8fEuTQ-BGid6dnqQB4o5PQ@mail.gmail.com
State New
Headers show
Series
  • Implement objcopy/strip --keep-section=<sectionpattern>
Related show

Commit Message

Palmer Dabbelt via binutils Nov. 1, 2019, 12:06 a.m.
llvm-objcopy and llvm-strip support an option --keep-section that
keeps some sections from being removed.
https://llvm.org/docs/CommandGuide/llvm-objcopy.html#cmdoption-llvm-objcopy-keep-section

This may be useful for distributions that really want to keep .ctf
https://sourceware.org/ml/binutils/2019-10/msg00016.html

Comments

Alan Modra Nov. 1, 2019, 2 a.m. | #1
On Thu, Oct 31, 2019 at 05:06:58PM -0700, Fāng-ruì Sòng via binutils wrote:
> +	* objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.

> +	(SECTION_CONTEXT_KEEP): New macro.


This needs to be more detailed.  You haven't mentioned that you are
changing the other macros, nor have you mentioned the functions you
are changing in objcopy.c.  The NEWS, binutils.texi, and testsuite
changes also need entries in the ChangeLog.

For the macro changes,
	(SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.
would be sufficient.

> @@ -1367,6 +1373,10 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

>  static bfd_boolean

>  is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

>  {

> +  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)

> +      != NULL)

> +    return FALSE;

> +

>    if (is_strip_section_1 (abfd, sec))

>      return TRUE;

>  


I believe this change should be made in is_strip_section_1 instead.
Otherwise, with a proper ChangeLog entry the patch looks good to
commit.

-- 
Alan Modra
Australia Development Lab, IBM
Palmer Dabbelt via binutils Nov. 1, 2019, 4:16 a.m. | #2
On Thu, Oct 31, 2019 at 7:00 PM Alan Modra <amodra@gmail.com> wrote:
>

> On Thu, Oct 31, 2019 at 05:06:58PM -0700, Fāng-ruì Sòng via binutils wrote:

> > +     * objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.

> > +     (SECTION_CONTEXT_KEEP): New macro.

>

> This needs to be more detailed.  You haven't mentioned that you are

> changing the other macros, nor have you mentioned the functions you

> are changing in objcopy.c.  The NEWS, binutils.texi, and testsuite

> changes also need entries in the ChangeLog.

> For the macro changes,

>         (SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.

> would be sufficient.


Thanks. Changed in the updated patch.

> > @@ -1367,6 +1373,10 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> >  static bfd_boolean

> >  is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> >  {

> > +  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)

> > +      != NULL)

> > +    return FALSE;

> > +

> >    if (is_strip_section_1 (abfd, sec))

> >      return TRUE;

> >

>

> I believe this change should be made in is_strip_section_1 instead.

> Otherwise, with a proper ChangeLog entry the patch looks good to

> commit.


is_strip_section_1 returns either TRUE (strip the section) or FALSE
(fall through to other conditions). We cannot put the --keep-section
logic there.
From 14bc33dbaebc86dd7496d6356f561d4fa21aa1b6 Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Thu, 31 Oct 2019 16:51:54 -0700
Subject: [PATCH] Implement objcopy/strip --keep-section=<sectionpattern>

---
 binutils/ChangeLog                            | 10 ++++++
 binutils/NEWS                                 |  3 ++
 binutils/doc/binutils.texi                    | 10 ++++++
 binutils/objcopy.c                            | 31 ++++++++++++++-----
 .../testsuite/binutils-all/keep-section-1.d   |  8 +++++
 .../testsuite/binutils-all/keep-section-2.d   | 10 ++++++
 binutils/testsuite/binutils-all/objcopy.exp   |  3 ++
 7 files changed, 68 insertions(+), 7 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/keep-section-1.d
 create mode 100644 binutils/testsuite/binutils-all/keep-section-2.d

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 36b75c1f3c..530f1d925d 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,13 @@
+2019-10-31  Fangrui Song  <maskray@google.com>
+
+	* objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.
+	(SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.
+	* testsuite/binutils-all/objcopy.exp: Add tests.
+	* testsuite/binutils-all/keep-section-1.d: New test driver file.
+	* testsuite/binutils-all/keep-section-2.d: Likewise.
+	* doc/binutils.texi: Document the new feature.
+	* NEWS: Mention the new feature.
+
 2019-10-20  Palmer Dabbelt  <palmer@sifive.com>
 
         * MAINTAINERS: Change palmer@sifive.com to palmer@dabbelt.com.
diff --git a/binutils/NEWS b/binutils/NEWS
index fd14d71ce9..88b048995a 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -3,6 +3,9 @@
 * Add --output option to the "ar" program.  This option can be used to specify
   the output directory when extracting members from an archive.
 
+* Add --keep-section option to objcopy and strip.  This option keeps the
+  specified section from being removed.
+
 Changes in 2.33:
 
 * Add --source-comment[=<txt>] option to objdump which if present,
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 97abf980ba..2a86b92033 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1186,6 +1186,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{--keep-section=}@var{sectionpattern}]
         [@option{--remove-relocations=}@var{sectionpattern}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
@@ -1369,6 +1370,10 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @item --remove-relocations=@var{sectionpattern}
 Remove non-dynamic relocations from the output file for any section
 matching @var{sectionpattern}.  This option may be given more than
@@ -3242,6 +3247,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{--keep-section=}@var{sectionpattern}]
       [@option{--remove-relocations=}@var{sectionpattern}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
@@ -3312,6 +3318,10 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @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
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 7bdd447893..9280e453bc 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -143,13 +143,14 @@ struct section_list
      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.  */
-#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section.  */
-#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 8) /* Set alignment for section.  */
+#define SECTION_CONTEXT_KEEP      (1 << 2) /* Keep this section.  */
+#define SECTION_CONTEXT_SET_VMA   (1 << 3) /* Set the sections' VMA address.  */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 4) /* Increment or decrement the section's VMA address.  */
+#define SECTION_CONTEXT_SET_LMA   (1 << 5) /* Set the sections' LMA address.  */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 6) /* Increment or decrement the section's LMA address.  */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 7) /* Set the section's flags.  */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 8) /* Remove relocations for this section.  */
+#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 9) /* Set alignment for section.  */
 
   bfd_vma		vma_val;   /* Amount to change by or set to.  */
   bfd_vma		lma_val;   /* Amount to change by or set to.  */
@@ -332,6 +333,7 @@ enum command_line_switch
   OPTION_INTERLEAVE_WIDTH,
   OPTION_KEEPGLOBAL_SYMBOLS,
   OPTION_KEEP_FILE_SYMBOLS,
+  OPTION_KEEP_SECTION,
   OPTION_KEEP_SYMBOLS,
   OPTION_LOCALIZE_HIDDEN,
   OPTION_LOCALIZE_SYMBOLS,
@@ -386,6 +388,7 @@ static struct option strip_options[] =
   {"input-format", required_argument, 0, 'I'}, /* Obsolete */
   {"input-target", required_argument, 0, 'I'},
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"merge-notes", no_argument, 0, 'M'},
   {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
@@ -457,6 +460,7 @@ static struct option copy_options[] =
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
   {"keep-global-symbol", required_argument, 0, 'G'},
   {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
   {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
@@ -589,6 +593,7 @@ copy_usage (FILE *stream, int exit_status)
      --only-keep-debug             Strip everything but the debug information\n\
      --extract-dwo                 Copy only DWO sections\n\
      --extract-symbol              Remove section contents but keep symbols\n\
+     --keep-section <name>         Do not strip section <name>\n\
   -K --keep-symbol <name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
      --localize-hidden             Turn all ELF hidden symbols into locals\n\
@@ -722,6 +727,7 @@ strip_usage (FILE *stream, int exit_status)
   -M  --merge-notes                Remove redundant entries in note sections (default)\n\
       --no-merge-notes             Do not attempt to remove redundant notes\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
+     --keep-section=<name>         Do not strip section <name>\n\
   -K --keep-symbol=<name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
   -w --wildcard                    Permit wildcard in symbol comparison\n\
@@ -1367,6 +1373,10 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 static bfd_boolean
 is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
+  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)
+      != NULL)
+    return FALSE;
+
   if (is_strip_section_1 (abfd, sec))
     return TRUE;
 
@@ -4584,6 +4594,9 @@ strip_main (int argc, char *argv[])
 	case 'R':
 	  handle_remove_section_option (optarg);
 	  break;
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
 	case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
@@ -5010,6 +5023,10 @@ copy_main (int argc, char *argv[])
 	  handle_remove_section_option (optarg);
 	  break;
 
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
+
         case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
diff --git a/binutils/testsuite/binutils-all/keep-section-1.d b/binutils/testsuite/binutils-all/keep-section-1.d
new file mode 100644
index 0000000000..b28e29c170
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-1.d
@@ -0,0 +1,8 @@
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.02
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.02.*
+#...
diff --git a/binutils/testsuite/binutils-all/keep-section-2.d b/binutils/testsuite/binutils-all/keep-section-2.d
new file mode 100644
index 0000000000..7fea62f149
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-2.d
@@ -0,0 +1,10 @@
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.*
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.01.*
+  \[ [0-9]+\] \.data\.aa\.02.*
+  \[ [0-9]+\] \.data\.aa\.03.*
+#...
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index 6c4b0196ab..6739ab7de8 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -1222,6 +1222,9 @@ if [is_elf_format] {
     run_dump_test "only-section-01"
     run_dump_test "remove-section-01"
 
+    run_dump_test "keep-section-1"
+    run_dump_test "keep-section-2"
+
     # Test the remove relocation functionality
     set test_list [lsort [glob -nocomplain $srcdir/$subdir/remove-relocs-*.d]]
     foreach t $test_list {
Alan Modra Nov. 1, 2019, 7 a.m. | #3
On Thu, Oct 31, 2019 at 09:16:03PM -0700, Fāng-ruì Sòng wrote:
> On Thu, Oct 31, 2019 at 7:00 PM Alan Modra <amodra@gmail.com> wrote:

> >

> > On Thu, Oct 31, 2019 at 05:06:58PM -0700, Fāng-ruì Sòng via binutils wrote:

> > > +     * objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.

> > > +     (SECTION_CONTEXT_KEEP): New macro.

> >

> > This needs to be more detailed.  You haven't mentioned that you are

> > changing the other macros, nor have you mentioned the functions you

> > are changing in objcopy.c.  The NEWS, binutils.texi, and testsuite

> > changes also need entries in the ChangeLog.

> > For the macro changes,

> >         (SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.

> > would be sufficient.

> 

> Thanks. Changed in the updated patch.


Still not complete.

> > > @@ -1367,6 +1373,10 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> > >  static bfd_boolean

> > >  is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> > >  {

> > > +  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)

> > > +      != NULL)

> > > +    return FALSE;

> > > +

> > >    if (is_strip_section_1 (abfd, sec))

> > >      return TRUE;

> > >

> >

> > I believe this change should be made in is_strip_section_1 instead.

> > Otherwise, with a proper ChangeLog entry the patch looks good to

> > commit.

> 

> is_strip_section_1 returns either TRUE (strip the section) or FALSE

> (fall through to other conditions). We cannot put the --keep-section

> logic there.


Those "other conditions" are precisely why you should put the new
--keep-section logic in is_strip_section_1.  Really.  SEC_GROUP is
special.

-- 
Alan Modra
Australia Development Lab, IBM
Palmer Dabbelt via binutils Nov. 1, 2019, 9:47 p.m. | #4
On Fri, Nov 1, 2019 at 12:00 AM Alan Modra <amodra@gmail.com> wrote:
>

> On Thu, Oct 31, 2019 at 09:16:03PM -0700, Fāng-ruì Sòng wrote:

> > On Thu, Oct 31, 2019 at 7:00 PM Alan Modra <amodra@gmail.com> wrote:

> > >

> > > On Thu, Oct 31, 2019 at 05:06:58PM -0700, Fāng-ruì Sòng via binutils wrote:

> > > > +     * objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.

> > > > +     (SECTION_CONTEXT_KEEP): New macro.

> > >

> > > This needs to be more detailed.  You haven't mentioned that you are

> > > changing the other macros, nor have you mentioned the functions you

> > > are changing in objcopy.c.  The NEWS, binutils.texi, and testsuite

> > > changes also need entries in the ChangeLog.

> > > For the macro changes,

> > >         (SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.

> > > would be sufficient.

> >

> > Thanks. Changed in the updated patch.

>

> Still not complete.


Added some more items, but not clear whether they are complete now.
When can we stop writing ChangeLogs (looking at glibc)?
If it is still incomplete, I hope a maintainer can help writing it.

> > > > @@ -1367,6 +1373,10 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> > > >  static bfd_boolean

> > > >  is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)

> > > >  {

> > > > +  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)

> > > > +      != NULL)

> > > > +    return FALSE;

> > > > +

> > > >    if (is_strip_section_1 (abfd, sec))

> > > >      return TRUE;

> > > >

> > >

> > > I believe this change should be made in is_strip_section_1 instead.

> > > Otherwise, with a proper ChangeLog entry the patch looks good to

> > > commit.

> >

> > is_strip_section_1 returns either TRUE (strip the section) or FALSE

> > (fall through to other conditions). We cannot put the --keep-section

> > logic there.

>

> Those "other conditions" are precisely why you should put the new

> --keep-section logic in is_strip_section_1.  Really.  SEC_GROUP is

> special.


Moved from is_strip_section to is_strip_section_1.
From d57667fd5c0dd3cd2238f5d50e2158ba4306814a Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Fri, 1 Nov 2019 14:37:52 -0700
Subject: [PATCH] Implement objcopy/strip --keep-section=<sectionpattern>

---
 binutils/ChangeLog                            | 15 +++++++++
 binutils/NEWS                                 |  3 ++
 binutils/doc/binutils.texi                    | 10 ++++++
 binutils/objcopy.c                            | 31 ++++++++++++++-----
 .../testsuite/binutils-all/keep-section-1.d   |  8 +++++
 .../testsuite/binutils-all/keep-section-2.d   | 10 ++++++
 binutils/testsuite/binutils-all/objcopy.exp   |  3 ++
 7 files changed, 73 insertions(+), 7 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/keep-section-1.d
 create mode 100644 binutils/testsuite/binutils-all/keep-section-2.d

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 36b75c1f3c..0d15c44468 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,18 @@
+2019-11-01  Fangrui Song  <maskray@google.com>
+
+	* objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.
+	(SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.
+	(copy_usage): Describe --keep-section.
+	(strip_usage): Likewise.
+	(copy_main): Handle SECTION_CONTEXT_KEEP.
+	(strip_main): Likewise.
+	(is_strip_section_1): Likewise.
+	* testsuite/binutils-all/objcopy.exp: Add tests.
+	* testsuite/binutils-all/keep-section-1.d: New test driver file.
+	* testsuite/binutils-all/keep-section-2.d: Likewise.
+	* doc/binutils.texi: Document the new feature.
+	* NEWS: Mention the new feature.
+
 2019-10-20  Palmer Dabbelt  <palmer@sifive.com>
 
         * MAINTAINERS: Change palmer@sifive.com to palmer@dabbelt.com.
diff --git a/binutils/NEWS b/binutils/NEWS
index fd14d71ce9..88b048995a 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -3,6 +3,9 @@
 * Add --output option to the "ar" program.  This option can be used to specify
   the output directory when extracting members from an archive.
 
+* Add --keep-section option to objcopy and strip.  This option keeps the
+  specified section from being removed.
+
 Changes in 2.33:
 
 * Add --source-comment[=<txt>] option to objdump which if present,
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 97abf980ba..2a86b92033 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1186,6 +1186,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{--keep-section=}@var{sectionpattern}]
         [@option{--remove-relocations=}@var{sectionpattern}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
@@ -1369,6 +1370,10 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @item --remove-relocations=@var{sectionpattern}
 Remove non-dynamic relocations from the output file for any section
 matching @var{sectionpattern}.  This option may be given more than
@@ -3242,6 +3247,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{--keep-section=}@var{sectionpattern}]
       [@option{--remove-relocations=}@var{sectionpattern}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
@@ -3312,6 +3318,10 @@ would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @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
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 7bdd447893..56439700c2 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -143,13 +143,14 @@ struct section_list
      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.  */
-#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section.  */
-#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 8) /* Set alignment for section.  */
+#define SECTION_CONTEXT_KEEP      (1 << 2) /* Keep this section.  */
+#define SECTION_CONTEXT_SET_VMA   (1 << 3) /* Set the sections' VMA address.  */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 4) /* Increment or decrement the section's VMA address.  */
+#define SECTION_CONTEXT_SET_LMA   (1 << 5) /* Set the sections' LMA address.  */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 6) /* Increment or decrement the section's LMA address.  */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 7) /* Set the section's flags.  */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 8) /* Remove relocations for this section.  */
+#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 9) /* Set alignment for section.  */
 
   bfd_vma		vma_val;   /* Amount to change by or set to.  */
   bfd_vma		lma_val;   /* Amount to change by or set to.  */
@@ -332,6 +333,7 @@ enum command_line_switch
   OPTION_INTERLEAVE_WIDTH,
   OPTION_KEEPGLOBAL_SYMBOLS,
   OPTION_KEEP_FILE_SYMBOLS,
+  OPTION_KEEP_SECTION,
   OPTION_KEEP_SYMBOLS,
   OPTION_LOCALIZE_HIDDEN,
   OPTION_LOCALIZE_SYMBOLS,
@@ -386,6 +388,7 @@ static struct option strip_options[] =
   {"input-format", required_argument, 0, 'I'}, /* Obsolete */
   {"input-target", required_argument, 0, 'I'},
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"merge-notes", no_argument, 0, 'M'},
   {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
@@ -457,6 +460,7 @@ static struct option copy_options[] =
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
   {"keep-global-symbol", required_argument, 0, 'G'},
   {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
   {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
@@ -589,6 +593,7 @@ copy_usage (FILE *stream, int exit_status)
      --only-keep-debug             Strip everything but the debug information\n\
      --extract-dwo                 Copy only DWO sections\n\
      --extract-symbol              Remove section contents but keep symbols\n\
+     --keep-section <name>         Do not strip section <name>\n\
   -K --keep-symbol <name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
      --localize-hidden             Turn all ELF hidden symbols into locals\n\
@@ -722,6 +727,7 @@ strip_usage (FILE *stream, int exit_status)
   -M  --merge-notes                Remove redundant entries in note sections (default)\n\
       --no-merge-notes             Do not attempt to remove redundant notes\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
+     --keep-section=<name>         Do not strip section <name>\n\
   -K --keep-symbol=<name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
   -w --wildcard                    Permit wildcard in symbol comparison\n\
@@ -1311,6 +1317,10 @@ is_mergeable_note_section (bfd * abfd, asection * sec)
 static bfd_boolean
 is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
+  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)
+      != NULL)
+    return FALSE;
+
   if (sections_removed || sections_copied)
     {
       struct section_list *p;
@@ -4584,6 +4594,9 @@ strip_main (int argc, char *argv[])
 	case 'R':
 	  handle_remove_section_option (optarg);
 	  break;
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
 	case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
@@ -5010,6 +5023,10 @@ copy_main (int argc, char *argv[])
 	  handle_remove_section_option (optarg);
 	  break;
 
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
+
         case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
diff --git a/binutils/testsuite/binutils-all/keep-section-1.d b/binutils/testsuite/binutils-all/keep-section-1.d
new file mode 100644
index 0000000000..b28e29c170
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-1.d
@@ -0,0 +1,8 @@
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.02
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.02.*
+#...
diff --git a/binutils/testsuite/binutils-all/keep-section-2.d b/binutils/testsuite/binutils-all/keep-section-2.d
new file mode 100644
index 0000000000..7fea62f149
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-2.d
@@ -0,0 +1,10 @@
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.*
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.01.*
+  \[ [0-9]+\] \.data\.aa\.02.*
+  \[ [0-9]+\] \.data\.aa\.03.*
+#...
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index 6c4b0196ab..6739ab7de8 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -1222,6 +1222,9 @@ if [is_elf_format] {
     run_dump_test "only-section-01"
     run_dump_test "remove-section-01"
 
+    run_dump_test "keep-section-1"
+    run_dump_test "keep-section-2"
+
     # Test the remove relocation functionality
     set test_list [lsort [glob -nocomplain $srcdir/$subdir/remove-relocs-*.d]]
     foreach t $test_list {
Alan Modra Nov. 4, 2019, 1:57 a.m. | #5
On Fri, Nov 01, 2019 at 02:47:55PM -0700, Fāng-ruì Sòng wrote:
> Added some more items, but not clear whether they are complete now.


Thanks for persevering, that will do nicely.

> When can we stop writing ChangeLogs (looking at glibc)?


Good question.  :-)

> +	* objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.

> +	(SECTION_CONTEXT_KEEP): Define.  Adjust other SECTION_CONTEXT macros.

> +	(copy_usage): Describe --keep-section.

> +	(strip_usage): Likewise.

> +	(copy_main): Handle SECTION_CONTEXT_KEEP.

> +	(strip_main): Likewise.

> +	(is_strip_section_1): Likewise.

> +	* testsuite/binutils-all/objcopy.exp: Add tests.

> +	* testsuite/binutils-all/keep-section-1.d: New test driver file.

> +	* testsuite/binutils-all/keep-section-2.d: Likewise.

> +	* doc/binutils.texi: Document the new feature.

> +	* NEWS: Mention the new feature.


Committed.  I did notice a new failure

ia64-vms  +FAIL: ar extracting an element

but that is no doubt due to your and Nick's other patch to ar rather
than this patch.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

From 3a54177bf836a92f7015692e6ce35be0c696393e Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Thu, 31 Oct 2019 16:51:54 -0700
Subject: [PATCH] Implement objcopy/strip --keep-section=<sectionpattern>

---
 binutils/ChangeLog                            |  5 +++
 binutils/NEWS                                 |  3 ++
 binutils/doc/binutils.texi                    | 10 ++++++
 binutils/objcopy.c                            | 31 ++++++++++++++-----
 .../testsuite/binutils-all/keep-section-1.d   |  8 +++++
 .../testsuite/binutils-all/keep-section-2.d   | 10 ++++++
 binutils/testsuite/binutils-all/objcopy.exp   |  3 ++
 7 files changed, 63 insertions(+), 7 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/keep-section-1.d
 create mode 100644 binutils/testsuite/binutils-all/keep-section-2.d

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 36b75c1f3c..583f411216 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,8 @@ 
+2019-10-31  Fangrui Song  <maskray@google.com>
+
+	* objcopy.c (enum option_values): Add OPTION_KEEP_SECTION.
+	(SECTION_CONTEXT_KEEP): New macro.
+
 2019-10-20  Palmer Dabbelt  <palmer@sifive.com>
 
         * MAINTAINERS: Change palmer@sifive.com to palmer@dabbelt.com.
diff --git a/binutils/NEWS b/binutils/NEWS
index fd14d71ce9..88b048995a 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -3,6 +3,9 @@ 
 * Add --output option to the "ar" program.  This option can be used to specify
   the output directory when extracting members from an archive.
 
+* Add --keep-section option to objcopy and strip.  This option keeps the
+  specified section from being removed.
+
 Changes in 2.33:
 
 * Add --source-comment[=<txt>] option to objdump which if present,
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 97abf980ba..2a86b92033 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1186,6 +1186,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{--keep-section=}@var{sectionpattern}]
         [@option{--remove-relocations=}@var{sectionpattern}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
@@ -1369,6 +1370,10 @@  would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @item --remove-relocations=@var{sectionpattern}
 Remove non-dynamic relocations from the output file for any section
 matching @var{sectionpattern}.  This option may be given more than
@@ -3242,6 +3247,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{--keep-section=}@var{sectionpattern}]
       [@option{--remove-relocations=}@var{sectionpattern}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
@@ -3312,6 +3318,10 @@  would otherwise remove it.  For example:
 will remove all sections matching the pattern '.text.*', but will not
 remove the section '.text.foo'.
 
+@item --keep-section=@var{sectionpattern}
+When removing sections from the output file, keep sections that match
+@var{sectionpattern}.
+
 @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
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 7bdd447893..9280e453bc 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -143,13 +143,14 @@  struct section_list
      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.  */
-#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section.  */
-#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 8) /* Set alignment for section.  */
+#define SECTION_CONTEXT_KEEP      (1 << 2) /* Keep this section.  */
+#define SECTION_CONTEXT_SET_VMA   (1 << 3) /* Set the sections' VMA address.  */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 4) /* Increment or decrement the section's VMA address.  */
+#define SECTION_CONTEXT_SET_LMA   (1 << 5) /* Set the sections' LMA address.  */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 6) /* Increment or decrement the section's LMA address.  */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 7) /* Set the section's flags.  */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 8) /* Remove relocations for this section.  */
+#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 9) /* Set alignment for section.  */
 
   bfd_vma		vma_val;   /* Amount to change by or set to.  */
   bfd_vma		lma_val;   /* Amount to change by or set to.  */
@@ -332,6 +333,7 @@  enum command_line_switch
   OPTION_INTERLEAVE_WIDTH,
   OPTION_KEEPGLOBAL_SYMBOLS,
   OPTION_KEEP_FILE_SYMBOLS,
+  OPTION_KEEP_SECTION,
   OPTION_KEEP_SYMBOLS,
   OPTION_LOCALIZE_HIDDEN,
   OPTION_LOCALIZE_SYMBOLS,
@@ -386,6 +388,7 @@  static struct option strip_options[] =
   {"input-format", required_argument, 0, 'I'}, /* Obsolete */
   {"input-target", required_argument, 0, 'I'},
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"merge-notes", no_argument, 0, 'M'},
   {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
@@ -457,6 +460,7 @@  static struct option copy_options[] =
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
   {"keep-global-symbol", required_argument, 0, 'G'},
   {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
   {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
@@ -589,6 +593,7 @@  copy_usage (FILE *stream, int exit_status)
      --only-keep-debug             Strip everything but the debug information\n\
      --extract-dwo                 Copy only DWO sections\n\
      --extract-symbol              Remove section contents but keep symbols\n\
+     --keep-section <name>         Do not strip section <name>\n\
   -K --keep-symbol <name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
      --localize-hidden             Turn all ELF hidden symbols into locals\n\
@@ -722,6 +727,7 @@  strip_usage (FILE *stream, int exit_status)
   -M  --merge-notes                Remove redundant entries in note sections (default)\n\
       --no-merge-notes             Do not attempt to remove redundant notes\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
+     --keep-section=<name>         Do not strip section <name>\n\
   -K --keep-symbol=<name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
   -w --wildcard                    Permit wildcard in symbol comparison\n\
@@ -1367,6 +1373,10 @@  is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 static bfd_boolean
 is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
+  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)
+      != NULL)
+    return FALSE;
+
   if (is_strip_section_1 (abfd, sec))
     return TRUE;
 
@@ -4584,6 +4594,9 @@  strip_main (int argc, char *argv[])
 	case 'R':
 	  handle_remove_section_option (optarg);
 	  break;
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
 	case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
@@ -5010,6 +5023,10 @@  copy_main (int argc, char *argv[])
 	  handle_remove_section_option (optarg);
 	  break;
 
+	case OPTION_KEEP_SECTION:
+	  find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+	  break;
+
         case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
diff --git a/binutils/testsuite/binutils-all/keep-section-1.d b/binutils/testsuite/binutils-all/keep-section-1.d
new file mode 100644
index 0000000000..b28e29c170
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-1.d
@@ -0,0 +1,8 @@ 
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.02
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.02.*
+#...
diff --git a/binutils/testsuite/binutils-all/keep-section-2.d b/binutils/testsuite/binutils-all/keep-section-2.d
new file mode 100644
index 0000000000..7fea62f149
--- /dev/null
+++ b/binutils/testsuite/binutils-all/keep-section-2.d
@@ -0,0 +1,10 @@ 
+#PROG: objcopy
+#source: data-sections.s
+#objcopy: --remove-section=.data.aa.* --keep-section=.data.aa.*
+#readelf: -WS
+
+#...
+  \[ [0-9]+\] \.data\.aa\.01.*
+  \[ [0-9]+\] \.data\.aa\.02.*
+  \[ [0-9]+\] \.data\.aa\.03.*
+#...
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index 6c4b0196ab..6739ab7de8 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -1222,6 +1222,9 @@  if [is_elf_format] {
     run_dump_test "only-section-01"
     run_dump_test "remove-section-01"
 
+    run_dump_test "keep-section-1"
+    run_dump_test "keep-section-2"
+
     # Test the remove relocation functionality
     set test_list [lsort [glob -nocomplain $srcdir/$subdir/remove-relocs-*.d]]
     foreach t $test_list {
-- 
2.20.0