Index: llvm/tools/llvm-objcopy/CMakeLists.txt =================================================================== --- llvm/tools/llvm-objcopy/CMakeLists.txt +++ llvm/tools/llvm-objcopy/CMakeLists.txt @@ -21,6 +21,7 @@ COFF/Object.cpp COFF/Reader.cpp COFF/Writer.cpp + ELF/ELFConfig.cpp ELF/ELFObjcopy.cpp ELF/Object.cpp MachO/MachOObjcopy.cpp Index: llvm/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.h +++ llvm/tools/llvm-objcopy/CopyConfig.h @@ -111,15 +111,6 @@ 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 { // Main input/output options @@ -145,12 +136,12 @@ StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; - Optional NewSymbolVisibility; + Optional NewSymbolVisibility; // Repeated options std::vector AddSection; std::vector DumpSection; - std::vector SymbolsToAdd; + std::vector SymbolsToAdd; // Section matchers NameMatcher KeepSection; Index: llvm/tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.cpp +++ llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -177,87 +177,6 @@ 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; -} - static const StringMap ArchMap{ // Name, {EMachine, 64bit, LittleEndian} {"aarch64", {ELF::EM_AARCH64, true, true}}, @@ -491,20 +410,9 @@ Config.BinaryArch = *MI; } - if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility)) { - const uint8_t Invalid = 0xff; - Config.NewSymbolVisibility = StringSwitch(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 (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) + Config.NewSymbolVisibility = + InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); Config.OutputFormat = StringSwitch(OutputFormat) .Case("binary", FileFormat::Binary) @@ -713,14 +621,8 @@ if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), UseRegex)) return std::move(E); - 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); - } + for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) + Config.SymbolsToAdd.push_back(Arg->getValue()); Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); Index: llvm/tools/llvm-objcopy/ELF/ELFConfig.h =================================================================== --- /dev/null +++ llvm/tools/llvm-objcopy/ELF/ELFConfig.h @@ -0,0 +1,40 @@ +//===- 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 "CopyConfig.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; +}; + +class ELFCopyConfig { + const CopyConfig &Common; + +public: + Optional NewSymbolVisibility; + std::vector SymbolsToAdd; + + ELFCopyConfig(const CopyConfig &Common) : Common(Common){}; + Error parse(); +}; + +} // namespace objcopy +} // namespace llvm + +#endif Index: llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp @@ -0,0 +1,127 @@ +//===- 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 "ELFConfig.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Errc.h" + +namespace llvm { +namespace objcopy { + +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; +} + +Error ELFCopyConfig::parse() { + if (Common.NewSymbolVisibility) { + const uint8_t Invalid = 0xff; + NewSymbolVisibility = StringSwitch(*Common.NewSymbolVisibility) + .Case("default", ELF::STV_DEFAULT) + .Case("hidden", ELF::STV_HIDDEN) + .Case("internal", ELF::STV_INTERNAL) + .Case("protected", ELF::STV_PROTECTED) + .Default(Invalid); + + if (NewSymbolVisibility == Invalid) + return createStringError(errc::invalid_argument, + "'%s' is not a valid symbol visibility", + Common.NewSymbolVisibility->data()); + } + + for (auto Arg : Common.SymbolsToAdd) { + Expected NSI = parseNewSymbolInfo( + Arg, NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + SymbolsToAdd.push_back(*NSI); + } + + return Error::success(); +} + +} // end namespace objcopy +} // end namespace llvm Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -19,14 +19,18 @@ namespace objcopy { struct CopyConfig; +class ELFCopyConfig; class Buffer; namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, MemoryBuffer &In, Buffer &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out); +Error executeObjcopyOnRawBinary(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, + MemoryBuffer &In, Buffer &Out); Error executeObjcopyOnBinary(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, object::ELFObjectFileBase &In, Buffer &Out); } // end namespace elf Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -9,6 +9,7 @@ #include "ELFObjcopy.h" #include "Buffer.h" #include "CopyConfig.h" +#include "ELFConfig.h" #include "Object.h" #include "llvm-objcopy.h" @@ -131,6 +132,7 @@ } static std::unique_ptr createELFWriter(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, Object &Obj, Buffer &Buf, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. @@ -152,6 +154,7 @@ } static std::unique_ptr createWriter(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, Object &Obj, Buffer &Buf, ElfType OutputElfType) { switch (Config.OutputFormat) { @@ -160,13 +163,14 @@ case FileFormat::IHex: return std::make_unique(Obj, Buf); default: - return createELFWriter(Config, Obj, Buf, OutputElfType); + return createELFWriter(Config, ELFConfig, Obj, Buf, OutputElfType); } } template static Expected> -findBuildID(const CopyConfig &Config, const object::ELFFile &In) { +findBuildID(const CopyConfig &Config, const ELFCopyConfig &ELFConfig, + const object::ELFFile &In) { auto PhdrsOrErr = In.program_headers(); if (auto Err = PhdrsOrErr.takeError()) return createFileError(Config.InputFilename, std::move(Err)); @@ -189,15 +193,16 @@ } static Expected> -findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) { +findBuildID(const CopyConfig &Config, const ELFCopyConfig &ELFConfig, + const object::ELFObjectFileBase &In) { if (auto *O = dyn_cast>(&In)) - return findBuildID(Config, *O->getELFFile()); + return findBuildID(Config, ELFConfig, *O->getELFFile()); else if (auto *O = dyn_cast>(&In)) - return findBuildID(Config, *O->getELFFile()); + return findBuildID(Config, ELFConfig, *O->getELFFile()); else if (auto *O = dyn_cast>(&In)) - return findBuildID(Config, *O->getELFFile()); + return findBuildID(Config, ELFConfig, *O->getELFFile()); else if (auto *O = dyn_cast>(&In)) - return findBuildID(Config, *O->getELFFile()); + return findBuildID(Config, ELFConfig, *O->getELFFile()); llvm_unreachable("Bad file format"); } @@ -212,7 +217,8 @@ #define MODEL_16 MODEL_8 MODEL_8 #define MODEL_32 (MODEL_16 MODEL_16) -static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, +static Error linkToBuildIdDir(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, StringRef ToLink, StringRef Suffix, ArrayRef BuildIdBytes) { SmallString<128> Path = Config.BuildIdLinkDir; @@ -261,8 +267,10 @@ return Error::success(); } -static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, - StringRef File, ElfType OutputElfType) { +static Error splitDWOToFile(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, + const Reader &Reader, StringRef File, + ElfType OutputElfType) { auto DWOFile = Reader.create(); auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); @@ -275,7 +283,7 @@ DWOFile->OSABI = Config.OutputArch.getValue().OSABI; } FileBuffer FB(File); - auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); + auto Writer = createWriter(Config, ELFConfig, *DWOFile, FB, OutputElfType); if (Error E = Writer->finalize()) return E; return Writer->write(); @@ -344,7 +352,9 @@ Sym.Type != STT_SECTION; } -static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +static Error updateAndRemoveSymbols(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, + Object &Obj) { // TODO: update or remove symbols only if there is an option that affects // them. if (!Obj.SymbolTable) @@ -436,7 +446,9 @@ return Obj.removeSymbols(RemoveSymbolsPred); } -static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { +static Error replaceAndRemoveSections(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, + Object &Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: @@ -590,12 +602,13 @@ // 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, +static Error handleArgs(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, Object &Obj, const Reader &Reader, ElfType OutputElfType) { if (!Config.SplitDWO.empty()) - if (Error E = - splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) + if (Error E = splitDWOToFile(Config, ELFConfig, Reader, Config.SplitDWO, + OutputElfType)) return E; if (Config.OutputArch) { @@ -607,10 +620,10 @@ // 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(Config, ELFConfig, Obj)) return E; - if (Error E = updateAndRemoveSymbols(Config, Obj)) + if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj)) return E; if (!Config.SectionsToRename.empty()) { @@ -710,7 +723,7 @@ Obj.addSection(Config.AddGnuDebugLink, Config.GnuDebugLinkCRC32); - for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { + for (const NewSymbolInfo &SI : ELFConfig.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -723,30 +736,33 @@ return Error::success(); } -static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, - ElfType OutputElfType) { +static Error writeOutput(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, Object &Obj, + Buffer &Out, ElfType OutputElfType) { std::unique_ptr Writer = - createWriter(Config, Obj, Out, OutputElfType); + createWriter(Config, ELFConfig, Obj, Out, OutputElfType); if (Error E = Writer->finalize()) return E; return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, MemoryBuffer &In, Buffer &Out) { IHexReader Reader(&In); std::unique_ptr Obj = Reader.create(); const ElfType OutputElfType = getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); - if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) + if (Error E = handleArgs(Config, ELFConfig, *Obj, Reader, OutputElfType)) return E; - return writeOutput(Config, *Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, *Obj, Out, OutputElfType); } -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out) { +Error executeObjcopyOnRawBinary(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, + MemoryBuffer &In, Buffer &Out) { uint8_t NewSymbolVisibility = - Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); BinaryReader Reader(Config.BinaryArch, &In, NewSymbolVisibility); std::unique_ptr Obj = Reader.create(); @@ -754,12 +770,13 @@ // (-B). const ElfType OutputElfType = getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); - if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) + if (Error E = handleArgs(Config, ELFConfig, *Obj, Reader, OutputElfType)) return E; - return writeOutput(Config, *Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, *Obj, Out, OutputElfType); } Error executeObjcopyOnBinary(const CopyConfig &Config, + const ELFCopyConfig &ELFConfig, object::ELFObjectFileBase &In, Buffer &Out) { ELFReader Reader(&In, Config.ExtractPartition); std::unique_ptr Obj = Reader.create(); @@ -770,7 +787,7 @@ ArrayRef BuildIdBytes; if (!Config.BuildIdLinkDir.empty()) { - auto BuildIdBytesOrErr = findBuildID(Config, In); + auto BuildIdBytesOrErr = findBuildID(Config, ELFConfig, In); if (auto E = BuildIdBytesOrErr.takeError()) return E; BuildIdBytes = *BuildIdBytesOrErr; @@ -784,18 +801,18 @@ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) if (Error E = - linkToBuildIdDir(Config, Config.InputFilename, + linkToBuildIdDir(Config, ELFConfig, Config.InputFilename, Config.BuildIdLinkInput.getValue(), BuildIdBytes)) return E; - if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) + if (Error E = handleArgs(Config, ELFConfig, *Obj, Reader, OutputElfType)) return createFileError(Config.InputFilename, std::move(E)); - if (Error E = writeOutput(Config, *Obj, Out, OutputElfType)) + if (Error E = writeOutput(Config, ELFConfig, *Obj, Out, OutputElfType)) return createFileError(Config.InputFilename, std::move(E)); if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) if (Error E = - linkToBuildIdDir(Config, Config.OutputFilename, + linkToBuildIdDir(Config, ELFConfig, Config.OutputFilename, Config.BuildIdLinkOutput.getValue(), BuildIdBytes)) return createFileError(Config.OutputFilename, std::move(E)); Index: llvm/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -8,9 +8,10 @@ #include "llvm-objcopy.h" #include "Buffer.h" +#include "COFF/COFFObjcopy.h" #include "CopyConfig.h" +#include "ELF/ELFConfig.h" #include "ELF/ELFObjcopy.h" -#include "COFF/COFFObjcopy.h" #include "MachO/MachOObjcopy.h" #include "llvm/ADT/STLExtras.h" @@ -88,6 +89,22 @@ return Error::success(); } +struct Configurations { + const CopyConfig &Common; + Optional ELF; + + Configurations(const CopyConfig &Common) : Common(Common) {} + + Error parseELFConfig() { + if (!ELF) { + ELF.emplace(Common); + if (Error E = ELF->parse()) + return E; + } + return Error::success(); + } +}; + } // end namespace objcopy } // end namespace llvm @@ -130,17 +147,19 @@ /// 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(Configurations &Cfg, MemoryBuffer &In, Buffer &Out) { // TODO: support output formats other than ELF. - return elf::executeObjcopyOnIHex(Config, In, Out); + if (Error E = Cfg.parseELFConfig()) + return E; + return elf::executeObjcopyOnIHex(Cfg.Common, *Cfg.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(const CopyConfig &Config, - MemoryBuffer &In, Buffer &Out) { - switch (Config.OutputFormat) { +static Error executeObjcopyOnRawBinary(Configurations &Cfg, MemoryBuffer &In, + Buffer &Out) { + switch (Cfg.Common.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 @@ -148,7 +167,9 @@ case FileFormat::Binary: case FileFormat::IHex: case FileFormat::Unspecified: - return elf::executeObjcopyOnRawBinary(Config, In, Out); + if (Error E = Cfg.parseELFConfig()) + return E; + return elf::executeObjcopyOnRawBinary(Cfg.Common, *Cfg.ELF, In, Out); } llvm_unreachable("unsupported output format"); @@ -156,21 +177,22 @@ /// 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(&In)) - return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); - else if (auto *COFFBinary = dyn_cast(&In)) - return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out); +static Error executeObjcopyOnBinary(Configurations &Cfg, object::Binary &In, + Buffer &Out) { + if (auto *ELFBinary = dyn_cast(&In)) { + if (Error E = Cfg.parseELFConfig()) + return E; + return elf::executeObjcopyOnBinary(Cfg.Common, *Cfg.ELF, *ELFBinary, Out); + } else if (auto *COFFBinary = dyn_cast(&In)) + return coff::executeObjcopyOnBinary(Cfg.Common, *COFFBinary, Out); else if (auto *MachOBinary = dyn_cast(&In)) - return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); + return macho::executeObjcopyOnBinary(Cfg.Common, *MachOBinary, Out); else return createStringError(object_error::invalid_file_type, "unsupported object file format"); } -static Error executeObjcopyOnArchive(const CopyConfig &Config, - const Archive &Ar) { +static Error executeObjcopyOnArchive(Configurations &Cfg, const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -184,11 +206,11 @@ ChildOrErr.takeError()); MemBuffer MB(ChildNameOrErr.get()); - if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB)) + if (Error E = executeObjcopyOnBinary(Cfg, *ChildOrErr->get(), MB)) return E; Expected Member = - NewArchiveMember::getOldMember(Child, Config.DeterministicArchives); + NewArchiveMember::getOldMember(Child, Cfg.Common.DeterministicArchives); if (!Member) return createFileError(Ar.getFileName(), Member.takeError()); Member->Buf = MB.releaseMemoryBuffer(); @@ -196,11 +218,11 @@ NewArchiveMembers.push_back(std::move(*Member)); } if (Err) - return createFileError(Config.InputFilename, std::move(Err)); + return createFileError(Cfg.Common.InputFilename, std::move(Err)); - return deepWriteArchive(Config.OutputFilename, NewArchiveMembers, + return deepWriteArchive(Cfg.Common.OutputFilename, NewArchiveMembers, Ar.hasSymbolTable(), Ar.kind(), - Config.DeterministicArchives, Ar.isThin()); + Cfg.Common.DeterministicArchives, Ar.isThin()); } static Error restoreStatOnFile(StringRef Filename, @@ -246,18 +268,18 @@ /// 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(Configurations &Cfg) { sys::fs::file_status Stat; - if (Config.InputFilename != "-") { - if (auto EC = sys::fs::status(Config.InputFilename, Stat)) - return createFileError(Config.InputFilename, EC); + if (Cfg.Common.InputFilename != "-") { + if (auto EC = sys::fs::status(Cfg.Common.InputFilename, Stat)) + return createFileError(Cfg.Common.InputFilename, EC); } else { Stat.permissions(static_cast(0777)); } - typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &); + typedef Error (*ProcessRawFn)(Configurations &, MemoryBuffer &, Buffer &); ProcessRawFn ProcessRaw; - switch (Config.InputFormat) { + switch (Cfg.Common.InputFormat) { case FileFormat::Binary: ProcessRaw = executeObjcopyOnRawBinary; break; @@ -269,37 +291,37 @@ } if (ProcessRaw) { - auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename); + auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Cfg.Common.InputFilename); if (!BufOrErr) - return createFileError(Config.InputFilename, BufOrErr.getError()); - FileBuffer FB(Config.OutputFilename); - if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB)) + return createFileError(Cfg.Common.InputFilename, BufOrErr.getError()); + FileBuffer FB(Cfg.Common.OutputFilename); + if (Error E = ProcessRaw(Cfg, *BufOrErr->get(), FB)) return E; } else { Expected> BinaryOrErr = - createBinary(Config.InputFilename); + createBinary(Cfg.Common.InputFilename); if (!BinaryOrErr) - return createFileError(Config.InputFilename, BinaryOrErr.takeError()); + return createFileError(Cfg.Common.InputFilename, BinaryOrErr.takeError()); if (Archive *Ar = dyn_cast(BinaryOrErr.get().getBinary())) { - if (Error E = executeObjcopyOnArchive(Config, *Ar)) + if (Error E = executeObjcopyOnArchive(Cfg, *Ar)) return E; } else { - FileBuffer FB(Config.OutputFilename); - if (Error E = executeObjcopyOnBinary(Config, - *BinaryOrErr.get().getBinary(), FB)) + FileBuffer FB(Cfg.Common.OutputFilename); + if (Error E = + executeObjcopyOnBinary(Cfg, *BinaryOrErr.get().getBinary(), FB)) return E; } } - if (Error E = - restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates)) + if (Error E = restoreStatOnFile(Cfg.Common.OutputFilename, Stat, + Cfg.Common.PreserveDates)) return E; - if (!Config.SplitDWO.empty()) { + if (!Cfg.Common.SplitDWO.empty()) { Stat.permissions(static_cast(0666)); - if (Error E = - restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates)) + if (Error E = restoreStatOnFile(Cfg.Common.SplitDWO, Stat, + Cfg.Common.PreserveDates)) return E; } @@ -319,7 +341,8 @@ return 1; } for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { - if (Error E = executeObjcopy(CopyConfig)) { + Configurations Cfg(CopyConfig); + if (Error E = executeObjcopy(Cfg)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; }