PR30592 objcopy: allow --set-section-flags to add or remove SHF_X86_64_LARGE
authorFangrui Song <maskray@google.com>
Sun, 9 Jul 2023 17:57:19 +0000 (10:57 -0700)
committerFangrui Song <i@maskray.me>
Sun, 9 Jul 2023 17:57:19 +0000 (10:57 -0700)
For example, objcopy --set-section-flags .data=alloc,large will add
SHF_X86_64_LARGE to the .data section.  Omitting "large" will drop the
SHF_X86_64_LARGE flag.

The bfd_section flag is named generically, SEC_ELF_LARGE, in case other
processors want to follow SHF_X86_64_LARGE.  SEC_ELF_LARGE has the same
value as SEC_TIC54X_BLOCK used by coff.

bfd/
    * section.c: Define SEC_ELF_LARGE.
    * bfd-in2.h: Regenerate.
    * elf64-x86-64.c (elf_x86_64_section_flags, elf_x86_64_fake_sections,
    elf_x86_64_copy_private_section_data): New.

binutils/
    * NEWS: Mention the new feature for objcopy.
    * doc/binutils.texi: Mention "large".
    * objcopy.c (parse_flags): Parse "large".
    (check_new_section_flags): Error if "large" is used with a
    non-x86-64 ELF target.
    * testsuite/binutils-all/x86-64/large-sections.d: New.
    * testsuite/binutils-all/x86-64/large-sections.s: New.
    * testsuite/binutils-all/x86-64/large-sections-i386.d: New.
    * testsuite/binutils-all/x86-64/large-sections-2.d: New.
    * testsuite/binutils-all/x86-64/large-sections-2-x32.d: New.

13 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf64-x86-64.c
bfd/section.c
binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/objcopy.c
binutils/testsuite/binutils-all/x86-64/large-sections-2-x32.d [new file with mode: 0644]
binutils/testsuite/binutils-all/x86-64/large-sections-2.d [new file with mode: 0644]
binutils/testsuite/binutils-all/x86-64/large-sections-i386.d [new file with mode: 0644]
binutils/testsuite/binutils-all/x86-64/large-sections.d [new file with mode: 0644]
binutils/testsuite/binutils-all/x86-64/large-sections.s [new file with mode: 0644]

index e8a14716f7202cb4f308b0e043879d8b14914f81..553dea5d0b00719257efcddffadd8213453e04ae 100644 (file)
@@ -1,3 +1,11 @@
+2023-07-09  Fangrui Song  <maskray@google.com>
+
+       PR 30592
+       * section.c: Define SEC_ELF_LARGE.
+       * bfd-in2.h: Regenerate.
+       * elf64-x86-64.c (elf_x86_64_section_flags, elf_x86_64_fake_sections,
+       elf_x86_64_copy_private_section_data): New.
+
 2023-07-03  Nick Clifton  <nickc@redhat.com>
 
        * version.m4: Update version number to 2.41.50.
index b34c8ef9fc9d74017e4404b26a7b471333fe9da1..1b9a801966cdb7916b0a297ebd186eb27bc45519 100644 (file)
@@ -625,6 +625,9 @@ typedef struct bfd_section
      TMS320C54X only.  */
 #define SEC_TIC54X_BLOCK           0x10000000
 
+  /* This section has the SHF_X86_64_LARGE flag.  This is ELF x86-64 only.  */
+#define SEC_ELF_LARGE              0x10000000
+
   /* Conditionally link this section; do not link if there are no
      references found to any symbol in the section.  This is for TI
      TMS320C54X only.  */
index f926464d8128472df616b52b5143ff8c5d78e7d5..e7a0a9166f53c27845e952b1cf5bcd37889a42d8 100644 (file)
@@ -5281,6 +5281,39 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
   return true;
 }
 
+static bool
+elf_x86_64_section_flags (const Elf_Internal_Shdr *hdr)
+{
+  if ((hdr->sh_flags & SHF_X86_64_LARGE) != 0)
+    hdr->bfd_section->flags |= SEC_ELF_LARGE;
+
+  return true;
+}
+
+static bool
+elf_x86_64_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+                         Elf_Internal_Shdr *hdr, asection *sec)
+{
+  if (sec->flags & SEC_ELF_LARGE)
+    hdr->sh_flags |= SHF_X86_64_LARGE;
+
+  return true;
+}
+
+static bool
+elf_x86_64_copy_private_section_data (bfd *ibfd, asection *isec,
+                                     bfd *obfd, asection *osec)
+{
+  if (!_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec))
+    return false;
+
+  /* objcopy --set-section-flags without "large" drops SHF_X86_64_LARGE.  */
+  if (ibfd != obfd)
+    elf_section_flags (osec) &= ~SHF_X86_64_LARGE;
+
+  return true;
+}
+
 static int
 elf_x86_64_additional_program_headers (bfd *abfd,
                                       struct bfd_link_info *info ATTRIBUTE_UNUSED)
@@ -5408,6 +5441,8 @@ elf_x86_64_special_sections[]=
 
 #define elf_info_to_howto                  elf_x86_64_info_to_howto
 
+#define bfd_elf64_bfd_copy_private_section_data \
+  elf_x86_64_copy_private_section_data
 #define bfd_elf64_bfd_reloc_type_lookup            elf_x86_64_reloc_type_lookup
 #define bfd_elf64_bfd_reloc_name_lookup \
   elf_x86_64_reloc_name_lookup
@@ -5448,6 +5483,8 @@ elf_x86_64_special_sections[]=
   elf_x86_64_merge_symbol
 #define elf_backend_special_sections \
   elf_x86_64_special_sections
+#define elf_backend_section_flags          elf_x86_64_section_flags
+#define elf_backend_fake_sections          elf_x86_64_fake_sections
 #define elf_backend_additional_program_headers \
   elf_x86_64_additional_program_headers
 #define elf_backend_setup_gnu_properties \
@@ -5564,6 +5601,8 @@ elf64_x86_64_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUS
 #undef ELF_TARGET_OS
 #undef ELF_OSABI
 
+#define bfd_elf32_bfd_copy_private_section_data \
+  elf_x86_64_copy_private_section_data
 #define bfd_elf32_bfd_reloc_type_lookup        \
   elf_x86_64_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup \
index 73770294e56d2a66616c94377ee5e608779f8071..e9af59dfd159d174203bcb545617acca27de5f74 100644 (file)
@@ -359,6 +359,9 @@ CODE_FRAGMENT
 .     TMS320C54X only.  *}
 .#define SEC_TIC54X_BLOCK           0x10000000
 .
+.  {* This section has the SHF_X86_64_LARGE flag.  This is ELF x86-64 only.  *}
+.#define SEC_ELF_LARGE              0x10000000
+.
 .  {* Conditionally link this section; do not link if there are no
 .     references found to any symbol in the section.  This is for TI
 .     TMS320C54X only.  *}
index 866cf56d16af7994e23414c2d87cf08d119188cb..097673f783e68604163d6a4854e33b390916838b 100644 (file)
@@ -1,3 +1,17 @@
+2023-07-09  Fangrui Song  <maskray@google.com>
+
+       PR 30592
+       * NEWS: Mention the new feature for objcopy.
+       * doc/binutils.texi: Mention "large".
+       * objcopy.c (parse_flags): Parse "large".
+       (check_new_section_flags): Error if "large" is used with a
+       non-x86-64 ELF target.
+       * testsuite/binutils-all/x86-64/large-sections.d: New.
+       * testsuite/binutils-all/x86-64/large-sections.s: New.
+       * testsuite/binutils-all/x86-64/large-sections-i386.d: New.
+       * testsuite/binutils-all/x86-64/large-sections-2.d: New.
+       * testsuite/binutils-all/x86-64/large-sections-2-x32.d: New.
+
 2023-07-03  Nick Clifton  <nickc@redhat.com>
 
        * README-how-to-make-a-release: Change some version numbers.
index 563062c690481ea064be5f165617d2627b4d25d8..d64cae009eb46120004f85347717c008d61a6d8a 100644 (file)
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* objcopy --set-section-flags now supports "large" to set SHF_X86_64_LARGE
+  for ELF x86-64 objects.
+
 Changes in 2.41:
 
 * The MIPS port now supports the Sony Interactive Entertainment Allegrex
index 8314cb57562c187391bb4a9837208ebb6f66a51e..309bedf6110997174e8f4ff55d2fb1de0159816c 100644 (file)
@@ -1745,13 +1745,14 @@ Set the flags for any sections matching @var{sectionpattern}.  The
 @var{flags} argument is a comma separated string of flag names.  The
 recognized names are @samp{alloc}, @samp{contents}, @samp{load},
 @samp{noload}, @samp{readonly}, @samp{code}, @samp{data}, @samp{rom},
-@samp{exclude}, @samp{share}, and @samp{debug}.  You can set the
-@samp{contents} flag for a section which does not have contents, but it
-is not meaningful to clear the @samp{contents} flag of a section which
-does have contents--just remove the section instead.  Not all flags are
-meaningful for all object file formats.  In particular the
-@samp{share} flag is only meaningful for COFF format files and not for
-ELF format files.
+@samp{exclude}, @samp{share}, @samp{debug}, and @samp{large}.
+You can set the @samp{contents} flag for a section which does not have
+contents, but it is not meaningful to clear the @samp{contents} flag of a
+section which does have contents--just remove the section instead.  Not all
+flags are meaningful for all object file formats.  In particular the
+@samp{share} flag is only meaningful for COFF format files and not for ELF
+format files.  The ELF x86-64 specific flag @samp{large} corresponds to
+SHF_X86_64_LARGE.
 
 @item --set-section-alignment @var{sectionpattern}=@var{align}
 Set the alignment for any sections matching @var{sectionpattern}.
index 3569b890c7d74728c5277edc68d14ab12d1a631b..c931f67a224d766e60180348dbb178145af954fd 100644 (file)
@@ -803,6 +803,7 @@ parse_flags (const char *s)
       PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
       PARSE_FLAG ("merge", SEC_MERGE);
       PARSE_FLAG ("strings", SEC_STRINGS);
+      PARSE_FLAG ("large", SEC_ELF_LARGE);
 #undef PARSE_FLAG
       else
        {
@@ -812,8 +813,10 @@ parse_flags (const char *s)
          strncpy (copy, s, len);
          copy[len] = '\0';
          non_fatal (_("unrecognized section flag `%s'"), copy);
-         fatal (_("supported flags: %s"),
-                "alloc, load, noload, readonly, debug, code, data, rom, exclude, share, contents, merge, strings");
+         fatal (_ ("supported flags: %s"),
+                "alloc, load, noload, readonly, debug, code, data, rom, "
+                "exclude, contents, merge, strings, (COFF specific) share, "
+                "(ELF x86-64 specific) large");
        }
 
       s = snext;
@@ -2618,7 +2621,7 @@ merge_gnu_build_notes (bfd *          abfd,
 }
 
 static flagword
-check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
+check_new_section_flags (flagword flags, bfd *abfd, const char * secname)
 {
   /* Only set the SEC_COFF_SHARED flag on COFF files.
      The same bit value is used by ELF targets to indicate
@@ -2631,6 +2634,19 @@ check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
                 bfd_get_filename (abfd), secname);
       flags &= ~ SEC_COFF_SHARED;
     }
+
+  /* Report a fatal error if 'large' is used with a non-x86-64 ELF target.
+     Suppress the error for non-ELF targets to allow -O binary and formats that
+     use the bit value SEC_ELF_LARGE for other purposes.  */
+  if ((flags & SEC_ELF_LARGE) != 0
+      && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && get_elf_backend_data (abfd)->elf_machine_code != EM_X86_64)
+    {
+      fatal (_ ("%s[%s]: 'large' flag is ELF x86-64 specific"),
+            bfd_get_filename (abfd), secname);
+      flags &= ~SEC_ELF_LARGE;
+    }
+
   return flags;
 }
 
diff --git a/binutils/testsuite/binutils-all/x86-64/large-sections-2-x32.d b/binutils/testsuite/binutils-all/x86-64/large-sections-2-x32.d
new file mode 100644 (file)
index 0000000..fb28d08
--- /dev/null
@@ -0,0 +1,15 @@
+#source: large-sections.s
+#PROG: objcopy
+#as: --x32
+#objcopy: --set-section-flags .ldata=alloc
+#readelf: -S -W
+
+#...
+  \[[ 0-9]+\] \.text.*[ \t]+PROGBITS[ \t0-9a-f]+AX[ \t]+.*
+#...
+  \[[ 0-9]+\] \.data.*[ \t]+PROGBITS[ \t0-9a-f]+WA[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ltext.*[ \t]+PROGBITS[ \t0-9a-f]+AXl[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ldata.*[ \t]+PROGBITS[ \t0-9a-f]+WA[ \t]+.*
+#pass
diff --git a/binutils/testsuite/binutils-all/x86-64/large-sections-2.d b/binutils/testsuite/binutils-all/x86-64/large-sections-2.d
new file mode 100644 (file)
index 0000000..29ace42
--- /dev/null
@@ -0,0 +1,15 @@
+#source: large-sections.s
+#PROG: objcopy
+#as: --64
+#objcopy: --set-section-flags .ldata=alloc
+#readelf: -S -W
+
+#...
+  \[[ 0-9]+\] \.text.*[ \t]+PROGBITS[ \t0-9a-f]+AX[ \t]+.*
+#...
+  \[[ 0-9]+\] \.data.*[ \t]+PROGBITS[ \t0-9a-f]+WA[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ltext.*[ \t]+PROGBITS[ \t0-9a-f]+AXl[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ldata.*[ \t]+PROGBITS[ \t0-9a-f]+WA[ \t]+.*
+#pass
diff --git a/binutils/testsuite/binutils-all/x86-64/large-sections-i386.d b/binutils/testsuite/binutils-all/x86-64/large-sections-i386.d
new file mode 100644 (file)
index 0000000..b06c7c9
--- /dev/null
@@ -0,0 +1,6 @@
+#source: large-sections.s
+#PROG: objcopy
+#as: --64
+#objcopy: -O elf32-i386 --set-section-flags .data=alloc,large
+#target: x86_64-*-linux*
+#error: \A[^[]*\[.data\]: 'large' flag is ELF x86-64 specific
diff --git a/binutils/testsuite/binutils-all/x86-64/large-sections.d b/binutils/testsuite/binutils-all/x86-64/large-sections.d
new file mode 100644 (file)
index 0000000..5d945e4
--- /dev/null
@@ -0,0 +1,14 @@
+#PROG: objcopy
+#as: --64
+#objcopy: --set-section-flags .text=alloc,readonly,code,large --set-section-flags .data=alloc,large
+#readelf: -S -W
+
+#...
+  \[[ 0-9]+\] \.text.*[ \t]+PROGBITS[ \t0-9a-f]+AXl[ \t]+.*
+#...
+  \[[ 0-9]+\] \.data.*[ \t]+PROGBITS[ \t0-9a-f]+WAl[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ltext.*[ \t]+PROGBITS[ \t0-9a-f]+AXl[ \t]+.*
+#...
+  \[[ 0-9]+\] \.ldata.*[ \t]+PROGBITS[ \t0-9a-f]+WAl[ \t]+.*
+#pass
diff --git a/binutils/testsuite/binutils-all/x86-64/large-sections.s b/binutils/testsuite/binutils-all/x86-64/large-sections.s
new file mode 100644 (file)
index 0000000..072e456
--- /dev/null
@@ -0,0 +1,8 @@
+       .section .text, "ax"
+       nop
+       .section .data, "aw"
+       .byte 1
+       .section .ltext, "axl"
+       nop
+       .section .ldata, "awl"
+       .byte 1