diff --git a/llvm/tools/llvm-objcopy/CommonConfig.h b/llvm/tools/llvm-objcopy/CommonConfig.h --- a/llvm/tools/llvm-objcopy/CommonConfig.h +++ b/llvm/tools/llvm-objcopy/CommonConfig.h @@ -149,30 +149,13 @@ StringRef OutputFilename; FileFormat OutputFormat = FileFormat::Unspecified; - // Only applicable when --output-format!=binary (e.g. elf64-x86-64). - Optional OutputArch; - // Advanced options StringRef AddGnuDebugLink; - // Cached gnu_debuglink's target CRC - uint32_t GnuDebugLinkCRC32; - Optional ExtractPartition; - StringRef SplitDWO; - StringRef SymbolsPrefix; - StringRef AllocSectionsPrefix; DiscardType DiscardMode = DiscardType::None; // Repeated options std::vector AddSection; std::vector DumpSection; - std::vector RPathToAdd; - std::vector RPathToPrepend; - DenseMap RPathsToUpdate; - DenseMap InstallNamesToUpdate; - DenseSet RPathsToRemove; - - // install-name-tool's id option - Optional SharedLibId; // Section matchers NameMatcher KeepSection; @@ -180,50 +163,21 @@ NameMatcher ToRemove; // Symbol matchers - NameMatcher SymbolsToGlobalize; - NameMatcher SymbolsToKeep; - NameMatcher SymbolsToLocalize; NameMatcher SymbolsToRemove; NameMatcher UnneededSymbolsToRemove; - NameMatcher SymbolsToWeaken; - NameMatcher SymbolsToKeepGlobal; // Map options - StringMap SectionsToRename; - StringMap SetSectionAlignment; StringMap SetSectionFlags; StringMap SymbolsToRename; - // ELF entry point address expression. The input parameter is an entry point - // address in the input ELF file. The entry address in the output file is - // calculated with EntryExpr(input_address), when either --set-start or - // --change-start is used. - std::function EntryExpr; - // Boolean options - bool AllowBrokenLinks = false; bool DeterministicArchives = true; - bool ExtractDWO = false; - bool ExtractMainPartition = false; - bool KeepFileSymbols = false; - bool KeepUndefined = false; - bool LocalizeHidden = false; bool OnlyKeepDebug = false; bool PreserveDates = false; bool StripAll = false; bool StripAllGNU = false; - bool StripDWO = false; bool StripDebug = false; - bool StripNonAlloc = false; - bool StripSections = false; - bool StripSwiftSymbols = false; bool StripUnneeded = false; - bool Weaken = false; - bool DecompressDebugSections = false; - // install-name-tool's --delete_all_rpaths - bool RemoveAllRpaths = false; - - DebugCompressionType CompressionType = DebugCompressionType::None; }; } // namespace objcopy diff --git a/llvm/tools/llvm-objcopy/ConfigManager.h b/llvm/tools/llvm-objcopy/ConfigManager.h --- a/llvm/tools/llvm-objcopy/ConfigManager.h +++ b/llvm/tools/llvm-objcopy/ConfigManager.h @@ -38,7 +38,8 @@ // All configs. CommonConfig Common; - mutable Optional ELF; + mutable bool AreELFLazyOptionsParsed = false; + ELFConfig ELF; COFFConfig COFF; MachOConfig MachO; WasmConfig Wasm; diff --git a/llvm/tools/llvm-objcopy/ConfigManager.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp --- a/llvm/tools/llvm-objcopy/ConfigManager.cpp +++ b/llvm/tools/llvm-objcopy/ConfigManager.cpp @@ -548,17 +548,17 @@ } Expected ConfigManager::getELFConfig() const { - if (!ELF) { - if (Common.StripSwiftSymbols || Common.KeepUndefined) - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for ELF"); + if (MachO.StripSwiftSymbols || MachO.KeepUndefined) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for ELF"); - // Parse lazy options. - ELFConfig ResConfig; + // Parse lazy options. + if (!AreELFLazyOptionsParsed) { + AreELFLazyOptionsParsed = true; if (NewSymbolVisibility) { const uint8_t Invalid = 0xff; - ResConfig.NewSymbolVisibility = + const_cast(this)->ELF.NewSymbolVisibility = StringSwitch(*NewSymbolVisibility) .Case("default", ELF::STV_DEFAULT) .Case("hidden", ELF::STV_HIDDEN) @@ -566,7 +566,7 @@ .Case("protected", ELF::STV_PROTECTED) .Default(Invalid); - if (ResConfig.NewSymbolVisibility == Invalid) + if (ELF.NewSymbolVisibility == Invalid) return createStringError(errc::invalid_argument, "'%s' is not a valid symbol visibility", NewSymbolVisibility->str().c_str()); @@ -574,33 +574,30 @@ for (StringRef Arg : SymbolsToAdd) { Expected NSI = parseNewSymbolInfo( - Arg, - ResConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + Arg, ELF.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); if (!NSI) return NSI.takeError(); - ResConfig.SymbolsToAdd.push_back(*NSI); + const_cast(this)->ELF.SymbolsToAdd.push_back(*NSI); } - - ELF = std::move(ResConfig); } - return *ELF; + return ELF; } Expected ConfigManager::getCOFFConfig() const { - if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() || - !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() || + if (ELF.AllowBrokenLinks || !ELF.SplitDWO.empty() || + !ELF.SymbolsPrefix.empty() || !ELF.AllocSectionsPrefix.empty() || !Common.DumpSection.empty() || !Common.KeepSection.empty() || - NewSymbolVisibility || !Common.SymbolsToGlobalize.empty() || - !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() || - !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || - !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || - Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates || - Common.StripDWO || Common.StripNonAlloc || Common.StripSections || - Common.StripSwiftSymbols || Common.KeepUndefined || Common.Weaken || - Common.DecompressDebugSections || + NewSymbolVisibility || !ELF.SymbolsToGlobalize.empty() || + !ELF.SymbolsToKeep.empty() || !ELF.SymbolsToLocalize.empty() || + !ELF.SymbolsToWeaken.empty() || !ELF.SymbolsToKeepGlobal.empty() || + !ELF.SectionsToRename.empty() || !ELF.SetSectionAlignment.empty() || + ELF.ExtractDWO || ELF.LocalizeHidden || Common.PreserveDates || + ELF.StripDWO || ELF.StripNonAlloc || ELF.StripSections || + MachO.StripSwiftSymbols || MachO.KeepUndefined || ELF.Weaken || + ELF.DecompressDebugSections || Common.DiscardMode == DiscardType::Locals || !SymbolsToAdd.empty() || - Common.EntryExpr) { + ELF.EntryExpr) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for COFF"); } @@ -609,19 +606,19 @@ } Expected ConfigManager::getMachOConfig() const { - if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() || - !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() || - !Common.KeepSection.empty() || NewSymbolVisibility || - !Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() || - !Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() || - !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() || + if (ELF.AllowBrokenLinks || !ELF.SplitDWO.empty() || + !ELF.SymbolsPrefix.empty() || !ELF.AllocSectionsPrefix.empty() || + !ELF.KeepSection.empty() || NewSymbolVisibility || + !ELF.SymbolsToGlobalize.empty() || !ELF.SymbolsToKeep.empty() || + !ELF.SymbolsToLocalize.empty() || !ELF.SymbolsToWeaken.empty() || + !ELF.SymbolsToKeepGlobal.empty() || !ELF.SectionsToRename.empty() || !Common.UnneededSymbolsToRemove.empty() || - !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() || - Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates || - Common.StripAllGNU || Common.StripDWO || Common.StripNonAlloc || - Common.StripSections || Common.Weaken || Common.DecompressDebugSections || + !ELF.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() || + ELF.ExtractDWO || ELF.LocalizeHidden || Common.PreserveDates || + Common.StripAllGNU || ELF.StripDWO || ELF.StripNonAlloc || + ELF.StripSections || ELF.Weaken || ELF.DecompressDebugSections || Common.StripUnneeded || Common.DiscardMode == DiscardType::Locals || - !SymbolsToAdd.empty() || Common.EntryExpr) { + !SymbolsToAdd.empty() || ELF.EntryExpr) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for MachO"); } @@ -630,18 +627,18 @@ } Expected ConfigManager::getWasmConfig() const { - if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition || - !Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() || - !Common.AllocSectionsPrefix.empty() || + if (!Common.AddGnuDebugLink.empty() || ELF.ExtractPartition || + !ELF.SplitDWO.empty() || !ELF.SymbolsPrefix.empty() || + !ELF.AllocSectionsPrefix.empty() || Common.DiscardMode != DiscardType::None || NewSymbolVisibility || - !SymbolsToAdd.empty() || !Common.RPathToAdd.empty() || - !Common.OnlySection.empty() || !Common.SymbolsToGlobalize.empty() || - !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() || + !SymbolsToAdd.empty() || !MachO.RPathToAdd.empty() || + !Common.OnlySection.empty() || !ELF.SymbolsToGlobalize.empty() || + !ELF.SymbolsToKeep.empty() || !ELF.SymbolsToLocalize.empty() || !Common.SymbolsToRemove.empty() || - !Common.UnneededSymbolsToRemove.empty() || - !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() || - !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() || - !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) { + !Common.UnneededSymbolsToRemove.empty() || !ELF.SymbolsToWeaken.empty() || + !ELF.SymbolsToKeepGlobal.empty() || !ELF.SectionsToRename.empty() || + !ELF.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() || + !Common.SymbolsToRename.empty()) { return createStringError( llvm::errc::invalid_argument, "only add-section, dump-section, and remove-section are supported"); @@ -696,6 +693,8 @@ ConfigManager ConfigMgr; CommonConfig &Config = ConfigMgr.Common; + ELFConfig &ELFConfig = ConfigMgr.ELF; + MachOConfig &MachOConfig = ConfigMgr.MachO; Config.InputFilename = Positional[0]; Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; if (InputArgs.hasArg(OBJCOPY_target) && @@ -751,22 +750,22 @@ if (!Target) return Target.takeError(); Config.OutputFormat = Target->Format; - Config.OutputArch = Target->Machine; + ELFConfig.OutputArch = Target->Machine; } } if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, OBJCOPY_compress_debug_sections_eq)) { - Config.CompressionType = DebugCompressionType::Z; + ELFConfig.CompressionType = DebugCompressionType::Z; if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) { - Config.CompressionType = + ELFConfig.CompressionType = StringSwitch( InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)) .Case("zlib-gnu", DebugCompressionType::GNU) .Case("zlib", DebugCompressionType::Z) .Default(DebugCompressionType::None); - if (Config.CompressionType == DebugCompressionType::None) + if (ELFConfig.CompressionType == DebugCompressionType::None) return createStringError( errc::invalid_argument, "invalid or unsupported --compress-debug-sections format: %s", @@ -790,15 +789,15 @@ if (!DebugOrErr) return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError()); auto Debug = std::move(*DebugOrErr); - Config.GnuDebugLinkCRC32 = + ELFConfig.GnuDebugLinkCRC32 = llvm::crc32(arrayRefFromStringRef(Debug->getBuffer())); } - Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); - Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); - Config.AllocSectionsPrefix = + ELFConfig.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); + ELFConfig.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); + ELFConfig.AllocSectionsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections); if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition)) - Config.ExtractPartition = Arg->getValue(); + ELFConfig.ExtractPartition = Arg->getValue(); for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { if (!StringRef(Arg->getValue()).contains('=')) @@ -821,7 +820,7 @@ parseRenameSectionValue(StringRef(Arg->getValue())); if (!SR) return SR.takeError(); - if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) + if (!ELFConfig.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) return createStringError(errc::invalid_argument, "multiple renames of section '%s'", SR->OriginalName.str().c_str()); @@ -831,7 +830,7 @@ parseSetSectionAlignment(Arg->getValue()); if (!NameAndAlign) return NameAndAlign.takeError(); - Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; + ELFConfig.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; } for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) { Expected SFU = @@ -846,7 +845,7 @@ } // Prohibit combinations of --set-section-flags when the section name is used // by --rename-section, either as a source or a destination. - for (const auto &E : Config.SectionsToRename) { + for (const auto &E : ELFConfig.SectionsToRename) { const SectionRename &SR = E.second; if (Config.SetSectionFlags.count(SR.OriginalName)) return createStringError( @@ -896,62 +895,63 @@ Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); - Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); - Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); - Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); + ELFConfig.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); + ELFConfig.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); + ELFConfig.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); - Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); - Config.ExtractMainPartition = + ELFConfig.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); + ELFConfig.ExtractMainPartition = InputArgs.hasArg(OBJCOPY_extract_main_partition); - Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); - Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); + ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); + ELFConfig.Weaken = InputArgs.hasArg(OBJCOPY_weaken); if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) Config.DiscardMode = InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals) ? DiscardType::All : DiscardType::Locals; Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); - Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); - Config.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined); - Config.DecompressDebugSections = + ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); + MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined); + ELFConfig.DecompressDebugSections = InputArgs.hasArg(OBJCOPY_decompress_debug_sections); if (Config.DiscardMode == DiscardType::All) { Config.StripDebug = true; - Config.KeepFileSymbols = true; + ELFConfig.KeepFileSymbols = true; } for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) - if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create( + if (Error E = ELFConfig.SymbolsToLocalize.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, + if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToLocalize, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) - if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( - Arg->getValue(), SymbolMatchStyle, ErrorCallback))) + if (Error E = + ELFConfig.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( + Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, + if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToKeepGlobal, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) - if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create( + if (Error E = ELFConfig.SymbolsToGlobalize.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, + if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToGlobalize, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) - if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create( + if (Error E = ELFConfig.SymbolsToWeaken.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols)) - if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, + if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToWeaken, DC.Alloc, Arg->getValue(), SymbolMatchStyle, ErrorCallback)) return std::move(E); @@ -975,18 +975,18 @@ ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) - if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( + if (Error E = ELFConfig.SymbolsToKeep.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols)) - if (Error E = - addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), - SymbolMatchStyle, ErrorCallback)) + if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToKeep, DC.Alloc, + Arg->getValue(), SymbolMatchStyle, + ErrorCallback)) return std::move(E); for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) ConfigMgr.SymbolsToAdd.push_back(Arg->getValue()); - Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); + ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); Config.DeterministicArchives = InputArgs.hasFlag( OBJCOPY_enable_deterministic_archives, @@ -1006,34 +1006,34 @@ return createStringError( EAddr.getError(), "bad entry point address: '%s'", Arg->getValue()); - Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; + ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; } else if (Arg->getOption().matches(OBJCOPY_change_start)) { auto EIncr = getAsInteger(Arg->getValue()); if (!EIncr) return createStringError(EIncr.getError(), "bad entry point increment: '%s'", Arg->getValue()); - auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr) - : [](uint64_t A) { return A; }; - Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) { + auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr) + : [](uint64_t A) { return A; }; + ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) { return Expr(EAddr) + *EIncr; }; } - if (Config.DecompressDebugSections && - Config.CompressionType != DebugCompressionType::None) { + if (ELFConfig.DecompressDebugSections && + ELFConfig.CompressionType != DebugCompressionType::None) { return createStringError( errc::invalid_argument, "cannot specify both --compress-debug-sections and " "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !zlib::isAvailable()) + if (ELFConfig.DecompressDebugSections && !zlib::isAvailable()) return createStringError( errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); - if (Config.ExtractPartition && Config.ExtractMainPartition) + if (ELFConfig.ExtractPartition && ELFConfig.ExtractMainPartition) return createStringError(errc::invalid_argument, "cannot specify --extract-partition together with " "--extract-main-partition"); @@ -1050,6 +1050,7 @@ DriverConfig DC; ConfigManager ConfigMgr; CommonConfig &Config = ConfigMgr.Common; + MachOConfig &MachOConfig = ConfigMgr.MachO; InstallNameToolOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -1080,27 +1081,27 @@ } for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) - Config.RPathToAdd.push_back(Arg->getValue()); + MachOConfig.RPathToAdd.push_back(Arg->getValue()); for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath)) - Config.RPathToPrepend.push_back(Arg->getValue()); + MachOConfig.RPathToPrepend.push_back(Arg->getValue()); for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) { StringRef RPath = Arg->getValue(); // Cannot add and delete the same rpath at the same time. - if (is_contained(Config.RPathToAdd, RPath)) + if (is_contained(MachOConfig.RPathToAdd, RPath)) return createStringError( errc::invalid_argument, "cannot specify both -add_rpath '%s' and -delete_rpath '%s'", RPath.str().c_str(), RPath.str().c_str()); - if (is_contained(Config.RPathToPrepend, RPath)) + if (is_contained(MachOConfig.RPathToPrepend, RPath)) return createStringError( errc::invalid_argument, "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'", RPath.str().c_str(), RPath.str().c_str()); - Config.RPathsToRemove.insert(RPath); + MachOConfig.RPathsToRemove.insert(RPath); } for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) { @@ -1111,51 +1112,52 @@ // Cannot specify duplicate -rpath entries auto It1 = find_if( - Config.RPathsToUpdate, + MachOConfig.RPathsToUpdate, [&Match](const DenseMap::value_type &OldNew) { return Match(OldNew.getFirst()) || Match(OldNew.getSecond()); }); - if (It1 != Config.RPathsToUpdate.end()) + if (It1 != MachOConfig.RPathsToUpdate.end()) return createStringError(errc::invalid_argument, "cannot specify both -rpath '" + It1->getFirst() + "' '" + It1->getSecond() + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -delete_rpath and -rpath - auto It2 = find_if(Config.RPathsToRemove, Match); - if (It2 != Config.RPathsToRemove.end()) + auto It2 = find_if(MachOConfig.RPathsToRemove, Match); + if (It2 != MachOConfig.RPathsToRemove.end()) return createStringError(errc::invalid_argument, "cannot specify both -delete_rpath '" + *It2 + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -add_rpath and -rpath - auto It3 = find_if(Config.RPathToAdd, Match); - if (It3 != Config.RPathToAdd.end()) + auto It3 = find_if(MachOConfig.RPathToAdd, Match); + if (It3 != MachOConfig.RPathToAdd.end()) return createStringError(errc::invalid_argument, "cannot specify both -add_rpath '" + *It3 + "' and -rpath '" + Old + "' '" + New + "'"); // Cannot specify the same rpath under both -prepend_rpath and -rpath. - auto It4 = find_if(Config.RPathToPrepend, Match); - if (It4 != Config.RPathToPrepend.end()) + auto It4 = find_if(MachOConfig.RPathToPrepend, Match); + if (It4 != MachOConfig.RPathToPrepend.end()) return createStringError(errc::invalid_argument, "cannot specify both -prepend_rpath '" + *It4 + "' and -rpath '" + Old + "' '" + New + "'"); - Config.RPathsToUpdate.insert({Old, New}); + MachOConfig.RPathsToUpdate.insert({Old, New}); } if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) { - Config.SharedLibId = Arg->getValue(); - if (Config.SharedLibId->empty()) + MachOConfig.SharedLibId = Arg->getValue(); + if (MachOConfig.SharedLibId->empty()) return createStringError(errc::invalid_argument, "cannot specify an empty id"); } for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change)) - Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)}); + MachOConfig.InstallNamesToUpdate.insert( + {Arg->getValue(0), Arg->getValue(1)}); - Config.RemoveAllRpaths = + MachOConfig.RemoveAllRpaths = InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths); SmallVector Positional; @@ -1266,6 +1268,8 @@ ConfigManager ConfigMgr; CommonConfig &Config = ConfigMgr.Common; + ELFConfig &ELFConfig = ConfigMgr.ELF; + MachOConfig &MachOConfig = ConfigMgr.MachO; if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) return createStringError(errc::invalid_argument, @@ -1277,7 +1281,7 @@ : InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard : MatchStyle::Literal; - Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); + ELFConfig.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals)) @@ -1285,15 +1289,15 @@ InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals) ? DiscardType::All : DiscardType::Locals; - Config.StripSections = InputArgs.hasArg(STRIP_strip_sections); + ELFConfig.StripSections = InputArgs.hasArg(STRIP_strip_sections); Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all)) Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu); - Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); + MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug); - Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); - Config.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined); + ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); + MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined); for (auto Arg : InputArgs.filtered(STRIP_keep_section)) if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( @@ -1311,7 +1315,7 @@ return std::move(E); for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) - if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( + if (Error E = ELFConfig.SymbolsToKeep.addMatcher(NameOrPattern::create( Arg->getValue(), SymbolMatchStyle, ErrorCallback))) return std::move(E); @@ -1322,7 +1326,7 @@ if (Config.DiscardMode == DiscardType::All) { Config.StripDebug = true; - Config.KeepFileSymbols = true; + ELFConfig.KeepFileSymbols = true; } Config.DeterministicArchives = diff --git a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h --- a/llvm/tools/llvm-objcopy/ELF/ELFConfig.h +++ b/llvm/tools/llvm-objcopy/ELF/ELFConfig.h @@ -9,6 +9,7 @@ #ifndef LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H #define LLVM_TOOLS_LLVM_OBJCOPY_ELFCONFIG_H +#include "CommonConfig.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELFTypes.h" @@ -28,8 +29,51 @@ // ELF specific configuration for copying/stripping a single file. struct ELFConfig { + // Only applicable when --output-format!=binary (e.g. elf64-x86-64). + Optional OutputArch; + + // Cached gnu_debuglink's target CRC + uint32_t GnuDebugLinkCRC32; + Optional ExtractPartition; + StringRef SplitDWO; + StringRef SymbolsPrefix; + StringRef AllocSectionsPrefix; Optional NewSymbolVisibility; std::vector SymbolsToAdd; + + // Section matchers + NameMatcher KeepSection; + + // Map options + StringMap SectionsToRename; + StringMap SetSectionAlignment; + + // Symbol matchers + NameMatcher SymbolsToGlobalize; + NameMatcher SymbolsToKeep; + NameMatcher SymbolsToLocalize; + NameMatcher SymbolsToWeaken; + NameMatcher SymbolsToKeepGlobal; + + // ELF entry point address expression. The input parameter is an entry point + // address in the input ELF file. The entry address in the output file is + // calculated with EntryExpr(input_address), when either --set-start or + // --change-start is used. + std::function EntryExpr; + + // Boolean options + bool AllowBrokenLinks = false; + bool ExtractDWO = false; + bool ExtractMainPartition = false; + bool KeepFileSymbols = false; + bool LocalizeHidden = false; + bool StripDWO = false; + bool StripNonAlloc = false; + bool StripSections = false; + bool Weaken = false; + bool DecompressDebugSections = false; + + DebugCompressionType CompressionType = DebugCompressionType::None; }; } // namespace objcopy diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -134,27 +134,29 @@ } static std::unique_ptr createELFWriter(const CommonConfig &Config, + const ELFConfig &ELFConfig, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. switch (OutputElfType) { case ELFT_ELF32LE: - return std::make_unique>(Obj, Out, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Out, !ELFConfig.StripSections, Config.OnlyKeepDebug); case ELFT_ELF64LE: - return std::make_unique>(Obj, Out, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Out, !ELFConfig.StripSections, Config.OnlyKeepDebug); case ELFT_ELF32BE: - return std::make_unique>(Obj, Out, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Out, !ELFConfig.StripSections, Config.OnlyKeepDebug); case ELFT_ELF64BE: - return std::make_unique>(Obj, Out, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Out, !ELFConfig.StripSections, Config.OnlyKeepDebug); } llvm_unreachable("Invalid output format"); } static std::unique_ptr createWriter(const CommonConfig &Config, + const ELFConfig &ELFConfig, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { switch (Config.OutputFormat) { @@ -163,7 +165,7 @@ case FileFormat::IHex: return std::make_unique(Obj, Out); default: - return createELFWriter(Config, Obj, Out, OutputElfType); + return createELFWriter(Config, ELFConfig, Obj, Out, OutputElfType); } } @@ -244,7 +246,8 @@ Sym.Type != STT_SECTION; } -static Error updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) { +static Error updateAndRemoveSymbols(const CommonConfig &Config, + const ELFConfig &ELFConfig, Object &Obj) { // TODO: update or remove symbols only if there is an option that affects // them. if (!Obj.SymbolTable) @@ -254,9 +257,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 && + ((ELFConfig.LocalizeHidden && (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || - Config.SymbolsToLocalize.matches(Sym.Name))) + ELFConfig.SymbolsToLocalize.matches(Sym.Name))) Sym.Binding = STB_LOCAL; // Note: these two globalize flags have very similar names but different @@ -269,19 +272,20 @@ // 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 (!ELFConfig.SymbolsToKeepGlobal.empty() && + !ELFConfig.SymbolsToKeepGlobal.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_LOCAL; - if (Config.SymbolsToGlobalize.matches(Sym.Name) && + if (ELFConfig.SymbolsToGlobalize.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_GLOBAL; - if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL) + if (ELFConfig.SymbolsToWeaken.matches(Sym.Name) && + Sym.Binding == STB_GLOBAL) Sym.Binding = STB_WEAK; - if (Config.Weaken && Sym.Binding == STB_GLOBAL && + if (ELFConfig.Weaken && Sym.Binding == STB_GLOBAL && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_WEAK; @@ -289,8 +293,8 @@ if (I != Config.SymbolsToRename.end()) Sym.Name = std::string(I->getValue()); - if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) - Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); + if (!ELFConfig.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) + Sym.Name = (ELFConfig.SymbolsPrefix + Sym.Name).str(); }); // The purpose of this loop is to mark symbols referenced by sections @@ -303,8 +307,8 @@ } auto RemoveSymbolsPred = [&](const Symbol &Sym) { - if (Config.SymbolsToKeep.matches(Sym.Name) || - (Config.KeepFileSymbols && Sym.Type == STT_FILE)) + if (ELFConfig.SymbolsToKeep.matches(Sym.Name) || + (ELFConfig.KeepFileSymbols && Sym.Type == STT_FILE)) return false; if ((Config.DiscardMode == DiscardType::All || @@ -339,7 +343,8 @@ return Obj.removeSymbols(RemoveSymbolsPred); } -static Error replaceAndRemoveSections(const CommonConfig &Config, Object &Obj) { +static Error replaceAndRemoveSections(const CommonConfig &Config, + const ELFConfig &ELFConfig, Object &Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: @@ -349,12 +354,12 @@ }; } - if (Config.StripDWO) + if (ELFConfig.StripDWO) RemovePred = [RemovePred](const SectionBase &Sec) { return isDWOSection(Sec) || RemovePred(Sec); }; - if (Config.ExtractDWO) + if (ELFConfig.ExtractDWO) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); }; @@ -377,7 +382,7 @@ return isDebugSection(Sec); }; - if (Config.StripSections) { + if (ELFConfig.StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || Sec.ParentSegment == nullptr; }; @@ -389,7 +394,7 @@ }; } - if (Config.StripNonAlloc) + if (ELFConfig.StripNonAlloc) RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -417,7 +422,7 @@ return (Sec.Flags & SHF_ALLOC) == 0; }; - if (Config.ExtractPartition || Config.ExtractMainPartition) { + if (ELFConfig.ExtractPartition || ELFConfig.ExtractMainPartition) { RemovePred = [RemovePred](const SectionBase &Sec) { if (RemovePred(Sec)) return true; @@ -465,7 +470,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 ((!ELFConfig.SymbolsToKeep.empty() || ELFConfig.KeepFileSymbols) && Obj.SymbolTable && !Obj.SymbolTable->empty()) { RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) @@ -474,19 +479,20 @@ }; } - if (Config.CompressionType != DebugCompressionType::None) { + if (ELFConfig.CompressionType != DebugCompressionType::None) { if (Error Err = replaceDebugSections( Obj, RemovePred, isCompressable, - [&Config, &Obj](const SectionBase *S) -> Expected { + [&ELFConfig, + &Obj](const SectionBase *S) -> Expected { Expected NewSection = - CompressedSection::create(*S, Config.CompressionType); + CompressedSection::create(*S, ELFConfig.CompressionType); if (!NewSection) return NewSection.takeError(); return &Obj.addSection(std::move(*NewSection)); })) return Err; - } else if (Config.DecompressDebugSections) { + } else if (ELFConfig.DecompressDebugSections) { if (Error Err = replaceDebugSections( Obj, RemovePred, [](const SectionBase &S) { return isa(&S); }, @@ -497,7 +503,7 @@ return Err; } - return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); + return Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred); } // This function handles the high level operations of GNU objcopy including @@ -509,14 +515,14 @@ // system. The only priority is that keeps/copies overrule removes. static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, Object &Obj) { - if (Config.OutputArch) { - Obj.Machine = Config.OutputArch.getValue().EMachine; - Obj.OSABI = Config.OutputArch.getValue().OSABI; + if (ELFConfig.OutputArch) { + Obj.Machine = ELFConfig.OutputArch.getValue().EMachine; + Obj.OSABI = ELFConfig.OutputArch.getValue().OSABI; } - if (!Config.SplitDWO.empty() && Config.ExtractDWO) { + if (!ELFConfig.SplitDWO.empty() && ELFConfig.ExtractDWO) { return Obj.removeSections( - Config.AllowBrokenLinks, + ELFConfig.AllowBrokenLinks, [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); }); } @@ -533,16 +539,16 @@ // 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()) { + if (!ELFConfig.SectionsToRename.empty()) { for (SectionBase &Sec : Obj.sections()) { - const auto Iter = Config.SectionsToRename.find(Sec.Name); - if (Iter != Config.SectionsToRename.end()) { + const auto Iter = ELFConfig.SectionsToRename.find(Sec.Name); + if (Iter != ELFConfig.SectionsToRename.end()) { const SectionRename &SR = Iter->second; Sec.Name = std::string(SR.NewName); if (SR.NewFlags.hasValue()) @@ -554,11 +560,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()) { + if (!ELFConfig.AllocSectionsPrefix.empty()) { DenseSet PrefixedSections; for (SectionBase &Sec : Obj.sections()) { if (Sec.Flags & SHF_ALLOC) { - Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); + Sec.Name = (ELFConfig.AllocSectionsPrefix + Sec.Name).str(); PrefixedSections.insert(&Sec); } else if (auto *RelocSec = dyn_cast(&Sec)) { // Rename relocation sections associated to the allocated sections. @@ -590,16 +596,17 @@ Sec.Name = (prefix + TargetSec->Name).str(); else Sec.Name = - (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str(); + (prefix + ELFConfig.AllocSectionsPrefix + TargetSec->Name) + .str(); } } } } - if (!Config.SetSectionAlignment.empty()) { + if (!ELFConfig.SetSectionAlignment.empty()) { for (SectionBase &Sec : Obj.sections()) { - auto I = Config.SetSectionAlignment.find(Sec.Name); - if (I != Config.SetSectionAlignment.end()) + auto I = ELFConfig.SetSectionAlignment.find(Sec.Name); + if (I != ELFConfig.SetSectionAlignment.end()) Sec.Align = I->second; } } @@ -629,7 +636,7 @@ if (!Config.AddGnuDebugLink.empty()) Obj.addSection(Config.AddGnuDebugLink, - Config.GnuDebugLinkCRC32); + ELFConfig.GnuDebugLinkCRC32); // If the symbol table was previously removed, we need to create a new one // before adding new symbols. @@ -656,15 +663,15 @@ } } - if (Config.EntryExpr) - Obj.Entry = Config.EntryExpr(Obj.Entry); + if (ELFConfig.EntryExpr) + Obj.Entry = ELFConfig.EntryExpr(Obj.Entry); return Error::success(); } -static Error writeOutput(const CommonConfig &Config, Object &Obj, - raw_ostream &Out, ElfType OutputElfType) { +static Error writeOutput(const CommonConfig &Config, const ELFConfig &ELFConfig, + Object &Obj, raw_ostream &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(); @@ -679,10 +686,10 @@ return Obj.takeError(); const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); + getOutputElfType(ELFConfig.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, ELFConfig, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType); } Error executeObjcopyOnRawBinary(const CommonConfig &Config, @@ -698,29 +705,29 @@ // Prefer OutputArch (-O) if set, otherwise fallback to BinaryArch // (-B). const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); + getOutputElfType(ELFConfig.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, ELFConfig, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType); } Error executeObjcopyOnBinary(const CommonConfig &Config, - const ELFConfig &ElfConfig, + const ELFConfig &ELFConfig, object::ELFObjectFileBase &In, raw_ostream &Out) { - ELFReader Reader(&In, Config.ExtractPartition); + ELFReader Reader(&In, ELFConfig.ExtractPartition); Expected> Obj = - Reader.create(!ElfConfig.SymbolsToAdd.empty()); + Reader.create(!ELFConfig.SymbolsToAdd.empty()); if (!Obj) return Obj.takeError(); // Prefer OutputArch (-O) if set, otherwise infer it from the input. const ElfType OutputElfType = - Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) - : getOutputElfType(In); + ELFConfig.OutputArch ? getOutputElfType(ELFConfig.OutputArch.getValue()) + : getOutputElfType(In); - if (Error E = handleArgs(Config, ElfConfig, **Obj)) + if (Error E = handleArgs(Config, ELFConfig, **Obj)) 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)); return Error::success(); diff --git a/llvm/tools/llvm-objcopy/MachO/MachOConfig.h b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h --- a/llvm/tools/llvm-objcopy/MachO/MachOConfig.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOConfig.h @@ -9,11 +9,30 @@ #ifndef LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H #define LLVM_TOOLS_LLVM_OBJCOPY_MACHOCONFIG_H +#include "CommonConfig.h" + namespace llvm { namespace objcopy { // Mach-O specific configuration for copying/stripping a single file. -struct MachOConfig {}; +struct MachOConfig { + // Repeated options + std::vector RPathToAdd; + std::vector RPathToPrepend; + DenseMap RPathsToUpdate; + DenseSet RPathsToRemove; + DenseMap InstallNamesToUpdate; + + // install-name-tool's id option + Optional SharedLibId; + + // Boolean options + bool KeepUndefined = false; + bool StripSwiftSymbols = false; + + // install-name-tool's --delete_all_rpaths + bool RemoveAllRpaths = false; +}; } // namespace objcopy } // namespace llvm diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h @@ -24,7 +24,8 @@ class MultiFormatConfig; namespace macho { -Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &, +Error executeObjcopyOnBinary(const CommonConfig &Config, + const MachOConfig &MachOConfig, object::MachOObjectFile &In, raw_ostream &Out); Error executeObjcopyOnMachOUniversalBinary( diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -9,6 +9,7 @@ #include "MachOObjcopy.h" #include "../llvm-objcopy.h" #include "CommonConfig.h" +#include "MachOConfig.h" #include "MachOReader.h" #include "MachOWriter.h" #include "MultiFormatConfig.h" @@ -87,25 +88,29 @@ (*ISE.Symbol)->Referenced = true; } -static void updateAndRemoveSymbols(const CommonConfig &Config, Object &Obj) { +static void updateAndRemoveSymbols(const CommonConfig &Config, + const MachOConfig &MachOConfig, + Object &Obj) { for (SymbolEntry &Sym : Obj.SymTable) { auto I = Config.SymbolsToRename.find(Sym.Name); if (I != Config.SymbolsToRename.end()) Sym.Name = std::string(I->getValue()); } - auto RemovePred = [Config, &Obj](const std::unique_ptr &N) { + auto RemovePred = [&Config, &MachOConfig, + &Obj](const std::unique_ptr &N) { if (N->Referenced) return false; - if (Config.KeepUndefined && N->isUndefinedSymbol()) + if (MachOConfig.KeepUndefined && N->isUndefinedSymbol()) return false; if (Config.StripAll) return true; if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT)) return true; // This behavior is consistent with cctools' strip. - if (Config.StripSwiftSymbols && (Obj.Header.Flags & MachO::MH_DYLDLINK) && - Obj.SwiftVersion && *Obj.SwiftVersion && N->isSwiftSymbol()) + if (MachOConfig.StripSwiftSymbols && + (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion && + *Obj.SwiftVersion && N->isSwiftSymbol()) return true; return false; }; @@ -137,17 +142,18 @@ return LC; } -static Error processLoadCommands(const CommonConfig &Config, Object &Obj) { +static Error processLoadCommands(const CommonConfig &Config, + const MachOConfig &MachOConfig, Object &Obj) { // Remove RPaths. - DenseSet RPathsToRemove(Config.RPathsToRemove.begin(), - Config.RPathsToRemove.end()); + DenseSet RPathsToRemove(MachOConfig.RPathsToRemove.begin(), + MachOConfig.RPathsToRemove.end()); LoadCommandPred RemovePred = [&RPathsToRemove, - &Config](const LoadCommand &LC) { + &MachOConfig](const LoadCommand &LC) { if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) { // When removing all RPaths we don't need to care // about what it contains - if (Config.RemoveAllRpaths) + if (MachOConfig.RemoveAllRpaths) return true; StringRef RPath = getPayloadString(LC); @@ -164,7 +170,7 @@ // Emit an error if the Mach-O binary does not contain an rpath path name // specified in -delete_rpath. - for (StringRef RPath : Config.RPathsToRemove) { + for (StringRef RPath : MachOConfig.RPathsToRemove) { if (RPathsToRemove.count(RPath)) return createStringError(errc::invalid_argument, "no LC_RPATH load command with path: %s", @@ -180,7 +186,7 @@ } // Throw errors for invalid RPaths. - for (const auto &OldNew : Config.RPathsToUpdate) { + for (const auto &OldNew : MachOConfig.RPathsToUpdate) { StringRef Old = OldNew.getFirst(); StringRef New = OldNew.getSecond(); if (!RPaths.contains(Old)) @@ -196,14 +202,14 @@ for (LoadCommand &LC : Obj.LoadCommands) { switch (LC.MachOLoadCommand.load_command_data.cmd) { case MachO::LC_ID_DYLIB: - if (Config.SharedLibId) + if (MachOConfig.SharedLibId) updateLoadCommandPayloadString( - LC, *Config.SharedLibId); + LC, *MachOConfig.SharedLibId); break; case MachO::LC_RPATH: { StringRef RPath = getPayloadString(LC); - StringRef NewRPath = Config.RPathsToUpdate.lookup(RPath); + StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath); if (!NewRPath.empty()) updateLoadCommandPayloadString(LC, NewRPath); break; @@ -215,7 +221,7 @@ case MachO::LC_LOAD_WEAK_DYLIB: StringRef InstallName = getPayloadString(LC); StringRef NewInstallName = - Config.InstallNamesToUpdate.lookup(InstallName); + MachOConfig.InstallNamesToUpdate.lookup(InstallName); if (!NewInstallName.empty()) updateLoadCommandPayloadString(LC, NewInstallName); @@ -224,7 +230,7 @@ } // Add new RPaths. - for (StringRef RPath : Config.RPathToAdd) { + for (StringRef RPath : MachOConfig.RPathToAdd) { if (RPaths.contains(RPath)) return createStringError(errc::invalid_argument, "rpath '" + RPath + @@ -233,7 +239,7 @@ Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath)); } - for (StringRef RPath : Config.RPathToPrepend) { + for (StringRef RPath : MachOConfig.RPathToPrepend) { if (RPaths.contains(RPath)) return createStringError(errc::invalid_argument, "rpath '" + RPath + @@ -246,7 +252,7 @@ // Unlike appending rpaths, the indexes of subsequent load commands must // be recalculated after prepending one. - if (!Config.RPathToPrepend.empty()) + if (!MachOConfig.RPathToPrepend.empty()) Obj.updateLoadCommandIndexes(); return Error::success(); @@ -331,7 +337,8 @@ return Error::success(); } -static Error handleArgs(const CommonConfig &Config, Object &Obj) { +static Error handleArgs(const CommonConfig &Config, + const MachOConfig &MachOConfig, Object &Obj) { // Dump sections before add/remove for compatibility with GNU objcopy. for (StringRef Flag : Config.DumpSection) { StringRef SectionName; @@ -348,7 +355,7 @@ if (Config.StripAll) markSymbols(Config, Obj); - updateAndRemoveSymbols(Config, Obj); + updateAndRemoveSymbols(Config, MachOConfig, Obj); if (Config.StripAll) for (LoadCommand &LC : Obj.LoadCommands) @@ -365,20 +372,21 @@ return E; } - if (Error E = processLoadCommands(Config, Obj)) + if (Error E = processLoadCommands(Config, MachOConfig, Obj)) return E; return Error::success(); } -Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &, +Error executeObjcopyOnBinary(const CommonConfig &Config, + const MachOConfig &MachOConfig, object::MachOObjectFile &In, raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); if (!O) return createFileError(Config.InputFilename, O.takeError()); - if (Error E = handleArgs(Config, **O)) + if (Error E = handleArgs(Config, MachOConfig, **O)) return createFileError(Config.InputFilename, std::move(E)); // Page size used for alignment of segment sizes in Mach-O executables and diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -375,21 +375,21 @@ } if (ObjcopyFunc) { - if (ConfigMgr.Common.SplitDWO.empty()) { + if (ConfigMgr.ELF.SplitDWO.empty()) { // Apply transformations described by Config and store result into // Config.OutputFilename using specified ObjcopyFunc function. if (Error E = writeToOutput(ConfigMgr.getCommonConfig().OutputFilename, ObjcopyFunc)) return E; } else { - ConfigMgr.Common.ExtractDWO = true; - ConfigMgr.Common.StripDWO = false; + ConfigMgr.ELF.ExtractDWO = true; + ConfigMgr.ELF.StripDWO = false; // Copy .dwo tables from the Config.InputFilename into Config.SplitDWO // file using specified ObjcopyFunc function. - if (Error E = writeToOutput(ConfigMgr.Common.SplitDWO, ObjcopyFunc)) + if (Error E = writeToOutput(ConfigMgr.ELF.SplitDWO, ObjcopyFunc)) return E; - ConfigMgr.Common.ExtractDWO = false; - ConfigMgr.Common.StripDWO = true; + ConfigMgr.ELF.ExtractDWO = false; + ConfigMgr.ELF.StripDWO = true; // Apply transformations described by Config, remove .dwo tables and // store result into Config.OutputFilename using specified ObjcopyFunc // function. @@ -402,9 +402,9 @@ restoreStatOnFile(ConfigMgr.Common.OutputFilename, Stat, ConfigMgr)) return E; - if (!ConfigMgr.Common.SplitDWO.empty()) { + if (!ConfigMgr.ELF.SplitDWO.empty()) { Stat.permissions(static_cast(0666)); - if (Error E = restoreStatOnFile(ConfigMgr.Common.SplitDWO, Stat, ConfigMgr)) + if (Error E = restoreStatOnFile(ConfigMgr.ELF.SplitDWO, Stat, ConfigMgr)) return E; }