aboutsummaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorJez Ng <jezng@fb.com>2020-08-31 23:23:37 -0700
committerJez Ng <jezng@fb.com>2020-09-25 11:28:32 -0700
commitf23f5126912b7da3f2a118a7cb1bcf6be3d8c1bc (patch)
treedd9b4337d31674063c93fa65b7c9018ca7d1930b /lld
parente4e673e75a067236c9c4ff2e1ab19d6a3a87003d (diff)
downloadllvm-f23f5126912b7da3f2a118a7cb1bcf6be3d8c1bc.zip
llvm-f23f5126912b7da3f2a118a7cb1bcf6be3d8c1bc.tar.gz
llvm-f23f5126912b7da3f2a118a7cb1bcf6be3d8c1bc.tar.bz2
[lld-macho] Support -bundle
Not 100% sure but it appears that bundles are almost identical to dylibs, aside from the fact that they do not contain `LC_ID_DYLIB`. ld64's code seems to treat bundles and dylibs identically in most places. Supporting bundles allows us to run e.g. XCTests, as all test suites are compiled into bundles which get dynamically loaded by the `xctest` test runner. Reviewed By: #lld-macho, smeenai Differential Revision: https://reviews.llvm.org/D87856
Diffstat (limited to 'lld')
-rw-r--r--lld/MachO/Driver.cpp21
-rw-r--r--lld/MachO/Writer.cpp3
-rw-r--r--lld/test/MachO/load-commands.s51
3 files changed, 63 insertions, 12 deletions
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 38dc561..4991966 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -88,6 +88,24 @@ void MachOOptTable::printHelp(const char *argv0, bool showHidden) const {
lld::outs() << "\n";
}
+HeaderFileType getOutputType(const opt::InputArgList &args) {
+ // TODO: -r, -dylinker, -preload...
+ opt::Arg *outputArg = args.getLastArg(OPT_bundle, OPT_dylib, OPT_execute);
+ if (outputArg == nullptr)
+ return MH_EXECUTE;
+
+ switch (outputArg->getOption().getID()) {
+ case OPT_bundle:
+ return MH_BUNDLE;
+ case OPT_dylib:
+ return MH_DYLIB;
+ case OPT_execute:
+ return MH_EXECUTE;
+ default:
+ llvm_unreachable("internal error");
+ }
+}
+
static Optional<std::string>
findAlongPathsWithExtensions(StringRef name, ArrayRef<StringRef> extensions) {
llvm::SmallString<261> base;
@@ -575,7 +593,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
config->headerPadMaxInstallNames =
args.hasArg(OPT_headerpad_max_install_names);
- config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
+ config->outputType = getOutputType(args);
config->runtimePaths = args::getStrings(args, OPT_rpath);
config->allLoad = args.hasArg(OPT_all_load);
config->forceLoadObjC = args.hasArg(OPT_ObjC);
@@ -661,6 +679,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
}
config->isPic = config->outputType == MH_DYLIB ||
+ config->outputType == MH_BUNDLE ||
(config->outputType == MH_EXECUTE && args.hasArg(OPT_pie));
// Now that all dylibs have been loaded, search for those that should be
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 055e2f2..4572c52 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -377,6 +377,8 @@ void Writer::createLoadCommands() {
case MH_DYLIB:
in.header->addLoadCommand(make<LCDylib>(LC_ID_DYLIB, config->installName));
break;
+ case MH_BUNDLE:
+ break;
default:
llvm_unreachable("unhandled output file type");
}
@@ -532,6 +534,7 @@ void Writer::createOutputSections() {
make<PageZeroSection>();
break;
case MH_DYLIB:
+ case MH_BUNDLE:
break;
default:
llvm_unreachable("unhandled output file type");
diff --git a/lld/test/MachO/load-commands.s b/lld/test/MachO/load-commands.s
index c9f5d9b..3e9c07c 100644
--- a/lld/test/MachO/load-commands.s
+++ b/lld/test/MachO/load-commands.s
@@ -1,19 +1,48 @@
# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
-# RUN: lld -flavor darwinnew -o %t %t.o
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o
+# RUN: lld -flavor darwinnew -o %t/executable %t/test.o
+# RUN: lld -flavor darwinnew -bundle -o %t/bundle %t/test.o
+# RUN: lld -flavor darwinnew -dylib -o %t/dylib %t/test.o
+
+## These load commands should be in every final output binary.
+# COMMON-DAG: cmd LC_DYLD_INFO_ONLY
+# COMMON-DAG: cmd LC_SYMTAB
+# COMMON-DAG: cmd LC_DYSYMTAB
## Check for the presence of load commands that are essential for a working
-## executable.
-# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s
-# CHECK-DAG: cmd LC_DYLD_INFO_ONLY
-# CHECK-DAG: cmd LC_SYMTAB
-# CHECK-DAG: cmd LC_DYSYMTAB
-# CHECK-DAG: cmd LC_MAIN
-# CHECK-DAG: cmd LC_LOAD_DYLINKER
+## executable. Also check that it has the right filetype.
+# RUN: llvm-objdump --macho --all-headers %t/executable | FileCheck %s --check-prefix=COMMON
+# RUN: llvm-objdump --macho --all-headers %t/executable | FileCheck %s --check-prefix=EXEC
+# EXEC: magic cputype cpusubtype caps filetype
+# EXEC-NEXT: MH_MAGIC_64 X86_64 ALL {{.*}} EXECUTE
+# EXEC-DAG: cmd LC_MAIN
+# EXEC-DAG: cmd LC_LOAD_DYLINKER
## Check for the absence of load commands that should not be in an executable.
-# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s --check-prefix=NCHECK
-# NCHECK-NOT: cmd: LC_ID_DYLIB
+# RUN: llvm-objdump --macho --all-headers %t/executable | FileCheck %s --check-prefix=NEXEC
+# NEXEC-NOT: cmd: LC_ID_DYLIB
+
+## Check for the presence / absence of load commands for the dylib.
+# RUN: llvm-objdump --macho --all-headers %t/dylib | FileCheck %s --check-prefix=COMMON
+# RUN: llvm-objdump --macho --all-headers %t/dylib | FileCheck %s --check-prefix=DYLIB
+# DYLIB: magic cputype cpusubtype caps filetype
+# DYLIB-NEXT: MH_MAGIC_64 X86_64 ALL {{.*}} DYLIB
+# DYLIB: cmd LC_ID_DYLIB
+
+# RUN: llvm-objdump --macho --all-headers %t/bundle | FileCheck %s --check-prefix=NDYLIB
+# NDYLIB-NOT: cmd: LC_MAIN
+# NDYLIB-NOT: cmd: LC_LOAD_DYLINKER
+
+## Check for the presence / absence of load commands for the bundle.
+# RUN: llvm-objdump --macho --all-headers %t/bundle | FileCheck %s --check-prefix=COMMON
+# RUN: llvm-objdump --macho --all-headers %t/bundle | FileCheck %s --check-prefix=BUNDLE
+# BUNDLE: magic cputype cpusubtype caps filetype
+# BUNDLE-NEXT: MH_MAGIC_64 X86_64 ALL {{.*}} BUNDLE
+
+# RUN: llvm-objdump --macho --all-headers %t/bundle | FileCheck %s --check-prefix=NBUNDLE
+# NBUNDLE-NOT: cmd: LC_MAIN
+# NBUNDLE-NOT: cmd: LC_LOAD_DYLINKER
.text
.global _main