diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -315,11 +315,20 @@ newFile = *dylibFile; break; } + case file_magic::macho_executable: + case file_magic::macho_bundle: + if (Optional dylibFile = loadDylib(mbref)) + newFile = *dylibFile; + else + error(Twine("Unable to parse bundle_loader target ") + path); + + break; case file_magic::bitcode: newFile = make(mbref); break; + default: - error(path + ": unhandled file type"); + error(path + ": unhandled file type: " + Twine(magic)); } if (newFile) { // printArchiveMemberLoad() prints both .a and .o names, so no need to @@ -781,8 +790,15 @@ const auto &opt = arg->getOption(); warnIfDeprecatedOption(opt); warnIfUnimplementedOption(opt); + // TODO: are any of these better handled via filtered() or getLastArg()? switch (opt.getID()) { + case OPT_bundle_loader: + if (fs::exists(arg->getValue())) + addFile(arg->getValue(), false); + else + warn(Twine("bundle_loader not found: ") + arg->getValue()); + break; case OPT_INPUT: addFile(arg->getValue(), false); break; diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -190,7 +190,9 @@ file = make(**result, umbrella); } else { assert(magic == file_magic::macho_dynamically_linked_shared_lib || - magic == file_magic::macho_dynamically_linked_shared_lib_stub); + magic == file_magic::macho_dynamically_linked_shared_lib_stub || + magic == file_magic::macho_executable || + magic == file_magic::macho_bundle); file = make(mbref, umbrella); } return file; diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -125,10 +125,12 @@ // the root dylib to ensure symbols in the child library are correctly bound // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. - explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr); + explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr, + bool isBundleLoader = false); explicit DylibFile(const llvm::MachO::InterfaceFile &interface, - DylibFile *umbrella = nullptr); + DylibFile *umbrella = nullptr, + bool isBundleLoader = false); static bool classof(const InputFile *f) { return f->kind() == DylibKind; } @@ -139,6 +141,7 @@ RefState refState; bool reexport = false; bool forceWeakImport = false; + bool isBundleLoader; }; // .a file diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -559,8 +559,10 @@ inputFiles.insert(*reexport); } -DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella) - : InputFile(DylibKind, mb), refState(RefState::Unreferenced) { +DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella, + bool isBundleLoader) + : InputFile(DylibKind, mb), refState(RefState::Unreferenced), + isBundleLoader(isBundleLoader) { if (umbrella == nullptr) umbrella = this; @@ -573,13 +575,15 @@ currentVersion = read32le(&c->dylib.current_version); compatibilityVersion = read32le(&c->dylib.compatibility_version); dylibName = reinterpret_cast(cmd) + read32le(&c->dylib.name); - } else { + } else if (!isBundleLoader) { + // macho_executable and macho_bundle don't have LC_ID_DYLIB error("dylib " + toString(this) + " missing LC_ID_DYLIB load command"); return; } // Initialize symbols. - DylibFile *exportingFile = isImplicitlyLinked(dylibName) ? this : umbrella; + DylibFile *exportingFile = + (isBundleLoader || isImplicitlyLinked(dylibName)) ? this : umbrella; if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) { auto *c = reinterpret_cast(cmd); parseTrie(buf + c->export_off, c->export_size, @@ -612,8 +616,10 @@ } } -DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella) - : InputFile(DylibKind, interface), refState(RefState::Unreferenced) { +DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella, + bool isBundleLoader) + : InputFile(DylibKind, interface), refState(RefState::Unreferenced), + isBundleLoader(isBundleLoader) { if (umbrella == nullptr) umbrella = this; diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -396,7 +396,6 @@ def bundle_loader : Separate<["-"], "bundle_loader">, MetaVarName<"">, HelpText<"Resolve undefined symbols from ">, - Flags<[HelpHidden]>, Group; def grp_object : OptionGroup<"object">, HelpText<"CREATING AN OBJECT FILE">; diff --git a/lld/test/MachO/bundle_loader-darwin.test b/lld/test/MachO/bundle_loader-darwin.test new file mode 100644 --- /dev/null +++ b/lld/test/MachO/bundle_loader-darwin.test @@ -0,0 +1,24 @@ +REQUIRES: x86 +REQUIRES: darwin + +RUN: mkdir -p %t1 + +RUN: echo 'int my_func() { return 2020; }' > %t1/my_lib.c + +RUN: echo '#include ' > %t1/bundle.c +RUN: echo 'extern int my_func();' >> %t1/bundle.c +RUN: echo 'int user() {return my_func();}' >> %t1/bundle.c + +RUN: echo 'int main() {return 0;}' > %t1/main.c + +RUN: clang -fuse-ld=lld.darwinnew --target=x86_64-apple-macosx10.12 my_lib.c -dynamiclib -o mylib.dylib +RUN: clang -fuse-ld=lld.darwinnew --target=x86_64-apple-macosx10.12 main.c my_lib.c -o main +RUN: clang -fuse-ld=lld.darwinnew --target=x86_64-apple-macosx10.12 bundle.c -bundle -bundle_loader main mylib.dylib -o bundle.bunddle + +#TODO: expected soemthing like this: +# 0000000000002000 (__DATA,__data) non-external __dyld_private +# (undefined) external _main (from ) +# (undefined) external _my_func (from ) +#0000000000000530 (__TEXT,__text) external _user +# (undefined) external dyld_stub_binder (from libSystem) +