[lld/mac] Implement -application_extension
authorNico Weber <thakis@chromium.org>
Mon, 12 Jul 2021 14:26:54 +0000 (10:26 -0400)
committerNico Weber <thakis@chromium.org>
Mon, 12 Jul 2021 17:42:16 +0000 (13:42 -0400)
Differential Revision: https://reviews.llvm.org/D105818

lld/MachO/Config.h
lld/MachO/Driver.cpp
lld/MachO/InputFiles.cpp
lld/MachO/InputFiles.h
lld/MachO/Options.td
lld/MachO/SyntheticSections.cpp
lld/test/MachO/application-extension.s [new file with mode: 0644]

index 654fd79..51ead8b 100644 (file)
@@ -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;
index 9834008..e146991 100644 (file)
@@ -1176,6 +1176,8 @@ bool macho::link(ArrayRef<const char *> 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);
index 89f768a..8f5df25 100644 (file)
@@ -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<rpath_command>(hdr, LC_RPATH)) {
     StringRef rpath{reinterpret_cast<const char *>(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<object::Archive> &&f)
     : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) {
   for (const object::Archive::Symbol &sym : file->symbols())
index df8e006..3bf9e77 100644 (file)
@@ -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
index b351645..9b233f4 100644 (file)
@@ -689,12 +689,10 @@ def allow_heap_execute : Flag<["-"], "allow_heap_execute">,
     Flags<[HelpHidden]>,
     Group<grp_rare>;
 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<grp_rare>;
 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<grp_rare>;
 def fatal_warnings : Flag<["-"], "fatal_warnings">,
     HelpText<"Treat warnings as errors">,
index 12c6255..403da56 100644 (file)
@@ -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 (file)
index 0000000..eb4c619
--- /dev/null
@@ -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 ]
+...