forked from OSchip/llvm-project
[ThinLTO] Avoid archive member collisions.
This fixes PR30665. Differential Revision: https://reviews.llvm.org/D25495 llvm-svn: 284034
This commit is contained in:
parent
c37e2231ad
commit
bcdd6c60a0
|
@ -471,13 +471,14 @@ template <class ELFT> void ArchiveFile::parse() {
|
|||
}
|
||||
|
||||
// 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(const Archive::Symbol *Sym) {
|
|||
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 DenseSet<const Comdat *> &KeptComdats,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -508,9 +508,9 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
|
|||
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>
|
||||
|
|
|
@ -245,13 +245,13 @@ LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue