Index: llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -204,7 +204,7 @@ Config.BuildIdLinkInput || Config.BuildIdLinkOutput || !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() || - !Config.KeepSection.empty() || Config.NewSymbolVisibility || + !Config.KeepSection.empty() || Config.Unparsed.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || @@ -213,7 +213,7 @@ Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc || Config.StripSections || Config.Weaken || Config.DecompressDebugSections || Config.DiscardMode == DiscardType::Locals || - !Config.SymbolsToAdd.empty() || Config.EntryExpr) { + !Config.Unparsed.SymbolsToAdd.empty() || Config.EntryExpr) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for COFF"); } Index: llvm/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.h +++ llvm/tools/llvm-objcopy/CopyConfig.h @@ -111,17 +111,16 @@ 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; +// File format specific configuration. +struct UnparsedCopyConfig { + Optional NewSymbolVisibility; + std::vector SymbolsToAdd; }; // Configuration for copying/stripping a single file. struct CopyConfig { + UnparsedCopyConfig Unparsed; + // Main input/output options StringRef InputFilename; FileFormat InputFormat; @@ -145,12 +144,10 @@ StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; - Optional NewSymbolVisibility; // Repeated options std::vector AddSection; std::vector DumpSection; - 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.Unparsed.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(ELF::STV_DEFAULT)); - if (!NSI) - return NSI.takeError(); - Config.SymbolsToAdd.push_back(*NSI); - } + for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) + Config.Unparsed.SymbolsToAdd.push_back(Arg->getValue()); Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -9,6 +9,8 @@ #ifndef LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H #define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H +#include "CopyConfig.h" + namespace llvm { class Error; class MemoryBuffer; @@ -18,9 +20,26 @@ } // end namespace object namespace objcopy { -struct CopyConfig; class Buffer; +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 { + const CopyConfig &Common; + Optional NewSymbolVisibility; + std::vector SymbolsToAdd; + + ELFCopyConfig(const CopyConfig &Common) : Common(Common){}; + Error parse(); +}; + namespace elf { Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, Buffer &Out); Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -47,6 +47,117 @@ 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.Unparsed.NewSymbolVisibility) { + const uint8_t Invalid = 0xff; + NewSymbolVisibility = + StringSwitch(*Common.Unparsed.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.Unparsed.NewSymbolVisibility->data()); + } + + for (const StringRef Arg : Common.Unparsed.SymbolsToAdd) { + Expected NSI = parseNewSymbolInfo( + Arg, NewSymbolVisibility.getValueOr(ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + SymbolsToAdd.push_back(*NSI); + } + + return Error::success(); +} + namespace elf { using namespace object; @@ -130,31 +241,31 @@ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; } -static std::unique_ptr createELFWriter(const CopyConfig &Config, +static std::unique_ptr createELFWriter(const ELFCopyConfig &Config, Object &Obj, Buffer &Buf, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. switch (OutputElfType) { case ELFT_ELF32LE: return std::make_unique>(Obj, Buf, - !Config.StripSections); + !Config.Common.StripSections); case ELFT_ELF64LE: return std::make_unique>(Obj, Buf, - !Config.StripSections); + !Config.Common.StripSections); case ELFT_ELF32BE: return std::make_unique>(Obj, Buf, - !Config.StripSections); + !Config.Common.StripSections); case ELFT_ELF64BE: return std::make_unique>(Obj, Buf, - !Config.StripSections); + !Config.Common.StripSections); } llvm_unreachable("Invalid output format"); } -static std::unique_ptr createWriter(const CopyConfig &Config, +static std::unique_ptr createWriter(const ELFCopyConfig &Config, Object &Obj, Buffer &Buf, ElfType OutputElfType) { - switch (Config.OutputFormat) { + switch (Config.Common.OutputFormat) { case FileFormat::Binary: return std::make_unique(Obj, Buf); case FileFormat::IHex: @@ -166,10 +277,10 @@ template static Expected> -findBuildID(const CopyConfig &Config, const object::ELFFile &In) { +findBuildID(const ELFCopyConfig &Config, const object::ELFFile &In) { auto PhdrsOrErr = In.program_headers(); if (auto Err = PhdrsOrErr.takeError()) - return createFileError(Config.InputFilename, std::move(Err)); + return createFileError(Config.Common.InputFilename, std::move(Err)); for (const auto &Phdr : *PhdrsOrErr) { if (Phdr.p_type != PT_NOTE) @@ -179,17 +290,16 @@ if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) return Note.getDesc(); if (Err) - return createFileError(Config.InputFilename, std::move(Err)); + return createFileError(Config.Common.InputFilename, std::move(Err)); } - return createFileError( - Config.InputFilename, - createStringError(llvm::errc::invalid_argument, - "could not find build ID")); + return createFileError(Config.Common.InputFilename, + createStringError(llvm::errc::invalid_argument, + "could not find build ID")); } static Expected> -findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) { +findBuildID(const ELFCopyConfig &Config, const object::ELFObjectFileBase &In) { if (auto *O = dyn_cast>(&In)) return findBuildID(Config, *O->getELFFile()); else if (auto *O = dyn_cast>(&In)) @@ -212,10 +322,10 @@ #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 ELFCopyConfig &Config, StringRef ToLink, StringRef Suffix, ArrayRef BuildIdBytes) { - SmallString<128> Path = Config.BuildIdLinkDir; + SmallString<128> Path = Config.Common.BuildIdLinkDir; sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); if (auto EC = sys::fs::create_directories(Path)) return createFileError( @@ -261,18 +371,18 @@ return Error::success(); } -static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, +static Error splitDWOToFile(const ELFCopyConfig &Config, const Reader &Reader, StringRef File, ElfType OutputElfType) { auto DWOFile = Reader.create(); auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }; - if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks, + if (Error E = DWOFile->removeSections(Config.Common.AllowBrokenLinks, OnlyKeepDWOPred)) return E; - if (Config.OutputArch) { - DWOFile->Machine = Config.OutputArch.getValue().EMachine; - DWOFile->OSABI = Config.OutputArch.getValue().OSABI; + if (Config.Common.OutputArch) { + DWOFile->Machine = Config.Common.OutputArch.getValue().EMachine; + DWOFile->OSABI = Config.Common.OutputArch.getValue().OSABI; } FileBuffer FB(File); auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); @@ -344,7 +454,7 @@ Sym.Type != STT_SECTION; } -static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +static Error updateAndRemoveSymbols(const ELFCopyConfig &Config, Object &Obj) { // TODO: update or remove symbols only if there is an option that affects // them. if (!Obj.SymbolTable) @@ -354,9 +464,9 @@ // Common and undefined symbols don't make sense as local symbols, and can // even cause crashes if we localize those, so skip them. if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF && - ((Config.LocalizeHidden && + ((Config.Common.LocalizeHidden && (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || - Config.SymbolsToLocalize.matches(Sym.Name))) + Config.Common.SymbolsToLocalize.matches(Sym.Name))) Sym.Binding = STB_LOCAL; // Note: these two globalize flags have very similar names but different @@ -369,64 +479,66 @@ // global in the output file even if it is not included via // --keep-global-symbol. Because of that, make sure to check // --globalize-symbol second. - if (!Config.SymbolsToKeepGlobal.empty() && - !Config.SymbolsToKeepGlobal.matches(Sym.Name) && + if (!Config.Common.SymbolsToKeepGlobal.empty() && + !Config.Common.SymbolsToKeepGlobal.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_LOCAL; - if (Config.SymbolsToGlobalize.matches(Sym.Name) && + if (Config.Common.SymbolsToGlobalize.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_GLOBAL; - if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL) + if (Config.Common.SymbolsToWeaken.matches(Sym.Name) && + Sym.Binding == STB_GLOBAL) Sym.Binding = STB_WEAK; - if (Config.Weaken && Sym.Binding == STB_GLOBAL && + if (Config.Common.Weaken && Sym.Binding == STB_GLOBAL && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_WEAK; - const auto I = Config.SymbolsToRename.find(Sym.Name); - if (I != Config.SymbolsToRename.end()) + const auto I = Config.Common.SymbolsToRename.find(Sym.Name); + if (I != Config.Common.SymbolsToRename.end()) Sym.Name = I->getValue(); - if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) - Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); + if (!Config.Common.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) + Sym.Name = (Config.Common.SymbolsPrefix + Sym.Name).str(); }); // The purpose of this loop is to mark symbols referenced by sections // (like GroupSection or RelocationSection). This way, we know which // symbols are still 'needed' and which are not. - if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || - !Config.OnlySection.empty()) { + if (Config.Common.StripUnneeded || + !Config.Common.UnneededSymbolsToRemove.empty() || + !Config.Common.OnlySection.empty()) { for (auto &Section : Obj.sections()) Section.markSymbols(); } auto RemoveSymbolsPred = [&](const Symbol &Sym) { - if (Config.SymbolsToKeep.matches(Sym.Name) || - (Config.KeepFileSymbols && Sym.Type == STT_FILE)) + if (Config.Common.SymbolsToKeep.matches(Sym.Name) || + (Config.Common.KeepFileSymbols && Sym.Type == STT_FILE)) return false; - if ((Config.DiscardMode == DiscardType::All || - (Config.DiscardMode == DiscardType::Locals && + if ((Config.Common.DiscardMode == DiscardType::All || + (Config.Common.DiscardMode == DiscardType::Locals && StringRef(Sym.Name).startswith(".L"))) && Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && Sym.Type != STT_SECTION) return true; - if (Config.StripAll || Config.StripAllGNU) + if (Config.Common.StripAll || Config.Common.StripAllGNU) return true; - if (Config.SymbolsToRemove.matches(Sym.Name)) + if (Config.Common.SymbolsToRemove.matches(Sym.Name)) return true; - if ((Config.StripUnneeded || - Config.UnneededSymbolsToRemove.matches(Sym.Name)) && + if ((Config.Common.StripUnneeded || + Config.Common.UnneededSymbolsToRemove.matches(Sym.Name)) && (!Obj.isRelocatable() || isUnneededSymbol(Sym))) return true; // We want to remove undefined symbols if all references have been stripped. - if (!Config.OnlySection.empty() && !Sym.Referenced && + if (!Config.Common.OnlySection.empty() && !Sym.Referenced && Sym.getShndx() == SHN_UNDEF) return true; @@ -436,27 +548,28 @@ return Obj.removeSymbols(RemoveSymbolsPred); } -static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { +static Error replaceAndRemoveSections(const ELFCopyConfig &Config, + Object &Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: - if (!Config.ToRemove.empty()) { + if (!Config.Common.ToRemove.empty()) { RemovePred = [&Config](const SectionBase &Sec) { - return Config.ToRemove.matches(Sec.Name); + return Config.Common.ToRemove.matches(Sec.Name); }; } - if (Config.StripDWO || !Config.SplitDWO.empty()) + if (Config.Common.StripDWO || !Config.Common.SplitDWO.empty()) RemovePred = [RemovePred](const SectionBase &Sec) { return isDWOSection(Sec) || RemovePred(Sec); }; - if (Config.ExtractDWO) + if (Config.Common.ExtractDWO) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); }; - if (Config.StripAllGNU) + if (Config.Common.StripAllGNU) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -474,19 +587,19 @@ return isDebugSection(Sec); }; - if (Config.StripSections) { + if (Config.Common.StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || Sec.ParentSegment == nullptr; }; } - if (Config.StripDebug || Config.StripUnneeded) { + if (Config.Common.StripDebug || Config.Common.StripUnneeded) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || isDebugSection(Sec); }; } - if (Config.StripNonAlloc) + if (Config.Common.StripNonAlloc) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -495,7 +608,7 @@ return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr; }; - if (Config.StripAll) + if (Config.Common.StripAll) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -508,7 +621,7 @@ return (Sec.Flags & SHF_ALLOC) == 0; }; - if (Config.ExtractPartition || Config.ExtractMainPartition) { + if (Config.Common.ExtractPartition || Config.Common.ExtractMainPartition) { RemovePred = [RemovePred](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -519,10 +632,10 @@ } // Explicit copies: - if (!Config.OnlySection.empty()) { + if (!Config.Common.OnlySection.empty()) { RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. - if (Config.OnlySection.matches(Sec.Name)) + if (Config.Common.OnlySection.matches(Sec.Name)) return false; // Allow all implicit removes. @@ -541,10 +654,10 @@ }; } - if (!Config.KeepSection.empty()) { + if (!Config.Common.KeepSection.empty()) { RemovePred = [&Config, RemovePred](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. - if (Config.KeepSection.matches(Sec.Name)) + if (Config.Common.KeepSection.matches(Sec.Name)) return false; // Otherwise defer to RemovePred. return RemovePred(Sec); @@ -556,7 +669,7 @@ // and at least one of those symbols is present // (equivalently, the updated symbol table is not empty) // the symbol table and the string table should not be removed. - if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && + if ((!Config.Common.SymbolsToKeep.empty() || Config.Common.KeepFileSymbols) && Obj.SymbolTable && !Obj.SymbolTable->empty()) { RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) @@ -565,13 +678,13 @@ }; } - if (Config.CompressionType != DebugCompressionType::None) - replaceDebugSections(Obj, RemovePred, isCompressable, + if (Config.Common.CompressionType != DebugCompressionType::None) + replaceDebugSections(Obj, RemovePred, isCompressable, [&Config, &Obj](const SectionBase *S) { return &Obj.addSection( - *S, Config.CompressionType); - }); - else if (Config.DecompressDebugSections) + *S, Config.Common.CompressionType); + }); + else if (Config.Common.DecompressDebugSections) replaceDebugSections( Obj, RemovePred, [](const SectionBase &S) { return isa(&S); }, @@ -580,7 +693,7 @@ return &Obj.addSection(*CS); }); - return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); + return Obj.removeSections(Config.Common.AllowBrokenLinks, RemovePred); } // This function handles the high level operations of GNU objcopy including @@ -590,17 +703,17 @@ // 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 ELFCopyConfig &Config, Object &Obj, const Reader &Reader, ElfType OutputElfType) { - if (!Config.SplitDWO.empty()) - if (Error E = - splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) + if (!Config.Common.SplitDWO.empty()) + if (Error E = splitDWOToFile(Config, Reader, Config.Common.SplitDWO, + OutputElfType)) return E; - if (Config.OutputArch) { - Obj.Machine = Config.OutputArch.getValue().EMachine; - Obj.OSABI = Config.OutputArch.getValue().OSABI; + if (Config.Common.OutputArch) { + Obj.Machine = Config.Common.OutputArch.getValue().EMachine; + Obj.OSABI = Config.Common.OutputArch.getValue().OSABI; } // It is important to remove the sections first. For example, we want to @@ -613,11 +726,12 @@ if (Error E = updateAndRemoveSymbols(Config, Obj)) return E; - if (!Config.SectionsToRename.empty() || !Config.AllocSectionsPrefix.empty()) { + if (!Config.Common.SectionsToRename.empty() || + !Config.Common.AllocSectionsPrefix.empty()) { DenseSet PrefixedSections; for (auto &Sec : Obj.sections()) { - const auto Iter = Config.SectionsToRename.find(Sec.Name); - if (Iter != Config.SectionsToRename.end()) { + const auto Iter = Config.Common.SectionsToRename.find(Sec.Name); + if (Iter != Config.Common.SectionsToRename.end()) { const SectionRename &SR = Iter->second; Sec.Name = SR.NewName; if (SR.NewFlags.hasValue()) @@ -625,11 +739,11 @@ } // Add a prefix to allocated sections and their relocation sections. This - // should be done after renaming the section by Config.SectionToRename to - // imitate the GNU objcopy behavior. - if (!Config.AllocSectionsPrefix.empty()) { + // should be done after renaming the section by + // Config.Common.SectionToRename to imitate the GNU objcopy behavior. + if (!Config.Common.AllocSectionsPrefix.empty()) { if (Sec.Flags & SHF_ALLOC) { - Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); + Sec.Name = (Config.Common.AllocSectionsPrefix + Sec.Name).str(); PrefixedSections.insert(&Sec); // Rename relocation sections associated to the allocated sections. @@ -655,23 +769,24 @@ } // If the relocation section comes *after* the target section, we - // don't add Config.AllocSectionsPrefix because we've already added - // the prefix to TargetSec->Name. Otherwise, if the relocation + // don't add Config.Common.AllocSectionsPrefix because we've already + // added the prefix to TargetSec->Name. Otherwise, if the relocation // section comes *before* the target section, we add the prefix. if (PrefixedSections.count(TargetSec)) { Sec.Name = (prefix + TargetSec->Name).str(); } else { - const auto Iter = Config.SectionsToRename.find(TargetSec->Name); - if (Iter != Config.SectionsToRename.end()) { + const auto Iter = + Config.Common.SectionsToRename.find(TargetSec->Name); + if (Iter != Config.Common.SectionsToRename.end()) { // Both `--rename-section` and `--prefix-alloc-sections` are // given but the target section is not yet renamed. - Sec.Name = - (prefix + Config.AllocSectionsPrefix + Iter->second.NewName) - .str(); + Sec.Name = (prefix + Config.Common.AllocSectionsPrefix + + Iter->second.NewName) + .str(); } else { - Sec.Name = - (prefix + Config.AllocSectionsPrefix + TargetSec->Name) - .str(); + Sec.Name = (prefix + Config.Common.AllocSectionsPrefix + + TargetSec->Name) + .str(); } } } @@ -680,17 +795,17 @@ } } - if (!Config.SetSectionFlags.empty()) { + if (!Config.Common.SetSectionFlags.empty()) { for (auto &Sec : Obj.sections()) { - const auto Iter = Config.SetSectionFlags.find(Sec.Name); - if (Iter != Config.SetSectionFlags.end()) { + const auto Iter = Config.Common.SetSectionFlags.find(Sec.Name); + if (Iter != Config.Common.SetSectionFlags.end()) { const SectionFlagsUpdate &SFU = Iter->second; setSectionFlagsAndType(Sec, SFU.NewFlags); } } } - for (const auto &Flag : Config.AddSection) { + for (const auto &Flag : Config.Common.AddSection) { std::pair SecPair = Flag.split("="); StringRef SecName = SecPair.first; StringRef File = SecPair.second; @@ -708,7 +823,7 @@ NewSection.Type = SHT_NOTE; } - for (const auto &Flag : Config.DumpSection) { + for (const auto &Flag : Config.Common.DumpSection) { std::pair SecPair = Flag.split("="); StringRef SecName = SecPair.first; StringRef File = SecPair.second; @@ -716,9 +831,9 @@ return E; } - if (!Config.AddGnuDebugLink.empty()) - Obj.addSection(Config.AddGnuDebugLink, - Config.GnuDebugLinkCRC32); + if (!Config.Common.AddGnuDebugLink.empty()) + Obj.addSection(Config.Common.AddGnuDebugLink, + Config.Common.GnuDebugLinkCRC32); for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); @@ -728,12 +843,12 @@ Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); } - if (Config.EntryExpr) - Obj.Entry = Config.EntryExpr(Obj.Entry); + if (Config.Common.EntryExpr) + Obj.Entry = Config.Common.EntryExpr(Obj.Entry); return Error::success(); } -static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, +static Error writeOutput(const ELFCopyConfig &Config, Object &Obj, Buffer &Out, ElfType OutputElfType) { std::unique_ptr Writer = createWriter(Config, Obj, Out, OutputElfType); @@ -742,44 +857,57 @@ return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const CopyConfig &CommonConfig, MemoryBuffer &In, Buffer &Out) { + ELFCopyConfig Config(CommonConfig); + if (Error E = Config.parse()) + return E; + IHexReader Reader(&In); std::unique_ptr Obj = Reader.create(); - const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); + const ElfType OutputElfType = getOutputElfType( + Config.Common.OutputArch.getValueOr(Config.Common.BinaryArch)); if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) return E; return writeOutput(Config, *Obj, Out, OutputElfType); } -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out) { +Error executeObjcopyOnRawBinary(const CopyConfig &CommonConfig, + MemoryBuffer &In, Buffer &Out) { + ELFCopyConfig Config(CommonConfig); + if (Error E = Config.parse()) + return E; + uint8_t NewSymbolVisibility = Config.NewSymbolVisibility.getValueOr(ELF::STV_DEFAULT); - BinaryReader Reader(Config.BinaryArch, &In, NewSymbolVisibility); + BinaryReader Reader(Config.Common.BinaryArch, &In, NewSymbolVisibility); std::unique_ptr Obj = Reader.create(); // Prefer OutputArch (-O) if set, otherwise fallback to BinaryArch // (-B). - const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); + const ElfType OutputElfType = getOutputElfType( + Config.Common.OutputArch.getValueOr(Config.Common.BinaryArch)); if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) return E; return writeOutput(Config, *Obj, Out, OutputElfType); } -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const CopyConfig &CommonConfig, object::ELFObjectFileBase &In, Buffer &Out) { - ELFReader Reader(&In, Config.ExtractPartition); + ELFCopyConfig Config(CommonConfig); + if (Error E = Config.parse()) + return E; + + ELFReader Reader(&In, Config.Common.ExtractPartition); std::unique_ptr Obj = Reader.create(); // Prefer OutputArch (-O) if set, otherwise infer it from the input. const ElfType OutputElfType = - Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) - : getOutputElfType(In); + Config.Common.OutputArch + ? getOutputElfType(Config.Common.OutputArch.getValue()) + : getOutputElfType(In); ArrayRef BuildIdBytes; - if (!Config.BuildIdLinkDir.empty()) { + if (!Config.Common.BuildIdLinkDir.empty()) { auto BuildIdBytesOrErr = findBuildID(Config, In); if (auto E = BuildIdBytesOrErr.takeError()) return E; @@ -787,27 +915,27 @@ if (BuildIdBytes.size() < 2) return createFileError( - Config.InputFilename, + Config.Common.InputFilename, createStringError(object_error::parse_failed, "build ID is smaller than two bytes")); } - if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) - if (Error E = - linkToBuildIdDir(Config, Config.InputFilename, - Config.BuildIdLinkInput.getValue(), BuildIdBytes)) + if (!Config.Common.BuildIdLinkDir.empty() && Config.Common.BuildIdLinkInput) + if (Error E = linkToBuildIdDir(Config, Config.Common.InputFilename, + Config.Common.BuildIdLinkInput.getValue(), + BuildIdBytes)) return E; if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) - return createFileError(Config.InputFilename, std::move(E)); + return createFileError(Config.Common.InputFilename, std::move(E)); if (Error E = writeOutput(Config, *Obj, Out, OutputElfType)) - return createFileError(Config.InputFilename, std::move(E)); - if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) - if (Error E = - linkToBuildIdDir(Config, Config.OutputFilename, - Config.BuildIdLinkOutput.getValue(), BuildIdBytes)) - return createFileError(Config.OutputFilename, std::move(E)); + return createFileError(Config.Common.InputFilename, std::move(E)); + if (!Config.Common.BuildIdLinkDir.empty() && Config.Common.BuildIdLinkOutput) + if (Error E = linkToBuildIdDir(Config, Config.Common.OutputFilename, + Config.Common.BuildIdLinkOutput.getValue(), + BuildIdBytes)) + return createFileError(Config.Common.OutputFilename, std::move(E)); return Error::success(); } Index: llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -25,7 +25,7 @@ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() || !Config.DumpSection.empty() || !Config.KeepSection.empty() || - Config.NewSymbolVisibility || !Config.OnlySection.empty() || + Config.Unparsed.NewSymbolVisibility || !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || @@ -37,7 +37,7 @@ Config.StripSections || Config.Weaken || Config.DecompressDebugSections || Config.StripDebug || Config.StripNonAlloc || Config.StripSections || Config.StripUnneeded || Config.DiscardMode != DiscardType::None || - !Config.SymbolsToAdd.empty() || Config.EntryExpr) { + !Config.Unparsed.SymbolsToAdd.empty() || Config.EntryExpr) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for MachO"); }