[llvm] 081c625 - [llvm-objcopy] Refactor CopyConfig structure.

Alexey Lapshin via llvm-commits llvm-commits at lists.llvm.org
Thu May 20 03:17:33 PDT 2021


Author: Alexey Lapshin
Date: 2021-05-20T13:14:51+03:00
New Revision: 081c62501e4f0aad4ab31de52f871f98403073ad

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

LOG: [llvm-objcopy] Refactor CopyConfig structure.

This patch prepares llvm-objcopy to move its implementation
into a separate library. To make it possible it is necessary
to minimize internal dependencies.

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

Added: 
    llvm/tools/llvm-objcopy/COFF/COFFConfig.h
    llvm/tools/llvm-objcopy/CommonConfig.h
    llvm/tools/llvm-objcopy/ConfigManager.cpp
    llvm/tools/llvm-objcopy/ConfigManager.h
    llvm/tools/llvm-objcopy/MachO/MachOConfig.h
    llvm/tools/llvm-objcopy/MultiFormatConfig.h
    llvm/tools/llvm-objcopy/wasm/WasmConfig.h

Modified: 
    llvm/tools/llvm-objcopy/CMakeLists.txt
    llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
    llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
    llvm/tools/llvm-objcopy/ELF/ELFConfig.h
    llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
    llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
    llvm/tools/llvm-objcopy/ELF/Object.h
    llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
    llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
    llvm/tools/llvm-objcopy/llvm-objcopy.cpp
    llvm/tools/llvm-objcopy/llvm-objcopy.h
    llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
    llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h

Removed: 
    llvm/tools/llvm-objcopy/CopyConfig.cpp
    llvm/tools/llvm-objcopy/CopyConfig.h
    llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp


################################################################################
diff  --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt
index 20e1e40dcff2c..d14d2135f5db7 100644
--- a/llvm/tools/llvm-objcopy/CMakeLists.txt
+++ b/llvm/tools/llvm-objcopy/CMakeLists.txt
@@ -22,13 +22,12 @@ tablegen(LLVM StripOpts.inc -gen-opt-parser-defs)
 add_public_tablegen_target(StripOptsTableGen)
 
 add_llvm_tool(llvm-objcopy
-  CopyConfig.cpp
+  ConfigManager.cpp
   llvm-objcopy.cpp
   COFF/COFFObjcopy.cpp
   COFF/Object.cpp
   COFF/Reader.cpp
   COFF/Writer.cpp
-  ELF/ELFConfig.cpp
   ELF/ELFObjcopy.cpp
   ELF/Object.cpp
   MachO/MachOObjcopy.cpp

diff  --git a/llvm/tools/llvm-objcopy/COFF/COFFConfig.h b/llvm/tools/llvm-objcopy/COFF/COFFConfig.h
new file mode 100644
index 0000000000000..3897ff47724bb
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/COFF/COFFConfig.h
@@ -0,0 +1,21 @@
+//===- COFFConfig.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COFF_COFFCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_COFF_COFFCONFIG_H
+
+namespace llvm {
+namespace objcopy {
+
+// Coff specific configuration for copying/stripping a single file.
+struct COFFConfig {};
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_COFF_COFFCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
index de76fee526675..e50ac2e12e2f5 100644
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "COFFObjcopy.h"
-#include "CopyConfig.h"
+#include "COFFConfig.h"
+#include "CommonConfig.h"
 #include "Object.h"
 #include "Reader.h"
 #include "Writer.h"
@@ -130,7 +131,7 @@ static void setSectionFlags(Section &Sec, SectionFlag AllFlags) {
   Sec.Header.Characteristics = NewCharacteristics;
 }
 
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+static Error handleArgs(const CommonConfig &Config, Object &Obj) {
   // Perform the actual section removals.
   Obj.removeSections([&Config](const Section &Sec) {
     // Contrary to --only-keep-debug, --only-section fully removes sections that
@@ -248,28 +249,11 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
     if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
       return E;
 
-  if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() ||
-      !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
-      !Config.DumpSection.empty() || !Config.KeepSection.empty() ||
-      Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
-      !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
-      !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
-      !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() ||
-      Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
-      Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
-      Config.StripSwiftSymbols || Config.KeepUndefined || Config.Weaken ||
-      Config.DecompressDebugSections ||
-      Config.DiscardMode == DiscardType::Locals ||
-      !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
-    return createStringError(llvm::errc::invalid_argument,
-                             "option not supported by llvm-objcopy for COFF");
-  }
-
   return Error::success();
 }
 
-Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In,
-                             raw_ostream &Out) {
+Error executeObjcopyOnBinary(const CommonConfig &Config, const COFFConfig &,
+                             COFFObjectFile &In, raw_ostream &Out) {
   COFFReader Reader(In);
   Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
   if (!ObjOrErr)

diff  --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
index 64f65dbb7b093..2c7ccd34653d7 100644
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
@@ -18,10 +18,12 @@ class COFFObjectFile;
 } // end namespace object
 
 namespace objcopy {
-struct CopyConfig;
+struct CommonConfig;
+struct COFFConfig;
 
 namespace coff {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+
+Error executeObjcopyOnBinary(const CommonConfig &Config, const COFFConfig &,
                              object::COFFObjectFile &In, raw_ostream &Out);
 
 } // end namespace coff

diff  --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CommonConfig.h
similarity index 72%
rename from llvm/tools/llvm-objcopy/CopyConfig.h
rename to llvm/tools/llvm-objcopy/CommonConfig.h
index 1b99e24137dd6..d08765cbc5458 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/llvm/tools/llvm-objcopy/CommonConfig.h
@@ -1,4 +1,4 @@
-//===- CopyConfig.h -------------------------------------------------------===//
+//===- CommonConfig.h -------------------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,20 +6,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H
 
-#include "ELF/ELFConfig.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/ELFTypes.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Error.h"
 #include "llvm/Support/GlobPattern.h"
 #include "llvm/Support/Regex.h"
 // Necessary for llvm::DebugCompressionType::None
@@ -99,7 +95,7 @@ enum class MatchStyle {
 
 class NameOrPattern {
   StringRef Name;
-  // Regex is shared between multiple CopyConfig instances.
+  // Regex is shared between multiple CommonConfig instances.
   std::shared_ptr<Regex> R;
   std::shared_ptr<GlobPattern> G;
   bool IsPositiveMatch = true;
@@ -146,10 +142,7 @@ class NameMatcher {
 };
 
 // Configuration for copying/stripping a single file.
-struct CopyConfig {
-  // Format-specific options to be initialized lazily when needed.
-  Optional<elf::ELFCopyConfig> ELF;
-
+struct CommonConfig {
   // Main input/output options
   StringRef InputFilename;
   FileFormat InputFormat = FileFormat::Unspecified;
@@ -168,12 +161,10 @@ struct CopyConfig {
   StringRef SymbolsPrefix;
   StringRef AllocSectionsPrefix;
   DiscardType DiscardMode = DiscardType::None;
-  Optional<StringRef> NewSymbolVisibility;
 
   // Repeated options
   std::vector<StringRef> AddSection;
   std::vector<StringRef> DumpSection;
-  std::vector<StringRef> SymbolsToAdd;
   std::vector<StringRef> RPathToAdd;
   std::vector<StringRef> RPathToPrepend;
   DenseMap<StringRef, StringRef> RPathsToUpdate;
@@ -233,55 +224,9 @@ struct CopyConfig {
   bool RemoveAllRpaths = false;
 
   DebugCompressionType CompressionType = DebugCompressionType::None;
-
-  // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on
-  // success or returns an Error otherwise.
-  Error parseELFConfig() {
-    if (!ELF) {
-      Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this);
-      if (!ELFConfig)
-        return ELFConfig.takeError();
-      ELF = *ELFConfig;
-    }
-    return Error::success();
-  }
 };
 
-// Configuration for the overall invocation of this tool. When invoked as
-// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
-// will contain one or more CopyConfigs.
-struct DriverConfig {
-  SmallVector<CopyConfig, 1> CopyConfigs;
-  BumpPtrAllocator Alloc;
-};
-
-// ParseObjcopyOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
-                    llvm::function_ref<Error(Error)> ErrorCallback);
-
-// ParseInstallNameToolOptions returns the config and sets the input arguments.
-// If a help flag is set then ParseInstallNameToolOptions will print the help
-// messege and exit.
-Expected<DriverConfig>
-parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);
-
-// ParseBitcodeStripOptions returns the config and sets the input arguments.
-// If a help flag is set then ParseBitcodeStripOptions will print the help
-// messege and exit.
-Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr);
-
-// ParseStripOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseStripOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseStripOptions(ArrayRef<const char *> ArgsArr,
-                  llvm::function_ref<Error(Error)> ErrorCallback);
 } // namespace objcopy
 } // namespace llvm
 
-#endif
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp
similarity index 84%
rename from llvm/tools/llvm-objcopy/CopyConfig.cpp
rename to llvm/tools/llvm-objcopy/ConfigManager.cpp
index ce68101f0c859..b4bc6b1b0b57e 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/llvm/tools/llvm-objcopy/ConfigManager.cpp
@@ -1,4 +1,4 @@
-//===- CopyConfig.cpp -----------------------------------------------------===//
+//===- ConfigManager.cpp --------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CopyConfig.h"
-
+#include "ConfigManager.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -18,6 +17,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/StringSaver.h"
 #include <memory>
@@ -466,6 +466,190 @@ static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
   OS << "\nPass @FILE as argument to read options from FILE.\n";
 }
 
+static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
+                                                  uint8_t DefaultVisibility) {
+  // Parse value given with --add-symbol option and create the
+  // new symbol if possible. The value format for --add-symbol is:
+  //
+  // <name>=[<section>:]<value>[,<flags>]
+  //
+  // where:
+  // <name> - symbol name, can be empty string
+  // <section> - optional section name. If not given ABS symbol is created
+  // <value> - symbol value, can be decimal or hexadecimal number prefixed
+  //           with 0x.
+  // <flags> - optional flags affecting symbol type, binding or visibility:
+  //           The following are currently supported:
+  //
+  //           global, local, weak, default, hidden, file, section, object,
+  //           indirect-function.
+  //
+  //           The following flags are ignored and provided for GNU
+  //           compatibility only:
+  //
+  //           warning, debug, constructor, indirect, synthetic,
+  //           unique-object, before=<symbol>.
+  NewSymbolInfo SI;
+  StringRef Value;
+  std::tie(SI.SymbolName, Value) = FlagValue.split('=');
+  if (Value.empty())
+    return createStringError(
+        errc::invalid_argument,
+        "bad format for --add-symbol, missing '=' after '%s'",
+        SI.SymbolName.str().c_str());
+
+  if (Value.contains(':')) {
+    std::tie(SI.SectionName, Value) = Value.split(':');
+    if (SI.SectionName.empty() || Value.empty())
+      return createStringError(
+          errc::invalid_argument,
+          "bad format for --add-symbol, missing section name or symbol value");
+  }
+
+  SmallVector<StringRef, 6> Flags;
+  Value.split(Flags, ',');
+  if (Flags[0].getAsInteger(0, SI.Value))
+    return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
+                             Flags[0].str().c_str());
+
+  SI.Visibility = DefaultVisibility;
+  using Functor = std::function<void(void)>;
+  SmallVector<StringRef, 6> UnsupportedFlags;
+  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
+    static_cast<Functor>(
+        StringSwitch<Functor>(Flags[I])
+            .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
+            .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
+            .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
+            .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
+            .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
+            .CaseLower("protected",
+                       [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
+            .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
+            .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
+            .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
+            .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
+            .CaseLower("indirect-function",
+                       [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
+            .CaseLower("debug", [] {})
+            .CaseLower("constructor", [] {})
+            .CaseLower("warning", [] {})
+            .CaseLower("indirect", [] {})
+            .CaseLower("synthetic", [] {})
+            .CaseLower("unique-object", [] {})
+            .StartsWithLower("before", [] {})
+            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
+  if (!UnsupportedFlags.empty())
+    return createStringError(errc::invalid_argument,
+                             "unsupported flag%s for --add-symbol: '%s'",
+                             UnsupportedFlags.size() > 1 ? "s" : "",
+                             join(UnsupportedFlags, "', '").c_str());
+  return SI;
+}
+
+Expected<const ELFConfig &> ConfigManager::getELFConfig() const {
+  if (!ELF) {
+    if (Common.StripSwiftSymbols || Common.KeepUndefined)
+      return createStringError(llvm::errc::invalid_argument,
+                               "option not supported by llvm-objcopy for ELF");
+
+    // Parse lazy options.
+    ELFConfig ResConfig;
+
+    if (NewSymbolVisibility) {
+      const uint8_t Invalid = 0xff;
+      ResConfig.NewSymbolVisibility =
+          StringSwitch<uint8_t>(*NewSymbolVisibility)
+              .Case("default", ELF::STV_DEFAULT)
+              .Case("hidden", ELF::STV_HIDDEN)
+              .Case("internal", ELF::STV_INTERNAL)
+              .Case("protected", ELF::STV_PROTECTED)
+              .Default(Invalid);
+
+      if (ResConfig.NewSymbolVisibility == Invalid)
+        return createStringError(errc::invalid_argument,
+                                 "'%s' is not a valid symbol visibility",
+                                 NewSymbolVisibility->str().c_str());
+    }
+
+    for (StringRef Arg : SymbolsToAdd) {
+      Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(
+          Arg,
+          ResConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
+      if (!NSI)
+        return NSI.takeError();
+      ResConfig.SymbolsToAdd.push_back(*NSI);
+    }
+
+    ELF = std::move(ResConfig);
+  }
+
+  return *ELF;
+}
+
+Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
+  if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() ||
+      !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() ||
+      !Common.DumpSection.empty() || !Common.KeepSection.empty() ||
+      NewSymbolVisibility || !Common.SymbolsToGlobalize.empty() ||
+      !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
+      !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
+      !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
+      Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates ||
+      Common.StripDWO || Common.StripNonAlloc || Common.StripSections ||
+      Common.StripSwiftSymbols || Common.KeepUndefined || Common.Weaken ||
+      Common.DecompressDebugSections ||
+      Common.DiscardMode == DiscardType::Locals || !SymbolsToAdd.empty() ||
+      Common.EntryExpr) {
+    return createStringError(llvm::errc::invalid_argument,
+                             "option not supported by llvm-objcopy for COFF");
+  }
+
+  return COFF;
+}
+
+Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
+  if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() ||
+      !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() ||
+      !Common.KeepSection.empty() || NewSymbolVisibility ||
+      !Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() ||
+      !Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() ||
+      !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() ||
+      !Common.UnneededSymbolsToRemove.empty() ||
+      !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
+      Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates ||
+      Common.StripAllGNU || Common.StripDWO || Common.StripNonAlloc ||
+      Common.StripSections || Common.Weaken || Common.DecompressDebugSections ||
+      Common.StripUnneeded || Common.DiscardMode == DiscardType::Locals ||
+      !SymbolsToAdd.empty() || Common.EntryExpr) {
+    return createStringError(llvm::errc::invalid_argument,
+                             "option not supported by llvm-objcopy for MachO");
+  }
+
+  return MachO;
+}
+
+Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
+  if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition ||
+      !Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
+      !Common.AllocSectionsPrefix.empty() ||
+      Common.DiscardMode != DiscardType::None || NewSymbolVisibility ||
+      !SymbolsToAdd.empty() || !Common.RPathToAdd.empty() ||
+      !Common.OnlySection.empty() || !Common.SymbolsToGlobalize.empty() ||
+      !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
+      !Common.SymbolsToRemove.empty() ||
+      !Common.UnneededSymbolsToRemove.empty() ||
+      !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
+      !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
+      !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) {
+    return createStringError(
+        llvm::errc::invalid_argument,
+        "only add-section, dump-section, and remove-section are supported");
+  }
+
+  return Wasm;
+}
+
 // ParseObjcopyOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseObjcopyOptions will print the help messege and
 // exit.
@@ -519,7 +703,8 @@ parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
     return createStringError(errc::invalid_argument,
                              "too many positional arguments");
 
-  CopyConfig Config;
+  ConfigManager ConfigMgr;
+  CommonConfig &Config = ConfigMgr.Common;
   Config.InputFilename = Positional[0];
   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
   if (InputArgs.hasArg(OBJCOPY_target) &&
@@ -559,7 +744,7 @@ parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
                            .Default(FileFormat::Unspecified);
 
   if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility))
-    Config.NewSymbolVisibility =
+    ConfigMgr.NewSymbolVisibility =
         InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
 
   Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
@@ -808,7 +993,7 @@ parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
                                SymbolMatchStyle, ErrorCallback))
       return std::move(E);
   for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
-    Config.SymbolsToAdd.push_back(Arg->getValue());
+    ConfigMgr.SymbolsToAdd.push_back(Arg->getValue());
 
   Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
 
@@ -862,7 +1047,7 @@ parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
                              "cannot specify --extract-partition together with "
                              "--extract-main-partition");
 
-  DC.CopyConfigs.push_back(std::move(Config));
+  DC.CopyConfigs.push_back(std::move(ConfigMgr));
   return std::move(DC);
 }
 
@@ -872,7 +1057,8 @@ parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
 Expected<DriverConfig>
 parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
   DriverConfig DC;
-  CopyConfig Config;
+  ConfigManager ConfigMgr;
+  CommonConfig &Config = ConfigMgr.Common;
   InstallNameToolOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   llvm::opt::InputArgList InputArgs =
@@ -996,14 +1182,15 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
   Config.InputFilename = Positional[0];
   Config.OutputFilename = Positional[0];
 
-  DC.CopyConfigs.push_back(std::move(Config));
+  DC.CopyConfigs.push_back(std::move(ConfigMgr));
   return std::move(DC);
 }
 
 Expected<DriverConfig>
 parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
   DriverConfig DC;
-  CopyConfig Config;
+  ConfigManager ConfigMgr;
+  CommonConfig &Config = ConfigMgr.Common;
   BitcodeStripOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   opt::InputArgList InputArgs =
@@ -1040,7 +1227,7 @@ parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
   Config.InputFilename = Positional[0];
   Config.OutputFilename = Positional[0];
 
-  DC.CopyConfigs.push_back(std::move(Config));
+  DC.CopyConfigs.push_back(std::move(ConfigMgr));
   return std::move(DC);
 }
 
@@ -1086,7 +1273,8 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
         errc::invalid_argument,
         "multiple input files cannot be used in combination with -o");
 
-  CopyConfig Config;
+  ConfigManager ConfigMgr;
+  CommonConfig &Config = ConfigMgr.Common;
 
   if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
     return createStringError(errc::invalid_argument,
@@ -1159,7 +1347,7 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
     Config.InputFilename = Positional[0];
     Config.OutputFilename =
         InputArgs.getLastArgValue(STRIP_output, Positional[0]);
-    DC.CopyConfigs.push_back(std::move(Config));
+    DC.CopyConfigs.push_back(std::move(ConfigMgr));
   } else {
     StringMap<unsigned> InputFiles;
     for (StringRef Filename : Positional) {
@@ -1175,7 +1363,7 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
       }
       Config.InputFilename = Filename;
       Config.OutputFilename = Filename;
-      DC.CopyConfigs.push_back(Config);
+      DC.CopyConfigs.push_back(ConfigMgr);
     }
   }
 

diff  --git a/llvm/tools/llvm-objcopy/ConfigManager.h b/llvm/tools/llvm-objcopy/ConfigManager.h
new file mode 100644
index 0000000000000..ec1d2f33f6a0e
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/ConfigManager.h
@@ -0,0 +1,84 @@
+//===- ConfigManager.h ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H
+
+#include "COFF/COFFConfig.h"
+#include "CommonConfig.h"
+#include "ELF/ELFConfig.h"
+#include "MachO/MachOConfig.h"
+#include "MultiFormatConfig.h"
+#include "wasm/WasmConfig.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+
+// ConfigManager keeps all configurations and prepare
+// format-specific options.
+struct ConfigManager : public MultiFormatConfig {
+  virtual ~ConfigManager() {}
+
+  const CommonConfig &getCommonConfig() const override { return Common; }
+  Expected<const ELFConfig &> getELFConfig() const override;
+  Expected<const COFFConfig &> getCOFFConfig() const override;
+  Expected<const MachOConfig &> getMachOConfig() const override;
+  Expected<const WasmConfig &> getWasmConfig() const override;
+
+  // String representation for lazy ELF options.
+  std::vector<StringRef> SymbolsToAdd;
+  Optional<StringRef> NewSymbolVisibility;
+
+  // All configs.
+  CommonConfig Common;
+  mutable Optional<ELFConfig> ELF;
+  COFFConfig COFF;
+  MachOConfig MachO;
+  WasmConfig Wasm;
+};
+
+// Configuration for the overall invocation of this tool. When invoked as
+// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
+// will contain one or more CopyConfigs.
+struct DriverConfig {
+  SmallVector<ConfigManager, 1> CopyConfigs;
+  BumpPtrAllocator Alloc;
+};
+
+// ParseObjcopyOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseObjcopyOptions will print the help messege and
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+                    llvm::function_ref<Error(Error)> ErrorCallback);
+
+// ParseInstallNameToolOptions returns the config and sets the input arguments.
+// If a help flag is set then ParseInstallNameToolOptions will print the help
+// messege and exit.
+Expected<DriverConfig>
+parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);
+
+// ParseBitcodeStripOptions returns the config and sets the input arguments.
+// If a help flag is set then ParseBitcodeStripOptions will print the help
+// messege and exit.
+Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr);
+
+// ParseStripOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseStripOptions will print the help messege and
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseStripOptions(ArrayRef<const char *> ArgsArr,
+                  llvm::function_ref<Error(Error)> ErrorCallback);
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H

diff  --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp b/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp
deleted file mode 100644
index 40993760add79..0000000000000
--- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-//===- ELFConfig.cpp ------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "CopyConfig.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace objcopy {
-namespace elf {
-
-static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
-                                                  uint8_t DefaultVisibility) {
-  // Parse value given with --add-symbol option and create the
-  // new symbol if possible. The value format for --add-symbol is:
-  //
-  // <name>=[<section>:]<value>[,<flags>]
-  //
-  // where:
-  // <name> - symbol name, can be empty string
-  // <section> - optional section name. If not given ABS symbol is created
-  // <value> - symbol value, can be decimal or hexadecimal number prefixed
-  //           with 0x.
-  // <flags> - optional flags affecting symbol type, binding or visibility:
-  //           The following are currently supported:
-  //
-  //           global, local, weak, default, hidden, file, section, object,
-  //           indirect-function.
-  //
-  //           The following flags are ignored and provided for GNU
-  //           compatibility only:
-  //
-  //           warning, debug, constructor, indirect, synthetic,
-  //           unique-object, before=<symbol>.
-  NewSymbolInfo SI;
-  StringRef Value;
-  std::tie(SI.SymbolName, Value) = FlagValue.split('=');
-  if (Value.empty())
-    return createStringError(
-        errc::invalid_argument,
-        "bad format for --add-symbol, missing '=' after '%s'",
-        SI.SymbolName.str().c_str());
-
-  if (Value.contains(':')) {
-    std::tie(SI.SectionName, Value) = Value.split(':');
-    if (SI.SectionName.empty() || Value.empty())
-      return createStringError(
-          errc::invalid_argument,
-          "bad format for --add-symbol, missing section name or symbol value");
-  }
-
-  SmallVector<StringRef, 6> Flags;
-  Value.split(Flags, ',');
-  if (Flags[0].getAsInteger(0, SI.Value))
-    return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
-                             Flags[0].str().c_str());
-
-  SI.Visibility = DefaultVisibility;
-
-  using Functor = std::function<void(void)>;
-  SmallVector<StringRef, 6> UnsupportedFlags;
-  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
-    static_cast<Functor>(
-        StringSwitch<Functor>(Flags[I])
-            .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
-            .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
-            .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
-            .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
-            .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
-            .CaseLower("protected",
-                       [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
-            .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
-            .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
-            .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
-            .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
-            .CaseLower("indirect-function",
-                       [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
-            .CaseLower("debug", [] {})
-            .CaseLower("constructor", [] {})
-            .CaseLower("warning", [] {})
-            .CaseLower("indirect", [] {})
-            .CaseLower("synthetic", [] {})
-            .CaseLower("unique-object", [] {})
-            .StartsWithLower("before", [] {})
-            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
-  if (!UnsupportedFlags.empty())
-    return createStringError(errc::invalid_argument,
-                             "unsupported flag%s for --add-symbol: '%s'",
-                             UnsupportedFlags.size() > 1 ? "s" : "",
-                             join(UnsupportedFlags, "', '").c_str());
-  return SI;
-}
-
-Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
-  ELFCopyConfig ELFConfig;
-  if (Config.NewSymbolVisibility) {
-    const uint8_t Invalid = 0xff;
-    ELFConfig.NewSymbolVisibility =
-        StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
-            .Case("default", ELF::STV_DEFAULT)
-            .Case("hidden", ELF::STV_HIDDEN)
-            .Case("internal", ELF::STV_INTERNAL)
-            .Case("protected", ELF::STV_PROTECTED)
-            .Default(Invalid);
-
-    if (ELFConfig.NewSymbolVisibility == Invalid)
-      return createStringError(errc::invalid_argument,
-                               "'%s' is not a valid symbol visibility",
-                               Config.NewSymbolVisibility->str().c_str());
-  }
-
-  for (StringRef Arg : Config.SymbolsToAdd) {
-    Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
-        Arg,
-        ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
-    if (!NSI)
-      return NSI.takeError();
-    ELFConfig.SymbolsToAdd.push_back(*NSI);
-  }
-
-  return ELFConfig;
-}
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm

diff  --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h
index 977efbc4166fa..cb170bd93a5c5 100644
--- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h
+++ b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h
@@ -6,20 +6,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_TOOLS_OBJCOPY_ELFCONFIG_H
-#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_ELF_ELFCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_ELF_ELFCONFIG_H
 
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/ELFTypes.h"
-#include "llvm/Support/Error.h"
 #include <vector>
 
 namespace llvm {
 namespace objcopy {
-struct CopyConfig;
-
-namespace elf {
 
 struct NewSymbolInfo {
   StringRef SymbolName;
@@ -30,15 +26,13 @@ struct NewSymbolInfo {
   uint8_t Visibility = ELF::STV_DEFAULT;
 };
 
-struct ELFCopyConfig {
+// ELF specific configuration for copying/stripping a single file.
+struct ELFConfig {
   Optional<uint8_t> NewSymbolVisibility;
   std::vector<NewSymbolInfo> SymbolsToAdd;
 };
 
-Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config);
-
-} // namespace elf
 } // namespace objcopy
 } // namespace llvm
 
-#endif
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_ELF_ELFCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
index d139814617b14..806cd73dae0d0 100644
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ELFObjcopy.h"
-#include "CopyConfig.h"
+#include "CommonConfig.h"
+#include "ELFConfig.h"
 #include "Object.h"
 #include "llvm-objcopy.h"
 #include "llvm/ADT/BitmaskEnum.h"
@@ -132,7 +133,7 @@ static ElfType getOutputElfType(const MachineInfo &MI) {
     return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
 }
 
-static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
+static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,
                                                Object &Obj, raw_ostream &Out,
                                                ElfType OutputElfType) {
   // Depending on the initial ELFT and OutputFormat we need a 
diff erent Writer.
@@ -153,7 +154,7 @@ static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
   llvm_unreachable("Invalid output format");
 }
 
-static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
+static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
                                             Object &Obj, raw_ostream &Out,
                                             ElfType OutputElfType) {
   switch (Config.OutputFormat) {
@@ -243,7 +244,7 @@ static bool isUnneededSymbol(const Symbol &Sym) {
          Sym.Type != STT_SECTION;
 }
 
-static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
+static Error updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) {
   // TODO: update or remove symbols only if there is an option that affects
   // them.
   if (!Obj.SymbolTable)
@@ -338,7 +339,7 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
   return Obj.removeSymbols(RemoveSymbolsPred);
 }
 
-static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
+static Error replaceAndRemoveSections(const CommonConfig &Config, Object &Obj) {
   SectionPred RemovePred = [](const SectionBase &) { return false; };
 
   // Removes:
@@ -506,11 +507,8 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
 // any previous removals. Lastly whether or not something is removed shouldn't
 // depend a) on the order the options occur in or b) on some opaque priority
 // system. The only priority is that keeps/copies overrule removes.
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
-  if (Config.StripSwiftSymbols || Config.KeepUndefined)
-    return createStringError(llvm::errc::invalid_argument,
-                             "option not supported by llvm-objcopy for ELF");
-
+static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
+                        Object &Obj) {
   if (Config.OutputArch) {
     Obj.Machine = Config.OutputArch.getValue().EMachine;
     Obj.OSABI = Config.OutputArch.getValue().OSABI;
@@ -635,11 +633,11 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
 
   // If the symbol table was previously removed, we need to create a new one
   // before adding new symbols.
-  if (!Obj.SymbolTable && !Config.ELF->SymbolsToAdd.empty())
+  if (!Obj.SymbolTable && !ELFConfig.SymbolsToAdd.empty())
     if (Error E = Obj.addNewSymbolTable())
       return E;
 
-  for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {
+  for (const NewSymbolInfo &SI : ELFConfig.SymbolsToAdd) {
     SectionBase *Sec = Obj.findSection(SI.SectionName);
     uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
     Obj.SymbolTable->addSymbol(
@@ -663,7 +661,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
   return Error::success();
 }
 
-static Error writeOutput(const CopyConfig &Config, Object &Obj,
+static Error writeOutput(const CommonConfig &Config, Object &Obj,
                          raw_ostream &Out, ElfType OutputElfType) {
   std::unique_ptr<Writer> Writer =
       createWriter(Config, Obj, Out, OutputElfType);
@@ -672,7 +670,8 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj,
   return Writer->write();
 }
 
-Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+Error executeObjcopyOnIHex(const CommonConfig &Config,
+                           const ELFConfig &ELFConfig, MemoryBuffer &In,
                            raw_ostream &Out) {
   IHexReader Reader(&In);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
@@ -681,15 +680,16 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
 
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
-  if (Error E = handleArgs(Config, **Obj))
+  if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+Error executeObjcopyOnRawBinary(const CommonConfig &Config,
+                                const ELFConfig &ELFConfig, MemoryBuffer &In,
                                 raw_ostream &Out) {
   uint8_t NewSymbolVisibility =
-      Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
+      ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
   BinaryReader Reader(&In, NewSymbolVisibility);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
   if (!Obj)
@@ -699,16 +699,17 @@ Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
   // (-B<arch>).
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
-  if (Error E = handleArgs(Config, **Obj))
+  if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config,
+                             const ELFConfig &ELFConfig,
                              object::ELFObjectFileBase &In, raw_ostream &Out) {
   ELFReader Reader(&In, Config.ExtractPartition);
   Expected<std::unique_ptr<Object>> Obj =
-      Reader.create(!Config.SymbolsToAdd.empty());
+      Reader.create(!ELFConfig.SymbolsToAdd.empty());
   if (!Obj)
     return Obj.takeError();
   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
@@ -716,7 +717,7 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,
       Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
                         : getOutputElfType(In);
 
-  if (Error E = handleArgs(Config, **Obj))
+  if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return createFileError(Config.InputFilename, std::move(E));
 
   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))

diff  --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
index 13aa905e0caac..852661e68f37b 100644
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
@@ -19,14 +19,18 @@ class ELFObjectFileBase;
 } // end namespace object
 
 namespace objcopy {
-struct CopyConfig;
+struct CommonConfig;
+struct ELFConfig;
 
 namespace elf {
-Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+Error executeObjcopyOnIHex(const CommonConfig &Config,
+                           const ELFConfig &ELFConfig, MemoryBuffer &In,
                            raw_ostream &Out);
-Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+Error executeObjcopyOnRawBinary(const CommonConfig &Config,
+                                const ELFConfig &ELFConfig, MemoryBuffer &In,
                                 raw_ostream &Out);
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config,
+                             const ELFConfig &ELFConfig,
                              object::ELFObjectFileBase &In, raw_ostream &Out);
 
 } // end namespace elf

diff  --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h
index 6848100d3e84f..6fd26afa3ca1e 100644
--- a/llvm/tools/llvm-objcopy/ELF/Object.h
+++ b/llvm/tools/llvm-objcopy/ELF/Object.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H
 #define LLVM_TOOLS_OBJCOPY_OBJECT_H
 
-#include "CopyConfig.h"
+#include "CommonConfig.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"

diff  --git a/llvm/tools/llvm-objcopy/MachO/MachOConfig.h b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h
new file mode 100644
index 0000000000000..7c5dbfde19a0b
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h
@@ -0,0 +1,21 @@
+//===- MachOConfig.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_MACHO_MACHOCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_MACHO_MACHOCONFIG_H
+
+namespace llvm {
+namespace objcopy {
+
+// Mach-O specific configuration for copying/stripping a single file.
+struct MachOConfig {};
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_MACHO_MACHOCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
index 90babd7ad3fcc..30c2a166b7be9 100644
--- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -7,10 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "MachOObjcopy.h"
-#include "../CopyConfig.h"
 #include "../llvm-objcopy.h"
+#include "CommonConfig.h"
 #include "MachOReader.h"
 #include "MachOWriter.h"
+#include "MultiFormatConfig.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/Object/ArchiveWriter.h"
 #include "llvm/Object/MachOUniversal.h"
@@ -48,7 +49,7 @@ static StringRef getPayloadString(const LoadCommand &LC) {
       .rtrim('\0');
 }
 
-static Error removeSections(const CopyConfig &Config, Object &Obj) {
+static Error removeSections(const CommonConfig &Config, Object &Obj) {
   SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
     return false;
   };
@@ -79,14 +80,14 @@ static Error removeSections(const CopyConfig &Config, Object &Obj) {
   return Obj.removeSections(RemovePred);
 }
 
-static void markSymbols(const CopyConfig &Config, Object &Obj) {
+static void markSymbols(const CommonConfig &, Object &Obj) {
   // Symbols referenced from the indirect symbol table must not be removed.
   for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
     if (ISE.Symbol)
       (*ISE.Symbol)->Referenced = true;
 }
 
-static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
+static void updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) {
   for (SymbolEntry &Sym : Obj.SymTable) {
     auto I = Config.SymbolsToRename.find(Sym.Name);
     if (I != Config.SymbolsToRename.end())
@@ -136,7 +137,7 @@ static LoadCommand buildRPathLoadCommand(StringRef Path) {
   return LC;
 }
 
-static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
+static Error processLoadCommands(const CommonConfig &Config, Object &Obj) {
   // Remove RPaths.
   DenseSet<StringRef> RPathsToRemove(Config.RPathsToRemove.begin(),
                                      Config.RPathsToRemove.end());
@@ -330,24 +331,7 @@ static Error isValidMachOCannonicalName(StringRef Name) {
   return Error::success();
 }
 
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
-  if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() ||
-      !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
-      !Config.KeepSection.empty() || Config.NewSymbolVisibility ||
-      !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
-      !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
-      !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
-      !Config.UnneededSymbolsToRemove.empty() ||
-      !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
-      Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
-      Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc ||
-      Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
-      Config.StripUnneeded || Config.DiscardMode == DiscardType::Locals ||
-      !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
-    return createStringError(llvm::errc::invalid_argument,
-                             "option not supported by llvm-objcopy for MachO");
-  }
-
+static Error handleArgs(const CommonConfig &Config, Object &Obj) {
   // Dump sections before add/remove for compatibility with GNU objcopy.
   for (StringRef Flag : Config.DumpSection) {
     StringRef SectionName;
@@ -387,7 +371,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
   return Error::success();
 }
 
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &,
                              object::MachOObjectFile &In, raw_ostream &Out) {
   MachOReader Reader(In);
   Expected<std::unique_ptr<Object>> O = Reader.create();
@@ -416,7 +400,7 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,
   return Writer.write();
 }
 
-Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
+Error executeObjcopyOnMachOUniversalBinary(const MultiFormatConfig &Config,
                                            const MachOUniversalBinary &In,
                                            raw_ostream &Out) {
   SmallVector<OwningBinary<Binary>, 2> Binaries;
@@ -431,7 +415,7 @@ Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
       Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
           writeArchiveToBuffer(*NewArchiveMembersOrErr,
                                (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(),
-                               Config.DeterministicArchives,
+                               Config.getCommonConfig().DeterministicArchives,
                                (*ArOrErr)->isThin());
       if (!OutputBufferOrErr)
         return OutputBufferOrErr.takeError();
@@ -455,18 +439,24 @@ Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile();
     if (!ObjOrErr) {
       consumeError(ObjOrErr.takeError());
-      return createStringError(std::errc::invalid_argument,
-                               "slice for '%s' of the universal Mach-O binary "
-                               "'%s' is not a Mach-O object or an archive",
-                               O.getArchFlagName().c_str(),
-                               Config.InputFilename.str().c_str());
+      return createStringError(
+          std::errc::invalid_argument,
+          "slice for '%s' of the universal Mach-O binary "
+          "'%s' is not a Mach-O object or an archive",
+          O.getArchFlagName().c_str(),
+          Config.getCommonConfig().InputFilename.str().c_str());
     }
     std::string ArchFlagName = O.getArchFlagName();
 
     SmallVector<char, 0> Buffer;
     raw_svector_ostream MemStream(Buffer);
 
-    if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream))
+    Expected<const MachOConfig &> MachO = Config.getMachOConfig();
+    if (!MachO)
+      return MachO.takeError();
+
+    if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
+                                         **ObjOrErr, MemStream))
       return E;
 
     std::unique_ptr<MemoryBuffer> MB =

diff  --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
index 424c68771b777..e30940a8d6eba 100644
--- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
+++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
@@ -19,15 +19,16 @@ class MachOUniversalBinary;
 } // end namespace object
 
 namespace objcopy {
-struct CopyConfig;
-class Buffer;
+struct CommonConfig;
+struct MachOConfig;
+class MultiFormatConfig;
 
 namespace macho {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &,
                              object::MachOObjectFile &In, raw_ostream &Out);
 
 Error executeObjcopyOnMachOUniversalBinary(
-    CopyConfig &Config, const object::MachOUniversalBinary &In,
+    const MultiFormatConfig &Config, const object::MachOUniversalBinary &In,
     raw_ostream &Out);
 
 } // end namespace macho

diff  --git a/llvm/tools/llvm-objcopy/MultiFormatConfig.h b/llvm/tools/llvm-objcopy/MultiFormatConfig.h
new file mode 100644
index 0000000000000..31d9883d6d3a3
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/MultiFormatConfig.h
@@ -0,0 +1,37 @@
+//===- MultiFormatConfig.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+
+struct CommonConfig;
+struct ELFConfig;
+struct COFFConfig;
+struct MachOConfig;
+struct WasmConfig;
+
+class MultiFormatConfig {
+public:
+  virtual ~MultiFormatConfig() {}
+
+  virtual const CommonConfig &getCommonConfig() const = 0;
+  virtual Expected<const ELFConfig &> getELFConfig() const = 0;
+  virtual Expected<const COFFConfig &> getCOFFConfig() const = 0;
+  virtual Expected<const MachOConfig &> getMachOConfig() const = 0;
+  virtual Expected<const WasmConfig &> getWasmConfig() const = 0;
+};
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index d3cc94782bedd..af1e903c207fe 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -7,10 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm-objcopy.h"
+#include "COFF/COFFConfig.h"
 #include "COFF/COFFObjcopy.h"
-#include "CopyConfig.h"
+#include "CommonConfig.h"
+#include "ConfigManager.h"
+#include "ELF/ELFConfig.h"
 #include "ELF/ELFObjcopy.h"
+#include "MachO/MachOConfig.h"
 #include "MachO/MachOObjcopy.h"
+#include "wasm/WasmConfig.h"
 #include "wasm/WasmObjcopy.h"
 
 #include "llvm/ADT/STLExtras.h"
@@ -133,18 +138,22 @@ static Error deepWriteArchive(StringRef ArcName,
 
 /// The function executeObjcopyOnIHex does the dispatch based on the format
 /// of the output specified by the command line options.
-static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
+static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In,
                                   raw_ostream &Out) {
   // TODO: support output formats other than ELF.
-  if (Error E = Config.parseELFConfig())
-    return E;
-  return elf::executeObjcopyOnIHex(Config, In, Out);
+  Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig();
+  if (!ELFConfig)
+    return ELFConfig.takeError();
+
+  return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In,
+                                   Out);
 }
 
 /// The function executeObjcopyOnRawBinary does the dispatch based on the format
 /// of the output specified by the command line options.
-static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
-                                       raw_ostream &Out) {
+static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr,
+                                       MemoryBuffer &In, raw_ostream &Out) {
+  const CommonConfig &Config = ConfigMgr.getCommonConfig();
   switch (Config.OutputFormat) {
   case FileFormat::ELF:
   // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
@@ -153,9 +162,11 @@ static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
   case FileFormat::Binary:
   case FileFormat::IHex:
   case FileFormat::Unspecified:
-    if (Error E = Config.parseELFConfig())
-      return E;
-    return elf::executeObjcopyOnRawBinary(Config, In, Out);
+    Expected<const ELFConfig &> ELFConfig = ConfigMgr.getELFConfig();
+    if (!ELFConfig)
+      return ELFConfig.takeError();
+
+    return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out);
   }
 
   llvm_unreachable("unsupported output format");
@@ -163,23 +174,41 @@ static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
 
 /// The function executeObjcopyOnBinary does the dispatch based on the format
 /// of the input binary (ELF, MachO or COFF).
-static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In,
-                                    raw_ostream &Out) {
+static Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
+                                    object::Binary &In, raw_ostream &Out) {
   if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
-    if (Error E = Config.parseELFConfig())
-      return E;
-    return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
-  } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
-    return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
-  else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))
-    return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out);
-  else if (auto *MachOUniversalBinary =
-               dyn_cast<object::MachOUniversalBinary>(&In))
+    Expected<const ELFConfig &> ELFConfig = Config.getELFConfig();
+    if (!ELFConfig)
+      return ELFConfig.takeError();
+
+    return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig,
+                                       *ELFBinary, Out);
+  } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) {
+    Expected<const COFFConfig &> COFFConfig = Config.getCOFFConfig();
+    if (!COFFConfig)
+      return COFFConfig.takeError();
+
+    return coff::executeObjcopyOnBinary(Config.getCommonConfig(), *COFFConfig,
+                                        *COFFBinary, Out);
+  } else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In)) {
+    Expected<const MachOConfig &> MachOConfig = Config.getMachOConfig();
+    if (!MachOConfig)
+      return MachOConfig.takeError();
+
+    return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig,
+                                         *MachOBinary, Out);
+  } else if (auto *MachOUniversalBinary =
+                 dyn_cast<object::MachOUniversalBinary>(&In)) {
     return macho::executeObjcopyOnMachOUniversalBinary(
         Config, *MachOUniversalBinary, Out);
-  else if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In))
-    return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out);
-  else
+  } else if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In)) {
+    Expected<const WasmConfig &> WasmConfig = Config.getWasmConfig();
+    if (!WasmConfig)
+      return WasmConfig.takeError();
+
+    return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(),
+                                                 *WasmConfig, *WasmBinary, Out);
+  } else
     return createStringError(object_error::invalid_file_type,
                              "unsupported object file format");
 }
@@ -188,7 +217,7 @@ namespace llvm {
 namespace objcopy {
 
 Expected<std::vector<NewArchiveMember>>
-createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) {
+createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
   std::vector<NewArchiveMember> NewArchiveMembers;
   Error Err = Error::success();
   for (const Archive::Child &Child : Ar.children(Err)) {
@@ -207,8 +236,8 @@ createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) {
     if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
       return std::move(E);
 
-    Expected<NewArchiveMember> Member =
-        NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
+    Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember(
+        Child, Config.getCommonConfig().DeterministicArchives);
     if (!Member)
       return createFileError(Ar.getFileName(), Member.takeError());
 
@@ -218,19 +247,21 @@ createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) {
     NewArchiveMembers.push_back(std::move(*Member));
   }
   if (Err)
-    return createFileError(Config.InputFilename, std::move(Err));
+    return createFileError(Config.getCommonConfig().InputFilename,
+                           std::move(Err));
   return std::move(NewArchiveMembers);
 }
 
 } // end namespace objcopy
 } // end namespace llvm
 
-static Error executeObjcopyOnArchive(CopyConfig &Config,
+static Error executeObjcopyOnArchive(const ConfigManager &ConfigMgr,
                                      const object::Archive &Ar) {
   Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
-      createNewArchiveMembers(Config, Ar);
+      createNewArchiveMembers(ConfigMgr, Ar);
   if (!NewArchiveMembersOrErr)
     return NewArchiveMembersOrErr.takeError();
+  const CommonConfig &Config = ConfigMgr.getCommonConfig();
   return deepWriteArchive(Config.OutputFilename, *NewArchiveMembersOrErr,
                           Ar.hasSymbolTable(), Ar.kind(),
                           Config.DeterministicArchives, Ar.isThin());
@@ -238,8 +269,9 @@ static Error executeObjcopyOnArchive(CopyConfig &Config,
 
 static Error restoreStatOnFile(StringRef Filename,
                                const sys::fs::file_status &Stat,
-                               const CopyConfig &Config) {
+                               const ConfigManager &ConfigMgr) {
   int FD;
+  const CommonConfig &Config = ConfigMgr.getCommonConfig();
 
   // Writing to stdout should not be treated as an error here, just
   // do not set access/modification times or permissions.
@@ -285,7 +317,9 @@ static Error restoreStatOnFile(StringRef Filename,
 /// The function executeObjcopy does the higher level dispatch based on the type
 /// of input (raw binary, archive or single object file) and takes care of the
 /// format-agnostic modifications, i.e. preserving dates.
-static Error executeObjcopy(CopyConfig &Config) {
+static Error executeObjcopy(ConfigManager &ConfigMgr) {
+  CommonConfig &Config = ConfigMgr.Common;
+
   sys::fs::file_status Stat;
   if (Config.InputFilename != "-") {
     if (auto EC = sys::fs::status(Config.InputFilename, Stat))
@@ -310,12 +344,13 @@ static Error executeObjcopy(CopyConfig &Config) {
     if (Config.InputFormat == FileFormat::Binary)
       ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {
         // Handle FileFormat::Binary.
-        return executeObjcopyOnRawBinary(Config, *MemoryBufferHolder, OutFile);
+        return executeObjcopyOnRawBinary(ConfigMgr, *MemoryBufferHolder,
+                                         OutFile);
       };
     else
       ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {
         // Handle FileFormat::IHex.
-        return executeObjcopyOnIHex(Config, *MemoryBufferHolder, OutFile);
+        return executeObjcopyOnIHex(ConfigMgr, *MemoryBufferHolder, OutFile);
       };
   } else {
     Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
@@ -326,12 +361,12 @@ static Error executeObjcopy(CopyConfig &Config) {
 
     if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) {
       // Handle Archive.
-      if (Error E = executeObjcopyOnArchive(Config, *Ar))
+      if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar))
         return E;
     } else {
       // Handle llvm::object::Binary.
       ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {
-        return executeObjcopyOnBinary(Config, *BinaryHolder.getBinary(),
+        return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(),
                                       OutFile);
       };
     }
@@ -360,12 +395,12 @@ static Error executeObjcopy(CopyConfig &Config) {
     }
   }
 
-  if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, Config))
+  if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, ConfigMgr))
     return E;
 
   if (!Config.SplitDWO.empty()) {
     Stat.permissions(static_cast<sys::fs::perms>(0666));
-    if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, Config))
+    if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, ConfigMgr))
       return E;
   }
 
@@ -401,8 +436,8 @@ int main(int argc, char **argv) {
                           WithColor::error(errs(), ToolName));
     return 1;
   }
-  for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {
-    if (Error E = executeObjcopy(CopyConfig)) {
+  for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) {
+    if (Error E = executeObjcopy(ConfigMgr)) {
       logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
       return 1;
     }

diff  --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h
index 64b554f5c5aa3..182c95dc64c8c 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.h
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h
@@ -23,9 +23,10 @@ class Archive;
 } // end namespace object
 
 namespace objcopy {
-struct CopyConfig;
+class MultiFormatConfig;
 Expected<std::vector<NewArchiveMember>>
-createNewArchiveMembers(CopyConfig &Config, const object::Archive &Ar);
+createNewArchiveMembers(const MultiFormatConfig &Config,
+                        const object::Archive &Ar);
 
 } // end namespace objcopy
 } // end namespace llvm

diff  --git a/llvm/tools/llvm-objcopy/wasm/WasmConfig.h b/llvm/tools/llvm-objcopy/wasm/WasmConfig.h
new file mode 100644
index 0000000000000..4e40926ae4530
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/wasm/WasmConfig.h
@@ -0,0 +1,21 @@
+//===- WasmConfig.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMCONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMCONFIG_H
+
+namespace llvm {
+namespace objcopy {
+
+// Wasm specific configuration for copying/stripping a single file.
+struct WasmConfig {};
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMCONFIG_H

diff  --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
index fa88bee424b8b..75c4749167891 100644
--- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "WasmObjcopy.h"
-#include "CopyConfig.h"
+#include "CommonConfig.h"
 #include "Object.h"
 #include "Reader.h"
 #include "Writer.h"
@@ -39,7 +39,7 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
   return createStringError(errc::invalid_argument, "section '%s' not found",
                            SecName.str().c_str());
 }
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+static Error handleArgs(const CommonConfig &Config, Object &Obj) {
   // Only support AddSection, DumpSection, RemoveSection for now.
   for (StringRef Flag : Config.DumpSection) {
     StringRef SecName;
@@ -72,26 +72,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
     Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
   }
 
-  if (!Config.AddGnuDebugLink.empty() || Config.ExtractPartition ||
-      !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
-      !Config.AllocSectionsPrefix.empty() ||
-      Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility ||
-      !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() ||
-      !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
-      !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
-      !Config.SymbolsToRemove.empty() ||
-      !Config.UnneededSymbolsToRemove.empty() ||
-      !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
-      !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() ||
-      !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty()) {
-    return createStringError(
-        llvm::errc::invalid_argument,
-        "only add-section, dump-section, and remove-section are supported");
-  }
   return Error::success();
 }
 
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config, const WasmConfig &,
                              object::WasmObjectFile &In, raw_ostream &Out) {
   Reader TheReader(In);
   Expected<std::unique_ptr<Object>> ObjOrErr = TheReader.create();

diff  --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h
index 05a84d7ceb392..28268e38c5849 100644
--- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h
+++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h
@@ -18,10 +18,11 @@ class WasmObjectFile;
 } // end namespace object
 
 namespace objcopy {
-struct CopyConfig;
+struct CommonConfig;
+struct WasmConfig;
 
 namespace wasm {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
+Error executeObjcopyOnBinary(const CommonConfig &Config, const WasmConfig &,
                              object::WasmObjectFile &In, raw_ostream &Out);
 
 } // end namespace wasm


        


More information about the llvm-commits mailing list