[lld] r284034 - [ThinLTO] Avoid archive member collisions.

Davide Italiano via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 12 12:35:54 PDT 2016


Author: davide
Date: Wed Oct 12 14:35:54 2016
New Revision: 284034

URL: http://llvm.org/viewvc/llvm-project?rev=284034&view=rev
Log:
[ThinLTO] Avoid archive member collisions.

This fixes PR30665.

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

Added:
    lld/trunk/test/ELF/lto/Inputs/thin1.ll
    lld/trunk/test/ELF/lto/Inputs/thin2.ll
    lld/trunk/test/ELF/lto/thin-archivecollision.ll
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/Symbols.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=284034&r1=284033&r2=284034&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed Oct 12 14:35:54 2016
@@ -471,13 +471,14 @@ template <class ELFT> void ArchiveFile::
 }
 
 // Returns a buffer pointing to a member file containing a given symbol.
-MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
+std::pair<MemoryBufferRef, uint64_t>
+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 @@ MemoryBufferRef ArchiveFile::getMember(c
   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 <class ELFT>
@@ -713,7 +715,18 @@ static Symbol *createBitcodeSymbol(const
 
 template <class ELFT>
 void BitcodeFile::parse(DenseSet<StringRef> &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<const Comdat *> KeptComdats;
   for (const auto &P : Obj->getComdatSymbolTable()) {
     StringRef N = Saver.save(P.first());
@@ -803,10 +816,12 @@ static bool isBitcode(MemoryBufferRef MB
   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<ObjectFile>(MB);
   F->ArchiveName = ArchiveName;
+  F->OffsetInArchive = OffsetInArchive;
   return F;
 }
 

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=284034&r1=284033&r2=284034&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Oct 12 14:35:54 2016
@@ -66,6 +66,12 @@ public:
   // 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 @@ public:
   static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
   template <class ELFT> 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<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
 
 private:
   std::unique_ptr<Archive> File;
@@ -324,7 +331,8 @@ private:
   std::vector<uint8_t> ELFData;
 };
 
-InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "");
+InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
+                            uint64_t OffsetInArchive = 0);
 InputFile *createSharedFile(MemoryBufferRef MB);
 
 } // namespace elf

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=284034&r1=284033&r2=284034&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Wed Oct 12 14:35:54 2016
@@ -508,9 +508,9 @@ void SymbolTable<ELFT>::addLazyArchive(A
     replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
     return;
   }
-  MemoryBufferRef MBRef = F->getMember(&Sym);
-  if (!MBRef.getBuffer().empty())
-    addFile(createObjectFile(MBRef, F->getName()));
+  std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
+  if (!MBInfo.first.getBuffer().empty())
+    addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
 }
 
 template <class ELFT>

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=284034&r1=284033&r2=284034&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Wed Oct 12 14:35:54 2016
@@ -245,13 +245,13 @@ LazyObject::LazyObject(StringRef Name, L
 }
 
 InputFile *LazyArchive::fetch() {
-  MemoryBufferRef MBRef = file()->getMember(&Sym);
+  std::pair<MemoryBufferRef, uint64_t> 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() {

Added: lld/trunk/test/ELF/lto/Inputs/thin1.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/thin1.ll?rev=284034&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/thin1.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/thin1.ll Wed Oct 12 14:35:54 2016
@@ -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
+}

Added: lld/trunk/test/ELF/lto/Inputs/thin2.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/thin2.ll?rev=284034&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/thin2.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/thin2.ll Wed Oct 12 14:35:54 2016
@@ -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
+}

Added: lld/trunk/test/ELF/lto/thin-archivecollision.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/thin-archivecollision.ll?rev=284034&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/thin-archivecollision.ll (added)
+++ lld/trunk/test/ELF/lto/thin-archivecollision.ll Wed Oct 12 14:35:54 2016
@@ -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




More information about the llvm-commits mailing list