[llvm] 6f1395a - [llvm-objcopy] --set-section-flags: allow "large" to add SHF_X86_64_LARGE

Arthur Eubanks via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 25 09:47:41 PDT 2023


Author: Thomas Köppe
Date: 2023-07-25T09:47:02-07:00
New Revision: 6f1395a1fef5533a5a8dfdb8621eab7de3922cc3

URL: https://github.com/llvm/llvm-project/commit/6f1395a1fef5533a5a8dfdb8621eab7de3922cc3
DIFF: https://github.com/llvm/llvm-project/commit/6f1395a1fef5533a5a8dfdb8621eab7de3922cc3.diff

LOG: [llvm-objcopy] --set-section-flags: allow "large" to add SHF_X86_64_LARGE

Currently, objcopy cannot set the new flag SHF_X86_64_LARGE. This change introduces the named flag "large" which translates to that section flag.

An "invalid argument" error is produced if a user attempts to set the flag on an architecture other than X86_64.

Reviewed By: jhenderson, MaskRay

Differential Revision: https://reviews.llvm.org/D153262

Added: 
    llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test

Modified: 
    llvm/docs/CommandGuide/llvm-objcopy.rst
    llvm/include/llvm/ObjCopy/CommonConfig.h
    llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
    llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
    llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
    llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
    llvm/tools/llvm-objcopy/ObjcopyOpts.td

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 8894a7fea6bb75..0233a4f7b2f045 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -137,8 +137,9 @@ multiple file formats.
  sections.
 
  Supported flag names are `alloc`, `load`, `noload`, `readonly`, `exclude`,
- `debug`, `code`, `data`, `rom`, `share`, `contents`, `merge` and `strings`. Not
- all flags are meaningful for all object file formats.
+ `debug`, `code`, `data`, `rom`, `share`, `contents`, `merge`, `strings`, and
+ `large`. Not all flags are meaningful for all object file formats or target
+ architectures.
 
  For ELF objects, the flags have the following effects:
 
@@ -152,6 +153,8 @@ multiple file formats.
  - `strings` = add the `SHF_STRINGS` flag.
  - `contents` = if the section has `SHT_NOBITS` type, mark it as a `SHT_PROGBITS`
    section.
+ - `large` = add the `SHF_X86_64_LARGE` on x86_64; rejected if the target
+   architecture is not x86_64.
 
  For COFF objects, the flags have the following effects:
 

diff  --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index 17ca9e8be228ea..e7ce1e6f2c54d7 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -69,7 +69,8 @@ enum SectionFlag {
   SecContents = 1 << 10,
   SecShare = 1 << 11,
   SecExclude = 1 << 12,
-  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecExclude)
+  SecLarge = 1 << 13,
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecLarge)
 };
 
 struct SectionRename {

diff  --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index dfe843e1d4b7a4..58cb9cb65679b7 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -68,7 +68,8 @@ static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
   return !isDWOSection(Sec);
 }
 
-static uint64_t getNewShfFlags(SectionFlag AllFlags) {
+static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,
+                                         uint16_t EMachine) {
   uint64_t NewFlags = 0;
   if (AllFlags & SectionFlag::SecAlloc)
     NewFlags |= ELF::SHF_ALLOC;
@@ -82,18 +83,27 @@ static uint64_t getNewShfFlags(SectionFlag AllFlags) {
     NewFlags |= ELF::SHF_STRINGS;
   if (AllFlags & SectionFlag::SecExclude)
     NewFlags |= ELF::SHF_EXCLUDE;
+  if (AllFlags & SectionFlag::SecLarge) {
+    if (EMachine != EM_X86_64)
+      return createStringError(errc::invalid_argument,
+                               "section flag SHF_X86_64_LARGE can only be used "
+                               "with x86_64 architecture");
+    NewFlags |= ELF::SHF_X86_64_LARGE;
+  }
   return NewFlags;
 }
 
 static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
-                                            uint64_t NewFlags) {
+                                            uint64_t NewFlags,
+                                            uint16_t EMachine) {
   // Preserve some flags which should not be dropped when setting flags.
   // Also, preserve anything OS/processor dependant.
   const uint64_t PreserveMask =
       (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
        ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
        ELF::SHF_INFO_LINK) &
-      ~ELF::SHF_EXCLUDE;
+      ~ELF::SHF_EXCLUDE &
+      ~(EMachine == EM_X86_64 ? ELF::SHF_X86_64_LARGE : 0UL);
   return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
 }
 
@@ -105,8 +115,12 @@ static void setSectionType(SectionBase &Sec, uint64_t Type) {
   Sec.Type = Type;
 }
 
-static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
-  Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
+static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,
+                                    uint16_t EMachine) {
+  Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);
+  if (!NewFlags)
+    return NewFlags.takeError();
+  Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);
 
   // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
   // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
@@ -115,6 +129,8 @@ static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
       (!(Sec.Flags & ELF::SHF_ALLOC) ||
        Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
     setSectionType(Sec, ELF::SHT_PROGBITS);
+
+  return Error::success();
 }
 
 static ElfType getOutputElfType(const Binary &Bin) {
@@ -681,7 +697,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
       if (Iter != Config.SetSectionFlags.end()) {
         const SectionFlagsUpdate &SFU = Iter->second;
-        setSectionFlagsAndType(Sec, SFU.NewFlags);
+        if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))
+          return E;
       }
       auto It2 = Config.SetSectionType.find(Sec.Name);
       if (It2 != Config.SetSectionType.end())
@@ -698,8 +715,10 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
       if (Iter != Config.SectionsToRename.end()) {
         const SectionRename &SR = Iter->second;
         Sec.Name = std::string(SR.NewName);
-        if (SR.NewFlags)
-          setSectionFlagsAndType(Sec, *SR.NewFlags);
+        if (SR.NewFlags) {
+          if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))
+            return E;
+        }
         RenamedSections.insert(&Sec);
       } else if (RelocSec && !(Sec.Flags & SHF_ALLOC))
         // Postpone processing relocation sections which are not specified in

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
index f0f3c2d86a306f..6141f797ecd49e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
@@ -1,10 +1,14 @@
-# Test that cpu/processor-specific SHF_* flags are preserved.
+# Test that cpu/processor-specific SHF_* flags are preserved,
+# except SHF_X86_64_LARGE on x86_64 (which is controlled with the
+# "large" flag).
 
 # ===== x86_64 =====
 
 # RUN: yaml2obj --docnum=1 %s -o %t-x86_64.o
 # RUN: llvm-objcopy --rename-section=.foo=.bar,alloc %t-x86_64.o
 # RUN: llvm-readobj --sections %t-x86_64.o | FileCheck %s --check-prefix=X86_64
+# RUN: llvm-objcopy --rename-section=.bar=.quz,alloc,large %t-x86_64.o
+# RUN: llvm-readobj --sections %t-x86_64.o | FileCheck %s --check-prefix=X86_64-LARGE
 
 --- !ELF
 FileHeader:
@@ -22,9 +26,16 @@ Sections:
 # X86_64-NEXT:   Flags [
 # X86_64-NEXT:     SHF_ALLOC (0x2)
 # X86_64-NEXT:     SHF_WRITE (0x1)
-# X86_64-NEXT:     SHF_X86_64_LARGE (0x10000000)
 # X86_64-NEXT:   ]
 
+# X86_64-LARGE:        Name: .quz
+# X86_64-LARGE-NEXT:   Type: SHT_PROGBITS
+# X86_64-LARGE-NEXT:   Flags [
+# X86_64-LARGE-NEXT:     SHF_ALLOC (0x2)
+# X86_64-LARGE-NEXT:     SHF_WRITE (0x1)
+# X86_64-LARGE-NEXT:     SHF_X86_64_LARGE (0x10000000)
+# X86_64-LARGE-NEXT:   ]
+
 # ===== hex =====
 
 # RUN: yaml2obj --docnum=2 %s -o %t-hex.o

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test
new file mode 100644
index 00000000000000..f75ae170159401
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-large-multiarch.test
@@ -0,0 +1,69 @@
+# RUN: yaml2obj %s -o %t
+
+## When targetting non-x86_64, the "large" flag is not allowed:
+# RUN: not llvm-objcopy -O elf64-tradbigmips --set-section-flags=.foo=large %t %t.mips.large 2>&1 | FileCheck %s --check-prefixes=BAD-LARGE
+# BAD-LARGE: error: {{.*}}: section flag SHF_X86_64_LARGE can only be used with x86_64 architecture
+
+## Converting x86_64 to non-x86_64 preserves the flag equivalent to SHF_X86_64_LARGE.
+## (This is not a deliberate feature, but it reflects how preservation/setting of flags
+## works for arch-specific flags.)
+# RUN: llvm-objcopy -O elf64-tradbigmips --set-section-flags=.foo=alloc --set-section-flags=.bar=alloc %t %t.mips
+# RUN: llvm-readobj --sections %t.mips | FileCheck %s --check-prefixes=CHECK,REINTERPRET-GPREL
+
+## Converting non-x86_64 to x86_64 clears the flag equivalent to SHF_X86_64_LARGE,
+## and SHF_X86_64_LARGE is set according to the presence of the "large" flag,
+## as long as --set-section-flags is used. If --set-section-flag is _not_ used, then
+## the section flag is retained. (This latter behaviour is also not deliberate.)
+# RUN: llvm-objcopy -O elf64-x86-64 --set-section-flags=.foo=alloc --set-section-flags=.bar=alloc %t.mips %t.x86_64.no-large
+# RUN: llvm-readobj --sections %t.x86_64.no-large | FileCheck %s --check-prefixes=CHECK,REINTERPRET-LARGE
+# RUN: llvm-objcopy -O elf64-x86-64 --set-section-flags=.foo=alloc,large --set-section-flags=.bar=alloc,large %t.mips %t.x86_64.large
+# RUN: llvm-readobj --sections %t.x86_64.large | FileCheck %s --check-prefixes=CHECK,LARGE,REINTERPRET-LARGE
+
+!ELF
+FileHeader:
+  Class:    ELFCLASS64
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_X86_64
+Sections:
+  - Name:   .foo
+    Type:   SHT_PROGBITS
+    Flags:  [ ]
+  - Name:   .bar
+    Type:   SHT_PROGBITS
+    Flags:  [ SHF_X86_64_LARGE ]
+  - Name:   .untouched
+    Type:   SHT_PROGBITS
+    Flags:  [ ]
+  - Name:   .untouched_large
+    Type:   SHT_PROGBITS
+    Flags:  [ SHF_X86_64_LARGE ]
+
+# CHECK:         Name: .foo
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# LARGE-NEXT:      SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT:    ]
+
+# CHECK:         Name: .bar
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# REINTERPRET-GPREL-NEXT: SHF_MIPS_GPREL (0x10000000)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# LARGE-NEXT:      SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT:    ]
+
+# CHECK:         Name: .untouched
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:    ]
+
+# CHECK:         Name: .untouched_large
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# REINTERPRET-GPREL-NEXT: SHF_MIPS_GPREL (0x10000000)
+# REINTERPRET-LARGE-NEXT: SHF_X86_64_LARGE (0x10000000)
+# CHECK-NEXT:    ]

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
index afcac5527a57bc..c002c8807453d0 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags.test
@@ -40,6 +40,12 @@
 # RUN: llvm-objcopy --set-section-flags=.foo=share \
 # RUN:   --set-section-flags=.baz=share --set-section-flags=.rela.baz=share %t %t.share
 # RUN: llvm-readobj --sections %t.share | FileCheck %s --check-prefixes=CHECK,PROGBITS,WRITE
+# RUN: llvm-objcopy --set-section-flags=.foo=large \
+# RUN:   --set-section-flags=.baz=large --set-section-flags=.rela.baz=large %t %t.large
+# RUN: llvm-readobj --sections %t.large | FileCheck %s --check-prefixes=CHECK,LARGE,PROGBITS,WRITE
+# RUN: llvm-objcopy --set-section-flags=.foo=data \
+# RUN:   --set-section-flags=.baz=data --set-section-flags=.rela.baz=data %t %t.no-large
+# RUN: llvm-readobj --sections %t.no-large | FileCheck %s --check-prefixes=CHECK,PROGBITS,WRITE
 
 # Multiple flags:
 # RUN: llvm-objcopy --set-section-flags=.foo=alloc,readonly,strings \
@@ -102,6 +108,7 @@ Sections:
 # STRINGS-NEXT:    SHF_STRINGS (0x20)
 # EXCLUDE-NEXT:    SHF_EXCLUDE (0x80000000)
 # WRITE-NEXT:      SHF_WRITE (0x1)
+# LARGE-NEXT:      SHF_X86_64_LARGE (0x10000000)
 # CHECK-NEXT:    ]
 
 # CHECK:         Name: .baz
@@ -114,6 +121,7 @@ Sections:
 # STRINGS-NEXT:    SHF_STRINGS (0x20)
 # EXCLUDE-NEXT:    SHF_EXCLUDE (0x80000000)
 # WRITE-NEXT:      SHF_WRITE (0x1)
+# LARGE-NEXT:      SHF_X86_64_LARGE (0x10000000)
 # CHECK-NEXT:    ]
 
 # CHECK:         Name: .rela.baz
@@ -125,6 +133,7 @@ Sections:
 # STRINGS-NEXT:    SHF_STRINGS (0x20)
 # EXCLUDE-NEXT:    SHF_EXCLUDE (0x80000000)
 # WRITE-NEXT:      SHF_WRITE (0x1)
+# LARGE-NEXT:      SHF_X86_64_LARGE (0x10000000)
 # CHECK-NEXT:    ]
 
 # BAD-FORMAT: bad format for --set-section-flags: missing '='

diff  --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 265e4fc6073c2b..2e0c3ca8671aa1 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -205,6 +205,7 @@ static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
       .CaseLower("contents", SectionFlag::SecContents)
       .CaseLower("share", SectionFlag::SecShare)
       .CaseLower("exclude", SectionFlag::SecExclude)
+      .CaseLower("large", SectionFlag::SecLarge)
       .Default(SectionFlag::SecNone);
 }
 
@@ -218,7 +219,7 @@ parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
           errc::invalid_argument,
           "unrecognized section flag '%s'. Flags supported for GNU "
           "compatibility: alloc, load, noload, readonly, exclude, debug, "
-          "code, data, rom, share, contents, merge, strings",
+          "code, data, rom, share, contents, merge, strings, large",
           Flag.str().c_str());
     ParsedFlags |= ParsedFlag;
   }

diff  --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index a7e4263271d356..ea8828637222ac 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -52,7 +52,7 @@ defm rename_section
          "Renames a section from old to new, optionally with specified flags. "
          "Flags supported for GNU compatibility: alloc, load, noload, "
          "readonly, exclude, debug, code, data, rom, share, contents, merge, "
-         "strings">,
+         "strings, large">,
       MetaVarName<"old=new[,flag1,...]">;
 defm redefine_symbol
     : Eq<"redefine-sym", "Change the name of a symbol old to new">,
@@ -85,7 +85,7 @@ defm set_section_flags
     : Eq<"set-section-flags",
          "Set section flags for a given section. Flags supported for GNU "
          "compatibility: alloc, load, noload, readonly, exclude, debug, code, "
-         "data, rom, share, contents, merge, strings">,
+         "data, rom, share, contents, merge, strings, large">,
       MetaVarName<"section=flag1[,flag2,...]">;
 
 defm set_section_type


        


More information about the llvm-commits mailing list