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 + ParsedConfig.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,10 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CopyConfigCOFF; namespace coff { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigCOFF &Config, 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,7 @@ //===----------------------------------------------------------------------===// #include "COFFObjcopy.h" -#include "CopyConfig.h" +#include "CopyConfigCOFF.h" #include "Object.h" #include "Reader.h" #include "Writer.h" @@ -130,7 +130,7 @@ Sec.Header.Characteristics = NewCharacteristics; } -static Error handleArgs(const CopyConfig &Config, Object &Obj) { +static Error handleArgs(const CopyConfigCOFF &Config, Object &Obj) { // Perform the actual section removals. Obj.removeSections([&Config](const Section &Sec) { // Contrary to --only-keep-debug, --only-section fully removes sections that @@ -248,27 +248,10 @@ if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) return E; - if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() || - !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || - !Config.DumpSection.empty() || !Config.KeepSection.empty() || - Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || - !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || - !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || - Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates || - Config.StripDWO || Config.StripNonAlloc || Config.StripSections || - Config.StripSwiftSymbols || Config.KeepUndefined || Config.Weaken || - Config.DecompressDebugSections || - Config.DiscardMode == DiscardType::Locals || - !Config.SymbolsToAdd.empty() || Config.EntryExpr) { - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for COFF"); - } - return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In, +Error executeObjcopyOnBinary(const CopyConfigCOFF &Config, COFFObjectFile &In, raw_ostream &Out) { COFFReader Reader(In); Expected> ObjOrErr = Reader.create(); diff --git a/llvm/tools/llvm-objcopy/COFF/CopyConfigCOFF.h b/llvm/tools/llvm-objcopy/COFF/CopyConfigCOFF.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/COFF/CopyConfigCOFF.h @@ -0,0 +1,29 @@ +//===- CopyConfigCOFF.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_COFF_COPYCONFIGCOFF_H +#define LLVM_TOOLS_LLVM_OBJCOPY_COFF_COPYCONFIGCOFF_H + +#include "CopyConfigBase.h" + +namespace llvm { +namespace objcopy { + +struct COFFSpecificConfig {}; + +/// Configuration for copying/stripping a single file. This structure keeps +/// common options for all formats and COFF-specific options. +struct CopyConfigCOFF : virtual public CopyConfigBase, + virtual public COFFSpecificConfig { + CopyConfigCOFF &operator=(CopyConfigCOFF &&) = delete; +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_COFF_COPYCONFIGCOFF_H diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfigBase.h rename from llvm/tools/llvm-objcopy/CopyConfig.h rename to llvm/tools/llvm-objcopy/CopyConfigBase.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfigBase.h @@ -1,4 +1,4 @@ -//===- CopyConfig.h -------------------------------------------------------===// +//===- CopyConfigBase.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,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H -#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H +#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPYCONFIGBASE_H +#define LLVM_TOOLS_LLVM_OBJCOPY_COPYCONFIGBASE_H -#include "ELF/ELFConfig.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseSet.h" @@ -19,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/GlobPattern.h" #include "llvm/Support/Regex.h" @@ -145,143 +145,47 @@ bool empty() const { return PosMatchers.empty() && NegMatchers.empty(); } }; -// Configuration for copying/stripping a single file. -struct CopyConfig { - // Format-specific options to be initialized lazily when needed. - Optional ELF; - +/// Configuration for copying/stripping a single file. +/// This structure keeps common options for all formats. +struct CopyConfigBase { // Main input/output options StringRef InputFilename; FileFormat InputFormat = FileFormat::Unspecified; StringRef OutputFilename; FileFormat OutputFormat = FileFormat::Unspecified; - // Only applicable when --output-format!=binary (e.g. elf64-x86-64). - Optional OutputArch; - // Advanced options StringRef AddGnuDebugLink; - // Cached gnu_debuglink's target CRC - uint32_t GnuDebugLinkCRC32; - Optional ExtractPartition; - StringRef SplitDWO; - 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; - DenseMap InstallNamesToUpdate; - DenseSet RPathsToRemove; - - // install-name-tool's id option - Optional SharedLibId; // Section matchers - NameMatcher KeepSection; NameMatcher OnlySection; NameMatcher ToRemove; // Symbol matchers - NameMatcher SymbolsToGlobalize; - NameMatcher SymbolsToKeep; - NameMatcher SymbolsToLocalize; NameMatcher SymbolsToRemove; NameMatcher UnneededSymbolsToRemove; - NameMatcher SymbolsToWeaken; - NameMatcher SymbolsToKeepGlobal; // Map options - StringMap SectionsToRename; - StringMap SetSectionAlignment; StringMap SetSectionFlags; StringMap SymbolsToRename; - // ELF entry point address expression. The input parameter is an entry point - // address in the input ELF file. The entry address in the output file is - // calculated with EntryExpr(input_address), when either --set-start or - // --change-start is used. - std::function EntryExpr; - // Boolean options - bool AllowBrokenLinks = false; bool DeterministicArchives = true; - bool ExtractDWO = false; - bool ExtractMainPartition = false; - bool KeepFileSymbols = false; - bool KeepUndefined = false; - bool LocalizeHidden = false; bool OnlyKeepDebug = false; bool PreserveDates = false; bool StripAll = false; bool StripAllGNU = false; - bool StripDWO = false; bool StripDebug = false; - bool StripNonAlloc = false; - bool StripSections = false; - bool StripSwiftSymbols = false; bool StripUnneeded = false; - bool Weaken = false; - bool DecompressDebugSections = false; - // install-name-tool's --delete_all_rpaths - 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_COPYCONFIGBASE_H diff --git a/llvm/tools/llvm-objcopy/CopyConfigFull.h b/llvm/tools/llvm-objcopy/CopyConfigFull.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/CopyConfigFull.h @@ -0,0 +1,61 @@ +//===- CopyConfigFull.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_COPYCONFIGFULL_H +#define LLVM_TOOLS_LLVM_OBJCOPY_COPYCONFIGFULL_H + +#include "COFF/CopyConfigCOFF.h" +#include "ELF/CopyConfigELF.h" +#include "MachO/CopyConfigMachO.h" +#include "wasm/CopyConfigWasm.h" + +namespace llvm { +namespace objcopy { + +/// Configuration for copying/stripping a single file. This structure keeps all +/// options(all common and all format-specific options). +struct CopyConfigFull : virtual public CopyConfigELF, + virtual public CopyConfigCOFF, + virtual public CopyConfigMachO, + virtual public CopyConfigWasm { + CopyConfigFull &operator=(const CopyConfigFull &Other) { + if (this != &Other) { + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + } + return *this; + } + CopyConfigFull &operator=(CopyConfigFull &&Other) { + if (this != &Other) { + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + static_cast(*this) = + static_cast(Other); + } + return *this; + } +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_COPYCONFIGFULL_H diff --git a/llvm/tools/llvm-objcopy/ELF/CopyConfigELF.h b/llvm/tools/llvm-objcopy/ELF/CopyConfigELF.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/ELF/CopyConfigELF.h @@ -0,0 +1,86 @@ +//===- CopyConfigELF.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_ELF_COPYCONFIGELF_H +#define LLVM_TOOLS_LLVM_OBJCOPY_ELF_COPYCONFIGELF_H + +#include "CopyConfigBase.h" + +namespace llvm { +namespace objcopy { + +struct NewSymbolInfo { + StringRef SymbolName; + StringRef SectionName; + uint64_t Value = 0; + uint8_t Type = ELF::STT_NOTYPE; + uint8_t Bind = ELF::STB_GLOBAL; + uint8_t Visibility = ELF::STV_DEFAULT; +}; + +/// Keeps ELF-specific copy options. +struct ELFSpecificConfig { + // Only applicable when --output-format!=binary (e.g. elf64-x86-64). + Optional OutputArch; + + // Advanced options + // Cached gnu_debuglink's target CRC + uint32_t GnuDebugLinkCRC32; + Optional ExtractPartition; + StringRef SplitDWO; + StringRef SymbolsPrefix; + StringRef AllocSectionsPrefix; + Optional NewSymbolVisibility; + std::vector SymbolsToAdd; + + // Section matchers + NameMatcher KeepSection; + + // Map options + StringMap SectionsToRename; + StringMap SetSectionAlignment; + + // Symbol matchers + NameMatcher SymbolsToGlobalize; + NameMatcher SymbolsToKeep; + NameMatcher SymbolsToLocalize; + NameMatcher SymbolsToWeaken; + NameMatcher SymbolsToKeepGlobal; + + // ELF entry point address expression. The input parameter is an entry point + // address in the input ELF file. The entry address in the output file is + // calculated with EntryExpr(input_address), when either --set-start or + // --change-start is used. + std::function EntryExpr; + + // Boolean options + bool AllowBrokenLinks = false; + bool ExtractDWO = false; + bool ExtractMainPartition = false; + bool KeepFileSymbols = false; + bool LocalizeHidden = false; + bool StripDWO = false; + bool StripNonAlloc = false; + bool StripSections = false; + bool Weaken = false; + bool DecompressDebugSections = false; + + DebugCompressionType CompressionType = DebugCompressionType::None; +}; + +/// Configuration for copying/stripping a single file. This structure keeps +/// common options for all formats and ELF-specific options. +struct CopyConfigELF : virtual public CopyConfigBase, + virtual public ELFSpecificConfig { + CopyConfigELF &operator=(CopyConfigELF &&) = delete; +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_ELF_COPYCONFIGELF_H diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h deleted file mode 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- ELFConfig.h ----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_OBJCOPY_ELFCONFIG_H -#define LLVM_TOOLS_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; - StringRef SectionName; - uint64_t Value = 0; - uint8_t Type = ELF::STT_NOTYPE; - uint8_t Bind = ELF::STB_GLOBAL; - uint8_t Visibility = ELF::STV_DEFAULT; -}; - -struct ELFCopyConfig { - Optional NewSymbolVisibility; - std::vector SymbolsToAdd; -}; - -Expected parseConfig(const CopyConfig &Config); - -} // namespace elf -} // namespace objcopy -} // namespace llvm - -#endif 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,16 +19,15 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CopyConfigELF; namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CopyConfigELF &Config, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CopyConfigELF &Config, MemoryBuffer &In, raw_ostream &Out); -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigELF &Config, object::ELFObjectFileBase &In, raw_ostream &Out); - } // end namespace elf } // end namespace objcopy } // end namespace llvm 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,7 @@ //===----------------------------------------------------------------------===// #include "ELFObjcopy.h" -#include "CopyConfig.h" +#include "CopyConfigELF.h" #include "Object.h" #include "llvm-objcopy.h" #include "llvm/ADT/BitmaskEnum.h" @@ -132,7 +132,7 @@ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; } -static std::unique_ptr createELFWriter(const CopyConfig &Config, +static std::unique_ptr createELFWriter(const CopyConfigELF &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. @@ -153,7 +153,7 @@ llvm_unreachable("Invalid output format"); } -static std::unique_ptr createWriter(const CopyConfig &Config, +static std::unique_ptr createWriter(const CopyConfigELF &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { switch (Config.OutputFormat) { @@ -243,7 +243,7 @@ Sym.Type != STT_SECTION; } -static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +static Error updateAndRemoveSymbols(const CopyConfigELF &Config, Object &Obj) { // TODO: update or remove symbols only if there is an option that affects // them. if (!Obj.SymbolTable) @@ -338,7 +338,8 @@ return Obj.removeSymbols(RemoveSymbolsPred); } -static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { +static Error replaceAndRemoveSections(const CopyConfigELF &Config, + Object &Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: @@ -506,11 +507,7 @@ // any previous removals. Lastly whether or not something is removed shouldn't // depend a) on the order the options occur in or b) on some opaque priority // system. The only priority is that keeps/copies overrule removes. -static Error handleArgs(const CopyConfig &Config, Object &Obj) { - if (Config.StripSwiftSymbols || Config.KeepUndefined) - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for ELF"); - +static Error handleArgs(const CopyConfigELF &Config, Object &Obj) { if (Config.OutputArch) { Obj.Machine = Config.OutputArch.getValue().EMachine; Obj.OSABI = Config.OutputArch.getValue().OSABI; @@ -635,11 +632,11 @@ // 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 && !Config.SymbolsToAdd.empty()) if (Error E = Obj.addNewSymbolTable()) return E; - for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { + for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -663,7 +660,7 @@ return Error::success(); } -static Error writeOutput(const CopyConfig &Config, Object &Obj, +static Error writeOutput(const CopyConfigELF &Config, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { std::unique_ptr Writer = createWriter(Config, Obj, Out, OutputElfType); @@ -672,7 +669,7 @@ return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CopyConfigELF &Config, MemoryBuffer &In, raw_ostream &Out) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); @@ -686,10 +683,10 @@ return writeOutput(Config, **Obj, Out, OutputElfType); } -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const CopyConfigELF &Config, MemoryBuffer &In, raw_ostream &Out) { uint8_t NewSymbolVisibility = - Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); BinaryReader Reader(&In, NewSymbolVisibility); Expected> Obj = Reader.create(true); if (!Obj) @@ -704,7 +701,7 @@ return writeOutput(Config, **Obj, Out, OutputElfType); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigELF &Config, object::ELFObjectFileBase &In, raw_ostream &Out) { ELFReader Reader(&In, Config.ExtractPartition); Expected> Obj = 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,6 @@ #ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H #define LLVM_TOOLS_OBJCOPY_OBJECT_H -#include "CopyConfig.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" diff --git a/llvm/tools/llvm-objcopy/MachO/CopyConfigMachO.h b/llvm/tools/llvm-objcopy/MachO/CopyConfigMachO.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MachO/CopyConfigMachO.h @@ -0,0 +1,45 @@ +//===- CopyConfigMachO.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_MACHO_COPYCONFIGMACHO_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MACHO_COPYCONFIGMACHO_H + +#include "CopyConfigBase.h" + +namespace llvm { +namespace objcopy { + +/// Keeps MachO-specific copy options. +struct MachOSpecificConfig { + // Repeated options + std::vector RPathToAdd; + std::vector RPathToPrepend; + DenseMap RPathsToUpdate; + DenseSet RPathsToRemove; + DenseMap InstallNamesToUpdate; + + // install-name-tool's id option + Optional SharedLibId; + + // Boolean options + bool KeepUndefined = false; + bool StripSwiftSymbols = false; + // install-name-tool's --delete_all_rpaths + bool RemoveAllRpaths = false; +}; + +/// Configuration for copying/stripping a single file. This structure keeps +/// common options for all formats and MachO-specific options. +struct CopyConfigMachO : virtual public CopyConfigBase, + virtual public MachOSpecificConfig { + CopyConfigMachO &operator=(CopyConfigMachO &&) = delete; +}; +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MACHO_COPYCONFIGMACHO_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,15 @@ } // end namespace object namespace objcopy { -struct CopyConfig; -class Buffer; +struct CopyConfigMachO; +struct MultiFormatCopyConfig; namespace macho { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigMachO &Config, object::MachOObjectFile &In, raw_ostream &Out); Error executeObjcopyOnMachOUniversalBinary( - CopyConfig &Config, const object::MachOUniversalBinary &In, + const MultiFormatCopyConfig &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,10 @@ //===----------------------------------------------------------------------===// #include "MachOObjcopy.h" -#include "../CopyConfig.h" #include "../llvm-objcopy.h" #include "MachOReader.h" #include "MachOWriter.h" +#include "MultiFormatCopyConfig.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/MachOUniversal.h" @@ -48,7 +48,7 @@ .rtrim('\0'); } -static Error removeSections(const CopyConfig &Config, Object &Obj) { +static Error removeSections(const CopyConfigMachO &Config, Object &Obj) { SectionPred RemovePred = [](const std::unique_ptr
&) { return false; }; @@ -79,21 +79,21 @@ return Obj.removeSections(RemovePred); } -static void markSymbols(const CopyConfig &Config, Object &Obj) { +static void markSymbols(const CopyConfigMachO &Config, 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 CopyConfigMachO &Config, Object &Obj) { for (SymbolEntry &Sym : Obj.SymTable) { auto I = Config.SymbolsToRename.find(Sym.Name); if (I != Config.SymbolsToRename.end()) Sym.Name = std::string(I->getValue()); } - auto RemovePred = [Config, &Obj](const std::unique_ptr &N) { + auto RemovePred = [&Config, &Obj](const std::unique_ptr &N) { if (N->Referenced) return false; if (Config.KeepUndefined && N->isUndefinedSymbol()) @@ -136,7 +136,7 @@ return LC; } -static Error processLoadCommands(const CopyConfig &Config, Object &Obj) { +static Error processLoadCommands(const CopyConfigMachO &Config, Object &Obj) { // Remove RPaths. DenseSet RPathsToRemove(Config.RPathsToRemove.begin(), Config.RPathsToRemove.end()); @@ -330,24 +330,7 @@ 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 CopyConfigMachO &Config, Object &Obj) { // Dump sections before add/remove for compatibility with GNU objcopy. for (StringRef Flag : Config.DumpSection) { StringRef SectionName; @@ -387,7 +370,7 @@ return Error::success(); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigMachO &Config, object::MachOObjectFile &In, raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); @@ -416,7 +399,7 @@ return Writer.write(); } -Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config, +Error executeObjcopyOnMachOUniversalBinary(const MultiFormatCopyConfig &Config, const MachOUniversalBinary &In, raw_ostream &Out) { SmallVector, 2> Binaries; @@ -465,8 +448,11 @@ SmallVector Buffer; raw_svector_ostream MemStream(Buffer); + Expected MachOConfig = Config.getMachOConfig(); + if (!MachOConfig) + return MachOConfig.takeError(); - if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream)) + if (Error E = executeObjcopyOnBinary(*MachOConfig, **ObjOrErr, MemStream)) return E; std::unique_ptr MB = diff --git a/llvm/tools/llvm-objcopy/MultiFormatCopyConfig.h b/llvm/tools/llvm-objcopy/MultiFormatCopyConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MultiFormatCopyConfig.h @@ -0,0 +1,105 @@ +//===- MultiFormatCopyConfig.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_MULTIFORMATCOPYCONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCOPYCONFIG_H + +#include "COFF/CopyConfigCOFF.h" +#include "ELF/CopyConfigELF.h" +#include "MachO/CopyConfigMachO.h" +#include "wasm/CopyConfigWasm.h" + +namespace llvm { +namespace objcopy { + +/// Configuration for copying/stripping a single file. This structure keeps all +/// options(all common and all format-specific) and it provides format-specific +/// view on keeping options. +struct MultiFormatCopyConfig : virtual public CopyConfigBase, + virtual protected CopyConfigELF, + virtual protected CopyConfigCOFF, + virtual protected CopyConfigMachO, + virtual protected CopyConfigWasm { + MultiFormatCopyConfig &operator=(const MultiFormatCopyConfig &) = delete; + MultiFormatCopyConfig &operator=(MultiFormatCopyConfig &&) = delete; + + virtual ~MultiFormatCopyConfig() {} + + /// Check that only ELF options are set and return ELF specific view. + virtual Expected getELFConfig() const { + if (StripSwiftSymbols || KeepUndefined) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for ELF"); + + return static_cast(*this); + } + + /// Check that only COFF options are set and return COFF specific view. + virtual Expected getCOFFConfig() const { + if (AllowBrokenLinks || !SplitDWO.empty() || !SymbolsPrefix.empty() || + !AllocSectionsPrefix.empty() || !DumpSection.empty() || + !KeepSection.empty() || NewSymbolVisibility || + !SymbolsToGlobalize.empty() || !SymbolsToKeep.empty() || + !SymbolsToLocalize.empty() || !SymbolsToWeaken.empty() || + !SymbolsToKeepGlobal.empty() || !SectionsToRename.empty() || + !SetSectionAlignment.empty() || ExtractDWO || LocalizeHidden || + PreserveDates || StripDWO || StripNonAlloc || StripSections || + StripSwiftSymbols || KeepUndefined || Weaken || + DecompressDebugSections || DiscardMode == DiscardType::Locals || + !SymbolsToAdd.empty() || EntryExpr) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for COFF"); + + return static_cast(*this); + } + + /// Check that only MachO options are set and return MachO specific view. + virtual Expected getMachOConfig() const { + if (AllowBrokenLinks || !SplitDWO.empty() || !SymbolsPrefix.empty() || + !AllocSectionsPrefix.empty() || !KeepSection.empty() || + NewSymbolVisibility || !SymbolsToGlobalize.empty() || + !SymbolsToKeep.empty() || !SymbolsToLocalize.empty() || + !SymbolsToWeaken.empty() || !SymbolsToKeepGlobal.empty() || + !SectionsToRename.empty() || !UnneededSymbolsToRemove.empty() || + !SetSectionAlignment.empty() || !SetSectionFlags.empty() || + ExtractDWO || LocalizeHidden || PreserveDates || StripAllGNU || + StripDWO || StripNonAlloc || StripSections || Weaken || + DecompressDebugSections || StripUnneeded || + DiscardMode == DiscardType::Locals || !SymbolsToAdd.empty() || + EntryExpr) + return createStringError( + llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for MachO"); + + return static_cast(*this); + } + + /// Check that only Wasm options are set and return Wasm specific view. + virtual Expected getWasmConfig() const { + if (!AddGnuDebugLink.empty() || ExtractPartition || !SplitDWO.empty() || + !SymbolsPrefix.empty() || !AllocSectionsPrefix.empty() || + DiscardMode != DiscardType::None || NewSymbolVisibility || + !SymbolsToAdd.empty() || !RPathToAdd.empty() || !OnlySection.empty() || + !SymbolsToGlobalize.empty() || !SymbolsToKeep.empty() || + !SymbolsToLocalize.empty() || !SymbolsToRemove.empty() || + !UnneededSymbolsToRemove.empty() || !SymbolsToWeaken.empty() || + !SymbolsToKeepGlobal.empty() || !SectionsToRename.empty() || + !SetSectionAlignment.empty() || !SetSectionFlags.empty() || + !SymbolsToRename.empty()) + return createStringError( + llvm::errc::invalid_argument, + "only add-section, dump-section, and remove-section are supported"); + + return static_cast(*this); + } +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_MULTIFORMATCOPYCONFIG_H diff --git a/llvm/tools/llvm-objcopy/ParsedConfig.h b/llvm/tools/llvm-objcopy/ParsedConfig.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/ParsedConfig.h @@ -0,0 +1,97 @@ +//===- ParsedConfig.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_PARSED_CONFIG_H +#define LLVM_TOOLS_LLVM_OBJCOPY_PARSED_CONFIG_H + +#include "CopyConfigFull.h" +#include "MultiFormatCopyConfig.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 +#include "llvm/Target/TargetOptions.h" +#include + +namespace llvm { +namespace objcopy { + +/// Configuration for copying/stripping a single file. This structure keeps all +/// options(all common and all format-specific) and it provides two kinds of +/// access to options: format-specific view on keeping options and all options +/// available as a plain structure. +struct ParsedMultiFormatConfig : virtual public CopyConfigFull, + virtual protected MultiFormatCopyConfig { + ParsedMultiFormatConfig() {} + ParsedMultiFormatConfig(const ParsedMultiFormatConfig &Other) { + static_cast(*this) = + static_cast(Other); + } + ParsedMultiFormatConfig &operator=(const ParsedMultiFormatConfig &Other) { + if (this != &Other) + static_cast(*this) = + static_cast(Other); + return *this; + } + ParsedMultiFormatConfig &operator=(ParsedMultiFormatConfig &&Other) { + if (this != &Other) + static_cast(*this) = + static_cast(Other); + return *this; + } + + const MultiFormatCopyConfig &getMultiFormatConfig() const { return *this; } +}; + +// 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_PARSED_CONFIG_H diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/ParsedConfig.cpp rename from llvm/tools/llvm-objcopy/CopyConfig.cpp rename to llvm/tools/llvm-objcopy/ParsedConfig.cpp --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/ParsedConfig.cpp @@ -1,4 +1,4 @@ -//===- CopyConfig.cpp -----------------------------------------------------===// +//===- ParsedConfig.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 "ParsedConfig.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -244,9 +243,10 @@ "bad format for --set-section-alignment: missing section name"); uint64_t NewAlign; if (Split.second.getAsInteger(0, NewAlign)) - return createStringError(errc::invalid_argument, - "invalid alignment for --set-section-alignment: '%s'", - Split.second.str().c_str()); + return createStringError( + errc::invalid_argument, + "invalid alignment for --set-section-alignment: '%s'", + Split.second.str().c_str()); return std::make_pair(Split.first, NewAlign); } @@ -272,6 +272,88 @@ return SFU; } +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; +} + struct TargetInfo { FileFormat Format; MachineInfo Machine; @@ -509,7 +591,7 @@ return createStringError(errc::invalid_argument, "too many positional arguments"); - CopyConfig Config; + ParsedMultiFormatConfig Config; Config.InputFilename = Positional[0]; Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; if (InputArgs.hasArg(OBJCOPY_target) && @@ -548,9 +630,22 @@ .Case("ihex", FileFormat::IHex) .Default(FileFormat::Unspecified); - if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) - Config.NewSymbolVisibility = + if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) { + const uint8_t Invalid = 0xff; + StringRef NewSymbolVisibilityValue = InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); + Config.NewSymbolVisibility = StringSwitch(NewSymbolVisibilityValue) + .Case("default", ELF::STV_DEFAULT) + .Case("hidden", ELF::STV_HIDDEN) + .Case("internal", ELF::STV_INTERNAL) + .Case("protected", ELF::STV_PROTECTED) + .Default(Invalid); + + if (Config.NewSymbolVisibility == Invalid) + return createStringError(errc::invalid_argument, + "'%s' is not a valid symbol visibility", + NewSymbolVisibilityValue.data()); + } Config.OutputFormat = StringSwitch(OutputFormat) .Case("binary", FileFormat::Binary) @@ -791,8 +886,14 @@ addSymbolsFromFile(Config.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()); + for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) { + Expected NSI = parseNewSymbolInfo( + Arg->getValue(), + Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + Config.SymbolsToAdd.push_back(*NSI); + } Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); @@ -856,7 +957,8 @@ Expected parseInstallNameToolOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ParsedMultiFormatConfig Config; + InstallNameToolOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -987,7 +1089,8 @@ Expected parseBitcodeStripOptions(ArrayRef ArgsArr) { DriverConfig DC; - CopyConfig Config; + ParsedMultiFormatConfig Config; + BitcodeStripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; opt::InputArgList InputArgs = @@ -1070,7 +1173,7 @@ errc::invalid_argument, "multiple input files cannot be used in combination with -o"); - CopyConfig Config; + ParsedMultiFormatConfig Config; if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) return createStringError(errc::invalid_argument, 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 @@ -9,6 +9,7 @@ #ifndef LLVM_TOOLS_OBJCOPY_OBJCOPY_H #define LLVM_TOOLS_OBJCOPY_OBJCOPY_H +#include "MultiFormatCopyConfig.h" #include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" @@ -23,9 +24,9 @@ } // end namespace object namespace objcopy { -struct CopyConfig; Expected> -createNewArchiveMembers(CopyConfig &Config, const object::Archive &Ar); +createNewArchiveMembers(const MultiFormatCopyConfig &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,9 @@ #include "llvm-objcopy.h" #include "COFF/COFFObjcopy.h" -#include "CopyConfig.h" #include "ELF/ELFObjcopy.h" #include "MachO/MachOObjcopy.h" +#include "ParsedConfig.h" #include "wasm/WasmObjcopy.h" #include "llvm/ADT/STLExtras.h" @@ -133,18 +133,20 @@ /// 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, - raw_ostream &Out) { +static Error executeObjcopyOnIHex(const MultiFormatCopyConfig &Config, + 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 ELFConfig = Config.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnIHex(*ELFConfig, In, Out); } /// The function executeObjcopyOnRawBinary does the dispatch based on the format /// of the output specified by the command line options. -static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In, - raw_ostream &Out) { +static Error executeObjcopyOnRawBinary(const MultiFormatCopyConfig &Config, + MemoryBuffer &In, raw_ostream &Out) { switch (Config.OutputFormat) { case FileFormat::ELF: // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the @@ -153,9 +155,11 @@ case FileFormat::Binary: case FileFormat::IHex: case FileFormat::Unspecified: - if (Error E = Config.parseELFConfig()) - return E; - return elf::executeObjcopyOnRawBinary(Config, In, Out); + Expected ELFConfig = Config.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnRawBinary(*ELFConfig, In, Out); } llvm_unreachable("unsupported output format"); @@ -163,23 +167,37 @@ /// 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 MultiFormatCopyConfig &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 ELFConfig = Config.getELFConfig(); + if (!ELFConfig) + return ELFConfig.takeError(); + + return elf::executeObjcopyOnBinary(*ELFConfig, *ELFBinary, Out); + } else if (auto *COFFBinary = dyn_cast(&In)) { + Expected COFFConfig = Config.getCOFFConfig(); + if (!COFFConfig) + return COFFConfig.takeError(); + + return coff::executeObjcopyOnBinary(*COFFConfig, *COFFBinary, Out); + } else if (auto *MachOBinary = dyn_cast(&In)) { + Expected MachOConfig = Config.getMachOConfig(); + if (!MachOConfig) + return MachOConfig.takeError(); + + return macho::executeObjcopyOnBinary(*MachOConfig, *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 WasmConfig = Config.getWasmConfig(); + if (!WasmConfig) + return WasmConfig.takeError(); + + return objcopy::wasm::executeObjcopyOnBinary(*WasmConfig, *WasmBinary, Out); + } else return createStringError(object_error::invalid_file_type, "unsupported object file format"); } @@ -188,7 +206,8 @@ namespace objcopy { Expected> -createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) { +createNewArchiveMembers(const MultiFormatCopyConfig &Config, + const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -225,7 +244,7 @@ } // end namespace objcopy } // end namespace llvm -static Error executeObjcopyOnArchive(CopyConfig &Config, +static Error executeObjcopyOnArchive(const MultiFormatCopyConfig &Config, const object::Archive &Ar) { Expected> NewArchiveMembersOrErr = createNewArchiveMembers(Config, Ar); @@ -238,7 +257,7 @@ static Error restoreStatOnFile(StringRef Filename, const sys::fs::file_status &Stat, - const CopyConfig &Config) { + const CopyConfigBase &Config) { int FD; // Writing to stdout should not be treated as an error here, just @@ -285,7 +304,7 @@ /// 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(ParsedMultiFormatConfig &Config) { sys::fs::file_status Stat; if (Config.InputFilename != "-") { if (auto EC = sys::fs::status(Config.InputFilename, Stat)) @@ -310,12 +329,14 @@ if (Config.InputFormat == FileFormat::Binary) ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { // Handle FileFormat::Binary. - return executeObjcopyOnRawBinary(Config, *MemoryBufferHolder, OutFile); + return executeObjcopyOnRawBinary(Config.getMultiFormatConfig(), + *MemoryBufferHolder, OutFile); }; else ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { // Handle FileFormat::IHex. - return executeObjcopyOnIHex(Config, *MemoryBufferHolder, OutFile); + return executeObjcopyOnIHex(Config.getMultiFormatConfig(), + *MemoryBufferHolder, OutFile); }; } else { Expected> BinaryOrErr = @@ -326,13 +347,13 @@ if (Archive *Ar = dyn_cast(BinaryHolder.getBinary())) { // Handle Archive. - if (Error E = executeObjcopyOnArchive(Config, *Ar)) + if (Error E = executeObjcopyOnArchive(Config.getMultiFormatConfig(), *Ar)) return E; } else { // Handle llvm::object::Binary. ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { - return executeObjcopyOnBinary(Config, *BinaryHolder.getBinary(), - OutFile); + return executeObjcopyOnBinary(Config.getMultiFormatConfig(), + *BinaryHolder.getBinary(), OutFile); }; } } @@ -401,7 +422,7 @@ WithColor::error(errs(), ToolName)); return 1; } - for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { + for (ParsedMultiFormatConfig &CopyConfig : DriverConfig->CopyConfigs) { if (Error E = executeObjcopy(CopyConfig)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; diff --git a/llvm/tools/llvm-objcopy/wasm/CopyConfigWasm.h b/llvm/tools/llvm-objcopy/wasm/CopyConfigWasm.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objcopy/wasm/CopyConfigWasm.h @@ -0,0 +1,29 @@ +//===- CopyConfigWasm.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_WASM_COPYCONFIGWASM_H +#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_COPYCONFIGWASM_H + +#include "CopyConfigBase.h" + +namespace llvm { +namespace objcopy { + +struct WasmSpecificConfig {}; + +/// Configuration for copying/stripping a single file. This structure keeps +/// common options for all formats and Wasm-specific options. +struct CopyConfigWasm : virtual public CopyConfigBase, + virtual public WasmSpecificConfig { + CopyConfigWasm &operator=(CopyConfigWasm &&) = delete; +}; + +} // namespace objcopy +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_COPYCONFIGWASM_H 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,10 @@ } // end namespace object namespace objcopy { -struct CopyConfig; +struct CopyConfigWasm; namespace wasm { -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfigWasm &Config, 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 "CopyConfigWasm.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 CopyConfigWasm &Config, Object &Obj) { // Only support AddSection, DumpSection, RemoveSection for now. for (StringRef Flag : Config.DumpSection) { StringRef SecName; @@ -72,26 +72,10 @@ 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 CopyConfigWasm &Config, object::WasmObjectFile &In, raw_ostream &Out) { Reader TheReader(In); Expected> ObjOrErr = TheReader.create();