diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy')
-rw-r--r-- | llvm/tools/llvm-objcopy/CMakeLists.txt | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/CopyConfig.cpp | 89 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/CopyConfig.h | 12 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/InstallNameToolOpts.td | 22 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp | 26 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 18 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/Object.cpp | 4 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/MachO/Object.h | 3 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 20 |
10 files changed, 186 insertions, 20 deletions
diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt index 50c890b5..6d4048f 100644 --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -9,6 +9,10 @@ set(LLVM_TARGET_DEFINITIONS ObjcopyOpts.td) tablegen(LLVM ObjcopyOpts.inc -gen-opt-parser-defs) add_public_tablegen_target(ObjcopyOptsTableGen) +set(LLVM_TARGET_DEFINITIONS InstallNameToolOpts.td) +tablegen(LLVM InstallNameToolOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(InstallNameToolOptsTableGen) + set(LLVM_TARGET_DEFINITIONS StripOpts.td) tablegen(LLVM StripOpts.inc -gen-opt-parser-defs) add_public_tablegen_target(StripOptsTableGen) @@ -31,9 +35,11 @@ add_llvm_tool(llvm-objcopy MachO/Object.cpp DEPENDS ObjcopyOptsTableGen + InstallNameToolOptsTableGen StripOptsTableGen ) +add_llvm_tool_symlink(llvm-install-name-tool llvm-objcopy) add_llvm_tool_symlink(llvm-strip llvm-objcopy) if(LLVM_INSTALL_BINUTILS_SYMLINKS) diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp index d707bec..73ed00b 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -63,6 +63,44 @@ public: ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {} }; +enum InstallNameToolID { + INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + INSTALL_NAME_TOOL_##ID, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) \ + const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE; +#include "InstallNameToolOpts.inc" +#undef PREFIX + +static const opt::OptTable::Info InstallNameToolInfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {INSTALL_NAME_TOOL_##PREFIX, \ + NAME, \ + HELPTEXT, \ + METAVAR, \ + INSTALL_NAME_TOOL_##ID, \ + opt::Option::KIND##Class, \ + PARAM, \ + FLAGS, \ + INSTALL_NAME_TOOL_##GROUP, \ + INSTALL_NAME_TOOL_##ALIAS, \ + ALIASARGS, \ + VALUES}, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +class InstallNameToolOptTable : public opt::OptTable { +public: + InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {} +}; + enum StripID { STRIP_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ @@ -752,6 +790,57 @@ parseObjcopyOptions(ArrayRef<const char *> ArgsArr, return std::move(DC); } +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { + DriverConfig DC; + CopyConfig Config; + InstallNameToolOptTable T; + unsigned MissingArgumentIndex, MissingArgumentCount; + llvm::opt::InputArgList InputArgs = + T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); + + if (InputArgs.size() == 0) { + printHelp(T, errs(), "llvm-install-name-tool"); + exit(1); + } + + if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) { + printHelp(T, outs(), "llvm-install-name-tool"); + exit(0); + } + + if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) { + outs() << "llvm-install-name-tool, compatible with cctools " + "install_name_tool\n"; + cl::PrintVersionMessage(); + exit(0); + } + + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) + Config.RPathToAdd.push_back(Arg->getValue()); + + SmallVector<StringRef, 2> Positional; + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN)) + return createStringError(errc::invalid_argument, "unknown argument '%s'", + Arg->getAsString(InputArgs).c_str()); + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT)) + Positional.push_back(Arg->getValue()); + if (Positional.empty()) + return createStringError(errc::invalid_argument, "no input file specified"); + if (Positional.size() > 1) + return createStringError( + errc::invalid_argument, + "llvm-install-name-tool expects a single input file"); + Config.InputFilename = Positional[0]; + Config.OutputFilename = Positional[0]; + + DC.CopyConfigs.push_back(std::move(Config)); + return std::move(DC); +} + // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h index 55a55d3..c262934 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -150,9 +150,9 @@ struct CopyConfig { // Main input/output options StringRef InputFilename; - FileFormat InputFormat; + FileFormat InputFormat = FileFormat::Unspecified; StringRef OutputFilename; - FileFormat OutputFormat; + FileFormat OutputFormat = FileFormat::Unspecified; // Only applicable when --output-format!=binary (e.g. elf64-x86-64). Optional<MachineInfo> OutputArch; @@ -175,6 +175,7 @@ struct CopyConfig { std::vector<StringRef> AddSection; std::vector<StringRef> DumpSection; std::vector<StringRef> SymbolsToAdd; + std::vector<StringRef> RPathToAdd; // Section matchers NameMatcher KeepSection; @@ -251,6 +252,12 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr, llvm::function_ref<Error(Error)> ErrorCallback); +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr); + // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. ErrorCallback is used to handle recoverable errors. An Error returned @@ -258,7 +265,6 @@ parseObjcopyOptions(ArrayRef<const char *> ArgsArr, Expected<DriverConfig> parseStripOptions(ArrayRef<const char *> ArgsArr, llvm::function_ref<Error(Error)> ErrorCallback); - } // namespace objcopy } // namespace llvm diff --git a/llvm/tools/llvm-objcopy/InstallNameToolOpts.td b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td new file mode 100644 index 0000000..35047a5 --- /dev/null +++ b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td @@ -0,0 +1,22 @@ +//===-- InstallNameToolOpts.td - llvm-install-name-tool options --------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file describes the command line options of llvm-install-name. +// +//===----------------------------------------------------------------------===// + +include "llvm/Option/OptParser.td" + +def help : Flag<["--"], "help">; +def h : Flag<["-"], "h">, Alias<help>; + +def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>, + HelpText<"Add new rpath">; + +def version : Flag<["--"], "version">, + HelpText<"Print the version and exit.">; diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp index dbdd44c..e589674 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -72,6 +72,18 @@ static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { Obj.SymTable.removeSymbols(RemovePred); } +static LoadCommand buildRPathLoadCommand(StringRef Path) { + LoadCommand LC; + MachO::rpath_command RPathLC; + RPathLC.cmd = MachO::LC_RPATH; + RPathLC.path = sizeof(MachO::rpath_command); + RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size(), 8); + LC.MachOLoadCommand.rpath_command_data = RPathLC; + LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0); + std::copy(Path.begin(), Path.end(), LC.Payload.begin()); + return LC; +} + static Error handleArgs(const CopyConfig &Config, Object &Obj) { if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput || Config.BuildIdLinkOutput || @@ -94,7 +106,6 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for MachO"); } - removeSections(Config, Obj); // Mark symbols to determine which symbols are still needed. @@ -108,6 +119,19 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) { for (Section &Sec : LC.Sections) Sec.Relocations.clear(); + for (StringRef RPath : Config.RPathToAdd) { + for (LoadCommand &LC : Obj.LoadCommands) { + if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH && + RPath == StringRef(reinterpret_cast<char *>(LC.Payload.data()), + LC.Payload.size()) + .trim(0)) { + return createStringError(errc::invalid_argument, + "rpath " + RPath + + " would create a duplicate load command"); + } + } + Obj.addLoadCommand(buildRPathLoadCommand(RPath)); + } return Error::success(); } diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp index 7e2ebdc..cf8c93b 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -150,10 +150,11 @@ void MachOReader::readLoadCommands(Object &O) const { sizeof(MachO::LCStruct)); \ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \ MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \ - LC.Payload = ArrayRef<uint8_t>( \ - reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ - sizeof(MachO::LCStruct), \ - LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ + if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \ + LC.Payload = ArrayRef<uint8_t>( \ + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ + sizeof(MachO::LCStruct), \ + LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ break; switch (LoadCmd.C.cmd) { @@ -162,10 +163,11 @@ void MachOReader::readLoadCommands(Object &O) const { sizeof(MachO::load_command)); if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) MachO::swapStruct(LC.MachOLoadCommand.load_command_data); - LC.Payload = ArrayRef<uint8_t>( - reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + - sizeof(MachO::load_command), - LoadCmd.C.cmdsize - sizeof(MachO::load_command)); + if (LoadCmd.C.cmdsize > sizeof(MachO::load_command)) + LC.Payload = ArrayRef<uint8_t>( + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + + sizeof(MachO::load_command), + LoadCmd.C.cmdsize - sizeof(MachO::load_command)); break; #include "llvm/BinaryFormat/MachO.def" } diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp index 59d57f7..0d95906 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -180,7 +180,8 @@ void MachOWriter::writeLoadCommands() { MachO::swapStruct(MLC.LCStruct##_data); \ memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \ Begin += sizeof(MachO::LCStruct); \ - memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ + if (!LC.Payload.empty()) \ + memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ Begin += LC.Payload.size(); \ break; @@ -193,7 +194,8 @@ void MachOWriter::writeLoadCommands() { MachO::swapStruct(MLC.load_command_data); memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command)); Begin += sizeof(MachO::load_command); - memcpy(Begin, LC.Payload.data(), LC.Payload.size()); + if (!LC.Payload.empty()) + memcpy(Begin, LC.Payload.data(), LC.Payload.size()); Begin += LC.Payload.size(); break; #include "llvm/BinaryFormat/MachO.def" diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp index 5626782..812853e 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -29,6 +29,10 @@ void Object::removeSections(function_ref<bool(const Section &)> ToRemove) { std::end(LC.Sections)); } +void Object::addLoadCommand(LoadCommand LC) { + LoadCommands.push_back(std::move(LC)); +} + } // end namespace macho } // end namespace objcopy } // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h index fb57637..1ce4881 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -74,7 +74,7 @@ struct LoadCommand { // The raw content of the payload of the load command (located right after the // corresponding struct). In some cases it is either empty or can be // copied-over without digging into its structure. - ArrayRef<uint8_t> Payload; + std::vector<uint8_t> Payload; // Some load commands can contain (inside the payload) an array of sections, // though the contents of the sections are stored separately. The struct @@ -276,6 +276,7 @@ struct Object { Optional<size_t> FunctionStartsCommandIndex; void removeSections(function_ref<bool(const Section &)> ToRemove); + void addLoadCommand(LoadCommand LC); }; } // end namespace macho diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index a68210f..e662f35 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -313,11 +313,20 @@ static Error executeObjcopy(CopyConfig &Config) { return Error::success(); } +namespace { + +enum class ToolType { Objcopy, Strip, InstallNameTool }; + +} // anonymous namespace + int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - bool IsStrip = sys::path::stem(ToolName).contains("strip"); - + ToolType Tool = StringSwitch<ToolType>(sys::path::stem(ToolName)) + .EndsWith("strip", ToolType::Strip) + .EndsWith("install-name-tool", ToolType::InstallNameTool) + .EndsWith("install_name_tool", ToolType::InstallNameTool) + .Default(ToolType::Objcopy); // Expand response files. // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, // into a separate function in the CommandLine library and call that function @@ -332,10 +341,11 @@ int main(int argc, char **argv) { NewArgv); auto Args = makeArrayRef(NewArgv).drop_front(); - Expected<DriverConfig> DriverConfig = - IsStrip ? parseStripOptions(Args, reportWarning) - : parseObjcopyOptions(Args, reportWarning); + (Tool == ToolType::Strip) ? parseStripOptions(Args, reportWarning) + : ((Tool == ToolType::InstallNameTool) + ? parseInstallNameToolOptions(Args) + : parseObjcopyOptions(Args, reportWarning)); if (!DriverConfig) { logAllUnhandledErrors(DriverConfig.takeError(), WithColor::error(errs(), ToolName)); |