[lld] f843bb8 - [lld-macho] Force-loading should share code path with regular archive loads

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 3 10:43:59 PST 2021


Author: Jez Ng
Date: 2021-02-03T13:43:47-05:00
New Revision: f843bb82c042f9e669135957bb5bd1c233c5c316

URL: https://github.com/llvm/llvm-project/commit/f843bb82c042f9e669135957bb5bd1c233c5c316
DIFF: https://github.com/llvm/llvm-project/commit/f843bb82c042f9e669135957bb5bd1c233c5c316.diff

LOG: [lld-macho] Force-loading should share code path with regular archive loads

This extends {D92539} to work even when we are loading archive
members via `-force_load`. I uncovered this issue while trying to
force-load archives containing bitcode -- we were segfaulting.

In addition to fixing the `-force_load` case, this diff also addresses
the behavior of `-ObjC` when LTO bitcode is involved -- we need to
force-load those archive members if they contain ObjC categories.

Reviewed By: #lld-macho, smeenai

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

Added: 
    

Modified: 
    lld/MachO/CMakeLists.txt
    lld/MachO/Driver.cpp
    lld/MachO/Driver.h
    lld/MachO/DriverUtils.cpp
    lld/MachO/InputFiles.cpp
    lld/test/MachO/invalid/bad-archive-member.s
    lld/test/MachO/invalid/bad-archive.s
    lld/test/MachO/lto-archive.ll

Removed: 
    


################################################################################
diff  --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt
index b76f37dcc6e6..2c2effd954d9 100644
--- a/lld/MachO/CMakeLists.txt
+++ b/lld/MachO/CMakeLists.txt
@@ -27,6 +27,7 @@ add_lld_library(lldMachO2
   LINK_COMPONENTS
   ${LLVM_TARGETS_TO_BUILD}
   BinaryFormat
+  BitReader
   Core
   DebugInfoDWARF
   LTO

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 6d4dbf1e9761..53036ce6296a 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -276,10 +276,13 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive) {
     if (config->allLoad || forceLoadArchive) {
       if (Optional<MemoryBufferRef> buffer = readFile(path)) {
         for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
-          inputFiles.insert(make<ObjFile>(member.mbref, member.modTime, path));
-          printArchiveMemberLoad(
-              (forceLoadArchive ? "-force_load" : "-all_load"),
-              inputFiles.back());
+          if (Optional<InputFile *> file = loadArchiveMember(
+                  member.mbref, member.modTime, path, /*objCOnly=*/false)) {
+            inputFiles.insert(*file);
+            printArchiveMemberLoad(
+                (forceLoadArchive ? "-force_load" : "-all_load"),
+                inputFiles.back());
+          }
         }
       }
     } else if (config->forceLoadObjC) {
@@ -294,9 +297,9 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive) {
       // these files here and below (as part of the ArchiveFile).
       if (Optional<MemoryBufferRef> buffer = readFile(path)) {
         for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
-          if (hasObjCSection(member.mbref)) {
-            inputFiles.insert(
-                make<ObjFile>(member.mbref, member.modTime, path));
+          if (Optional<InputFile *> file = loadArchiveMember(
+                  member.mbref, member.modTime, path, /*objCOnly=*/true)) {
+            inputFiles.insert(*file);
             printArchiveMemberLoad("-ObjC", inputFiles.back());
           }
         }

diff  --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
index 97b897f0271b..08491f51261a 100644
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -46,6 +46,10 @@ llvm::Optional<std::string> resolveDylibPath(llvm::StringRef path);
 llvm::Optional<DylibFile *> loadDylib(llvm::MemoryBufferRef mbref,
                                       DylibFile *umbrella = nullptr);
 
+llvm::Optional<InputFile *> loadArchiveMember(MemoryBufferRef, uint32_t modTime,
+                                              StringRef archiveName,
+                                              bool objCOnly);
+
 uint32_t getModTime(llvm::StringRef path);
 
 void printArchiveMemberLoad(StringRef reason, const InputFile *);

diff  --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 563ae266735d..836b86346ab8 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -6,9 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Driver.h"
 #include "Config.h"
+#include "Driver.h"
 #include "InputFiles.h"
+#include "ObjC.h"
 
 #include "lld/Common/Args.h"
 #include "lld/Common/ErrorHandler.h"
@@ -16,6 +17,8 @@
 #include "lld/Common/Reproduce.h"
 #include "llvm/ADT/CachedHashString.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/LTO/LTO.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
@@ -196,6 +199,26 @@ Optional<DylibFile *> macho::loadDylib(MemoryBufferRef mbref,
   return file;
 }
 
+Optional<InputFile *> macho::loadArchiveMember(MemoryBufferRef mb,
+                                               uint32_t modTime,
+                                               StringRef archiveName,
+                                               bool objCOnly) {
+  switch (identify_magic(mb.getBuffer())) {
+  case file_magic::macho_object:
+    if (!objCOnly || hasObjCSection(mb))
+      return make<ObjFile>(mb, modTime, archiveName);
+    return None;
+  case file_magic::bitcode:
+    if (!objCOnly || check(isBitcodeContainingObjCCategory(mb)))
+      return make<BitcodeFile>(mb);
+    return None;
+  default:
+    error(archiveName + ": archive member " + mb.getBufferIdentifier() +
+          " has unhandled file type");
+    return None;
+  }
+}
+
 uint32_t macho::getModTime(StringRef path) {
   fs::file_status stat;
   if (!fs::status(path, stat))

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 3fc3f436eb3e..07255a7ddfea 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -746,26 +746,13 @@ void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
   // to it later.
   const object::Archive::Symbol sym_copy = sym;
 
-  InputFile *file;
-  switch (identify_magic(mb.getBuffer())) {
-  case file_magic::macho_object:
-    file = make<ObjFile>(mb, modTime, getName());
-    break;
-  case file_magic::bitcode:
-    file = make<BitcodeFile>(mb);
-    break;
-  default:
-    StringRef bufname =
-        CHECK(c.getName(), toString(this) + ": could not get buffer name");
-    error(toString(this) + ": archive member " + bufname +
-          " has unhandled file type");
-    return;
+  if (Optional<InputFile *> file =
+          loadArchiveMember(mb, modTime, getName(), /*objCOnly=*/false)) {
+    inputFiles.insert(*file);
+    // ld64 doesn't demangle sym here even with -demangle. Match that, so
+    // intentionally no call to toMachOString() here.
+    printArchiveMemberLoad(sym_copy.getName(), *file);
   }
-  inputFiles.insert(file);
-
-  // ld64 doesn't demangle sym here even with -demangle. Match that, so
-  // intentionally no call to toMachOString() here.
-  printArchiveMemberLoad(sym_copy.getName(), file);
 }
 
 BitcodeFile::BitcodeFile(MemoryBufferRef mbref)

diff  --git a/lld/test/MachO/invalid/bad-archive-member.s b/lld/test/MachO/invalid/bad-archive-member.s
index a76cecf239b7..d8bb4092153c 100644
--- a/lld/test/MachO/invalid/bad-archive-member.s
+++ b/lld/test/MachO/invalid/bad-archive-member.s
@@ -5,6 +5,8 @@
 # RUN: %lld -dylib -lSystem %t/foo.o -o %t/foo.dylib
 # RUN: llvm-ar rcs %t/foo.a %t/foo.dylib
 # RUN: not %lld %t/test.o %t/foo.a -o /dev/null 2>&1 | FileCheck %s -DFILE=%t/foo.a
+# RUN: not %lld %t/test.o -force_load %t/foo.a -o /dev/null 2>&1 | FileCheck %s -DFILE=%t/foo.a
+# RUN: not %lld %t/test.o -ObjC %t/foo.a -o /dev/null 2>&1 | FileCheck %s -DFILE=%t/foo.a
 # CHECK: error: [[FILE]]: archive member foo.dylib has unhandled file type
 
 #--- foo.s

diff  --git a/lld/test/MachO/invalid/bad-archive.s b/lld/test/MachO/invalid/bad-archive.s
index b00ff61bc4af..24f7a5d6f835 100644
--- a/lld/test/MachO/invalid/bad-archive.s
+++ b/lld/test/MachO/invalid/bad-archive.s
@@ -5,6 +5,7 @@
 
 # RUN: not %lld %t.o %t.a -o /dev/null 2>&1 | FileCheck -DFILE=%t.a %s
 # RUN: not %lld %t.o -force_load %t.a -o /dev/null 2>&1 | FileCheck -DFILE=%t.a %s
+# RUN: not %lld %t.o -ObjC %t.a -o /dev/null 2>&1 | FileCheck -DFILE=%t.a %s
 # CHECK: error: [[FILE]]: failed to parse archive: truncated or malformed archive (remaining size of archive too small for next archive member header at offset 8)
 
 .global _main

diff  --git a/lld/test/MachO/lto-archive.ll b/lld/test/MachO/lto-archive.ll
index 2aa7beb0c951..3c9c6403d0a0 100644
--- a/lld/test/MachO/lto-archive.ll
+++ b/lld/test/MachO/lto-archive.ll
@@ -1,14 +1,37 @@
 ; REQUIRES: x86
 ; RUN: rm -rf %t; split-file %s %t
 ; RUN: llvm-as %t/foo.ll -o %t/foo.o
-; RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+; RUN: llvm-as %t/objc.ll -o %t/objc.o
 ; RUN: llvm-ar rcs %t/foo.a %t/foo.o
-; RUN: %lld -save-temps -lSystem %t/test.o %t/foo.a -o %t/test
-; RUN: llvm-objdump -d --macho --no-show-raw-insn %t/test | FileCheck %s
+; RUN: llvm-ar rcs %t/objc.a %t/objc.o
 
-; CHECK:      _main:
-; CHECK-NEXT: callq _foo
-; CHECK-NEXT: retq
+; RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/main.s -o %t/main.o
+; RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/references-foo.s -o %t/references-foo.o
+
+; RUN: %lld -lSystem %t/references-foo.o %t/foo.a -o %t/test
+; RUN: llvm-objdump --macho --syms %t/test | FileCheck %s --check-prefix=FOO
+
+; RUN: %lld -lSystem -force_load %t/foo.a %t/main.o -o %t/force-load
+; RUN: llvm-objdump --macho --syms %t/force-load | FileCheck %s --check-prefix=FOO
+
+; RUN: %lld -lSystem %t/foo.a %t/main.o -o %t/no-force-load
+; RUN: llvm-objdump --macho --syms %t/no-force-load | FileCheck %s --check-prefix=NO-FOO
+
+; RUN: %lld -lSystem -ObjC -framework CoreFoundation %t/objc.a %t/main.o -o %t/objc
+; RUN: llvm-objdump --macho --syms %t/objc | FileCheck %s --check-prefix=OBJC
+
+; RUN: %lld -lSystem -framework CoreFoundation %t/objc.a %t/main.o -o %t/no-objc
+; RUN: llvm-objdump --macho --syms %t/no-objc | FileCheck %s --check-prefix=NO-OBJC
+
+; FOO: _foo
+
+; NO-FOO-NOT: _foo
+
+; OBJC-DAG: _OBJC_CLASS_$_Foo
+; OBJC-DAG: _OBJC_METACLASS_$_Foo
+
+; NO-OBJC-NOT: _OBJC_CLASS_$_Foo
+; NO-OBJC-NOT: _OBJC_METACLASS_$_Foo
 
 ;--- foo.ll
 
@@ -19,7 +42,46 @@ define void @foo() {
   ret void
 }
 
-;--- test.s
+;--- objc.ll
+
+target triple = "x86_64-apple-macosx10.15.0"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._class_ro_t* }
+%struct._class_ro_t = type { i8* }
+
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Foo\00",
+  section "__TEXT,__objc_classname,cstring_literals"
+@"_OBJC_METACLASS_RO_$_Foo" = internal global %struct._class_ro_t {
+    i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0)
+  },
+  section "__DATA, __objc_const"
+@"OBJC_METACLASS_$_Foo" = global %struct._class_t {
+    %struct._class_t* @"OBJC_METACLASS_$_NSObject",
+    %struct._class_t* @"OBJC_METACLASS_$_NSObject",
+    %struct._class_ro_t* @"_OBJC_METACLASS_RO_$_Foo"
+  },
+  section "__DATA, __objc_data"
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"_OBJC_CLASS_RO_$_Foo" = internal global %struct._class_ro_t {
+    i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0)
+  },
+  section "__DATA, __objc_const"
+@"OBJC_CLASS_$_Foo" = global %struct._class_t {
+    %struct._class_t* @"OBJC_METACLASS_$_Foo",
+    %struct._class_t* @"OBJC_CLASS_$_NSObject",
+    %struct._class_ro_t* @"_OBJC_CLASS_RO_$_Foo"
+  },
+  section "__DATA, __objc_data"
+
+;--- main.s
+
+.globl _main
+_main:
+  ret
+
+;--- references-foo.s
 
 .globl _main
 _main:


        


More information about the llvm-commits mailing list