diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy')
-rw-r--r-- | llvm/tools/llvm-objcopy/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/CopyConfig.cpp | 108 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/CopyConfig.h | 29 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp | 133 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/ELFConfig.h | 44 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 4 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 29 |
7 files changed, 220 insertions, 128 deletions
diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt index d281bf8..50c890b5 100644 --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -21,6 +21,7 @@ add_llvm_tool(llvm-objcopy 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/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp index a84114e..1425321 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -177,87 +177,6 @@ parseSetSectionFlagValue(StringRef FlagValue) { return SFU; } -static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue, - uint8_t DefaultVisibility) { - // Parse value given with --add-symbol option and create the - // new symbol if possible. The value format for --add-symbol is: - // - // <name>=[<section>:]<value>[,<flags>] - // - // where: - // <name> - symbol name, can be empty string - // <section> - optional section name. If not given ABS symbol is created - // <value> - symbol value, can be decimal or hexadecimal number prefixed - // with 0x. - // <flags> - optional flags affecting symbol type, binding or visibility: - // The following are currently supported: - // - // global, local, weak, default, hidden, file, section, object, - // indirect-function. - // - // The following flags are ignored and provided for GNU - // compatibility only: - // - // warning, debug, constructor, indirect, synthetic, - // unique-object, before=<symbol>. - NewSymbolInfo SI; - StringRef Value; - std::tie(SI.SymbolName, Value) = FlagValue.split('='); - if (Value.empty()) - return createStringError( - errc::invalid_argument, - "bad format for --add-symbol, missing '=' after '%s'", - SI.SymbolName.str().c_str()); - - if (Value.contains(':')) { - std::tie(SI.SectionName, Value) = Value.split(':'); - if (SI.SectionName.empty() || Value.empty()) - return createStringError( - errc::invalid_argument, - "bad format for --add-symbol, missing section name or symbol value"); - } - - SmallVector<StringRef, 6> Flags; - Value.split(Flags, ','); - if (Flags[0].getAsInteger(0, SI.Value)) - return createStringError(errc::invalid_argument, "bad symbol value: '%s'", - Flags[0].str().c_str()); - - SI.Visibility = DefaultVisibility; - - using Functor = std::function<void(void)>; - SmallVector<StringRef, 6> UnsupportedFlags; - for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) - static_cast<Functor>( - StringSwitch<Functor>(Flags[I]) - .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) - .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) - .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) - .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) - .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) - .CaseLower("protected", [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) - .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) - .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) - .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) - .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) - .CaseLower("indirect-function", - [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) - .CaseLower("debug", [] {}) - .CaseLower("constructor", [] {}) - .CaseLower("warning", [] {}) - .CaseLower("indirect", [] {}) - .CaseLower("synthetic", [] {}) - .CaseLower("unique-object", [] {}) - .StartsWithLower("before", [] {}) - .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); - if (!UnsupportedFlags.empty()) - return createStringError(errc::invalid_argument, - "unsupported flag%s for --add-symbol: '%s'", - UnsupportedFlags.size() > 1 ? "s" : "", - join(UnsupportedFlags, "', '").c_str()); - return SI; -} - struct TargetInfo { FileFormat Format; MachineInfo Machine; @@ -467,20 +386,9 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { .Case("ihex", FileFormat::IHex) .Default(FileFormat::Unspecified); - if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility)) { - const uint8_t Invalid = 0xff; - Config.NewSymbolVisibility = StringSwitch<uint8_t>(A->getValue()) - .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", - InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility).str().c_str()); - } + if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility)) + Config.NewSymbolVisibility = + InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat) .Case("binary", FileFormat::Binary) @@ -694,14 +602,8 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), UseRegex)) return std::move(E); - for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) { - Expected<NewSymbolInfo> NSI = parseNewSymbolInfo( - Arg->getValue(), - Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); - if (!NSI) - return NSI.takeError(); - Config.SymbolsToAdd.push_back(*NSI); - } + for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) + Config.SymbolsToAdd.push_back(Arg->getValue()); Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h index 0b68d23..85d6604 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -9,6 +9,7 @@ #ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H #define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H +#include "ELF/ELFConfig.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/Optional.h" @@ -111,17 +112,11 @@ public: bool empty() const { return Matchers.empty(); } }; -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; -}; - // Configuration for copying/stripping a single file. struct CopyConfig { + // Format-specific options to be initialized lazily when needed. + Optional<elf::ELFCopyConfig> ELF; + // Main input/output options StringRef InputFilename; FileFormat InputFormat; @@ -143,12 +138,12 @@ struct CopyConfig { StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; - Optional<uint8_t> NewSymbolVisibility; + Optional<StringRef> NewSymbolVisibility; // Repeated options std::vector<StringRef> AddSection; std::vector<StringRef> DumpSection; - std::vector<NewSymbolInfo> SymbolsToAdd; + std::vector<StringRef> SymbolsToAdd; // Section matchers NameMatcher KeepSection; @@ -194,6 +189,18 @@ struct CopyConfig { bool Weaken = false; bool DecompressDebugSections = false; DebugCompressionType CompressionType = DebugCompressionType::None; + + // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on + // success or returns an Error otherwise. + Error parseELFConfig() { + if (!ELF) { + Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this); + if (!ELFConfig) + return ELFConfig.takeError(); + ELF = *ELFConfig; + } + return Error::success(); + } }; // Configuration for the overall invocation of this tool. When invoked as diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp b/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp new file mode 100644 index 0000000..4099376 --- /dev/null +++ b/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp @@ -0,0 +1,133 @@ +//===- ELFConfig.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CopyConfig.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace objcopy { +namespace elf { + +static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue, + uint8_t DefaultVisibility) { + // Parse value given with --add-symbol option and create the + // new symbol if possible. The value format for --add-symbol is: + // + // <name>=[<section>:]<value>[,<flags>] + // + // where: + // <name> - symbol name, can be empty string + // <section> - optional section name. If not given ABS symbol is created + // <value> - symbol value, can be decimal or hexadecimal number prefixed + // with 0x. + // <flags> - optional flags affecting symbol type, binding or visibility: + // The following are currently supported: + // + // global, local, weak, default, hidden, file, section, object, + // indirect-function. + // + // The following flags are ignored and provided for GNU + // compatibility only: + // + // warning, debug, constructor, indirect, synthetic, + // unique-object, before=<symbol>. + NewSymbolInfo SI; + StringRef Value; + std::tie(SI.SymbolName, Value) = FlagValue.split('='); + if (Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing '=' after '%s'", + SI.SymbolName.str().c_str()); + + if (Value.contains(':')) { + std::tie(SI.SectionName, Value) = Value.split(':'); + if (SI.SectionName.empty() || Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing section name or symbol value"); + } + + SmallVector<StringRef, 6> Flags; + Value.split(Flags, ','); + if (Flags[0].getAsInteger(0, SI.Value)) + return createStringError(errc::invalid_argument, "bad symbol value: '%s'", + Flags[0].str().c_str()); + + SI.Visibility = DefaultVisibility; + + using Functor = std::function<void(void)>; + SmallVector<StringRef, 6> UnsupportedFlags; + for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) + static_cast<Functor>( + StringSwitch<Functor>(Flags[I]) + .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) + .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) + .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) + .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) + .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) + .CaseLower("protected", + [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) + .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) + .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) + .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) + .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) + .CaseLower("indirect-function", + [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) + .CaseLower("debug", [] {}) + .CaseLower("constructor", [] {}) + .CaseLower("warning", [] {}) + .CaseLower("indirect", [] {}) + .CaseLower("synthetic", [] {}) + .CaseLower("unique-object", [] {}) + .StartsWithLower("before", [] {}) + .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); + if (!UnsupportedFlags.empty()) + return createStringError(errc::invalid_argument, + "unsupported flag%s for --add-symbol: '%s'", + UnsupportedFlags.size() > 1 ? "s" : "", + join(UnsupportedFlags, "', '").c_str()); + return SI; +} + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) { + ELFCopyConfig ELFConfig; + if (Config.NewSymbolVisibility) { + const uint8_t Invalid = 0xff; + ELFConfig.NewSymbolVisibility = + StringSwitch<uint8_t>(*Config.NewSymbolVisibility) + .Case("default", ELF::STV_DEFAULT) + .Case("hidden", ELF::STV_HIDDEN) + .Case("internal", ELF::STV_INTERNAL) + .Case("protected", ELF::STV_PROTECTED) + .Default(Invalid); + + if (ELFConfig.NewSymbolVisibility == Invalid) + return createStringError(errc::invalid_argument, + "'%s' is not a valid symbol visibility", + Config.NewSymbolVisibility->str().c_str()); + } + + for (StringRef Arg : Config.SymbolsToAdd) { + Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo( + Arg, + ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + ELFConfig.SymbolsToAdd.push_back(*NSI); + } + + return ELFConfig; +} + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h new file mode 100644 index 0000000..977efbc --- /dev/null +++ b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h @@ -0,0 +1,44 @@ +//===- 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 <vector> + +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<uint8_t> NewSymbolVisibility; + std::vector<NewSymbolInfo> SymbolsToAdd; +}; + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config); + +} // namespace elf +} // namespace objcopy +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 04ff920..2f29d90 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -710,7 +710,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, Config.GnuDebugLinkCRC32); - for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { + for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -746,7 +746,7 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, Buffer &Out) { uint8_t NewSymbolVisibility = - Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); BinaryReader Reader(&In, NewSymbolVisibility); std::unique_ptr<Object> Obj = Reader.create(); diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index e9094f2..db6d751 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -132,16 +132,18 @@ static Error deepWriteArchive(StringRef ArcName, /// The function executeObjcopyOnIHex does the dispatch based on the format /// of the output specified by the command line options. -static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In, Buffer &Out) { // TODO: support output formats other than ELF. + if (Error E = Config.parseELFConfig()) + return E; return elf::executeObjcopyOnIHex(Config, In, Out); } /// The function executeObjcopyOnRawBinary does the dispatch based on the format /// of the output specified by the command line options. -static Error executeObjcopyOnRawBinary(const CopyConfig &Config, - MemoryBuffer &In, Buffer &Out) { +static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In, + Buffer &Out) { switch (Config.OutputFormat) { case FileFormat::ELF: // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the @@ -150,6 +152,8 @@ static Error executeObjcopyOnRawBinary(const CopyConfig &Config, case FileFormat::Binary: case FileFormat::IHex: case FileFormat::Unspecified: + if (Error E = Config.parseELFConfig()) + return E; return elf::executeObjcopyOnRawBinary(Config, In, Out); } @@ -158,11 +162,13 @@ static Error executeObjcopyOnRawBinary(const CopyConfig &Config, /// The function executeObjcopyOnBinary does the dispatch based on the format /// of the input binary (ELF, MachO or COFF). -static Error executeObjcopyOnBinary(const CopyConfig &Config, - object::Binary &In, Buffer &Out) { - if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) +static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In, + Buffer &Out) { + if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) { + if (Error E = Config.parseELFConfig()) + return E; return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); - else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) + } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out); else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In)) return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); @@ -171,8 +177,7 @@ static Error executeObjcopyOnBinary(const CopyConfig &Config, "unsupported object file format"); } -static Error executeObjcopyOnArchive(const CopyConfig &Config, - const Archive &Ar) { +static Error executeObjcopyOnArchive(CopyConfig &Config, const Archive &Ar) { std::vector<NewArchiveMember> NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -248,7 +253,7 @@ static Error restoreStatOnFile(StringRef Filename, /// The function executeObjcopy does the higher level dispatch based on the type /// of input (raw binary, archive or single object file) and takes care of the /// format-agnostic modifications, i.e. preserving dates. -static Error executeObjcopy(const CopyConfig &Config) { +static Error executeObjcopy(CopyConfig &Config) { sys::fs::file_status Stat; if (Config.InputFilename != "-") { if (auto EC = sys::fs::status(Config.InputFilename, Stat)) @@ -257,7 +262,7 @@ static Error executeObjcopy(const CopyConfig &Config) { Stat.permissions(static_cast<sys::fs::perms>(0777)); } - typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &); + using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &); ProcessRawFn ProcessRaw; switch (Config.InputFormat) { case FileFormat::Binary: @@ -336,7 +341,7 @@ int main(int argc, char **argv) { WithColor::error(errs(), ToolName)); return 1; } - for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { + for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { if (Error E = executeObjcopy(CopyConfig)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; |