Skip to content

Commit 77cbf25

Browse files
keithAlexander Shaposhnikov
authored andcommitted
[llvm-install-name-tool] Add -prepend_rpath option
This diff adds the option -prepend_rpath which inserts an rpath as the first rpath in the binary. Test plan: make check-all Differential revision: https://reviews.llvm.org/D89605
1 parent 71e1a56 commit 77cbf25

File tree

5 files changed

+98
-0
lines changed

5 files changed

+98
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
## This test checks prepending a new LC_RPATH load command to a MachO binary.
2+
3+
# RUN: yaml2obj %p/Inputs/i386.yaml -o %t.i386
4+
# RUN: llvm-install-name-tool -add_rpath @executable_path/. %t.i386
5+
# RUN: llvm-install-name-tool -prepend_rpath first_rpath %t.i386
6+
# RUN: llvm-objdump -p %t.i386 | FileCheck --check-prefix=NEW-RPATH %s
7+
8+
# RUN: yaml2obj %p/Inputs/x86_64.yaml -o %t.x86_64
9+
# RUN: llvm-install-name-tool -add_rpath @executable_path/. %t.x86_64
10+
# RUN: llvm-install-name-tool -prepend_rpath first_rpath %t.x86_64
11+
# RUN: llvm-objdump -p %t.x86_64 | FileCheck --check-prefix=NEW-RPATH %s
12+
13+
# NEW-RPATH: cmd LC_RPATH
14+
# NEW-RPATH-NEXT: cmdsize
15+
# NEW-RPATH-NEXT: first_rpath
16+
17+
# NEW-RPATH: cmd LC_RPATH
18+
# NEW-RPATH-NEXT: cmdsize
19+
# NEW-RPATH-NEXT: @executable_path/.
20+
21+
## Prepend with dylib loads:
22+
# RUN: yaml2obj %p/Inputs/strip-all.yaml -o %t.dylib
23+
# RUN: llvm-install-name-tool -prepend_rpath first_rpath %t.dylib
24+
# RUN: llvm-objdump -p %t.dylib | FileCheck --check-prefix=DYLIB %s
25+
26+
# DYLIB: cmd LC_RPATH
27+
# DYLIB-NEXT: cmdsize
28+
# DYLIB-NEXT: first_rpath
29+
30+
# RUN: not llvm-install-name-tool -prepend_rpath first_rpath %t.i386 2>&1 | \
31+
# RUN: FileCheck --check-prefix=DUPLICATE-RPATH %s
32+
33+
# DUPLICATE-RPATH: rpath first_rpath would create a duplicate load command
34+
35+
## Prepend same RPATH twice:
36+
# RUN: not llvm-install-name-tool -prepend_rpath @executable_X \
37+
# RUN: -prepend_rpath @executable_X %t.i386 2>&1 | \
38+
# RUN: FileCheck --check-prefix=DOUBLE %s
39+
40+
# DOUBLE: rpath @executable_X would create a duplicate load command
41+
42+
## Prepend and delete RPATH:
43+
# RUN: not llvm-install-name-tool -prepend_rpath foo \
44+
# RUN: -delete_rpath foo %t.i386 2>&1 | \
45+
# RUN: FileCheck --check-prefix=DELETE %s
46+
47+
# DELETE: cannot specify both -prepend_rpath foo and -delete_rpath foo
48+
49+
## Prepend and replace RPATH:
50+
# RUN: not llvm-install-name-tool -prepend_rpath foo \
51+
# RUN: -rpath foo bar %t.i386 2>&1 | \
52+
# RUN: FileCheck --check-prefix=REPLACE %s
53+
54+
# REPLACE: cannot specify both -prepend_rpath foo and -rpath foo bar
55+
56+
## Check that cmdsize accounts for NULL terminator:
57+
# RUN: yaml2obj %p/Inputs/x86_64.yaml -o %t.x86_64
58+
# RUN: llvm-install-name-tool -prepend_rpath abcd %t.x86_64
59+
# RUN: llvm-objdump -p %t.x86_64 | FileCheck %s --check-prefix=RPATH-SIZE
60+
61+
# RPATH-SIZE: cmd LC_RPATH
62+
# RPATH-SIZE-NEXT: cmdsize 24
63+
# RPATH-SIZE-NEXT: path abcd

llvm/tools/llvm-objcopy/CopyConfig.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
895895
for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
896896
Config.RPathToAdd.push_back(Arg->getValue());
897897

898+
for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
899+
Config.RPathToPrepend.push_back(Arg->getValue());
900+
898901
for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
899902
StringRef RPath = Arg->getValue();
900903

@@ -904,6 +907,11 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
904907
errc::invalid_argument,
905908
"cannot specify both -add_rpath %s and -delete_rpath %s",
906909
RPath.str().c_str(), RPath.str().c_str());
910+
if (is_contained(Config.RPathToPrepend, RPath))
911+
return createStringError(
912+
errc::invalid_argument,
913+
"cannot specify both -prepend_rpath %s and -delete_rpath %s",
914+
RPath.str().c_str(), RPath.str().c_str());
907915

908916
Config.RPathsToRemove.insert(RPath);
909917
}
@@ -940,6 +948,13 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
940948
"cannot specify both -add_rpath " + *It3 +
941949
" and -rpath " + Old + " " + New);
942950

951+
// Cannot specify the same rpath under both -prepend_rpath and -rpath.
952+
auto It4 = find_if(Config.RPathToPrepend, Match);
953+
if (It4 != Config.RPathToPrepend.end())
954+
return createStringError(errc::invalid_argument,
955+
"cannot specify both -prepend_rpath " + *It4 +
956+
" and -rpath " + Old + " " + New);
957+
943958
Config.RPathsToUpdate.insert({Old, New});
944959
}
945960

llvm/tools/llvm-objcopy/CopyConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ struct CopyConfig {
178178
std::vector<StringRef> DumpSection;
179179
std::vector<StringRef> SymbolsToAdd;
180180
std::vector<StringRef> RPathToAdd;
181+
std::vector<StringRef> RPathToPrepend;
181182
DenseMap<StringRef, StringRef> RPathsToUpdate;
182183
DenseMap<StringRef, StringRef> InstallNamesToUpdate;
183184
DenseSet<StringRef> RPathsToRemove;

llvm/tools/llvm-objcopy/InstallNameToolOpts.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def h : Flag<["-"], "h">, Alias<help>;
1818
def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>,
1919
HelpText<"Add new rpath">;
2020

21+
def prepend_rpath : Option<["-", "--"], "prepend_rpath", KIND_SEPARATE>,
22+
HelpText<"Add new rpath before other rpaths">;
23+
2124
def delete_rpath: Option<["-", "--"], "delete_rpath", KIND_SEPARATE>,
2225
HelpText<"Delete specified rpath">;
2326

llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,22 @@ static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
228228
Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
229229
}
230230

231+
for (StringRef RPath : Config.RPathToPrepend) {
232+
if (RPaths.count(RPath) != 0)
233+
return createStringError(errc::invalid_argument,
234+
"rpath " + RPath +
235+
" would create a duplicate load command");
236+
237+
RPaths.insert(RPath);
238+
Obj.LoadCommands.insert(Obj.LoadCommands.begin(),
239+
buildRPathLoadCommand(RPath));
240+
}
241+
242+
// Unlike appending rpaths, the indexes of subsequent load commands must
243+
// be recalculated after prepending one.
244+
if (!Config.RPathToPrepend.empty())
245+
Obj.updateLoadCommandIndexes();
246+
231247
return Error::success();
232248
}
233249

0 commit comments

Comments
 (0)