diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -95,6 +95,7 @@ Symbol *entry = nullptr; bool hasReexports = false; bool allLoad = false; + bool applicationExtension = false; bool archMultiple = false; bool exportDynamic = false; bool forceLoadObjC = false; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1176,6 +1176,8 @@ config->runtimePaths = args::getStrings(args, OPT_rpath); config->allLoad = args.hasArg(OPT_all_load); config->archMultiple = args.hasArg(OPT_arch_multiple); + config->applicationExtension = args.hasFlag( + OPT_application_extension, OPT_no_application_extension, false); config->exportDynamic = args.hasArg(OPT_export_dynamic); config->forceLoadObjC = args.hasArg(OPT_ObjC); config->forceLoadSwift = args.hasArg(OPT_force_load_swift_libs); diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -177,6 +177,7 @@ bool handleLDSymbol(StringRef originalName); void handleLDPreviousSymbol(StringRef name, StringRef originalName); void handleLDInstallNameSymbol(StringRef name, StringRef originalName); + void checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const; }; // .a file diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -954,6 +954,8 @@ if (!checkCompatibility(this)) return; + checkAppExtensionSafety(hdr->flags & MH_APP_EXTENSION_SAFE); + for (auto *cmd : findCommands(hdr, LC_RPATH)) { StringRef rpath{reinterpret_cast(cmd) + cmd->path}; rpaths.push_back(rpath); @@ -1043,6 +1045,8 @@ return; } + checkAppExtensionSafety(interface.isApplicationExtensionSafe()); + exportingFile = isImplicitlyLinked(installName) ? this : umbrella; auto addSymbol = [&](const Twine &name) -> void { symbols.push_back(symtab->addDylib(saver.save(name), exportingFile, @@ -1171,6 +1175,11 @@ this->installName = saver.save(installName); } +void DylibFile::checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const { + if (config->applicationExtension && !dylibIsAppExtensionSafe) + warn("using '-application_extension' with unsafe dylib: " + toString(this)); +} + ArchiveFile::ArchiveFile(std::unique_ptr &&f) : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) { for (const object::Archive::Symbol &sym : file->symbols()) diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -689,12 +689,10 @@ Flags<[HelpHidden]>, Group; def application_extension : Flag<["-"], "application_extension">, - HelpText<"Designate the linker output as safe for use in an application extension">, - Flags<[HelpHidden]>, + HelpText<"Mark output as safe for use in an application extension, and validate that linked dylibs are safe">, Group; def no_application_extension : Flag<["-"], "no_application_extension">, - HelpText<"Designate the linker output as unsafe for use in an application extension">, - Flags<[HelpHidden]>, + HelpText<"Disable application extension functionality (default)">, Group; def fatal_warnings : Flag<["-"], "fatal_warnings">, HelpText<"Treat warnings as errors">, diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -113,6 +113,9 @@ if (config->outputType == MH_EXECUTE && config->isPic) hdr->flags |= MH_PIE; + if (config->outputType == MH_DYLIB && config->applicationExtension) + hdr->flags |= MH_APP_EXTENSION_SAFE; + if (in.exports->hasWeakSymbol || in.weakBinding->hasNonWeakDefinition()) hdr->flags |= MH_WEAK_DEFINES; diff --git a/lld/test/MachO/application-extension.s b/lld/test/MachO/application-extension.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/application-extension.s @@ -0,0 +1,115 @@ +# REQUIRES: aarch64 + +## --no-leading-lines is needed for .tbd files. +# RUN: rm -rf %t; split-file --no-leading-lines %s %t + +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o %t/foo.o %t/foo.s +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o %t/bar.o %t/bar.s + +## MH_APP_EXTENSION_SAFE is only set on dylibs, and only if requested. +# RUN: %lld -arch arm64 -dylib -o %t/foo.dylib %t/foo.o +# RUN: llvm-otool -hv %t/foo.dylib | FileCheck --check-prefix=NOAPPEXT %s +# RUN: %lld -arch arm64 -dylib -o %t/foo-appext.dylib %t/foo.o \ +# RUN: -application_extension +# RUN: llvm-otool -hv %t/foo-appext.dylib | FileCheck --check-prefix=APPEXT %s +# RUN: %lld -arch arm64 -dylib -o %t/foo-noappext.dylib %t/foo.o \ +# RUN: -application_extension -no_application_extension +# RUN: llvm-otool -hv %t/foo-noappext.dylib \ +# RUN: | FileCheck --check-prefix=NOAPPEXT %s +# RUN: %lld -arch arm64 -bundle -o %t/foo.so %t/foo.o \ +# RUN: -application_extension +# RUN: llvm-otool -hv %t/foo.so | FileCheck --check-prefix=NOAPPEXT %s + +# APPEXT: APP_EXTENSION_SAFE +# NOAPPEXT-NOT: APP_EXTENSION_SAFE + +## The warning is emitted for all target types. +# RUN: %lld -arch arm64 -dylib -o %t/bar.dylib %t/bar.o \ +# RUN: -application_extension %t/foo-appext.dylib +# RUN: %lld -arch arm64 -dylib -o %t/bar.dylib %t/bar.o \ +# RUN: -application_extension -L %t -ltbd-appext +# RUN: not %lld -arch arm64 -dylib -o %t/bar.dylib %t/bar.o \ +# RUN: -application_extension %t/foo-noappext.dylib \ +# RUN: 2>&1 | FileCheck --check-prefix=WARN %s +# RUN: not %lld -arch arm64 -dylib -o %t/bar.dylib %t/bar.o \ +# RUN: -application_extension -L %t -ltbd-noappext \ +# RUN: 2>&1 | FileCheck --check-prefix=WARN %s +# RUN: not %lld -arch arm64 -bundle -o %t/bar.so %t/bar.o \ +# RUN: -application_extension %t/foo-noappext.dylib \ +# RUN: 2>&1 | FileCheck --check-prefix=WARN %s +# RUN: not %lld -arch arm64 -bundle -o %t/bar.so %t/bar.o \ +# RUN: -application_extension -L %t -ltbd-noappext \ +# RUN: 2>&1 | FileCheck --check-prefix=WARN %s + +# WARN: using '-application_extension' with unsafe dylib: + +## Test we warn on dylibs loaded indirectly via reexports. +# RUN: not %lld -arch arm64 -dylib -o %t/bar.dylib %t/bar.o \ +# RUN: -application_extension -L %t -lbaz-noappext-reexport \ +# RUN: -u _baz 2>&1 | FileCheck --check-prefix=WARN %s + +#--- foo.s +.globl _foo +.p2align 2 +_foo: + ret + +#--- libtbd-appext.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-macos ] +uuids: + - target: arm64-macos + value: 2E994C7F-3F03-3A07-879C-55690D22BEDA +install-name: '/usr/lib/libtbd-appext.dylib' +exports: + - targets: [ arm64-macos ] + symbols: [ _foo ] +... + +#--- libtbd-noappext.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-macos ] +flags: [ not_app_extension_safe ] +uuids: + - target: arm64-macos + value: 2E994C7F-3F03-3A07-879C-55690D22BEDA +install-name: '/usr/lib/libtbd-noappext.dylib' +exports: + - targets: [ arm64-macos ] + symbols: [ _foo ] +... + +#--- bar.s +.globl _bar +.p2align 2 +_bar: + ret + +#--- libbaz-noappext-reexport.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-macos ] +uuids: + - target: arm64-macos + value: 00000000-0000-0000-0000-000000000001 +install-name: '/usr/lib/libbaz.dylib' +reexported-libraries: + - targets: [ arm64-macos ] + libraries: [ '/usr/lib/libbaz-noappext-reexport.dylib'] +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-macos ] +flags: [ not_app_extension_safe ] +uuids: + - target: arm64-macos + value: 00000000-0000-0000-0000-000000000003 +install-name: '/usr/lib/libbaz-noappext-reexport.dylib' +parent-umbrella: + - targets: [ arm64-macos ] + umbrella: baz +exports: + - targets: [ arm64-macos ] + symbols: [ _baz ] +...