From f21801dab249df506af4c62c70af34a11fa3d3e1 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 12 Jul 2021 10:26:54 -0400 Subject: [PATCH] [lld/mac] Implement -application_extension Differential Revision: https://reviews.llvm.org/D105818 --- lld/MachO/Config.h | 1 + lld/MachO/Driver.cpp | 2 + lld/MachO/InputFiles.cpp | 9 +++ lld/MachO/InputFiles.h | 1 + lld/MachO/Options.td | 6 +- lld/MachO/SyntheticSections.cpp | 3 + lld/test/MachO/application-extension.s | 115 +++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 lld/test/MachO/application-extension.s diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index 654fd79..51ead8b 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -95,6 +95,7 @@ struct Configuration { 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 index 9834008..e146991 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1176,6 +1176,8 @@ bool macho::link(ArrayRef argsArr, bool canExitEarly, 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.cpp b/lld/MachO/InputFiles.cpp index 89f768a..8f5df25 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -954,6 +954,8 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella, 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 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella, 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 @@ void DylibFile::handleLDInstallNameSymbol(StringRef name, 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/InputFiles.h b/lld/MachO/InputFiles.h index df8e006..3bf9e77 100644 --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -177,6 +177,7 @@ private: 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/Options.td b/lld/MachO/Options.td index b351645..9b233f4 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -689,12 +689,10 @@ def allow_heap_execute : Flag<["-"], "allow_heap_execute">, 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 index 12c6255..403da56 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -113,6 +113,9 @@ void MachHeaderSection::writeTo(uint8_t *buf) const { 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 index 0000000..eb4c6196 --- /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 ] +... -- 2.7.4