diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -247,9 +247,12 @@ } static DenseMap loadedArchives; +static DenseMap implicitlyLoadedObjects; +static DenseMap explicitlyLoadedObjects; static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive, bool isExplicit = true, bool isBundleLoader = false) { + Optional buffer = readFile(path); if (!buffer) return nullptr; @@ -319,7 +322,20 @@ break; } case file_magic::macho_object: - newFile = make(mbref, getModTime(path), ""); + // Implicitly loaded objects need to be deduplicated to not cause duplicate + // symbol errors. If an implicitly loaded object is loaded explicitly, it + // is also deduplicated. + if (InputFile *cachedFile = implicitlyLoadedObjects[path]) + return cachedFile; + + if (isExplicit) { + newFile = explicitlyLoadedObjects[path] = make(mbref, getModTime(path), ""); + } else { + // If an object is explicitly loaded, ignore any implicit loads of it + if (InputFile *cachedFile = explicitlyLoadedObjects[path]) + return cachedFile; + newFile = implicitlyLoadedObjects[path] = make(mbref, getModTime(path), ""); + } break; case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamically_linked_shared_lib_stub: @@ -331,7 +347,17 @@ } break; case file_magic::bitcode: - newFile = make(mbref, "", 0); + // See comments above for macho_object file type + if (InputFile *cachedFile = implicitlyLoadedObjects[path]) + return cachedFile; + + if (isExplicit) { + newFile = explicitlyLoadedObjects[path] = make(mbref, "", 0); + } else { + if (InputFile *cachedFile = explicitlyLoadedObjects[path]) + return cachedFile; + newFile = implicitlyLoadedObjects[path] = make(mbref, "", 0); + } break; case file_magic::macho_executable: case file_magic::macho_bundle: @@ -1098,6 +1124,8 @@ inputFiles.clear(); inputSections.clear(); loadedArchives.clear(); + implicitlyLoadedObjects.clear(); + explicitlyLoadedObjects.clear(); syntheticSections.clear(); thunkMap.clear(); diff --git a/lld/test/MachO/framework-object.ll b/lld/test/MachO/framework-object.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/framework-object.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 +; RUN: rm -rf %t; split-file %s %t + +; RUN: mkdir -p %t/Foo.framework +; RUN: llc --filetype=obj %t/framework.ll -o %t/Foo.framework/Foo +; RUN: llc --filetype=obj %t/load-framework-foo.ll -o %t/main +; Order of the object with the LC_LINKER_OPTION vs -framework arg is important. +; RUN: %lld %t/main -F %t -framework Foo +; RUN: %lld -F %t -framework Foo %t/main + +; RUN: llvm-as %t/framework.ll -o %t/Foo.framework/Foo +; RUN: llvm-as %t/load-framework-foo.ll -o %t/main +; Order of the object with the LC_LINKER_OPTION vs -framework arg is important. +; RUN: %lld %t/main -F %t -framework Foo +; RUN: %lld -F %t -framework Foo %t/main + +;--- framework.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" + +define void @foo() { + ret void +} + +;--- load-framework-foo.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" + +!0 = !{!"-framework", !"Foo"} +!llvm.linker.options = !{!0, !0} + +define void @main() { + ret void +} + diff --git a/lld/test/MachO/invalid/duplicate-symbol.ll b/lld/test/MachO/invalid/duplicate-symbol.ll --- a/lld/test/MachO/invalid/duplicate-symbol.ll +++ b/lld/test/MachO/invalid/duplicate-symbol.ll @@ -13,3 +13,4 @@ define void @foo() { ret void } + diff --git a/lld/test/MachO/invalid/duplicate-symbol.s b/lld/test/MachO/invalid/duplicate-symbol.s --- a/lld/test/MachO/invalid/duplicate-symbol.s +++ b/lld/test/MachO/invalid/duplicate-symbol.s @@ -13,3 +13,4 @@ _main: mov $0, %rax ret +