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,38 @@ +//===- 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; +}; + +struct ELFCopyConfig { + const CopyConfig &Common; + 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,15 @@ namespace objcopy { struct CopyConfig; +struct ELFCopyConfig; class Buffer; namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const ELFCopyConfig &Config, MemoryBuffer &In, Buffer &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnRawBinary(const ELFCopyConfig &Config, MemoryBuffer &In, Buffer &Out); -Error executeObjcopyOnBinary(const CopyConfig &Config, +Error executeObjcopyOnBinary(const ELFCopyConfig &Config, 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" @@ -130,31 +131,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 +167,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 +180,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 +212,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 +261,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 +344,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 +354,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 +369,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 (SectionBase &Sec : Obj.sections()) Sec.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 +438,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 +477,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 +498,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 +511,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 +522,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 +544,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 +559,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 +568,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 +583,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 +593,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,10 +616,10 @@ if (Error E = updateAndRemoveSymbols(Config, Obj)) return E; - if (!Config.SectionsToRename.empty()) { + if (!Config.Common.SectionsToRename.empty()) { for (SectionBase &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()) @@ -626,13 +629,13 @@ } // 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()) { DenseSet PrefixedSections; for (SectionBase &Sec : Obj.sections()) { if (Sec.Flags & SHF_ALLOC) { - Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); + Sec.Name = (Config.Common.AllocSectionsPrefix + Sec.Name).str(); PrefixedSections.insert(&Sec); } else if (auto *RelocSec = dyn_cast(&Sec)) { // Rename relocation sections associated to the allocated sections. @@ -657,30 +660,31 @@ } // 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 Sec.Name = - (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str(); + (prefix + Config.Common.AllocSectionsPrefix + TargetSec->Name) + .str(); } } } } - 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; @@ -698,7 +702,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; @@ -706,9 +710,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); @@ -718,12 +722,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); @@ -732,44 +736,45 @@ return Writer->write(); } -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +Error executeObjcopyOnIHex(const ELFCopyConfig &Config, MemoryBuffer &In, Buffer &Out) { 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, +Error executeObjcopyOnRawBinary(const ELFCopyConfig &Config, MemoryBuffer &In, Buffer &Out) { uint8_t NewSymbolVisibility = Config.NewSymbolVisibility.getValueOr((uint8_t)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 ELFCopyConfig &Config, object::ELFObjectFileBase &In, Buffer &Out) { - ELFReader Reader(&In, Config.ExtractPartition); + 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; @@ -777,27 +782,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/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 &Config, MemoryBuffer &In, Buffer &Out) { // TODO: support output formats other than ELF. - return elf::executeObjcopyOnIHex(Config, In, Out); + if (Error E = Config.parseELFConfig()) + return E; + return elf::executeObjcopyOnIHex(*Config.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 &Config, MemoryBuffer &In, + Buffer &Out) { + switch (Config.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 = Config.parseELFConfig()) + return E; + return elf::executeObjcopyOnRawBinary(*Config.ELF, In, Out); } llvm_unreachable("unsupported output format"); @@ -156,20 +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 &Config, object::Binary &In, + Buffer &Out) { + if (auto *ELFBinary = dyn_cast(&In)) { + if (Error E = Config.parseELFConfig()) + return E; + return elf::executeObjcopyOnBinary(*Config.ELF, *ELFBinary, Out); + } else if (auto *COFFBinary = dyn_cast(&In)) + return coff::executeObjcopyOnBinary(Config.Common, *COFFBinary, Out); else if (auto *MachOBinary = dyn_cast(&In)) - return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); + return macho::executeObjcopyOnBinary(Config.Common, *MachOBinary, Out); else return createStringError(object_error::invalid_file_type, "unsupported object file format"); } -static Error executeObjcopyOnArchive(const CopyConfig &Config, +static Error executeObjcopyOnArchive(Configurations &Config, const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); @@ -187,8 +210,8 @@ if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB)) return E; - Expected Member = - NewArchiveMember::getOldMember(Child, Config.DeterministicArchives); + Expected Member = NewArchiveMember::getOldMember( + Child, Config.Common.DeterministicArchives); if (!Member) return createFileError(Ar.getFileName(), Member.takeError()); Member->Buf = MB.releaseMemoryBuffer(); @@ -196,11 +219,11 @@ NewArchiveMembers.push_back(std::move(*Member)); } if (Err) - return createFileError(Config.InputFilename, std::move(Err)); + return createFileError(Config.Common.InputFilename, std::move(Err)); - return deepWriteArchive(Config.OutputFilename, NewArchiveMembers, + return deepWriteArchive(Config.Common.OutputFilename, NewArchiveMembers, Ar.hasSymbolTable(), Ar.kind(), - Config.DeterministicArchives, Ar.isThin()); + Config.Common.DeterministicArchives, Ar.isThin()); } static Error restoreStatOnFile(StringRef Filename, @@ -246,18 +269,19 @@ /// 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 &Config) { sys::fs::file_status Stat; - if (Config.InputFilename != "-") { - if (auto EC = sys::fs::status(Config.InputFilename, Stat)) - return createFileError(Config.InputFilename, EC); + if (Config.Common.InputFilename != "-") { + if (auto EC = sys::fs::status(Config.Common.InputFilename, Stat)) + return createFileError(Config.Common.InputFilename, EC); } else { Stat.permissions(static_cast(0777)); } - typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &); + typedef Error (*ProcessRawFn)(Configurations & Config, MemoryBuffer &, + Buffer &); ProcessRawFn ProcessRaw; - switch (Config.InputFormat) { + switch (Config.Common.InputFormat) { case FileFormat::Binary: ProcessRaw = executeObjcopyOnRawBinary; break; @@ -269,37 +293,38 @@ } if (ProcessRaw) { - auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename); + auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.Common.InputFilename); if (!BufOrErr) - return createFileError(Config.InputFilename, BufOrErr.getError()); - FileBuffer FB(Config.OutputFilename); + return createFileError(Config.Common.InputFilename, BufOrErr.getError()); + FileBuffer FB(Config.Common.OutputFilename); if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB)) return E; } else { Expected> BinaryOrErr = - createBinary(Config.InputFilename); + createBinary(Config.Common.InputFilename); if (!BinaryOrErr) - return createFileError(Config.InputFilename, BinaryOrErr.takeError()); + return createFileError(Config.Common.InputFilename, + BinaryOrErr.takeError()); if (Archive *Ar = dyn_cast(BinaryOrErr.get().getBinary())) { if (Error E = executeObjcopyOnArchive(Config, *Ar)) return E; } else { - FileBuffer FB(Config.OutputFilename); + FileBuffer FB(Config.Common.OutputFilename); if (Error E = executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB)) return E; } } - if (Error E = - restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates)) + if (Error E = restoreStatOnFile(Config.Common.OutputFilename, Stat, + Config.Common.PreserveDates)) return E; - if (!Config.SplitDWO.empty()) { + if (!Config.Common.SplitDWO.empty()) { Stat.permissions(static_cast(0666)); - if (Error E = - restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates)) + if (Error E = restoreStatOnFile(Config.Common.SplitDWO, Stat, + Config.Common.PreserveDates)) return E; } @@ -319,7 +344,8 @@ return 1; } for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { - if (Error E = executeObjcopy(CopyConfig)) { + Configurations Config(CopyConfig); + if (Error E = executeObjcopy(Config)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; }