[lld-macho] Support -weak_lx, -weak_library, -weak_framework
authorJez Ng <jezng@fb.com>
Fri, 18 Sep 2020 18:38:15 +0000 (11:38 -0700)
committerJez Ng <jezng@fb.com>
Thu, 24 Sep 2020 02:26:41 +0000 (19:26 -0700)
They cause their corresponding libraries / frameworks to be loaded via
`LC_LOAD_WEAK_DYLIB` instead of `LC_LOAD_DYLIB`.

Reviewed By: #lld-macho, gkm

Differential Revision: https://reviews.llvm.org/D87929

lld/MachO/Driver.cpp
lld/MachO/InputFiles.h
lld/MachO/Options.td
lld/MachO/Writer.cpp
lld/test/MachO/weak-import.s [new file with mode: 0644]

index cc0211a..0f1551a 100644 (file)
@@ -237,11 +237,12 @@ static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
   return v;
 }
 
-static void addFile(StringRef path) {
+static InputFile *addFile(StringRef path) {
   Optional<MemoryBufferRef> buffer = readFile(path);
   if (!buffer)
-    return;
+    return nullptr;
   MemoryBufferRef mbref = *buffer;
+  InputFile *newFile = nullptr;
 
   switch (identify_magic(mbref.getBuffer())) {
   case file_magic::archive: {
@@ -270,25 +271,27 @@ static void addFile(StringRef path) {
             inputFiles.push_back(make<ObjFile>(member));
     }
 
-    inputFiles.push_back(make<ArchiveFile>(std::move(file)));
+    newFile = make<ArchiveFile>(std::move(file));
     break;
   }
   case file_magic::macho_object:
-    inputFiles.push_back(make<ObjFile>(mbref));
+    newFile = make<ObjFile>(mbref);
     break;
   case file_magic::macho_dynamically_linked_shared_lib:
-    inputFiles.push_back(make<DylibFile>(mbref));
+    newFile = make<DylibFile>(mbref);
     break;
   case file_magic::tapi_file: {
     Optional<DylibFile *> dylibFile = makeDylibFromTAPI(mbref);
     if (!dylibFile)
-      return;
-    inputFiles.push_back(*dylibFile);
+      return nullptr;
+    newFile = *dylibFile;
     break;
   }
   default:
     error(path + ": unhandled file type");
   }
+  inputFiles.push_back(newFile);
+  return newFile;
 }
 
 static void addFileList(StringRef path) {
@@ -596,29 +599,41 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
     warnIfDeprecatedOption(opt);
     warnIfUnimplementedOption(opt);
     // TODO: are any of these better handled via filtered() or getLastArg()?
-    switch (arg->getOption().getID()) {
+    switch (opt.getID()) {
     case OPT_INPUT:
       addFile(arg->getValue());
       break;
+    case OPT_weak_library: {
+      auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(arg->getValue()));
+      if (dylibFile != nullptr)
+        dylibFile->forceWeakImport = true;
+      break;
+    }
     case OPT_filelist:
       addFileList(arg->getValue());
       break;
     case OPT_force_load:
       forceLoadArchive(arg->getValue());
       break;
-    case OPT_l: {
+    case OPT_l:
+    case OPT_weak_l: {
       StringRef name = arg->getValue();
       if (Optional<std::string> path = findLibrary(name)) {
-        addFile(*path);
+        auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path));
+        if (opt.getID() == OPT_weak_l && dylibFile != nullptr)
+          dylibFile->forceWeakImport = true;
         break;
       }
       error("library not found for -l" + name);
       break;
     }
-    case OPT_framework: {
+    case OPT_framework:
+    case OPT_weak_framework: {
       StringRef name = arg->getValue();
       if (Optional<std::string> path = findFramework(name)) {
-        addFile(*path);
+        auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path));
+        if (opt.getID() == OPT_weak_framework && dylibFile != nullptr)
+          dylibFile->forceWeakImport = true;
         break;
       }
       error("framework not found for -framework " + name);
index 194de0e..bb83c20 100644 (file)
@@ -107,6 +107,7 @@ public:
   StringRef dylibName;
   uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
   bool reexport = false;
+  bool forceWeakImport = false;
   std::vector<DylibFile *> reexported;
 };
 
index 2a05ddf..ddcf8aa 100644 (file)
@@ -64,12 +64,10 @@ def l : Joined<["-"], "l">,
 def weak_l : Joined<["-"], "weak-l">,
      MetaVarName<"<name>">,
      HelpText<"Like -l<name>, but mark library and its references as weak imports">,
-     Flags<[HelpHidden]>,
      Group<grp_libs>;
 def weak_library : Separate<["-"], "weak_library">,
      MetaVarName<"<path>">,
      HelpText<"Like bare <path>, but mark library and its references as weak imports">,
-     Flags<[HelpHidden]>,
      Group<grp_libs>;
 def reexport_l : Joined<["-"], "reexport-l">,
      MetaVarName<"<name>">,
@@ -115,7 +113,6 @@ def framework : Separate<["-"], "framework">,
 def weak_framework : Separate<["-"], "weak_framework">,
      MetaVarName<"<name>">,
      HelpText<"Like -framework <name>, but mark framework and its references as weak imports">,
-     Flags<[HelpHidden]>,
      Group<grp_libs>;
 def reexport_framework : Separate<["-"], "reexport_framework">,
      MetaVarName<"<name>">,
index 1f1c34c..aabe6a9 100644 (file)
@@ -376,8 +376,11 @@ void Writer::createLoadCommands() {
   uint64_t dylibOrdinal = 1;
   for (InputFile *file : inputFiles) {
     if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
-      in.header->addLoadCommand(
-          make<LCDylib>(LC_LOAD_DYLIB, dylibFile->dylibName));
+      // TODO: dylibs that are only referenced by weak refs should also be
+      // loaded via LC_LOAD_WEAK_DYLIB.
+      LoadCommandType lcType =
+          dylibFile->forceWeakImport ? LC_LOAD_WEAK_DYLIB : LC_LOAD_DYLIB;
+      in.header->addLoadCommand(make<LCDylib>(lcType, dylibFile->dylibName));
       dylibFile->ordinal = dylibOrdinal++;
 
       if (dylibFile->reexport)
diff --git a/lld/test/MachO/weak-import.s b/lld/test/MachO/weak-import.s
new file mode 100644 (file)
index 0000000..a203375
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib %t/foo.o -o %t/libfoo.dylib
+
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -weak-lSystem %t/test.o -weak_framework CoreFoundation -weak_library %t/libfoo.dylib -o %t/test
+# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t
+
+# CHECK:          cmd LC_LOAD_WEAK_DYLIB
+# CHECK-NEXT: cmdsize
+# CHECK-NEXT:    name /usr/lib/libSystem.B.dylib
+
+# CHECK:          cmd LC_LOAD_WEAK_DYLIB
+# CHECK-NEXT: cmdsize
+# CHECK-NEXT:    name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
+
+# CHECK:          cmd LC_LOAD_WEAK_DYLIB
+# CHECK-NEXT: cmdsize
+# CHECK-NEXT:    name [[DIR]]/libfoo.dylib
+
+#--- foo.s
+.globl _foo
+_foo:
+  ret
+
+#--- test.s
+.globl _main
+.text
+_main:
+  ret