diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -22,13 +22,12 @@ 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/COFFObjcopy.h b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h @@ -18,10 +18,12 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct COFFConfig; namespace coff { -Error executeObjcopyOnBinary(const CopyConfig &Config, + +Error executeObjcopyOnBinary(const CommonConfig &CommonCfg, const COFFConfig &, object::COFFObjectFile &In, raw_ostream &Out); } // end namespace coff diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp --- 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,28 +131,29 @@ Sec.Header.Characteristics = NewCharacteristics; } -static Error handleArgs(const CopyConfig &Config, Object &Obj) { +static Error handleArgs(const CommonConfig &CommonCfg, Object &Obj) { // Perform the actual section removals. - Obj.removeSections([&Config](const Section &Sec) { + Obj.removeSections([&CommonCfg](const Section &Sec) { // Contrary to --only-keep-debug, --only-section fully removes sections that // aren't mentioned. - if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name)) + if (!CommonCfg.OnlySection.empty() && + !CommonCfg.OnlySection.matches(Sec.Name)) return true; - if (Config.StripDebug || Config.StripAll || Config.StripAllGNU || - Config.DiscardMode == DiscardType::All || Config.StripUnneeded) { + if (CommonCfg.StripDebug || CommonCfg.StripAll || CommonCfg.StripAllGNU || + CommonCfg.DiscardMode == DiscardType::All || CommonCfg.StripUnneeded) { if (isDebugSection(Sec) && (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) return true; } - if (Config.ToRemove.matches(Sec.Name)) + if (CommonCfg.ToRemove.matches(Sec.Name)) return true; return false; }); - if (Config.OnlyKeepDebug) { + if (CommonCfg.OnlyKeepDebug) { // For --only-keep-debug, we keep all other sections, but remove their // content. The VirtualSize field in the section header is kept intact. Obj.truncateSections([](const Section &Sec) { @@ -162,34 +164,34 @@ } // StripAll removes all symbols and thus also removes all relocations. - if (Config.StripAll || Config.StripAllGNU) + if (CommonCfg.StripAll || CommonCfg.StripAllGNU) for (Section &Sec : Obj.getMutableSections()) Sec.Relocs.clear(); // If we need to do per-symbol removals, initialize the Referenced field. - if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All || - !Config.SymbolsToRemove.empty()) + if (CommonCfg.StripUnneeded || CommonCfg.DiscardMode == DiscardType::All || + !CommonCfg.SymbolsToRemove.empty()) if (Error E = Obj.markSymbols()) return E; for (Symbol &Sym : Obj.getMutableSymbols()) { - auto I = Config.SymbolsToRename.find(Sym.Name); - if (I != Config.SymbolsToRename.end()) + auto I = CommonCfg.SymbolsToRename.find(Sym.Name); + if (I != CommonCfg.SymbolsToRename.end()) Sym.Name = I->getValue(); } auto ToRemove = [&](const Symbol &Sym) -> Expected { // For StripAll, all relocations have been stripped and we remove all // symbols. - if (Config.StripAll || Config.StripAllGNU) + if (CommonCfg.StripAll || CommonCfg.StripAllGNU) return true; - if (Config.SymbolsToRemove.matches(Sym.Name)) { + if (CommonCfg.SymbolsToRemove.matches(Sym.Name)) { // Explicitly removing a referenced symbol is an error. if (Sym.Referenced) return createStringError( llvm::errc::invalid_argument, - "'" + Config.OutputFilename + "': not stripping symbol '" + + "'" + CommonCfg.OutputFilename + "': not stripping symbol '" + Sym.Name.str() + "' because it is named in a relocation"); return true; } @@ -201,14 +203,14 @@ // local symbol instead of removing all of such. if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC || Sym.Sym.SectionNumber == 0) - if (Config.StripUnneeded || - Config.UnneededSymbolsToRemove.matches(Sym.Name)) + if (CommonCfg.StripUnneeded || + CommonCfg.UnneededSymbolsToRemove.matches(Sym.Name)) return true; // GNU objcopy keeps referenced local symbols and external symbols // if --discard-all is set, similar to what --strip-unneeded does, // but undefined local symbols are kept when --discard-all is set. - if (Config.DiscardMode == DiscardType::All && + if (CommonCfg.DiscardMode == DiscardType::All && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC && Sym.Sym.SectionNumber != 0) return true; @@ -221,14 +223,14 @@ if (Error Err = Obj.removeSymbols(ToRemove)) return Err; - if (!Config.SetSectionFlags.empty()) + if (!CommonCfg.SetSectionFlags.empty()) for (Section &Sec : Obj.getMutableSections()) { - const auto It = Config.SetSectionFlags.find(Sec.Name); - if (It != Config.SetSectionFlags.end()) + const auto It = CommonCfg.SetSectionFlags.find(Sec.Name); + if (It != CommonCfg.SetSectionFlags.end()) setSectionFlags(Sec, It->second.NewFlags); } - for (const auto &Flag : Config.AddSection) { + for (const auto &Flag : CommonCfg.AddSection) { StringRef SecName, FileName; std::tie(SecName, FileName) = Flag.split("="); @@ -244,43 +246,26 @@ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES); } - if (!Config.AddGnuDebugLink.empty()) - if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) + if (!CommonCfg.AddGnuDebugLink.empty()) + if (Error E = addGnuDebugLink(Obj, CommonCfg.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 &CommonCfg, const COFFConfig &, + COFFObjectFile &In, raw_ostream &Out) { COFFReader Reader(In); Expected> ObjOrErr = Reader.create(); if (!ObjOrErr) - return createFileError(Config.InputFilename, ObjOrErr.takeError()); + return createFileError(CommonCfg.InputFilename, ObjOrErr.takeError()); Object *Obj = ObjOrErr->get(); assert(Obj && "Unable to deserialize COFF object"); - if (Error E = handleArgs(Config, *Obj)) - return createFileError(Config.InputFilename, std::move(E)); + if (Error E = handleArgs(CommonCfg, *Obj)) + return createFileError(CommonCfg.InputFilename, std::move(E)); COFFWriter Writer(*Obj, Out); if (Error E = Writer.write()) - return createFileError(Config.OutputFilename, std::move(E)); + return createFileError(CommonCfg.OutputFilename, std::move(E)); return Error::success(); } diff --git a/llvm/tools/llvm-objcopy/COFFConfig.h b/llvm/tools/llvm-objcopy/COFFConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/COFFConfig.h @@ -0,0 +1,21 @@ +//===- COFFConfig.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_COFFCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_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_COFFCONFIG_H diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CommonConfig.h rename from llvm/tools/llvm-objcopy/CopyConfig.h rename to llvm/tools/llvm-objcopy/CommonConfig.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CommonConfig.h @@ -1,4 +1,4 @@ -//===- CopyConfig.h -------------------------------------------------------===// +//===- CommonConfig.h -----------------------------------------------------===// // // 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 @@ class NameOrPattern { StringRef Name; - // Regex is shared between multiple CopyConfig instances. + // Regex is shared between multiple CommonConfig instances. std::shared_ptr R; std::shared_ptr G; bool IsPositiveMatch = true; @@ -146,10 +142,7 @@ }; // Configuration for copying/stripping a single file. -struct CopyConfig { - // Format-specific options to be initialized lazily when needed. - Optional ELF; - +struct CommonConfig { // Main input/output options StringRef InputFilename; FileFormat InputFormat = FileFormat::Unspecified; @@ -168,12 +161,10 @@ StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; - Optional NewSymbolVisibility; // Repeated options std::vector AddSection; std::vector DumpSection; - std::vector SymbolsToAdd; std::vector RPathToAdd; std::vector RPathToPrepend; DenseMap RPathsToUpdate; @@ -233,55 +224,9 @@ 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 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 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 -parseObjcopyOptions(ArrayRef ArgsArr, - llvm::function_ref 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 -parseInstallNameToolOptions(ArrayRef 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 parseBitcodeStripOptions(ArrayRef 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 -parseStripOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback); } // namespace objcopy } // namespace llvm -#endif +#endif // LLVM_TOOLS_LLVM_OBJCOPY_COMMONCONFIG_H diff --git a/llvm/tools/llvm-objcopy/ConfigManager.h b/llvm/tools/llvm-objcopy/ConfigManager.h new file mode 100644 --- /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 "COFFConfig.h" +#include "CommonConfig.h" +#include "ElfConfig.h" +#include "MachOConfig.h" +#include "MultiFormatConfig.h" +#include "WasmConfig.h" +#include "llvm/Support/Allocator.h" +#include + +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 getElfConfig() const override; + Expected getCOFFConfig() const override; + Expected getMachOConfig() const override; + Expected getWasmConfig() const override; + + // String representation for lazy Elf options. + std::vector SymbolsToAdd; + Optional NewSymbolVisibility; + + // All configs. + CommonConfig Common; + mutable Optional 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 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 +parseObjcopyOptions(ArrayRef ArgsArr, + llvm::function_ref 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 +parseInstallNameToolOptions(ArrayRef 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 parseBitcodeStripOptions(ArrayRef 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 +parseStripOptions(ArrayRef ArgsArr, + llvm::function_ref ErrorCallback); +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_CONFIGMANAGER_H diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp rename from llvm/tools/llvm-objcopy/CopyConfig.cpp rename to llvm/tools/llvm-objcopy/ConfigManager.cpp --- 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 @@ -466,6 +466,190 @@ OS << "\nPass @FILE as argument to read options from FILE.\n"; } +static Expected 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: + // + // =[
:][,] + // + // where: + // - symbol name, can be empty string + //
- optional section name. If not given ABS symbol is created + // - symbol value, can be decimal or hexadecimal number prefixed + // with 0x. + // - 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=. + 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 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; + SmallVector UnsupportedFlags; + for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) + static_cast( + StringSwitch(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 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(*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 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 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 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 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. @@ -510,9 +694,10 @@ return createStringError(errc::invalid_argument, "too many positional arguments"); - CopyConfig Config; - Config.InputFilename = Positional[0]; - Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; + ConfigManager ConfigMgr; + CommonConfig &CommonCfg = ConfigMgr.Common; + CommonCfg.InputFilename = Positional[0]; + CommonCfg.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; if (InputArgs.hasArg(OBJCOPY_target) && (InputArgs.hasArg(OBJCOPY_input_target) || InputArgs.hasArg(OBJCOPY_output_target))) @@ -544,44 +729,44 @@ // FIXME: Currently, we ignore the target for non-binary/ihex formats // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the // format by llvm::object::createBinary regardless of the option value. - Config.InputFormat = StringSwitch(InputFormat) - .Case("binary", FileFormat::Binary) - .Case("ihex", FileFormat::IHex) - .Default(FileFormat::Unspecified); + CommonCfg.InputFormat = StringSwitch(InputFormat) + .Case("binary", FileFormat::Binary) + .Case("ihex", FileFormat::IHex) + .Default(FileFormat::Unspecified); if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) - Config.NewSymbolVisibility = + ConfigMgr.NewSymbolVisibility = InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); - Config.OutputFormat = StringSwitch(OutputFormat) - .Case("binary", FileFormat::Binary) - .Case("ihex", FileFormat::IHex) - .Default(FileFormat::Unspecified); - if (Config.OutputFormat == FileFormat::Unspecified) { + CommonCfg.OutputFormat = StringSwitch(OutputFormat) + .Case("binary", FileFormat::Binary) + .Case("ihex", FileFormat::IHex) + .Default(FileFormat::Unspecified); + if (CommonCfg.OutputFormat == FileFormat::Unspecified) { if (OutputFormat.empty()) { - Config.OutputFormat = Config.InputFormat; + CommonCfg.OutputFormat = CommonCfg.InputFormat; } else { Expected Target = getOutputTargetInfoByTargetName(OutputFormat); if (!Target) return Target.takeError(); - Config.OutputFormat = Target->Format; - Config.OutputArch = Target->Machine; + CommonCfg.OutputFormat = Target->Format; + CommonCfg.OutputArch = Target->Machine; } } if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, OBJCOPY_compress_debug_sections_eq)) { - Config.CompressionType = DebugCompressionType::Z; + CommonCfg.CompressionType = DebugCompressionType::Z; if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) { - Config.CompressionType = + CommonCfg.CompressionType = StringSwitch( InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)) .Case("zlib-gnu", DebugCompressionType::GNU) .Case("zlib", DebugCompressionType::Z) .Default(DebugCompressionType::None); - if (Config.CompressionType == DebugCompressionType::None) + if (CommonCfg.CompressionType == DebugCompressionType::None) return createStringError( errc::invalid_argument, "invalid or unsupported --compress-debug-sections format: %s", @@ -595,40 +780,41 @@ "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); } - Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); + CommonCfg.AddGnuDebugLink = + InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); // The gnu_debuglink's target is expected to not change or else its CRC would // become invalidated and get rejected. We can avoid recalculating the // checksum for every target file inside an archive by precomputing the CRC // here. This prevents a significant amount of I/O. - if (!Config.AddGnuDebugLink.empty()) { - auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink); + if (!CommonCfg.AddGnuDebugLink.empty()) { + auto DebugOrErr = MemoryBuffer::getFile(CommonCfg.AddGnuDebugLink); if (!DebugOrErr) - return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError()); + return createFileError(CommonCfg.AddGnuDebugLink, DebugOrErr.getError()); auto Debug = std::move(*DebugOrErr); - Config.GnuDebugLinkCRC32 = + CommonCfg.GnuDebugLinkCRC32 = llvm::crc32(arrayRefFromStringRef(Debug->getBuffer())); } - Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); - Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); - Config.AllocSectionsPrefix = + CommonCfg.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); + CommonCfg.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); + CommonCfg.AllocSectionsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections); if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition)) - Config.ExtractPartition = Arg->getValue(); + CommonCfg.ExtractPartition = Arg->getValue(); for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { if (!StringRef(Arg->getValue()).contains('=')) return createStringError(errc::invalid_argument, "bad format for --redefine-sym"); auto Old2New = StringRef(Arg->getValue()).split('='); - if (!Config.SymbolsToRename.insert(Old2New).second) + if (!CommonCfg.SymbolsToRename.insert(Old2New).second) return createStringError(errc::invalid_argument, "multiple redefinition of symbol '%s'", Old2New.first.str().c_str()); } for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols)) - if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc, - Arg->getValue())) + if (Error E = addSymbolsToRenameFromFile(CommonCfg.SymbolsToRename, + DC.Alloc, Arg->getValue())) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { @@ -636,7 +822,7 @@ parseRenameSectionValue(StringRef(Arg->getValue())); if (!SR) return SR.takeError(); - if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) + if (!CommonCfg.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) return createStringError(errc::invalid_argument, "multiple renames of section '%s'", SR->OriginalName.str().c_str()); @@ -646,14 +832,14 @@ parseSetSectionAlignment(Arg->getValue()); if (!NameAndAlign) return NameAndAlign.takeError(); - Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; + CommonCfg.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; } for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) { Expected SFU = parseSetSectionFlagValue(Arg->getValue()); if (!SFU) return SFU.takeError(); - if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second) + if (!CommonCfg.SetSectionFlags.try_emplace(SFU->Name, *SFU).second) return createStringError( errc::invalid_argument, "--set-section-flags set multiple times for section '%s'", @@ -661,15 +847,15 @@ } // Prohibit combinations of --set-section-flags when the section name is used // by --rename-section, either as a source or a destination. - for (const auto &E : Config.SectionsToRename) { + for (const auto &E : CommonCfg.SectionsToRename) { const SectionRename &SR = E.second; - if (Config.SetSectionFlags.count(SR.OriginalName)) + if (CommonCfg.SetSectionFlags.count(SR.OriginalName)) return createStringError( errc::invalid_argument, "--set-section-flags=%s conflicts with --rename-section=%s=%s", SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(), SR.NewName.str().c_str()); - if (Config.SetSectionFlags.count(SR.NewName)) + if (CommonCfg.SetSectionFlags.count(SR.NewName)) return createStringError( errc::invalid_argument, "--set-section-flags=%s conflicts with --rename-section=%s=%s", @@ -678,15 +864,15 @@ } for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) - if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.ToRemove.addMatcher(NameOrPattern::create( Arg->getValue(), SectionMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section)) - if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.KeepSection.addMatcher(NameOrPattern::create( Arg->getValue(), SectionMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_only_section)) - if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.OnlySection.addMatcher(NameOrPattern::create( Arg->getValue(), SectionMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) { @@ -698,113 +884,114 @@ return createStringError( errc::invalid_argument, "bad format for --add-section: missing file name"); - Config.AddSection.push_back(ArgValue); + CommonCfg.AddSection.push_back(ArgValue); } for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section)) - Config.DumpSection.push_back(Arg->getValue()); - Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); - Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); - Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); - Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); - Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); - Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); - Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); - Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); - Config.ExtractMainPartition = + CommonCfg.DumpSection.push_back(Arg->getValue()); + CommonCfg.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); + CommonCfg.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); + CommonCfg.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); + CommonCfg.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); + CommonCfg.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); + CommonCfg.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); + CommonCfg.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); + CommonCfg.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); + CommonCfg.ExtractMainPartition = InputArgs.hasArg(OBJCOPY_extract_main_partition); - Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); - Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); + CommonCfg.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); + CommonCfg.Weaken = InputArgs.hasArg(OBJCOPY_weaken); if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) - Config.DiscardMode = + CommonCfg.DiscardMode = InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals) ? DiscardType::All : DiscardType::Locals; - Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); - Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); - Config.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined); - Config.DecompressDebugSections = + CommonCfg.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); + CommonCfg.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); + CommonCfg.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined); + CommonCfg.DecompressDebugSections = InputArgs.hasArg(OBJCOPY_decompress_debug_sections); - if (Config.DiscardMode == DiscardType::All) { - Config.StripDebug = true; - Config.KeepFileSymbols = true; + if (CommonCfg.DiscardMode == DiscardType::All) { + CommonCfg.StripDebug = true; + CommonCfg.KeepFileSymbols = true; } for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) - if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.SymbolsToLocalize.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToLocalize, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) - if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( - Arg->getValue(), SymbolMatchStyle, ErrorCallback))) + if (Error E = + CommonCfg.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( + Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToKeepGlobal, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) - if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.SymbolsToGlobalize.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToGlobalize, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) - if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.SymbolsToWeaken.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToWeaken, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) - if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.SymbolsToRemove.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToRemove, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol)) if (Error E = - Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create( + CommonCfg.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols)) - if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, - Arg->getValue(), SymbolMatchStyle, - ErrorCallback)) + if (Error E = addSymbolsFromFile(CommonCfg.UnneededSymbolsToRemove, + DC.Alloc, Arg->getValue(), + SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) - if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( + if (Error E = CommonCfg.SymbolsToKeep.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols)) - if (Error E = - addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), - SymbolMatchStyle, ErrorCallback)) + if (Error E = addSymbolsFromFile(CommonCfg.SymbolsToKeep, DC.Alloc, + Arg->getValue(), 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); + CommonCfg.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); - Config.DeterministicArchives = InputArgs.hasFlag( + CommonCfg.DeterministicArchives = InputArgs.hasFlag( OBJCOPY_enable_deterministic_archives, OBJCOPY_disable_deterministic_archives, /*default=*/true); - Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); + CommonCfg.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); - if (Config.PreserveDates && - (Config.OutputFilename == "-" || Config.InputFilename == "-")) + if (CommonCfg.PreserveDates && + (CommonCfg.OutputFilename == "-" || CommonCfg.InputFilename == "-")) return createStringError(errc::invalid_argument, "--preserve-dates requires a file"); @@ -815,39 +1002,39 @@ return createStringError( EAddr.getError(), "bad entry point address: '%s'", Arg->getValue()); - Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; + CommonCfg.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; } else if (Arg->getOption().matches(OBJCOPY_change_start)) { auto EIncr = getAsInteger(Arg->getValue()); if (!EIncr) return createStringError(EIncr.getError(), "bad entry point increment: '%s'", Arg->getValue()); - auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr) - : [](uint64_t A) { return A; }; - Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) { + auto Expr = CommonCfg.EntryExpr ? std::move(CommonCfg.EntryExpr) + : [](uint64_t A) { return A; }; + CommonCfg.EntryExpr = [Expr, EIncr](uint64_t EAddr) { return Expr(EAddr) + *EIncr; }; } - if (Config.DecompressDebugSections && - Config.CompressionType != DebugCompressionType::None) { + if (CommonCfg.DecompressDebugSections && + CommonCfg.CompressionType != DebugCompressionType::None) { return createStringError( errc::invalid_argument, "cannot specify both --compress-debug-sections and " "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !zlib::isAvailable()) + if (CommonCfg.DecompressDebugSections && !zlib::isAvailable()) return createStringError( errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); - if (Config.ExtractPartition && Config.ExtractMainPartition) + if (CommonCfg.ExtractPartition && CommonCfg.ExtractMainPartition) return createStringError(errc::invalid_argument, "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); } @@ -857,7 +1044,7 @@ Expected parseInstallNameToolOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ConfigManager Config; InstallNameToolOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -888,27 +1075,27 @@ } for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) - Config.RPathToAdd.push_back(Arg->getValue()); + Config.Common.RPathToAdd.push_back(Arg->getValue()); for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath)) - Config.RPathToPrepend.push_back(Arg->getValue()); + Config.Common.RPathToPrepend.push_back(Arg->getValue()); for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) { StringRef RPath = Arg->getValue(); // Cannot add and delete the same rpath at the same time. - if (is_contained(Config.RPathToAdd, RPath)) + if (is_contained(Config.Common.RPathToAdd, RPath)) return createStringError( errc::invalid_argument, "cannot specify both -add_rpath '%s' and -delete_rpath '%s'", RPath.str().c_str(), RPath.str().c_str()); - if (is_contained(Config.RPathToPrepend, RPath)) + if (is_contained(Config.Common.RPathToPrepend, RPath)) return createStringError( errc::invalid_argument, "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'", RPath.str().c_str(), RPath.str().c_str()); - Config.RPathsToRemove.insert(RPath); + Config.Common.RPathsToRemove.insert(RPath); } for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) { @@ -919,51 +1106,52 @@ // Cannot specify duplicate -rpath entries auto It1 = find_if( - Config.RPathsToUpdate, + Config.Common.RPathsToUpdate, [&Match](const DenseMap::value_type &OldNew) { return Match(OldNew.getFirst()) || Match(OldNew.getSecond()); }); - if (It1 != Config.RPathsToUpdate.end()) + if (It1 != Config.Common.RPathsToUpdate.end()) return createStringError(errc::invalid_argument, "cannot specify both -rpath '" + It1->getFirst() + "' '" + It1->getSecond() + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -delete_rpath and -rpath - auto It2 = find_if(Config.RPathsToRemove, Match); - if (It2 != Config.RPathsToRemove.end()) + auto It2 = find_if(Config.Common.RPathsToRemove, Match); + if (It2 != Config.Common.RPathsToRemove.end()) return createStringError(errc::invalid_argument, "cannot specify both -delete_rpath '" + *It2 + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -add_rpath and -rpath - auto It3 = find_if(Config.RPathToAdd, Match); - if (It3 != Config.RPathToAdd.end()) + auto It3 = find_if(Config.Common.RPathToAdd, Match); + if (It3 != Config.Common.RPathToAdd.end()) return createStringError(errc::invalid_argument, "cannot specify both -add_rpath '" + *It3 + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -prepend_rpath and -rpath. - auto It4 = find_if(Config.RPathToPrepend, Match); - if (It4 != Config.RPathToPrepend.end()) + auto It4 = find_if(Config.Common.RPathToPrepend, Match); + if (It4 != Config.Common.RPathToPrepend.end()) return createStringError(errc::invalid_argument, "cannot specify both -prepend_rpath '" + *It4 + "' and -rpath '" + Old + "' '" + New + "'"); - Config.RPathsToUpdate.insert({Old, New}); + Config.Common.RPathsToUpdate.insert({Old, New}); } if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) { - Config.SharedLibId = Arg->getValue(); - if (Config.SharedLibId->empty()) + Config.Common.SharedLibId = Arg->getValue(); + if (Config.Common.SharedLibId->empty()) return createStringError(errc::invalid_argument, "cannot specify an empty id"); } for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change)) - Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)}); + Config.Common.InstallNamesToUpdate.insert( + {Arg->getValue(0), Arg->getValue(1)}); - Config.RemoveAllRpaths = + Config.Common.RemoveAllRpaths = InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths); SmallVector Positional; @@ -978,8 +1166,8 @@ return createStringError( errc::invalid_argument, "llvm-install-name-tool expects a single input file"); - Config.InputFilename = Positional[0]; - Config.OutputFilename = Positional[0]; + Config.Common.InputFilename = Positional[0]; + Config.Common.OutputFilename = Positional[0]; DC.CopyConfigs.push_back(std::move(Config)); return std::move(DC); @@ -988,7 +1176,7 @@ Expected parseBitcodeStripOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ConfigManager Config; BitcodeStripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; opt::InputArgList InputArgs = @@ -1022,8 +1210,8 @@ return createStringError(errc::invalid_argument, "llvm-bitcode-strip expects a single input file"); assert(!Positional.empty()); - Config.InputFilename = Positional[0]; - Config.OutputFilename = Positional[0]; + Config.Common.InputFilename = Positional[0]; + Config.Common.OutputFilename = Positional[0]; DC.CopyConfigs.push_back(std::move(Config)); return std::move(DC); @@ -1071,7 +1259,7 @@ errc::invalid_argument, "multiple input files cannot be used in combination with -o"); - CopyConfig Config; + ConfigManager Config; if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) return createStringError(errc::invalid_argument, @@ -1083,66 +1271,68 @@ : InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard : MatchStyle::Literal; - Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); - Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); + Config.Common.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); + Config.Common.StripDebug = InputArgs.hasArg(STRIP_strip_debug); if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals)) - Config.DiscardMode = + Config.Common.DiscardMode = InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals) ? DiscardType::All : DiscardType::Locals; - Config.StripSections = InputArgs.hasArg(STRIP_strip_sections); - Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); + Config.Common.StripSections = InputArgs.hasArg(STRIP_strip_sections); + Config.Common.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all)) - Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; - Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu); - Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); - Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug); - Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); - Config.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined); + Config.Common.StripAll = Arg->getOption().getID() == STRIP_strip_all; + Config.Common.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu); + Config.Common.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); + Config.Common.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug); + Config.Common.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); + Config.Common.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined); for (auto Arg : InputArgs.filtered(STRIP_keep_section)) - if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( + if (Error E = Config.Common.KeepSection.addMatcher(NameOrPattern::create( Arg->getValue(), SectionMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(STRIP_remove_section)) - if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( + if (Error E = Config.Common.ToRemove.addMatcher(NameOrPattern::create( Arg->getValue(), SectionMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(STRIP_strip_symbol)) - if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( - Arg->getValue(), SymbolMatchStyle, ErrorCallback))) + if (Error E = + Config.Common.SymbolsToRemove.addMatcher(NameOrPattern::create( + Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) - if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( + if (Error E = Config.Common.SymbolsToKeep.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); - if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug && - !Config.StripUnneeded && Config.DiscardMode == DiscardType::None && - !Config.StripAllGNU && Config.SymbolsToRemove.empty()) - Config.StripAll = true; + if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.Common.StripDebug && + !Config.Common.StripUnneeded && + Config.Common.DiscardMode == DiscardType::None && + !Config.Common.StripAllGNU && Config.Common.SymbolsToRemove.empty()) + Config.Common.StripAll = true; - if (Config.DiscardMode == DiscardType::All) { - Config.StripDebug = true; - Config.KeepFileSymbols = true; + if (Config.Common.DiscardMode == DiscardType::All) { + Config.Common.StripDebug = true; + Config.Common.KeepFileSymbols = true; } - Config.DeterministicArchives = + Config.Common.DeterministicArchives = InputArgs.hasFlag(STRIP_enable_deterministic_archives, STRIP_disable_deterministic_archives, /*default=*/true); - Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); - Config.InputFormat = FileFormat::Unspecified; - Config.OutputFormat = FileFormat::Unspecified; + Config.Common.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); + Config.Common.InputFormat = FileFormat::Unspecified; + Config.Common.OutputFormat = FileFormat::Unspecified; DriverConfig DC; if (Positional.size() == 1) { - Config.InputFilename = Positional[0]; - Config.OutputFilename = + Config.Common.InputFilename = Positional[0]; + Config.Common.OutputFilename = InputArgs.getLastArgValue(STRIP_output, Positional[0]); DC.CopyConfigs.push_back(std::move(Config)); } else { @@ -1158,14 +1348,15 @@ Filename.str().c_str()))) return std::move(E); } - Config.InputFilename = Filename; - Config.OutputFilename = Filename; + Config.Common.InputFilename = Filename; + Config.Common.OutputFilename = Filename; DC.CopyConfigs.push_back(Config); } } - if (Config.PreserveDates && (is_contained(Positional, "-") || - InputArgs.getLastArgValue(STRIP_output) == "-")) + if (Config.Common.PreserveDates && + (is_contained(Positional, "-") || + InputArgs.getLastArgValue(STRIP_output) == "-")) return createStringError(errc::invalid_argument, "--preserve-dates requires a file"); diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp b/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp deleted file mode 100644 --- 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 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: - // - // =[
:][,] - // - // where: - // - symbol name, can be empty string - //
- optional section name. If not given ABS symbol is created - // - symbol value, can be decimal or hexadecimal number prefixed - // with 0x. - // - 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=. - 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 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; - SmallVector UnsupportedFlags; - for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) - static_cast( - StringSwitch(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 parseConfig(const CopyConfig &Config) { - ELFCopyConfig ELFConfig; - if (Config.NewSymbolVisibility) { - const uint8_t Invalid = 0xff; - ELFConfig.NewSymbolVisibility = - StringSwitch(*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 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/ELFObjcopy.h b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -19,14 +19,18 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct ElfConfig; namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, object::ELFObjectFileBase &In, raw_ostream &Out); } // end namespace elf diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp --- 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 @@ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; } -static std::unique_ptr createELFWriter(const CopyConfig &Config, +static std::unique_ptr createELFWriter(const CommonConfig &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. @@ -153,16 +154,16 @@ llvm_unreachable("Invalid output format"); } -static std::unique_ptr createWriter(const CopyConfig &Config, +static std::unique_ptr createWriter(const CommonConfig &Common, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { - switch (Config.OutputFormat) { + switch (Common.OutputFormat) { case FileFormat::Binary: return std::make_unique(Obj, Out); case FileFormat::IHex: return std::make_unique(Obj, Out); default: - return createELFWriter(Config, Obj, Out, OutputElfType); + return createELFWriter(Common, Obj, Out, OutputElfType); } } @@ -243,7 +244,7 @@ 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 @@ 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,24 +507,21 @@ // 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"); - - if (Config.OutputArch) { - Obj.Machine = Config.OutputArch.getValue().EMachine; - Obj.OSABI = Config.OutputArch.getValue().OSABI; +static Error handleArgs(const CommonConfig &Common, const ElfConfig &ElfCfg, + Object &Obj) { + if (Common.OutputArch) { + Obj.Machine = Common.OutputArch.getValue().EMachine; + Obj.OSABI = Common.OutputArch.getValue().OSABI; } - if (!Config.SplitDWO.empty() && Config.ExtractDWO) { + if (!Common.SplitDWO.empty() && Common.ExtractDWO) { return Obj.removeSections( - Config.AllowBrokenLinks, + Common.AllowBrokenLinks, [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); }); } // Dump sections before add/remove for compatibility with GNU objcopy. - for (StringRef Flag : Config.DumpSection) { + for (StringRef Flag : Common.DumpSection) { StringRef SectionName; StringRef FileName; std::tie(SectionName, FileName) = Flag.split('='); @@ -535,16 +533,16 @@ // remove the relocation sections before removing the symbols. That allows // us to avoid reporting the inappropriate errors about removing symbols // named in relocations. - if (Error E = replaceAndRemoveSections(Config, Obj)) + if (Error E = replaceAndRemoveSections(Common, Obj)) return E; - if (Error E = updateAndRemoveSymbols(Config, Obj)) + if (Error E = updateAndRemoveSymbols(Common, Obj)) return E; - if (!Config.SectionsToRename.empty()) { + if (!Common.SectionsToRename.empty()) { for (SectionBase &Sec : Obj.sections()) { - const auto Iter = Config.SectionsToRename.find(Sec.Name); - if (Iter != Config.SectionsToRename.end()) { + const auto Iter = Common.SectionsToRename.find(Sec.Name); + if (Iter != Common.SectionsToRename.end()) { const SectionRename &SR = Iter->second; Sec.Name = std::string(SR.NewName); if (SR.NewFlags.hasValue()) @@ -556,11 +554,11 @@ // Add a prefix to allocated sections and their relocation sections. This // should be done after renaming the section by Config.SectionToRename to // imitate the GNU objcopy behavior. - if (!Config.AllocSectionsPrefix.empty()) { + if (!Common.AllocSectionsPrefix.empty()) { DenseSet PrefixedSections; for (SectionBase &Sec : Obj.sections()) { if (Sec.Flags & SHF_ALLOC) { - Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); + Sec.Name = (Common.AllocSectionsPrefix + Sec.Name).str(); PrefixedSections.insert(&Sec); } else if (auto *RelocSec = dyn_cast(&Sec)) { // Rename relocation sections associated to the allocated sections. @@ -592,26 +590,26 @@ Sec.Name = (prefix + TargetSec->Name).str(); else Sec.Name = - (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str(); + (prefix + Common.AllocSectionsPrefix + TargetSec->Name).str(); } } } } - if (!Config.SetSectionAlignment.empty()) { + if (!Common.SetSectionAlignment.empty()) { for (SectionBase &Sec : Obj.sections()) { - auto I = Config.SetSectionAlignment.find(Sec.Name); - if (I != Config.SetSectionAlignment.end()) + auto I = Common.SetSectionAlignment.find(Sec.Name); + if (I != Common.SetSectionAlignment.end()) Sec.Align = I->second; } } - if (Config.OnlyKeepDebug) + if (Common.OnlyKeepDebug) for (auto &Sec : Obj.sections()) if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) Sec.Type = SHT_NOBITS; - for (const auto &Flag : Config.AddSection) { + for (const auto &Flag : Common.AddSection) { std::pair SecPair = Flag.split("="); StringRef SecName = SecPair.first; StringRef File = SecPair.second; @@ -629,17 +627,17 @@ NewSection.Type = SHT_NOTE; } - if (!Config.AddGnuDebugLink.empty()) - Obj.addSection(Config.AddGnuDebugLink, - Config.GnuDebugLinkCRC32); + if (!Common.AddGnuDebugLink.empty()) + Obj.addSection(Common.AddGnuDebugLink, + Common.GnuDebugLinkCRC32); // 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 && !ElfCfg.SymbolsToAdd.empty()) if (Error E = Obj.addNewSymbolTable()) return E; - for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { + for (const NewSymbolInfo &SI : ElfCfg.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -648,31 +646,32 @@ } // --set-section-flags works with sections added by --add-section. - if (!Config.SetSectionFlags.empty()) { + if (!Common.SetSectionFlags.empty()) { for (auto &Sec : Obj.sections()) { - const auto Iter = Config.SetSectionFlags.find(Sec.Name); - if (Iter != Config.SetSectionFlags.end()) { + const auto Iter = Common.SetSectionFlags.find(Sec.Name); + if (Iter != Common.SetSectionFlags.end()) { const SectionFlagsUpdate &SFU = Iter->second; setSectionFlagsAndType(Sec, SFU.NewFlags); } } } - if (Config.EntryExpr) - Obj.Entry = Config.EntryExpr(Obj.Entry); + if (Common.EntryExpr) + Obj.Entry = Common.EntryExpr(Obj.Entry); return Error::success(); } -static Error writeOutput(const CopyConfig &Config, Object &Obj, +static Error writeOutput(const CommonConfig &Common, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { std::unique_ptr Writer = - createWriter(Config, Obj, Out, OutputElfType); + createWriter(Common, Obj, Out, OutputElfType); if (Error E = Writer->finalize()) return E; return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, MemoryBuffer &In, raw_ostream &Out) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); @@ -680,16 +679,17 @@ return Obj.takeError(); const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); - if (Error E = handleArgs(Config, **Obj)) + getOutputElfType(CommonCfg.OutputArch.getValueOr(MachineInfo())); + if (Error E = handleArgs(CommonCfg, ElfCfg, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(CommonCfg, **Obj, Out, OutputElfType); } -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, MemoryBuffer &In, raw_ostream &Out) { uint8_t NewSymbolVisibility = - Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + ElfCfg.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); BinaryReader Reader(&In, NewSymbolVisibility); Expected> Obj = Reader.create(true); if (!Obj) @@ -698,29 +698,30 @@ // Prefer OutputArch (-O) if set, otherwise fallback to BinaryArch // (-B). const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); - if (Error E = handleArgs(Config, **Obj)) + getOutputElfType(CommonCfg.OutputArch.getValueOr(MachineInfo())); + if (Error E = handleArgs(CommonCfg, ElfCfg, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(CommonCfg, **Obj, Out, OutputElfType); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &CommonCfg, + const ElfConfig &ElfCfg, object::ELFObjectFileBase &In, raw_ostream &Out) { - ELFReader Reader(&In, Config.ExtractPartition); + ELFReader Reader(&In, CommonCfg.ExtractPartition); Expected> Obj = - Reader.create(!Config.SymbolsToAdd.empty()); + Reader.create(!ElfCfg.SymbolsToAdd.empty()); if (!Obj) return Obj.takeError(); // Prefer OutputArch (-O) if set, otherwise infer it from the input. const ElfType OutputElfType = - Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) - : getOutputElfType(In); + CommonCfg.OutputArch ? getOutputElfType(CommonCfg.OutputArch.getValue()) + : getOutputElfType(In); - if (Error E = handleArgs(Config, **Obj)) - return createFileError(Config.InputFilename, std::move(E)); + if (Error E = handleArgs(CommonCfg, ElfCfg, **Obj)) + return createFileError(CommonCfg.InputFilename, std::move(E)); - if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) - return createFileError(Config.InputFilename, std::move(E)); + if (Error E = writeOutput(CommonCfg, **Obj, Out, OutputElfType)) + return createFileError(CommonCfg.InputFilename, std::move(E)); return Error::success(); } diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h --- 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/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ElfConfig.h rename from llvm/tools/llvm-objcopy/ELF/ELFConfig.h rename to llvm/tools/llvm-objcopy/ElfConfig.h --- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h +++ b/llvm/tools/llvm-objcopy/ElfConfig.h @@ -1,4 +1,4 @@ -//===- ELFConfig.h ----------------------------------------------*- C++ -*-===// +//===- ElfConfig.h --------------------------------------------------------===// // // 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_OBJCOPY_ELFCONFIG_H -#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELFTypes.h" -#include "llvm/Support/Error.h" #include namespace llvm { namespace objcopy { -struct CopyConfig; - -namespace elf { struct NewSymbolInfo { StringRef SymbolName; @@ -30,15 +26,13 @@ uint8_t Visibility = ELF::STV_DEFAULT; }; -struct ELFCopyConfig { +// Elf specific configuration for copying/stripping a single file. +struct ElfConfig { Optional NewSymbolVisibility; std::vector SymbolsToAdd; }; -Expected parseConfig(const CopyConfig &Config); - -} // namespace elf } // namespace objcopy } // namespace llvm -#endif +#endif // LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h @@ -19,15 +19,16 @@ } // 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 &Common, 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/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- 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,18 +49,18 @@ .rtrim('\0'); } -static Error removeSections(const CopyConfig &Config, Object &Obj) { +static Error removeSections(const CommonConfig &CommonCfg, Object &Obj) { SectionPred RemovePred = [](const std::unique_ptr
&) { return false; }; - if (!Config.ToRemove.empty()) { - RemovePred = [&Config, RemovePred](const std::unique_ptr
&Sec) { - return Config.ToRemove.matches(Sec->CanonicalName); + if (!CommonCfg.ToRemove.empty()) { + RemovePred = [&CommonCfg, RemovePred](const std::unique_ptr
&Sec) { + return CommonCfg.ToRemove.matches(Sec->CanonicalName); }; } - if (Config.StripAll || Config.StripDebug) { + if (CommonCfg.StripAll || CommonCfg.StripDebug) { // Remove all debug sections. RemovePred = [RemovePred](const std::unique_ptr
&Sec) { if (Sec->Segname == "__DWARF") @@ -69,42 +70,44 @@ }; } - if (!Config.OnlySection.empty()) { + if (!CommonCfg.OnlySection.empty()) { // Overwrite RemovePred because --only-section takes priority. - RemovePred = [&Config](const std::unique_ptr
&Sec) { - return !Config.OnlySection.matches(Sec->CanonicalName); + RemovePred = [&CommonCfg](const std::unique_ptr
&Sec) { + return !CommonCfg.OnlySection.matches(Sec->CanonicalName); }; } 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 &CommonCfg, Object &Obj) { for (SymbolEntry &Sym : Obj.SymTable) { - auto I = Config.SymbolsToRename.find(Sym.Name); - if (I != Config.SymbolsToRename.end()) + auto I = CommonCfg.SymbolsToRename.find(Sym.Name); + if (I != CommonCfg.SymbolsToRename.end()) Sym.Name = std::string(I->getValue()); } - auto RemovePred = [Config, &Obj](const std::unique_ptr &N) { + auto RemovePred = [CommonCfg, &Obj](const std::unique_ptr &N) { if (N->Referenced) return false; - if (Config.KeepUndefined && N->isUndefinedSymbol()) + if (CommonCfg.KeepUndefined && N->isUndefinedSymbol()) return false; - if (Config.StripAll) + if (CommonCfg.StripAll) return true; - if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT)) + if (CommonCfg.DiscardMode == DiscardType::All && + !(N->n_type & MachO::N_EXT)) return true; // This behavior is consistent with cctools' strip. - if (Config.StripSwiftSymbols && (Obj.Header.Flags & MachO::MH_DYLDLINK) && - Obj.SwiftVersion && *Obj.SwiftVersion && N->isSwiftSymbol()) + if (CommonCfg.StripSwiftSymbols && + (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion && + *Obj.SwiftVersion && N->isSwiftSymbol()) return true; return false; }; @@ -136,17 +139,17 @@ return LC; } -static Error processLoadCommands(const CopyConfig &Config, Object &Obj) { +static Error processLoadCommands(const CommonConfig &CommonCfg, Object &Obj) { // Remove RPaths. - DenseSet RPathsToRemove(Config.RPathsToRemove.begin(), - Config.RPathsToRemove.end()); + DenseSet RPathsToRemove(CommonCfg.RPathsToRemove.begin(), + CommonCfg.RPathsToRemove.end()); LoadCommandPred RemovePred = [&RPathsToRemove, - &Config](const LoadCommand &LC) { + &CommonCfg](const LoadCommand &LC) { if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) { // When removing all RPaths we don't need to care // about what it contains - if (Config.RemoveAllRpaths) + if (CommonCfg.RemoveAllRpaths) return true; StringRef RPath = getPayloadString(LC); @@ -163,7 +166,7 @@ // Emit an error if the Mach-O binary does not contain an rpath path name // specified in -delete_rpath. - for (StringRef RPath : Config.RPathsToRemove) { + for (StringRef RPath : CommonCfg.RPathsToRemove) { if (RPathsToRemove.count(RPath)) return createStringError(errc::invalid_argument, "no LC_RPATH load command with path: %s", @@ -179,7 +182,7 @@ } // Throw errors for invalid RPaths. - for (const auto &OldNew : Config.RPathsToUpdate) { + for (const auto &OldNew : CommonCfg.RPathsToUpdate) { StringRef Old = OldNew.getFirst(); StringRef New = OldNew.getSecond(); if (!RPaths.contains(Old)) @@ -195,14 +198,14 @@ for (LoadCommand &LC : Obj.LoadCommands) { switch (LC.MachOLoadCommand.load_command_data.cmd) { case MachO::LC_ID_DYLIB: - if (Config.SharedLibId) + if (CommonCfg.SharedLibId) updateLoadCommandPayloadString( - LC, *Config.SharedLibId); + LC, *CommonCfg.SharedLibId); break; case MachO::LC_RPATH: { StringRef RPath = getPayloadString(LC); - StringRef NewRPath = Config.RPathsToUpdate.lookup(RPath); + StringRef NewRPath = CommonCfg.RPathsToUpdate.lookup(RPath); if (!NewRPath.empty()) updateLoadCommandPayloadString(LC, NewRPath); break; @@ -214,7 +217,7 @@ case MachO::LC_LOAD_WEAK_DYLIB: StringRef InstallName = getPayloadString(LC); StringRef NewInstallName = - Config.InstallNamesToUpdate.lookup(InstallName); + CommonCfg.InstallNamesToUpdate.lookup(InstallName); if (!NewInstallName.empty()) updateLoadCommandPayloadString(LC, NewInstallName); @@ -223,7 +226,7 @@ } // Add new RPaths. - for (StringRef RPath : Config.RPathToAdd) { + for (StringRef RPath : CommonCfg.RPathToAdd) { if (RPaths.contains(RPath)) return createStringError(errc::invalid_argument, "rpath '" + RPath + @@ -232,7 +235,7 @@ Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath)); } - for (StringRef RPath : Config.RPathToPrepend) { + for (StringRef RPath : CommonCfg.RPathToPrepend) { if (RPaths.contains(RPath)) return createStringError(errc::invalid_argument, "rpath '" + RPath + @@ -245,7 +248,7 @@ // Unlike appending rpaths, the indexes of subsequent load commands must // be recalculated after prepending one. - if (!Config.RPathToPrepend.empty()) + if (!CommonCfg.RPathToPrepend.empty()) Obj.updateLoadCommandIndexes(); return Error::success(); @@ -330,26 +333,9 @@ 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 &CommonCfg, Object &Obj) { // Dump sections before add/remove for compatibility with GNU objcopy. - for (StringRef Flag : Config.DumpSection) { + for (StringRef Flag : CommonCfg.DumpSection) { StringRef SectionName; StringRef FileName; std::tie(SectionName, FileName) = Flag.split('='); @@ -357,21 +343,21 @@ return E; } - if (Error E = removeSections(Config, Obj)) + if (Error E = removeSections(CommonCfg, Obj)) return E; // Mark symbols to determine which symbols are still needed. - if (Config.StripAll) - markSymbols(Config, Obj); + if (CommonCfg.StripAll) + markSymbols(CommonCfg, Obj); - updateAndRemoveSymbols(Config, Obj); + updateAndRemoveSymbols(CommonCfg, Obj); - if (Config.StripAll) + if (CommonCfg.StripAll) for (LoadCommand &LC : Obj.LoadCommands) for (std::unique_ptr
&Sec : LC.Sections) Sec->Relocations.clear(); - for (const auto &Flag : Config.AddSection) { + for (const auto &Flag : CommonCfg.AddSection) { std::pair SecPair = Flag.split("="); StringRef SecName = SecPair.first; StringRef File = SecPair.second; @@ -381,21 +367,21 @@ return E; } - if (Error E = processLoadCommands(Config, Obj)) + if (Error E = processLoadCommands(CommonCfg, Obj)) return E; return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &CommonCfg, const MachOConfig &, object::MachOObjectFile &In, raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); if (!O) - return createFileError(Config.InputFilename, O.takeError()); + return createFileError(CommonCfg.InputFilename, O.takeError()); - if (Error E = handleArgs(Config, **O)) - return createFileError(Config.InputFilename, std::move(E)); + if (Error E = handleArgs(CommonCfg, **O)) + return createFileError(CommonCfg.InputFilename, std::move(E)); // Page size used for alignment of segment sizes in Mach-O executables and // dynamic libraries. @@ -416,7 +402,7 @@ return Writer.write(); } -Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config, +Error executeObjcopyOnMachOUniversalBinary(const MultiFormatConfig &Config, const MachOUniversalBinary &In, raw_ostream &Out) { SmallVector, 2> Binaries; @@ -431,7 +417,7 @@ Expected> OutputBufferOrErr = writeArchiveToBuffer(*NewArchiveMembersOrErr, (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(), - Config.DeterministicArchives, + Config.getCommonConfig().DeterministicArchives, (*ArOrErr)->isThin()); if (!OutputBufferOrErr) return OutputBufferOrErr.takeError(); @@ -455,18 +441,24 @@ Expected> 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 Buffer; raw_svector_ostream MemStream(Buffer); - if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream)) + Expected MachO = Config.getMachOConfig(); + if (!MachO) + return MachO.takeError(); + + if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, + **ObjOrErr, MemStream)) return E; std::unique_ptr MB = diff --git a/llvm/tools/llvm-objcopy/MachOConfig.h b/llvm/tools/llvm-objcopy/MachOConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MachOConfig.h @@ -0,0 +1,21 @@ +//===- MachOConfig.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_MACHOCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H + +namespace llvm { +namespace objcopy { + +// MachO specific configuration for copying/stripping a single file. +struct MachOConfig {}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H diff --git a/llvm/tools/llvm-objcopy/MultiFormatConfig.h b/llvm/tools/llvm-objcopy/MultiFormatConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MultiFormatConfig.h @@ -0,0 +1,39 @@ +//===- MultiFormatConfig.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_MULTIFORMATCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Error.h" +#include + +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 getElfConfig() const = 0; + virtual Expected getCOFFConfig() const = 0; + virtual Expected getMachOConfig() const = 0; + virtual Expected getWasmConfig() const = 0; +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCONFIG_H diff --git a/llvm/tools/llvm-objcopy/WasmConfig.h b/llvm/tools/llvm-objcopy/WasmConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/WasmConfig.h @@ -0,0 +1,21 @@ +//===- WasmConfig.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_WASMCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_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_WASMCONFIG_H diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h --- a/llvm/tools/llvm-objcopy/llvm-objcopy.h +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h @@ -23,9 +23,10 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +class MultiFormatConfig; Expected> -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/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -8,9 +8,14 @@ #include "llvm-objcopy.h" #include "COFF/COFFObjcopy.h" -#include "CopyConfig.h" +#include "COFFConfig.h" +#include "CommonConfig.h" +#include "ConfigManager.h" #include "ELF/ELFObjcopy.h" +#include "ElfConfig.h" #include "MachO/MachOObjcopy.h" +#include "MachOConfig.h" +#include "WasmConfig.h" #include "wasm/WasmObjcopy.h" #include "llvm/ADT/STLExtras.h" @@ -133,19 +138,21 @@ /// 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 Elf = ConfigMgr.getElfConfig(); + if (!Elf) + return Elf.takeError(); + + return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *Elf, 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) { - switch (Config.OutputFormat) { +static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, + MemoryBuffer &In, raw_ostream &Out) { + switch (ConfigMgr.getCommonConfig().OutputFormat) { case FileFormat::ELF: // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the // output format is binary/ihex or it's not given. This behavior differs from @@ -153,9 +160,12 @@ case FileFormat::Binary: case FileFormat::IHex: case FileFormat::Unspecified: - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnRawBinary(Config, In, Out); + Expected Elf = ConfigMgr.getElfConfig(); + if (!Elf) + return Elf.takeError(); + + return elf::executeObjcopyOnRawBinary(ConfigMgr.getCommonConfig(), *Elf, In, + Out); } llvm_unreachable("unsupported output format"); @@ -163,23 +173,41 @@ /// 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(&In)) { - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); - } else if (auto *COFFBinary = dyn_cast(&In)) - return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out); - else if (auto *MachOBinary = dyn_cast(&In)) - return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); - else if (auto *MachOUniversalBinary = - dyn_cast(&In)) + Expected ElfCfg = Config.getElfConfig(); + if (!ElfCfg) + return ElfCfg.takeError(); + + return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ElfCfg, + *ELFBinary, Out); + } else if (auto *COFFBinary = dyn_cast(&In)) { + Expected COFFCfg = Config.getCOFFConfig(); + if (!COFFCfg) + return COFFCfg.takeError(); + + return coff::executeObjcopyOnBinary(Config.getCommonConfig(), *COFFCfg, + *COFFBinary, Out); + } else if (auto *MachOBinary = dyn_cast(&In)) { + Expected MachOCfg = Config.getMachOConfig(); + if (!MachOCfg) + return MachOCfg.takeError(); + + return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOCfg, + *MachOBinary, Out); + } else if (auto *MachOUniversalBinary = + dyn_cast(&In)) { return macho::executeObjcopyOnMachOUniversalBinary( Config, *MachOUniversalBinary, Out); - else if (auto *WasmBinary = dyn_cast(&In)) - return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out); - else + } else if (auto *WasmBinary = dyn_cast(&In)) { + Expected WasmCfg = Config.getWasmConfig(); + if (!WasmCfg) + return WasmCfg.takeError(); + + return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(), + *WasmCfg, *WasmBinary, Out); + } else return createStringError(object_error::invalid_file_type, "unsupported object file format"); } @@ -188,7 +216,7 @@ namespace objcopy { Expected> -createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) { +createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -207,8 +235,8 @@ if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) return std::move(E); - Expected Member = - NewArchiveMember::getOldMember(Child, Config.DeterministicArchives); + Expected Member = NewArchiveMember::getOldMember( + Child, Config.getCommonConfig().DeterministicArchives); if (!Member) return createFileError(Ar.getFileName(), Member.takeError()); @@ -218,27 +246,29 @@ 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> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, Ar); + createNewArchiveMembers(ConfigMgr, Ar); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); - return deepWriteArchive(Config.OutputFilename, *NewArchiveMembersOrErr, - Ar.hasSymbolTable(), Ar.kind(), - Config.DeterministicArchives, Ar.isThin()); + return deepWriteArchive( + ConfigMgr.getCommonConfig().OutputFilename, *NewArchiveMembersOrErr, + Ar.hasSymbolTable(), Ar.kind(), + ConfigMgr.getCommonConfig().DeterministicArchives, Ar.isThin()); } static Error restoreStatOnFile(StringRef Filename, const sys::fs::file_status &Stat, - const CopyConfig &Config) { + const ConfigManager &ConfigMgr) { int FD; // Writing to stdout should not be treated as an error here, just @@ -250,7 +280,7 @@ sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) return createFileError(Filename, EC); - if (Config.PreserveDates) + if (ConfigMgr.getCommonConfig().PreserveDates) if (auto EC = sys::fs::setLastAccessAndModificationTime( FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) return createFileError(Filename, EC); @@ -261,12 +291,15 @@ if (OStat.type() == sys::fs::file_type::regular_file) { #ifndef _WIN32 // Keep ownership if llvm-objcopy is called under root. - if (Config.InputFilename == Config.OutputFilename && OStat.getUser() == 0) + if (ConfigMgr.getCommonConfig().InputFilename == + ConfigMgr.getCommonConfig().OutputFilename && + OStat.getUser() == 0) sys::fs::changeFileOwnership(FD, Stat.getUser(), Stat.getGroup()); #endif sys::fs::perms Perm = Stat.permissions(); - if (Config.InputFilename != Config.OutputFilename) + if (ConfigMgr.getCommonConfig().InputFilename != + ConfigMgr.getCommonConfig().OutputFilename) Perm = static_cast(Perm & ~sys::fs::getUmask() & ~06000); #ifdef _WIN32 if (auto EC = sys::fs::setPermissions(Filename, Perm)) @@ -285,11 +318,11 @@ /// 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) { sys::fs::file_status Stat; - if (Config.InputFilename != "-") { - if (auto EC = sys::fs::status(Config.InputFilename, Stat)) - return createFileError(Config.InputFilename, EC); + if (ConfigMgr.Common.InputFilename != "-") { + if (auto EC = sys::fs::status(ConfigMgr.Common.InputFilename, Stat)) + return createFileError(ConfigMgr.Common.InputFilename, EC); } else { Stat.permissions(static_cast(0777)); } @@ -299,73 +332,78 @@ OwningBinary BinaryHolder; std::unique_ptr MemoryBufferHolder; - if (Config.InputFormat == FileFormat::Binary || - Config.InputFormat == FileFormat::IHex) { + if (ConfigMgr.Common.InputFormat == FileFormat::Binary || + ConfigMgr.Common.InputFormat == FileFormat::IHex) { ErrorOr> BufOrErr = - MemoryBuffer::getFileOrSTDIN(Config.InputFilename); + MemoryBuffer::getFileOrSTDIN(ConfigMgr.Common.InputFilename); if (!BufOrErr) - return createFileError(Config.InputFilename, BufOrErr.getError()); + return createFileError(ConfigMgr.Common.InputFilename, + BufOrErr.getError()); MemoryBufferHolder = std::move(*BufOrErr); - if (Config.InputFormat == FileFormat::Binary) + if (ConfigMgr.Common.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> BinaryOrErr = - createBinary(Config.InputFilename); + createBinary(ConfigMgr.Common.InputFilename); if (!BinaryOrErr) - return createFileError(Config.InputFilename, BinaryOrErr.takeError()); + return createFileError(ConfigMgr.Common.InputFilename, + BinaryOrErr.takeError()); BinaryHolder = std::move(*BinaryOrErr); if (Archive *Ar = dyn_cast(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); }; } } if (ObjcopyFunc) { - if (Config.SplitDWO.empty()) { + if (ConfigMgr.Common.SplitDWO.empty()) { // Apply transformations described by Config and store result into // Config.OutputFilename using specified ObjcopyFunc function. - if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.getCommonConfig().OutputFilename, + ObjcopyFunc)) return E; } else { - Config.ExtractDWO = true; - Config.StripDWO = false; + ConfigMgr.Common.ExtractDWO = true; + ConfigMgr.Common.StripDWO = false; // Copy .dwo tables from the Config.InputFilename into Config.SplitDWO // file using specified ObjcopyFunc function. - if (Error E = writeToOutput(Config.SplitDWO, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.Common.SplitDWO, ObjcopyFunc)) return E; - Config.ExtractDWO = false; - Config.StripDWO = true; + ConfigMgr.Common.ExtractDWO = false; + ConfigMgr.Common.StripDWO = true; // Apply transformations described by Config, remove .dwo tables and // store result into Config.OutputFilename using specified ObjcopyFunc // function. - if (Error E = writeToOutput(Config.OutputFilename, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.Common.OutputFilename, ObjcopyFunc)) return E; } } - if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, Config)) + if (Error E = + restoreStatOnFile(ConfigMgr.Common.OutputFilename, Stat, ConfigMgr)) return E; - if (!Config.SplitDWO.empty()) { + if (!ConfigMgr.Common.SplitDWO.empty()) { Stat.permissions(static_cast(0666)); - if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, Config)) + if (Error E = restoreStatOnFile(ConfigMgr.Common.SplitDWO, Stat, ConfigMgr)) return E; } @@ -401,8 +439,8 @@ 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/wasm/WasmObjcopy.h b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h @@ -18,10 +18,11 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CommonConfig; +struct WasmConfig; namespace wasm { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CommonConfig &Common, const WasmConfig &, object::WasmObjectFile &In, raw_ostream &Out); } // end namespace wasm diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp --- 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 @@ 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,38 +72,22 @@ 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 &Common, const WasmConfig &, object::WasmObjectFile &In, raw_ostream &Out) { Reader TheReader(In); Expected> ObjOrErr = TheReader.create(); if (!ObjOrErr) - return createFileError(Config.InputFilename, ObjOrErr.takeError()); + return createFileError(Common.InputFilename, ObjOrErr.takeError()); Object *Obj = ObjOrErr->get(); assert(Obj && "Unable to deserialize Wasm object"); - if (Error E = handleArgs(Config, *Obj)) + if (Error E = handleArgs(Common, *Obj)) return E; Writer TheWriter(*Obj, Out); if (Error E = TheWriter.write()) - return createFileError(Config.OutputFilename, std::move(E)); + return createFileError(Common.OutputFilename, std::move(E)); return Error::success(); }