[llvm] b28412d - [llvm-objcopy][ELF] Add --set-section-type

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 13 10:04:26 PDT 2022


Author: Fangrui Song
Date: 2022-07-13T10:04:21-07:00
New Revision: b28412d5397dc5a23f172d6ebeac760c82a82248

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

LOG: [llvm-objcopy][ELF] Add --set-section-type

The request is mentioned on D129053. I feel that having this functionality is
mildly useful (not strong).

* Rename .ctors to .init_array and change sh_type to SHT_INIT_ARRAY (GNU objcopy
  detects the special name but we don't).
* Craft tests for a new SHT_LLVM_* extension

Reviewed By: jhenderson

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

Added: 
    llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test
    llvm/test/tools/llvm-objcopy/ELF/set-section-type.test

Modified: 
    llvm/docs/CommandGuide/llvm-objcopy.rst
    llvm/include/llvm/ObjCopy/CommonConfig.h
    llvm/lib/ObjCopy/ConfigManager.cpp
    llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
    llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test
    llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test
    llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
    llvm/tools/llvm-objcopy/ObjcopyOpts.td

Removed: 
    llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 9462315f313dd..f144343acda93 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -428,6 +428,11 @@ them.
  specified ``<flag>`` values. See :option:`--set-section-flags` for a list of
  supported flags. Can be specified multiple times to rename multiple sections.
 
+.. option:: --set-section-type <section>=<type>
+
+ Set the type of section ``<section>`` to the integer ``<type>``. Can be
+ specified multiple times to update multiple sections.
+
 .. option:: --set-start-addr <addr>
 
  Set the start address of the output to ``<addr>``. Overrides any previously

diff  --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index 24503caed3427..4921f5281ca63 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -241,6 +241,7 @@ struct CommonConfig {
   StringMap<SectionRename> SectionsToRename;
   StringMap<uint64_t> SetSectionAlignment;
   StringMap<SectionFlagsUpdate> SetSectionFlags;
+  StringMap<uint64_t> SetSectionType;
   StringMap<StringRef> SymbolsToRename;
 
   // Symbol info specified by --add-symbol option.

diff  --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp
index 9d8883a15c0bf..77321829e614b 100644
--- a/llvm/lib/ObjCopy/ConfigManager.cpp
+++ b/llvm/lib/ObjCopy/ConfigManager.cpp
@@ -20,9 +20,9 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
       !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
-      Common.ExtractDWO || Common.PreserveDates || Common.StripDWO ||
-      Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
-      Common.DecompressDebugSections ||
+      !Common.SetSectionType.empty() || Common.ExtractDWO ||
+      Common.PreserveDates || Common.StripDWO || Common.StripNonAlloc ||
+      Common.StripSections || Common.Weaken || Common.DecompressDebugSections ||
       Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
     return createStringError(llvm::errc::invalid_argument,
                              "option is not supported for COFF");
@@ -38,9 +38,10 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
       !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() ||
       !Common.UnneededSymbolsToRemove.empty() ||
       !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
-      Common.ExtractDWO || Common.PreserveDates || Common.StripAllGNU ||
-      Common.StripDWO || Common.StripNonAlloc || Common.StripSections ||
-      Common.Weaken || Common.DecompressDebugSections || Common.StripUnneeded ||
+      !Common.SetSectionType.empty() || Common.ExtractDWO ||
+      Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
+      Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
+      Common.DecompressDebugSections || Common.StripUnneeded ||
       Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
     return createStringError(llvm::errc::invalid_argument,
                              "option is not supported for MachO");
@@ -58,7 +59,8 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
       !Common.UnneededSymbolsToRemove.empty() ||
       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
-      !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty())
+      !Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
+      !Common.SymbolsToRename.empty())
     return createStringError(llvm::errc::invalid_argument,
                              "only flags for section dumping, removal, and "
                              "addition are supported");
@@ -79,12 +81,12 @@ Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
       !Common.UnneededSymbolsToRemove.empty() ||
       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
-      !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty() ||
-      Common.ExtractDWO || Common.ExtractMainPartition ||
-      Common.OnlyKeepDebug || Common.PreserveDates || Common.StripAllGNU ||
-      Common.StripDWO || Common.StripDebug || Common.StripNonAlloc ||
-      Common.StripSections || Common.Weaken || Common.StripUnneeded ||
-      Common.DecompressDebugSections) {
+      !Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
+      !Common.SymbolsToRename.empty() || Common.ExtractDWO ||
+      Common.ExtractMainPartition || Common.OnlyKeepDebug ||
+      Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
+      Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
+      Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections) {
     return createStringError(
         llvm::errc::invalid_argument,
         "no flags are supported yet, only basic copying is allowed");

diff  --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index ee592bb9f3883..36e0d504d43d4 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -675,14 +675,17 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
   for (const NewSymbolInfo &SI : Config.SymbolsToAdd)
     addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);
 
-  // --set-section-flags works with sections added by --add-section.
-  if (!Config.SetSectionFlags.empty()) {
+  // --set-section-{flags,type} work with sections added by --add-section.
+  if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {
     for (auto &Sec : Obj.sections()) {
       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
       if (Iter != Config.SetSectionFlags.end()) {
         const SectionFlagsUpdate &SFU = Iter->second;
         setSectionFlagsAndType(Sec, SFU.NewFlags);
       }
+      auto It2 = Config.SetSectionType.find(Sec.Name);
+      if (It2 != Config.SetSectionType.end())
+        Sec.Type = It2->second;
     }
   }
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test
new file mode 100644
index 0000000000000..e467ce4fefe67
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-attr.test
@@ -0,0 +1,28 @@
+## Check --set-section-flags/--set-section-types work with sections added by --add-section.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-flags=foo=alloc,exclude %t %t.1
+# RUN: llvm-readobj -S %t.1 | FileCheck %s
+
+# CHECK:      Name: foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_EXCLUDE
+# CHECK-NEXT:   SHF_WRITE
+# CHECK-NEXT: ]
+
+# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-type=foo=7 %t %t.2
+# RUN: llvm-readobj -S %t.2 | FileCheck %s --check-prefix=CHECK2
+
+# CHECK2:      Name: foo
+# CHECK2-NEXT: Type: SHT_NOTE (0x7)
+# CHECK2-NEXT: Flags [
+# CHECK2-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test b/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test
deleted file mode 100644
index 0beb1a7b9a60c..0000000000000
--- a/llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test
+++ /dev/null
@@ -1,20 +0,0 @@
-## Check --set-section-flags works with sections added by --add-section.
-
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-flags=foo=alloc,exclude %t %t.out
-# RUN: llvm-readobj -S %t.out | FileCheck %s
-
-# CHECK:      Name: foo
-# CHECK-NEXT: Type: SHT_PROGBITS
-# CHECK-NEXT: Flags [
-# CHECK-NEXT:   SHF_ALLOC
-# CHECK-NEXT:   SHF_EXCLUDE
-# CHECK-NEXT:   SHF_WRITE
-# CHECK-NEXT: ]
-
---- !ELF
-FileHeader:
-  Class:   ELFCLASS64
-  Data:    ELFDATA2LSB
-  Type:    ET_EXEC
-  Machine: EM_X86_64

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test
index dbf5ddcbb35ea..b8e08cc753672 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test
@@ -43,7 +43,7 @@
 
 # RUN: not llvm-objcopy --set-section-alignment=.foo=bar %t /dev/null 2>&1 | \
 # RUN:   FileCheck --check-prefix=INVALID-ALIGN %s
-# INVALID-ALIGN:   error: invalid alignment for --set-section-alignment: 'bar'
+# INVALID-ALIGN:   error: invalid value for --set-section-alignment: 'bar'
 
 !ELF
 FileHeader:

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test
index ba6f521f77654..1e628559c107e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test
@@ -1,10 +1,10 @@
 # RUN: yaml2obj %s -o %t
 
-# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-alignment=.foo=16 --set-section-flags=.foo=alloc %t %t.1
+# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-alignment=.foo=16 --set-section-flags=.foo=alloc --set-section-type=.foo=5 %t %t.1
 # RUN: llvm-readobj -S %t.1 | FileCheck %s
 
 # CHECK:      Name: .bar
-# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Type: SHT_HASH (0x5)
 # CHECK-NEXT: Flags [
 # CHECK-NEXT:   SHF_ALLOC
 # CHECK-NEXT:   SHF_WRITE
@@ -13,7 +13,12 @@
 # CHECK-SAME:   {{^}} 16
 
 # RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | \
-# RUN:   FileCheck %s --check-prefix=SET-BAR
+# RUN:   FileCheck %s --check-prefix=SET-BAR1
+# SET-BAR1: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar
+
+# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-type=.bar=1 %t %t.2 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=SET-BAR2
+# SET-BAR2: --set-section-type=.bar conflicts with --rename-section=.foo=.bar
 
 !ELF
 FileHeader:
@@ -25,5 +30,3 @@ Sections:
   - Name:  .foo
     Type:  SHT_PROGBITS
     Flags: [ SHF_ALLOC ]
-
-# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test
new file mode 100644
index 0000000000000..35cea8a8232ee
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-type.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %s -o %t
+
+# RUN: llvm-objcopy --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1
+# RUN: llvm-readobj --sections %t.1 | FileCheck %s
+
+# RUN: llvm-objcopy --set-section-type=.foo=13 --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1
+# RUN: llvm-readobj --sections %t.1 | FileCheck %s
+
+# CHECK:        Name: .foo
+# CHECK-NEXT:   Type: SHT_INIT_ARRAY (0xE)
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+
+# CHECK:        Name: .bar
+# CHECK-NEXT:   Type: SHT_FINI_ARRAY (0xF)
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:   ]
+
+## --set-section-flags does not specify "readonly", so the output gets SHF_WRITE.
+## "contents" changes SHT_NOBITS to SHT_PROGBITS, but this is overridden by --set-section-type.
+## sh_type is a uint32_t. There is no diagnostic for an overflow value.
+# RUN: llvm-objcopy --set-section-flags=.foo=alloc,contents --set-section-type=.foo=0x10000000a %t %t.2 2>&1 | count 0
+# RUN: llvm-readobj --sections %t.2 | FileCheck %s --check-prefix=CHECK2
+
+# CHECK2:        Name: .foo
+# CHECK2-NEXT:   Type: SHT_SHLIB
+# CHECK2-NEXT:   Flags [
+# CHECK2-NEXT:     SHF_ALLOC
+# CHECK2-NEXT:     SHF_WRITE
+# CHECK2-NEXT:   ]
+
+# RUN: not llvm-objcopy --set-section-type=.foo %t /dev/null 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
+# BAD-FORMAT: bad format for --set-section-type: missing '='
+
+# RUN: not llvm-objcopy --set-section-type==4 %t /dev/null 2>&1 | FileCheck %s --check-prefix=MISSING-SECTION
+# MISSING-SECTION: error: bad format for --set-section-type: missing section name
+
+# RUN: not llvm-objcopy --set-section-type=.foo=aaa %t /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-TYPE
+# INVALID-TYPE: error: invalid value for --set-section-type: 'aaa'
+
+!ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name:  .foo
+    Type:  SHT_NOBITS
+    Flags: [ SHF_ALLOC ]
+  - Name:  .bar
+    Type:  SHT_PROGBITS
+    Flags: [ ]

diff  --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 30ca506f79e39..8a2b4855501bb 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -236,23 +236,21 @@ static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
 }
 
 static Expected<std::pair<StringRef, uint64_t>>
-parseSetSectionAlignment(StringRef FlagValue) {
+parseSetSectionAttribute(StringRef Option, StringRef FlagValue) {
   if (!FlagValue.contains('='))
-    return createStringError(
-        errc::invalid_argument,
-        "bad format for --set-section-alignment: missing '='");
+    return make_error<StringError>("bad format for " + Option + ": missing '='",
+                                   errc::invalid_argument);
   auto Split = StringRef(FlagValue).split('=');
   if (Split.first.empty())
-    return createStringError(
-        errc::invalid_argument,
-        "bad format for --set-section-alignment: missing section name");
-  uint64_t NewAlign;
-  if (Split.second.getAsInteger(0, NewAlign))
-    return createStringError(
-        errc::invalid_argument,
-        "invalid alignment for --set-section-alignment: '%s'",
-        Split.second.str().c_str());
-  return std::make_pair(Split.first, NewAlign);
+    return make_error<StringError>("bad format for " + Option +
+                                       ": missing section name",
+                                   errc::invalid_argument);
+  uint64_t Value;
+  if (Split.second.getAsInteger(0, Value))
+    return make_error<StringError>("invalid value for " + Option + ": '" +
+                                       Split.second + "'",
+                                   errc::invalid_argument);
+  return std::make_pair(Split.first, Value);
 }
 
 static Expected<SectionFlagsUpdate>
@@ -793,7 +791,7 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
   }
   for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
     Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
-        parseSetSectionAlignment(Arg->getValue());
+        parseSetSectionAttribute("--set-section-alignment", Arg->getValue());
     if (!NameAndAlign)
       return NameAndAlign.takeError();
     Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
@@ -809,16 +807,28 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
           "--set-section-flags set multiple times for section '%s'",
           SFU->Name.str().c_str());
   }
-  // Prohibit combinations of --set-section-flags when the section name is used
-  // as the destination of a --rename-section.
+  for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {
+    Expected<std::pair<StringRef, uint64_t>> NameAndType =
+        parseSetSectionAttribute("--set-section-type", Arg->getValue());
+    if (!NameAndType)
+      return NameAndType.takeError();
+    Config.SetSectionType[NameAndType->first] = NameAndType->second;
+  }
+  // Prohibit combinations of --set-section-{flags,type} when the section name
+  // is used as the destination of a --rename-section.
   for (const auto &E : Config.SectionsToRename) {
     const SectionRename &SR = E.second;
-    if (Config.SetSectionFlags.count(SR.NewName))
+    auto Err = [&](const char *Option) {
       return createStringError(
           errc::invalid_argument,
-          "--set-section-flags=%s conflicts with --rename-section=%s=%s",
+          "--set-section-%s=%s conflicts with --rename-section=%s=%s", Option,
           SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
           SR.NewName.str().c_str());
+    };
+    if (Config.SetSectionFlags.count(SR.NewName))
+      return Err("flags");
+    if (Config.SetSectionType.count(SR.NewName))
+      return Err("type");
   }
 
   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))

diff  --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index ff73265989f36..962028da47a04 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -87,6 +87,11 @@ defm set_section_flags
          "data, rom, share, contents, merge, strings.">,
       MetaVarName<"section=flag1[,flag2,...]">;
 
+defm set_section_type
+    : Eq<"set-section-type",
+         "Set the type of section <section> to the integer <type>">,
+      MetaVarName<"section=type">;
+
 def S : Flag<["-"], "S">,
         Alias<strip_all>,
         HelpText<"Alias for --strip-all">;


        


More information about the llvm-commits mailing list