diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -248,6 +248,8 @@ } static DenseMap loadedArchives; +static DenseMap implicitlyLoadedObjects; +static DenseMap explicitlyLoadedObjects; static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive, bool isLazy = false, bool isExplicit = true, @@ -321,7 +323,22 @@ break; } case file_magic::macho_object: - newFile = make(mbref, getModTime(path), "", isLazy); + // 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), "", isLazy); + } 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), "", isLazy); + } break; case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamically_linked_shared_lib_stub: @@ -333,7 +350,19 @@ } break; case file_magic::bitcode: - newFile = make(mbref, "", 0, isLazy); + // See comments above for macho_object file type + if (InputFile *cachedFile = implicitlyLoadedObjects[path]) + return cachedFile; + + if (isExplicit) { + newFile = explicitlyLoadedObjects[path] = + make(mbref, "", 0, isLazy); + } else { + if (InputFile *cachedFile = explicitlyLoadedObjects[path]) + return cachedFile; + newFile = implicitlyLoadedObjects[path] = + make(mbref, "", 0, isLazy); + } break; case file_magic::macho_executable: case file_magic::macho_bundle: @@ -1069,6 +1098,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,34 @@ +; 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 -o /dev/null +; RUN: %lld -F %t -framework Foo %t/main -o /dev/null + +; 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 -o /dev/null +; RUN: %lld -F %t -framework Foo %t/main -o /dev/null + +;--- 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 +}