struct ArchiveMember {
MemoryBufferRef mbref;
uint32_t modTime;
+ uint64_t offsetInArchive;
};
} // namespace
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() +
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
if (Optional<InputFile *> 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"),
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
if (Optional<InputFile *> 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());
}
}
break;
case file_magic::bitcode:
- newFile = make<BitcodeFile>(mbref);
+ newFile = make<BitcodeFile>(mbref, "", 0);
break;
case file_magic::macho_executable:
case file_magic::macho_bundle:
llvm::Optional<InputFile *> loadArchiveMember(MemoryBufferRef, uint32_t modTime,
StringRef archiveName,
- bool objCOnly);
+ bool objCOnly,
+ uint64_t offsetInArchive);
uint32_t getModTime(llvm::StringRef path);
Optional<InputFile *> macho::loadArchiveMember(MemoryBufferRef mb,
uint32_t modTime,
StringRef archiveName,
- bool objCOnly) {
+ bool objCOnly,
+ uint64_t offsetInArchive) {
if (config->zeroModTime)
modTime = 0;
return None;
case file_magic::bitcode:
if (!objCOnly || check(isBitcodeContainingObjCCategory(mb)))
- return make<BitcodeFile>(mb);
+ return make<BitcodeFile>(mb, archiveName, offsetInArchive);
return None;
default:
error(archiveName + ": archive member " + mb.getBufferIdentifier() +
// to it later.
const object::Archive::Symbol symCopy = sym;
- if (Optional<InputFile *> file =
- loadArchiveMember(mb, modTime, getName(), /*objCOnly=*/false)) {
+ if (Optional<InputFile *> 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().
/*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.getBufferIdentifier().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
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<llvm::lto::InputFile> obj;
--- /dev/null
+; 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
+}