Index: lld/MachO/Driver.h =================================================================== --- lld/MachO/Driver.h +++ lld/MachO/Driver.h @@ -70,7 +70,8 @@ llvm::Optional loadArchiveMember(MemoryBufferRef, uint32_t modTime, StringRef archiveName, - bool objCOnly); + bool objCOnly, + uint64_t offsetInArchive); uint32_t getModTime(llvm::StringRef path); Index: lld/MachO/Driver.cpp =================================================================== --- lld/MachO/Driver.cpp +++ lld/MachO/Driver.cpp @@ -228,6 +228,7 @@ struct ArchiveMember { MemoryBufferRef mbref; uint32_t modTime; + uint64_t offsetInArchive; }; } // namespace @@ -257,7 +258,7 @@ CHECK(c.getLastModified(), mb.getBufferIdentifier() + ": could not get the modification " "time for a child of the archive")); - v.push_back({mbref, modTime}); + v.push_back({mbref, modTime, c.getChildOffset()}); } if (err) fatal(mb.getBufferIdentifier() + @@ -298,7 +299,8 @@ if (Optional buffer = readFile(path)) { for (const ArchiveMember &member : getArchiveMembers(*buffer)) { if (Optional file = loadArchiveMember( - member.mbref, member.modTime, path, /*objCOnly=*/false)) { + member.mbref, member.modTime, path, /*objCOnly=*/false, + member.offsetInArchive)) { inputFiles.insert(*file); printArchiveMemberLoad( (forceLoadArchive ? "-force_load" : "-all_load"), @@ -319,7 +321,8 @@ if (Optional buffer = readFile(path)) { for (const ArchiveMember &member : getArchiveMembers(*buffer)) { if (Optional file = loadArchiveMember( - member.mbref, member.modTime, path, /*objCOnly=*/true)) { + member.mbref, member.modTime, path, /*objCOnly=*/true, + member.offsetInArchive)) { inputFiles.insert(*file); printArchiveMemberLoad("-ObjC", inputFiles.back()); } @@ -343,7 +346,7 @@ } break; case file_magic::bitcode: - newFile = make(mbref); + newFile = make(mbref, "", 0); break; case file_magic::macho_executable: case file_magic::macho_bundle: Index: lld/MachO/DriverUtils.cpp =================================================================== --- lld/MachO/DriverUtils.cpp +++ lld/MachO/DriverUtils.cpp @@ -280,7 +280,8 @@ Optional macho::loadArchiveMember(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName, - bool objCOnly) { + bool objCOnly, + uint64_t offsetInArchive) { if (config->zeroModTime) modTime = 0; @@ -291,7 +292,7 @@ return None; case file_magic::bitcode: if (!objCOnly || check(isBitcodeContainingObjCCategory(mb))) - return make(mb); + return make(mb, archiveName, offsetInArchive); return None; default: error(archiveName + ": archive member " + mb.getBufferIdentifier() + Index: lld/MachO/InputFiles.h =================================================================== --- lld/MachO/InputFiles.h +++ lld/MachO/InputFiles.h @@ -196,7 +196,8 @@ class BitcodeFile final : public InputFile { public: - explicit BitcodeFile(MemoryBufferRef mb); + explicit BitcodeFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive); static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } std::unique_ptr obj; Index: lld/MachO/InputFiles.cpp =================================================================== --- lld/MachO/InputFiles.cpp +++ lld/MachO/InputFiles.cpp @@ -1215,8 +1215,8 @@ // to it later. const object::Archive::Symbol symCopy = sym; - if (Optional file = - loadArchiveMember(mb, modTime, getName(), /*objCOnly=*/false)) { + if (Optional file = loadArchiveMember( + mb, modTime, getName(), /*objCOnly=*/false, c.getChildOffset())) { inputFiles.insert(*file); // ld64 doesn't demangle sym here even with -demangle. // Match that: intentionally don't call toMachOString(). @@ -1255,8 +1255,22 @@ /*noDeadStrip=*/false); } -BitcodeFile::BitcodeFile(MemoryBufferRef mbref) - : InputFile(BitcodeKind, mbref) { +BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive) + : InputFile(BitcodeKind, mb) { + std::string path = mb.getBufferIdentifbier().str(); + // ThinLTO assumes that all MemoryBufferRefs given to it have a unique + // name. If two members with the same name are provided, this causes a + // collision and ThinLTO can't proceed. + // So, we append the archive name to disambiguate two members with the same + // name from multiple different archives, and offset within the archive to + // disambiguate two members of the same name from a single archive. + MemoryBufferRef mbref( + mb.getBuffer(), + saver.save(archiveName.empty() ? path + : archiveName + sys::path::filename(path) + + utostr(offsetInArchive))); + obj = check(lto::InputFile::create(mbref)); // Convert LTO Symbols to LLD Symbols in order to perform resolution. The Index: lld/test/MachO/lto-archivecollision.ll =================================================================== --- /dev/null +++ lld/test/MachO/lto-archivecollision.ll @@ -0,0 +1,55 @@ +; RUN: rm -rf %t; split-file %s %t +; RUN: mkdir %t/a %t/b +; RUN: opt -thinlto-bc -o %t/main.o %t/main.ll +; RUN: opt -thinlto-bc -o %t/a/bar.o %t/foo.ll +; RUN: opt -thinlto-bc -o %t/b/bar.o %t/bar.ll +; RUN: llvm-ar crs %t/libbar.a %t/a/bar.o %t/b/bar.o +; RUN: %lld -save-temps %t/main.o %t/libbar.a -o %t/test +; RUN: FileCheck %s --check-prefix=SAME-ARCHIVE < %t/test.resolution.txt + +; RUN: llvm-ar crs %t/liba.a %t/a/bar.o +; RUN: llvm-ar crs %t/libb.a %t/b/bar.o +; RUN: %lld -save-temps %t/main.o %t/liba.a %t/libb.a -o %t/test +; RUN: FileCheck %s --check-prefix=DIFFERENT-ARCHIVES < %t/test.resolution.txt + +; SAME-ARCHIVE: libbar.abar.o[[#OFFSET:]] +; SAME-ARCHIVE-NEXT: -r={{.*}}/libbar.abar.o[[#OFFSET:]],_foo,p +; SAME-ARCHIVE-NEXT: libbar.abar.o[[#OTHEROFFSET:]] +; SAME-ARCHIVE-NEXT: -r={{.*}}/libbar.abar.o[[#OTHEROFFSET:]],_bar,p + +; DIFFERENT-ARCHIVES: liba.abar.o[[#OFFSET:]] +; DIFFERENT-ARCHIVES-NEXT: -r={{.*}}/liba.abar.o[[#OFFSET:]],_foo,p +; DIFFERENT-ARCHIVES-NEXT: libb.abar.o[[#OTHEROFFSET:]] +; DIFFERENT-ARCHIVES-NEXT: -r={{.*}}/libb.abar.o[[#OTHEROFFSET:]],_bar,p + +;--- main.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" + +declare void @bar() +declare void @foo() + +define i32 @main() { + call void @foo() + call void @bar() + ret i32 0 +} + +;--- 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" + +define void @foo() { + ret void +} + +;--- bar.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 @bar() { + ret void +}