[llvm] d332ec9 - [llvm-install-name-tool] Implement delete_rpath option
Alexander Shaposhnikov via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 22 16:50:06 PDT 2020
Author: Alexander Shaposhnikov
Date: 2020-06-22T16:49:49-07:00
New Revision: d332ec9209ac0a54fc4f1e5e4edc7948fcc4d6af
URL: https://github.com/llvm/llvm-project/commit/d332ec9209ac0a54fc4f1e5e4edc7948fcc4d6af
DIFF: https://github.com/llvm/llvm-project/commit/d332ec9209ac0a54fc4f1e5e4edc7948fcc4d6af.diff
LOG: [llvm-install-name-tool] Implement delete_rpath option
This diff adds support for deleting an rpath from a Mach-O binary.
Patch by Sameer Arora!
Test plan: make check-all
Differential revision: https://reviews.llvm.org/D81527
Added:
llvm/test/tools/llvm-objcopy/MachO/install-name-tool-delete-rpath.test
llvm/test/tools/llvm-objcopy/MachO/remove-lc-index-update.test
Modified:
llvm/tools/llvm-objcopy/CopyConfig.cpp
llvm/tools/llvm-objcopy/CopyConfig.h
llvm/tools/llvm-objcopy/InstallNameToolOpts.td
llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
llvm/tools/llvm-objcopy/MachO/Object.cpp
llvm/tools/llvm-objcopy/MachO/Object.h
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-delete-rpath.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-delete-rpath.test
new file mode 100644
index 000000000000..b5e6abb77752
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-delete-rpath.test
@@ -0,0 +1,75 @@
+## This test checks deleting a LC_RPATH load command from a MachO binary.
+
+# RUN: yaml2obj %s -o %t
+
+## Deleting a single RPath entry:
+# RUN: llvm-install-name-tool -delete_rpath @executable_a/. %t
+# RUN: llvm-objdump -p %t | \
+# RUN: FileCheck %s --check-prefix=RPATHS --implicit-check-not=@executable
+
+# RPATHS: @executable_b/.
+# RPATHS: @executable_c/.
+# RPATHS: @executable_d/.
+# RPATHS: @executable_e/.
+
+## Deleting multiple RPath entries:
+# RUN: llvm-install-name-tool -delete_rpath @executable_b/. \
+# RUN: -delete_rpath @executable_c/. %t
+# RUN: llvm-objdump -p %t | \
+# RUN: FileCheck %s --check-prefix=RPATHS-MULTIPLE --implicit-check-not=@executable
+
+# RPATHS-MULTIPLE: @executable_d/.
+# RPATHS-MULTIPLE: @executable_e/.
+
+## Duplicate delete_rpath commands:
+# RUN: llvm-install-name-tool -delete_rpath @executable_d/. \
+# RUN: -delete_rpath @executable_d/. %t
+# RUN: llvm-objdump -p %t | \
+# RUN: FileCheck %s --check-prefix=DUPLICATE --implicit-check-not=@executable
+
+# DUPLICATE: @executable_e/.
+
+## Deleting a nonexistent RPath:
+# RUN: not llvm-install-name-tool -delete_rpath @executable_a/. %t 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ABSENT-RPATH
+
+# ABSENT-RPATH: no LC_RPATH load command with path: @executable_a/.
+
+## Adding and deleting RPATH at the same time:
+# RUN: not llvm-install-name-tool -add_rpath @executable_b/. \
+# RUN: -delete_rpath @executable_b/. %t 2>&1 | \
+# RUN: FileCheck %s --check-prefix=COMBINED
+
+# COMBINED: cannot specify both -add_rpath @executable_b/. and -delete_rpath @executable_b/.
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 5
+ sizeofcmds: 160
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_a/.'
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_b/.'
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_c/.'
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_d/.'
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_e/.'
diff --git a/llvm/test/tools/llvm-objcopy/MachO/remove-lc-index-update.test b/llvm/test/tools/llvm-objcopy/MachO/remove-lc-index-update.test
new file mode 100644
index 000000000000..6543ae29fbc4
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/MachO/remove-lc-index-update.test
@@ -0,0 +1,343 @@
+## Check that removing load commands updates the indexes of special LCs:
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-install-name-tool -delete_rpath @executable_a/. %t
+# RUN: llvm-objdump -p %t | FileCheck %s --check-prefix=INDEX
+
+# INDEX: Load command 3
+# INDEX-NEXT: cmd LC_DYLD_INFO_ONLY
+# INDEX: Load command 5
+# INDEX-NEXT: cmd LC_DATA_IN_CODE
+# INDEX: Load command 8
+# INDEX-NEXT: cmd LC_FUNCTION_STARTS
+# INDEX: Load command 13
+# INDEX-NEXT: cmd LC_DYSYMTAB
+# INDEX: Load command 14
+# INDEX-NEXT: cmd LC_SYMTAB
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x80000003
+ filetype: 0x00000002
+ ncmds: 16
+ sizeofcmds: 1008
+ flags: 0x00200085
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __PAGEZERO
+ vmaddr: 0
+ vmsize: 4294967296
+ fileoff: 0
+ filesize: 0
+ maxprot: 0
+ initprot: 0
+ nsects: 0
+ flags: 0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: __TEXT
+ vmaddr: 4294967296
+ vmsize: 4096
+ fileoff: 0
+ filesize: 4096
+ maxprot: 7
+ initprot: 5
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x0000000100000F90
+ size: 36
+ offset: 0x00000F90
+ align: 4
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __unwind_info
+ segname: __TEXT
+ addr: 0x0000000100000FB4
+ size: 72
+ offset: 0x00000FB4
+ align: 2
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x00000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: __DATA
+ vmaddr: 4294971392
+ vmsize: 4096
+ fileoff: 4096
+ filesize: 4096
+ maxprot: 7
+ initprot: 3
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __data
+ segname: __DATA
+ addr: 0x0000000100001000
+ size: 4
+ offset: 0x00001000
+ align: 2
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x00000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __common
+ segname: __DATA
+ addr: 0x0000000100001004
+ size: 4
+ offset: 0x00000000
+ align: 2
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x00000001
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - cmd: LC_RPATH
+ cmdsize: 32
+ path: 12
+ PayloadString: '@executable_a/.'
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 8192
+ export_size: 56
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 4294975488
+ vmsize: 4096
+ fileoff: 8192
+ filesize: 496
+ maxprot: 7
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 8256
+ datasize: 8
+ - cmd: LC_LOAD_DYLINKER
+ cmdsize: 32
+ name: 12
+ PayloadString: '/usr/lib/dyld'
+ ZeroPadBytes: 7
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 56D84164-1DA8-393B-8589-BC4C6B56168E
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 8248
+ datasize: 8
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 658944
+ sdk: 658944
+ ntools: 1
+ Tools:
+ - tool: 3
+ version: 29491968
+ - cmd: LC_SOURCE_VERSION
+ cmdsize: 16
+ version: 0
+ - cmd: LC_MAIN
+ cmdsize: 24
+ entryoff: 3984
+ stacksize: 0
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 2
+ current_version: 82115073
+ compatibility_version: 65536
+ PayloadString: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 11
+ iextdefsym: 11
+ nextdefsym: 3
+ iundefsym: 14
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 8264
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 8264
+ nsyms: 15
+ stroff: 8504
+ strsize: 192
+LinkEditData:
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0000000000000000
+ Address: 0x0000000000000000
+ Other: 0x0000000000000000
+ ImportName: ''
+ Children:
+ - TerminalSize: 0
+ NodeOffset: 5
+ Name: _
+ Flags: 0x0000000000000000
+ Address: 0x0000000000000000
+ Other: 0x0000000000000000
+ ImportName: ''
+ Children:
+ - TerminalSize: 2
+ NodeOffset: 38
+ Name: _mh_execute_header
+ Flags: 0x0000000000000000
+ Address: 0x0000000000000000
+ Other: 0x0000000000000000
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 42
+ Name: main
+ Flags: 0x0000000000000000
+ Address: 0x0000000000000F90
+ Other: 0x0000000000000000
+ ImportName: ''
+ - TerminalSize: 3
+ NodeOffset: 47
+ Name: foo
+ Flags: 0x0000000000000000
+ Address: 0x0000000000001004
+ Other: 0x0000000000000000
+ ImportName: ''
+ NameList:
+ - n_strx: 50
+ n_type: 0x64
+ n_sect: 0
+ n_desc: 0
+ n_value: 0
+ - n_strx: 92
+ n_type: 0x64
+ n_sect: 0
+ n_desc: 0
+ n_value: 0
+ - n_strx: 100
+ n_type: 0x66
+ n_sect: 3
+ n_desc: 1
+ n_value: 1564714240
+ - n_strx: 1
+ n_type: 0x2E
+ n_sect: 1
+ n_desc: 0
+ n_value: 4294971280
+ - n_strx: 164
+ n_type: 0x24
+ n_sect: 1
+ n_desc: 0
+ n_value: 4294971280
+ - n_strx: 1
+ n_type: 0x24
+ n_sect: 0
+ n_desc: 0
+ n_value: 36
+ - n_strx: 1
+ n_type: 0x4E
+ n_sect: 1
+ n_desc: 0
+ n_value: 36
+ - n_strx: 170
+ n_type: 0x26
+ n_sect: 3
+ n_desc: 0
+ n_value: 4294971392
+ ## A local undefined SymDebugTable entry followed by
+ - n_strx: 175
+ n_type: 0x20
+ n_sect: 0
+ n_desc: 0
+ n_value: 0
+ ## a defined SymDebugTable entry.
+ - n_strx: 1
+ n_type: 0x64
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 180
+ n_type: 0x0E
+ n_sect: 3
+ n_desc: 0
+ n_value: 4294971392
+ - n_strx: 2
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 16
+ n_value: 4294967296
+ - n_strx: 22
+ n_type: 0x0F
+ n_sect: 4
+ n_desc: 0
+ n_value: 4294971396
+ - n_strx: 27
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 4294971280
+ - n_strx: 33
+ n_type: 0x01
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ StringTable:
+ - ' '
+ - __mh_execute_header
+ - _foo
+ - _main
+ - dyld_stub_binder
+ - '/Users/anonymous/llvm-project/llvm/build/'
+ - strip.c
+ - '/var/folders/g7/l0p5czpd2jz6w0gswg6cwgjc0000gn/T/strip-95c4bf.o'
+ - _main
+ - _bar
+ - _foo
+ - _bar
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+...
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp
index 1e151f01e01e..93fa3d764adb 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -826,6 +826,19 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
Config.RPathToAdd.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))
+ return createStringError(
+ errc::invalid_argument,
+ "cannot specify both -add_rpath %s and -delete_rpath %s",
+ RPath.str().c_str(), RPath.str().c_str());
+
+ Config.RPathsToRemove.insert(RPath);
+ }
+
SmallVector<StringRef, 2> Positional;
for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
return createStringError(errc::invalid_argument, "unknown argument '%s'",
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h
index acf783c7f278..427016ac179b 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -12,6 +12,7 @@
#include "ELF/ELFConfig.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -177,6 +178,7 @@ struct CopyConfig {
std::vector<StringRef> DumpSection;
std::vector<StringRef> SymbolsToAdd;
std::vector<StringRef> RPathToAdd;
+ DenseSet<StringRef> RPathsToRemove;
// Section matchers
NameMatcher KeepSection;
diff --git a/llvm/tools/llvm-objcopy/InstallNameToolOpts.td b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td
index 35047a57994c..b91aba05d624 100644
--- a/llvm/tools/llvm-objcopy/InstallNameToolOpts.td
+++ b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td
@@ -18,5 +18,8 @@ def h : Flag<["-"], "h">, Alias<help>;
def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>,
HelpText<"Add new rpath">;
+def delete_rpath: Option<["-", "--"], "delete_rpath", KIND_SEPARATE>,
+ HelpText<"Delete specified 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 17d84549544b..6a6f5e7eabe7 100644
--- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -10,6 +10,7 @@
#include "../CopyConfig.h"
#include "MachOReader.h"
#include "MachOWriter.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
@@ -19,6 +20,39 @@ namespace macho {
using namespace object;
using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
+using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
+
+static Error removeLoadCommands(const CopyConfig &Config, Object &Obj) {
+ DenseSet<StringRef> RPathsToRemove(Config.RPathsToRemove.begin(),
+ Config.RPathsToRemove.end());
+
+ LoadCommandPred RemovePred = [&RPathsToRemove](const LoadCommand &LC) {
+ if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
+ StringRef RPath =
+ StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
+ LC.Payload.size())
+ .rtrim('\0');
+ if (RPathsToRemove.count(RPath)) {
+ RPathsToRemove.erase(RPath);
+ return true;
+ }
+ }
+ return false;
+ };
+
+ if (Error E = Obj.removeLoadCommands(RemovePred))
+ return E;
+
+ // Emit an error if the Mach-O binary does not contain an rpath path name
+ // specified in -delete_rpath.
+ for (StringRef RPath : Config.RPathsToRemove) {
+ if (RPathsToRemove.count(RPath))
+ return createStringError(errc::invalid_argument,
+ "no LC_RPATH load command with path: %s",
+ RPath.str().c_str());
+ }
+ return Error::success();
+}
static Error removeSections(const CopyConfig &Config, Object &Obj) {
SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
@@ -220,6 +254,9 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
return E;
}
+ if (Error E = removeLoadCommands(Config, Obj))
+ return E;
+
for (StringRef RPath : Config.RPathToAdd) {
for (LoadCommand &LC : Obj.LoadCommands) {
if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH &&
diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp
index 0f28cb054a96..de8cb0af108d 100644
--- a/llvm/tools/llvm-objcopy/MachO/Object.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp
@@ -32,6 +32,42 @@ void SymbolTable::removeSymbols(
std::end(Symbols));
}
+void Object::updateLoadCommandIndexes() {
+ // Update indices of special load commands
+ for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
+ LoadCommand &LC = LoadCommands[Index];
+ switch (LC.MachOLoadCommand.load_command_data.cmd) {
+ case MachO::LC_SYMTAB:
+ SymTabCommandIndex = Index;
+ break;
+ case MachO::LC_DYSYMTAB:
+ DySymTabCommandIndex = Index;
+ break;
+ case MachO::LC_DYLD_INFO:
+ case MachO::LC_DYLD_INFO_ONLY:
+ DyLdInfoCommandIndex = Index;
+ break;
+ case MachO::LC_DATA_IN_CODE:
+ DataInCodeCommandIndex = Index;
+ break;
+ case MachO::LC_FUNCTION_STARTS:
+ FunctionStartsCommandIndex = Index;
+ break;
+ }
+ }
+}
+
+Error Object::removeLoadCommands(
+ function_ref<bool(const LoadCommand &)> ToRemove) {
+ auto It = std::stable_partition(
+ LoadCommands.begin(), LoadCommands.end(),
+ [&](const LoadCommand &LC) { return !ToRemove(LC); });
+ LoadCommands.erase(It, LoadCommands.end());
+
+ updateLoadCommandIndexes();
+ return Error::success();
+}
+
Error Object::removeSections(
function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
DenseMap<uint32_t, const Section *> OldIndexToSection;
diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h
index 5da31d27b6f8..e825d1867b09 100644
--- a/llvm/tools/llvm-objcopy/MachO/Object.h
+++ b/llvm/tools/llvm-objcopy/MachO/Object.h
@@ -326,6 +326,11 @@ struct Object {
Error
removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove);
+
+ Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove);
+
+ void updateLoadCommandIndexes();
+
void addLoadCommand(LoadCommand LC);
/// Creates a new segment load command in the object and returns a reference
More information about the llvm-commits
mailing list