[lld] 9260760 - [lld-macho] Support loading of zippered dylibs
Jez Ng via llvm-commits
llvm-commits at lists.llvm.org
Thu May 6 08:19:52 PDT 2021
Author: Jez Ng
Date: 2021-05-06T11:19:40-04:00
New Revision: 9260760235261a5cd150b15a3499f7988da65a02
URL: https://github.com/llvm/llvm-project/commit/9260760235261a5cd150b15a3499f7988da65a02
DIFF: https://github.com/llvm/llvm-project/commit/9260760235261a5cd150b15a3499f7988da65a02.diff
LOG: [lld-macho] Support loading of zippered dylibs
ld64 can emit dylibs that support more than one platform (typically macOS and
macCatalyst). This diff allows LLD to read in those dylibs. Note that this is a
super bare-bones implementation -- in particular, I haven't added support for
LLD to emit those multi-platform dylibs, nor have I added a variety of
validation checks that ld64 does. Until we have a use-case for emitting zippered
dylibs, I think this is good enough.
Fixes PR49597.
Reviewed By: #lld-macho, oontvoo
Differential Revision: https://reviews.llvm.org/D101954
Added:
lld/test/MachO/zippered.yaml
Modified:
lld/MachO/InputFiles.cpp
lld/MachO/InputFiles.h
lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd
Removed:
################################################################################
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index adc1bb20a47c..7df21616aa3f 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -102,41 +102,42 @@ static VersionTuple decodeVersion(uint32_t version) {
return VersionTuple(major, minor, subMinor);
}
-static Optional<PlatformInfo> getPlatformInfo(const InputFile *input) {
+static std::vector<PlatformInfo> getPlatformInfos(const InputFile *input) {
if (!isa<ObjFile>(input) && !isa<DylibFile>(input))
- return None;
+ return {};
const char *hdr = input->mb.getBufferStart();
- PlatformInfo platformInfo;
- if (const auto *cmd =
- findCommand<build_version_command>(hdr, LC_BUILD_VERSION)) {
- platformInfo.target.Platform = static_cast<PlatformKind>(cmd->platform);
- platformInfo.minimum = decodeVersion(cmd->minos);
- return platformInfo;
+ std::vector<PlatformInfo> platformInfos;
+ for (auto *cmd : findCommands<build_version_command>(hdr, LC_BUILD_VERSION)) {
+ PlatformInfo info;
+ info.target.Platform = static_cast<PlatformKind>(cmd->platform);
+ info.minimum = decodeVersion(cmd->minos);
+ platformInfos.emplace_back(std::move(info));
}
- if (const auto *cmd = findCommand<version_min_command>(
- hdr, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
- LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS)) {
+ for (auto *cmd : findCommands<version_min_command>(
+ hdr, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+ LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS)) {
+ PlatformInfo info;
switch (cmd->cmd) {
case LC_VERSION_MIN_MACOSX:
- platformInfo.target.Platform = PlatformKind::macOS;
+ info.target.Platform = PlatformKind::macOS;
break;
case LC_VERSION_MIN_IPHONEOS:
- platformInfo.target.Platform = PlatformKind::iOS;
+ info.target.Platform = PlatformKind::iOS;
break;
case LC_VERSION_MIN_TVOS:
- platformInfo.target.Platform = PlatformKind::tvOS;
+ info.target.Platform = PlatformKind::tvOS;
break;
case LC_VERSION_MIN_WATCHOS:
- platformInfo.target.Platform = PlatformKind::watchOS;
+ info.target.Platform = PlatformKind::watchOS;
break;
}
- platformInfo.minimum = decodeVersion(cmd->version);
- return platformInfo;
+ info.minimum = decodeVersion(cmd->version);
+ platformInfos.emplace_back(std::move(info));
}
- return None;
+ return platformInfos;
}
static PlatformKind removeSimulator(PlatformKind platform) {
@@ -153,22 +154,33 @@ static PlatformKind removeSimulator(PlatformKind platform) {
}
static bool checkCompatibility(const InputFile *input) {
- Optional<PlatformInfo> platformInfo = getPlatformInfo(input);
- if (!platformInfo)
+ std::vector<PlatformInfo> platformInfos = getPlatformInfos(input);
+ if (platformInfos.empty())
return true;
- if (removeSimulator(config->platform()) !=
- removeSimulator(platformInfo->target.Platform)) {
- error(toString(input) + " has platform " +
- getPlatformName(platformInfo->target.Platform) +
+ auto it = find_if(platformInfos, [&](const PlatformInfo &info) {
+ return removeSimulator(info.target.Platform) ==
+ removeSimulator(config->platform());
+ });
+ if (it == platformInfos.end()) {
+ std::string platformNames;
+ raw_string_ostream os(platformNames);
+ interleave(
+ platformInfos, os,
+ [&](const PlatformInfo &info) {
+ os << getPlatformName(info.target.Platform);
+ },
+ "/");
+ error(toString(input) + " has platform " + platformNames +
Twine(", which is
diff erent from target platform ") +
getPlatformName(config->platform()));
return false;
}
- if (platformInfo->minimum <= config->platformInfo.minimum)
+
+ if (it->minimum <= config->platformInfo.minimum)
return true;
- error(toString(input) + " has version " +
- platformInfo->minimum.getAsString() +
+
+ error(toString(input) + " has version " + it->minimum.getAsString() +
", which is newer than target minimum of " +
config->platformInfo.minimum.getAsString());
return false;
diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index d57e174f15c1..6e58601ae56a 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -187,20 +187,42 @@ extern llvm::SetVector<InputFile *> inputFiles;
llvm::Optional<MemoryBufferRef> readFile(StringRef path);
-// anyHdr should be a pointer to either mach_header or mach_header_64
-template <class CommandType = llvm::MachO::load_command, class... Types>
-const CommandType *findCommand(const void *anyHdr, Types... types) {
+namespace detail {
+
+template <class CommandType, class... Types>
+std::vector<const CommandType *>
+findCommands(const void *anyHdr, size_t maxCommands, Types... types) {
+ std::vector<const CommandType *> cmds;
std::initializer_list<uint32_t> typesList{types...};
const auto *hdr = reinterpret_cast<const llvm::MachO::mach_header *>(anyHdr);
const uint8_t *p =
reinterpret_cast<const uint8_t *>(hdr) + target->headerSize;
for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) {
auto *cmd = reinterpret_cast<const CommandType *>(p);
- if (llvm::is_contained(typesList, cmd->cmd))
- return cmd;
+ if (llvm::is_contained(typesList, cmd->cmd)) {
+ cmds.push_back(cmd);
+ if (cmds.size() == maxCommands)
+ return cmds;
+ }
p += cmd->cmdsize;
}
- return nullptr;
+ return cmds;
+}
+
+} // namespace detail
+
+// anyHdr should be a pointer to either mach_header or mach_header_64
+template <class CommandType = llvm::MachO::load_command, class... Types>
+const CommandType *findCommand(const void *anyHdr, Types... types) {
+ std::vector<const CommandType *> cmds =
+ detail::findCommands<CommandType>(anyHdr, 1, types...);
+ return cmds.size() ? cmds[0] : nullptr;
+}
+
+template <class CommandType = llvm::MachO::load_command, class... Types>
+std::vector<const CommandType *> findCommands(const void *anyHdr,
+ Types... types) {
+ return detail::findCommands<CommandType>(anyHdr, 0, types...);
}
} // namespace macho
diff --git a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd
index b333678cc8c3..716905997a91 100644
--- a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd
+++ b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd
@@ -1,64 +1,72 @@
--- !tapi-tbd
tbd-version: 4
-targets: [ x86_64-macos, arm64-macos ]
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
uuids:
- target: x86_64-macos
value: 00000000-0000-0000-0000-000000000000
+ - target: x86_64-maccatalyst
+ value: 00000000-0000-0000-0000-000000000000
- target: arm64-macos
value: 00000000-0000-0000-0000-000000000001
install-name: '/usr/lib/libSystem.dylib'
current-version: 0001.001.1
reexported-libraries:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
libraries: [ '/usr/lib/system/libdyld.dylib',
'/usr/lib/system/libsystem_c.dylib',
'/usr/lib/system/libsystem_m.dylib' ]
--- !tapi-tbd
tbd-version: 4
-targets: [ x86_64-macos, arm64-macos ]
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
uuids:
- target: x86_64-macos
value: 00000000-0000-0000-0000-000000000002
+ - target: x86_64-maccatalyst
+ value: 00000000-0000-0000-0000-000000000000
- target: arm64-macos
value: 00000000-0000-0000-0000-000000000003
install-name: '/usr/lib/system/libdyld.dylib'
current-version: 0001.001.1
parent-umbrella:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
umbrella: System
exports:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
symbols: [ dyld_stub_binder, __tlv_bootstrap ]
--- !tapi-tbd
tbd-version: 4
-targets: [ x86_64-macos, arm64-macos ]
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
uuids:
- target: x86_64-macos
value: 00000000-0000-0000-0000-000000000003
+ - target: x86_64-maccatalyst
+ value: 00000000-0000-0000-0000-000000000000
- target: arm64-macos
value: 00000000-0000-0000-0000-000000000004
install-name: '/usr/lib/system/libsystem_c.dylib'
current-version: 0001.001.1
parent-umbrella:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
umbrella: System
exports:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
symbols: [ ]
--- !tapi-tbd
tbd-version: 4
-targets: [ x86_64-macos, arm64-macos ]
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
uuids:
- target: x86_64-macos
value: 00000000-0000-0000-0000-000000000004
+ - target: x86_64-maccatalyst
+ value: 00000000-0000-0000-0000-000000000000
- target: arm64-macos
value: 00000000-0000-0000-0000-000000000005
install-name: '/usr/lib/system/libsystem_m.dylib'
current-version: 0001.001.1
parent-umbrella:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
umbrella: System
exports:
- - targets: [ x86_64-macos, arm64-macos ]
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos ]
symbols: [ ___nan ]
...
diff --git a/lld/test/MachO/zippered.yaml b/lld/test/MachO/zippered.yaml
new file mode 100644
index 000000000000..40fd1efba314
--- /dev/null
+++ b/lld/test/MachO/zippered.yaml
@@ -0,0 +1,64 @@
+# REQUIRES: x86
+# RUN: rm -rf %t; mkdir %t
+# RUN: yaml2obj %s > %t/test.dylib
+# RUN: echo "" | llvm-mc -filetype=obj -triple=x86_64-apple-macos10.15 -o %t/test_macos.o
+# RUN: echo "" | llvm-mc -filetype=obj -triple=x86_64-apple-ios13.15.0-macabi -o %t/test_maccatalyst.o
+# RUN: echo "" | llvm-mc -filetype=obj -triple=x86_64-apple-ios13.15.0 -o %t/test_ios.o
+
+# RUN: %lld -lSystem -dylib %t/test.dylib %t/test_macos.o -o /dev/null
+# RUN: %lld -lSystem -dylib -platform_version mac-catalyst 13.15.0 14.0 %t/test.dylib %t/test_maccatalyst.o -o /dev/null
+
+# RUN: not %lld -lSystem -dylib -platform_version ios 13.15.0 14.0 %t/test.dylib %t/test_ios.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: test.dylib has platform macOS/macCatalyst, which is
diff erent from target platform iOS
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 4
+ sizeofcmds: 600
+ flags: 0x100085
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_ID_DYLIB
+ cmdsize: 32
+ dylib:
+ name: 24
+ timestamp: 1
+ current_version: 0
+ compatibility_version: 0
+ PayloadString: test
+ ZeroPadBytes: 4
+ - 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: 0
+ export_size: 0
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 659200
+ sdk: 720896
+ ntools: 1
+ Tools:
+ - tool: 3
+ version: 39913472
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 6
+ minos: 855808
+ sdk: 917504
+ ntools: 1
+ Tools:
+ - tool: 3
+ version: 39913472
+...
More information about the llvm-commits
mailing list