Index: lld/trunk/ELF/InputFiles.h =================================================================== --- lld/trunk/ELF/InputFiles.h +++ lld/trunk/ELF/InputFiles.h @@ -66,6 +66,12 @@ // string for creating error messages. StringRef ArchiveName; + // If this file is in an archive, the member contains the offset of + // the file in the archive. Otherwise, it's just zero. We store this + // field so that we can pass it to lib/LTO in order to disambiguate + // between objects. + uint64_t OffsetInArchive; + // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. ELFKind EKind = ELFNoneKind; @@ -239,10 +245,11 @@ static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template void parse(); - // Returns a memory buffer for a given symbol. An empty memory buffer + // Returns a memory buffer for a given symbol and the offset in the archive + // for the member. An empty memory buffer and an offset of zero // is returned if we have already returned the same memory buffer. // (So that we don't instantiate same members more than once.) - MemoryBufferRef getMember(const Archive::Symbol *Sym); + std::pair getMember(const Archive::Symbol *Sym); private: std::unique_ptr File; @@ -324,7 +331,8 @@ std::vector ELFData; }; -InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = ""); +InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", + uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB); } // namespace elf Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -471,13 +471,14 @@ } // Returns a buffer pointing to a member file containing a given symbol. -MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { +std::pair +ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = check(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) - return MemoryBufferRef(); + return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = check(C.getMemoryBufferRef(), @@ -487,8 +488,9 @@ if (C.getParent()->isThin() && Driver->Cpio) Driver->Cpio->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer()); - - return Ret; + if (C.getParent()->isThin()) + return {Ret, 0}; + return {Ret, C.getChildOffset()}; } template @@ -713,7 +715,18 @@ template void BitcodeFile::parse(DenseSet &ComdatGroups) { - Obj = check(lto::InputFile::create(MB)); + + // Here we pass a new MemoryBufferRef which is identified by ArchiveName + // (the fully resolved path of the archive) + member name + offset of the + // member in the archive. + // ThinLTO uses the MemoryBufferRef identifier to access its internal + // data structures and if two archives define two members with the same name, + // this causes a collision which result in only one of the objects being + // taken into consideration at LTO time (which very likely causes undefined + // symbols later in the link stage). + Obj = check(lto::InputFile::create(MemoryBufferRef( + MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + + utostr(OffsetInArchive))))); DenseSet KeptComdats; for (const auto &P : Obj->getComdatSymbolTable()) { StringRef N = Saver.save(P.first()); @@ -803,10 +816,12 @@ return identify_magic(MB.getBuffer()) == file_magic::bitcode; } -InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName) { +InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) { InputFile *F = isBitcode(MB) ? new BitcodeFile(MB) : createELFFile(MB); F->ArchiveName = ArchiveName; + F->OffsetInArchive = OffsetInArchive; return F; } Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -508,9 +508,9 @@ replaceBody(S, *F, Sym, S->body()->Type); return; } - MemoryBufferRef MBRef = F->getMember(&Sym); - if (!MBRef.getBuffer().empty()) - addFile(createObjectFile(MBRef, F->getName())); + std::pair MBInfo = F->getMember(&Sym); + if (!MBInfo.first.getBuffer().empty()) + addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); } template Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -245,13 +245,13 @@ } InputFile *LazyArchive::fetch() { - MemoryBufferRef MBRef = file()->getMember(&Sym); + std::pair MBInfo = file()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. - if (MBRef.getBuffer().empty()) + if (MBInfo.first.getBuffer().empty()) return nullptr; - return createObjectFile(MBRef, file()->getName()); + return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); } InputFile *LazyObject::fetch() { Index: lld/trunk/test/ELF/lto/Inputs/thin1.ll =================================================================== --- lld/trunk/test/ELF/lto/Inputs/thin1.ll +++ lld/trunk/test/ELF/lto/Inputs/thin1.ll @@ -0,0 +1,12 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-scei-ps4" + +define i32 @foo(i32 %goo) { +entry: + %goo.addr = alloca i32, align 4 + store i32 %goo, i32* %goo.addr, align 4 + %0 = load i32, i32* %goo.addr, align 4 + %1 = load i32, i32* %goo.addr, align 4 + %mul = mul nsw i32 %0, %1 + ret i32 %mul +} Index: lld/trunk/test/ELF/lto/Inputs/thin2.ll =================================================================== --- lld/trunk/test/ELF/lto/Inputs/thin2.ll +++ lld/trunk/test/ELF/lto/Inputs/thin2.ll @@ -0,0 +1,11 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-scei-ps4" + +define i32 @blah(i32 %meh) #0 { +entry: + %meh.addr = alloca i32, align 4 + store i32 %meh, i32* %meh.addr, align 4 + %0 = load i32, i32* %meh.addr, align 4 + %sub = sub nsw i32 %0, 48 + ret i32 %sub +} Index: lld/trunk/test/ELF/lto/thin-archivecollision.ll =================================================================== --- lld/trunk/test/ELF/lto/thin-archivecollision.ll +++ lld/trunk/test/ELF/lto/thin-archivecollision.ll @@ -0,0 +1,25 @@ +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %p/Inputs/thin1.ll -o %t.coll.o +; RUN: llvm-ar rcs %t1.a %t.coll.o +; RUN: opt -module-summary %p/Inputs/thin2.ll -o %t.coll.o +; RUN: llvm-ar rcsc %t2.a %t.coll.o + +; RUN: ld.lld %t.o %t1.a %t2.a -o %t +; RUN: llvm-nm %t | FileCheck %s + +; CHECK: T _start +; CHECK: T blah +; CHECK: T foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-scei-ps4" + +define i32 @_start() { +entry: + %call = call i32 @foo(i32 23) + %call1 = call i32 @blah(i32 37) + ret i32 0 +} + +declare i32 @foo(i32) #1 +declare i32 @blah(i32) #1