From 88f00aef684ff84a6494e1f17d5466c5678f703d Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Mon, 18 Nov 2019 15:44:58 -0800 Subject: [PATCH] Introduce llvm-install-name-tool This diff adds a new "driver" for llvm-objcopy which is supposed to emulate the behavior of install-name-tool. This is a recommit of b5913e6d2 with ubsan issues fixed. Differential revision: https://reviews.llvm.org/D69146 Test plan: make check-all --- .../test/tools/llvm-objcopy/MachO/Inputs/i386.yaml | 88 +++++++++++++++++++++ .../tools/llvm-objcopy/MachO/Inputs/x86_64.yaml | 89 ++++++++++++++++++++++ .../MachO/install-name-tool-add-rpath.test | 23 ++++++ .../MachO/install-name-tool-help-message.test | 10 +++ .../MachO/install-name-tool-version.test | 2 + llvm/tools/llvm-objcopy/CMakeLists.txt | 6 ++ llvm/tools/llvm-objcopy/CopyConfig.cpp | 89 ++++++++++++++++++++++ llvm/tools/llvm-objcopy/CopyConfig.h | 12 ++- llvm/tools/llvm-objcopy/InstallNameToolOpts.td | 22 ++++++ llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp | 26 ++++++- llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 18 +++-- llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp | 6 +- llvm/tools/llvm-objcopy/MachO/Object.cpp | 4 + llvm/tools/llvm-objcopy/MachO/Object.h | 3 +- llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 20 +++-- 15 files changed, 398 insertions(+), 20 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/MachO/Inputs/i386.yaml create mode 100644 llvm/test/tools/llvm-objcopy/MachO/Inputs/x86_64.yaml create mode 100644 llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test create mode 100644 llvm/test/tools/llvm-objcopy/MachO/install-name-tool-help-message.test create mode 100644 llvm/test/tools/llvm-objcopy/MachO/install-name-tool-version.test create mode 100644 llvm/tools/llvm-objcopy/InstallNameToolOpts.td diff --git a/llvm/test/tools/llvm-objcopy/MachO/Inputs/i386.yaml b/llvm/test/tools/llvm-objcopy/MachO/Inputs/i386.yaml new file mode 100644 index 0000000..15e6220 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/Inputs/i386.yaml @@ -0,0 +1,88 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 312 + flags: 0x00002000 +LoadCommands: + - cmd: LC_SEGMENT + cmdsize: 192 + segname: '' + vmaddr: 0 + vmsize: 72 + fileoff: 340 + filesize: 72 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 18 + offset: 0x00000154 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000014 + size: 52 + offset: 0x00000168 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 656384 + sdk: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 412 + nsyms: 1 + stroff: 424 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... diff --git a/llvm/test/tools/llvm-objcopy/MachO/Inputs/x86_64.yaml b/llvm/test/tools/llvm-objcopy/MachO/Inputs/x86_64.yaml new file mode 100644 index 0000000..5b059bb --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/Inputs/x86_64.yaml @@ -0,0 +1,89 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 352 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 80 + fileoff: 384 + filesize: 80 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 15 + offset: 0x00000180 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000010 + size: 64 + offset: 0x00000190 + align: 3 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 656384 + sdk: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 464 + nsyms: 1 + stroff: 480 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test new file mode 100644 index 0000000..6d26201 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test @@ -0,0 +1,23 @@ +## This test checks adding a new LC_RPATH load command to a MachO binary. + +# RUN: yaml2obj %p/Inputs/i386.yaml > %t.i386 +# RUN: llvm-install-name-tool -add_rpath @executable_path/. %t.i386 +# RUN: llvm-objdump -p %t.i386 | FileCheck --check-prefix=NEW-RPATH %s + +# RUN: yaml2obj %p/Inputs/x86_64.yaml > %t.x86_64 +# RUN: llvm-install-name-tool -add_rpath @executable_path/. %t.x86_64 +# RUN: llvm-objdump -p %t.x86_64 | FileCheck --check-prefix=NEW-RPATH %s + +# NEW-RPATH: cmd LC_RPATH +# NEW-RPATH-NEXT: cmdsize +# NEW-RPATH-NEXT: @executable_path/. + +# RUN: not llvm-install-name-tool -add_rpath @executable_path/. %t.i386 2>&1 \ +# RUN: | FileCheck --check-prefix=DUPLICATE-RPATH %s + +# DUPLICATE-RPATH: duplicate load command + +# RUN: not llvm-install-name-tool -add_rpath @executable_path/. 2>&1 \ +# RUN: | FileCheck --check-prefix=NO-INPUT %s + +# NO-INPUT: no input file specified diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-help-message.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-help-message.test new file mode 100644 index 0000000..43e5290 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-help-message.test @@ -0,0 +1,10 @@ +# RUN: llvm-install-name-tool -h | FileCheck --check-prefix=INSTALL-NAME-TOOL-USAGE %s +# RUN: llvm-install-name-tool --help | FileCheck --check-prefix=INSTALL-NAME-TOOL-USAGE %s +# RUN: not llvm-install-name-tool 2>&1 | FileCheck --check-prefix=INSTALL-NAME-TOOL-USAGE %s +# RUN: not llvm-install-name-tool -abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG %s +# RUN: not llvm-install-name-tool --abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG %s + +# INSTALL-NAME-TOOL-USAGE: USAGE: llvm-install-name-tool +# INSTALL-NAME-TOOL-USAGE: @FILE + +# UNKNOWN-ARG: unknown argument '{{-+}}abcabc' diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-version.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-version.test new file mode 100644 index 0000000..295e573 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-version.test @@ -0,0 +1,2 @@ +# RUN: llvm-install-name-tool --version | FileCheck %s +# CHECK: {{ version }} diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt index 50c890b..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 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 +parseInstallNameToolOptions(ArrayRef 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 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 OutputArch; @@ -175,6 +175,7 @@ struct CopyConfig { std::vector AddSection; std::vector DumpSection; std::vector SymbolsToAdd; + std::vector RPathToAdd; // Section matchers NameMatcher KeepSection; @@ -251,6 +252,12 @@ Expected parseObjcopyOptions(ArrayRef ArgsArr, llvm::function_ref 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 +parseInstallNameToolOptions(ArrayRef 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 ArgsArr, Expected parseStripOptions(ArrayRef ArgsArr, llvm::function_ref 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; + +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(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( \ - reinterpret_cast(const_cast(LoadCmd.Ptr)) + \ - sizeof(MachO::LCStruct), \ - LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ + if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \ + LC.Payload = ArrayRef( \ + reinterpret_cast(const_cast(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( - reinterpret_cast(const_cast(LoadCmd.Ptr)) + - sizeof(MachO::load_command), - LoadCmd.C.cmdsize - sizeof(MachO::load_command)); + if (LoadCmd.C.cmdsize > sizeof(MachO::load_command)) + LC.Payload = ArrayRef( + reinterpret_cast(const_cast(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 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 Payload; + std::vector 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 FunctionStartsCommandIndex; void removeSections(function_ref 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(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 = - 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)); -- 2.7.4