Skip to content

Commit 2d28fe1

Browse files
committed
[lld][MachO] Respect dylibs linked with -allowable_client
ld64.lld will currently allow you to link against dylibs linked with `-allowable_client`, even if the client's name does not match any allowed client. This change fixes that. See #114146 for related discussion. It doesn't quite fix that issue yet, but this change should enable fixing that issue too, once lld learns how to parse the `allowable_clients` field in `.tbd`s.
1 parent 3de5dbb commit 2d28fe1

File tree

7 files changed

+61
-3
lines changed

7 files changed

+61
-3
lines changed

lld/MachO/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ struct Configuration {
164164
llvm::StringRef finalOutput;
165165

166166
llvm::StringRef installName;
167+
llvm::StringRef clientName;
167168
llvm::StringRef mapFile;
168169
llvm::StringRef ltoObjPath;
169170
llvm::StringRef thinLTOJobs;

lld/MachO/Driver.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,31 @@ static InputFile *addFile(StringRef path, LoadType loadType,
407407
case file_magic::macho_dynamically_linked_shared_lib_stub:
408408
case file_magic::tapi_file:
409409
if (DylibFile *dylibFile =
410-
loadDylib(mbref, nullptr, /*isBundleLoader=*/false, isExplicit))
410+
loadDylib(mbref, nullptr, /*isBundleLoader=*/false, isExplicit)) {
411+
if (isExplicit && !dylibFile->allowableClients.empty()) {
412+
bool allowed = false;
413+
414+
for (StringRef allowableClient : dylibFile->allowableClients) {
415+
// Not what you expect, but just as LD64 does it.
416+
if (allowableClient.starts_with(config->clientName)) {
417+
allowed = true;
418+
break;
419+
}
420+
}
421+
422+
// TODO: This behaviour doesn't quite match the latest available source
423+
// release of LD64 (ld64-951.9), which allows "parents" and "siblings"
424+
// to link to libraries even when they're not explicitly named as
425+
// allowable clients. However, behaviour around this seems to have
426+
// changed in the latest release of Xcode (ld64-1115.7.3), so it's not
427+
// clear what the correct thing to do is yet.
428+
if (!allowed)
429+
error("cannot link directly with '" +
430+
sys::path::filename(dylibFile->installName) + "' because " +
431+
config->clientName + " is not an allowed client");
432+
}
411433
newFile = dylibFile;
434+
}
412435
break;
413436
case file_magic::bitcode:
414437
newFile = make<BitcodeFile>(mbref, "", 0, isLazy);
@@ -1863,6 +1886,17 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
18631886
config->installName = config->finalOutput;
18641887
}
18651888

1889+
auto getClientName = [&]() {
1890+
StringRef cn = path::filename(config->finalOutput);
1891+
cn.consume_front("lib");
1892+
auto firstDot = cn.find_first_of('.');
1893+
cn = cn.take_front(firstDot);
1894+
auto firstUnderscore = cn.find_first_of('_');
1895+
cn = cn.take_front(firstUnderscore);
1896+
return cn;
1897+
};
1898+
config->clientName = args.getLastArgValue(OPT_client_name, getClientName());
1899+
18661900
if (args.hasArg(OPT_mark_dead_strippable_dylib)) {
18671901
if (config->outputType != MH_DYLIB)
18681902
warn("-mark_dead_strippable_dylib: ignored, only has effect with -dylib");

lld/MachO/InputFiles.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,14 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
17301730
? this
17311731
: this->umbrella;
17321732

1733+
if (!canBeImplicitlyLinked) {
1734+
for (auto *cmd : findCommands<sub_client_command>(hdr, LC_SUB_CLIENT)) {
1735+
StringRef allowableClient{reinterpret_cast<const char *>(cmd) +
1736+
cmd->client};
1737+
allowableClients.push_back(allowableClient);
1738+
}
1739+
}
1740+
17331741
const auto *dyldInfo = findCommand<dyld_info_command>(hdr, LC_DYLD_INFO_ONLY);
17341742
const auto *exportsTrie =
17351743
findCommand<linkedit_data_command>(hdr, LC_DYLD_EXPORTS_TRIE);

lld/MachO/InputFiles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class DylibFile final : public InputFile {
241241
DylibFile *exportingFile = nullptr;
242242
DylibFile *umbrella;
243243
SmallVector<StringRef, 2> rpaths;
244+
SmallVector<StringRef> allowableClients;
244245
uint32_t compatibilityVersion = 0;
245246
uint32_t currentVersion = 0;
246247
int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel

lld/MachO/Options.td

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,7 @@ def allowable_client : Separate<["-"], "allowable_client">,
875875
Group<grp_rare>;
876876
def client_name : Separate<["-"], "client_name">,
877877
MetaVarName<"<name>">,
878-
HelpText<"Specifies a <name> this client should match with the -allowable_client <name> in a dependent dylib">,
879-
Flags<[HelpHidden]>,
878+
HelpText<"Specifies a <name> this client should match with the -allowable_client <name> in an explicitly linked dylib">,
880879
Group<grp_rare>;
881880
def umbrella : Separate<["-"], "umbrella">,
882881
MetaVarName<"<name>">,
Binary file not shown.

lld/test/MachO/allowable-client.s

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
3+
# RUN: not %lld -o %t %t.o -L%S/Inputs -lallowable_client 2>&1 | FileCheck %s --check-prefix=NOTALLOWED1
4+
# RUN: not %lld -o %t %t.o -L%S/Inputs -lallowable_client -client_name notallowed 2>&1 | FileCheck %s --check-prefix=NOTALLOWED2
5+
# RUN: %lld -o %t %t.o -L%S/Inputs -lallowable_client -client_name allowed
6+
# RUN: %lld -o %t %t.o -L%S/Inputs -lallowable_client -client_name all
7+
8+
# NOTALLOWED1: error: cannot link directly with 'liballowable_client.dylib' because {{.*}} is not an allowed client
9+
# NOTALLOWED2: error: cannot link directly with 'liballowable_client.dylib' because notallowed is not an allowed client
10+
11+
.text
12+
.global _main
13+
_main:
14+
mov $0, %rax
15+
ret

0 commit comments

Comments
 (0)