diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -39,8 +39,9 @@ using namespace llvm; using namespace llvm::MachO; -using namespace llvm::sys; +using namespace llvm::object; using namespace llvm::opt; +using namespace llvm::sys; using namespace lld; using namespace lld::macho; @@ -251,6 +252,35 @@ addFile(path); } +// Returns slices of MB by parsing MB as an archive file. +// Each slice consists of a member file in the archive. +static std::vector getArchiveMembers(MemoryBufferRef mb) { + std::unique_ptr file = + CHECK(Archive::create(mb), + mb.getBufferIdentifier() + ": failed to parse archive"); + + std::vector v; + Error err = Error::success(); + for (const Archive::Child &c : file->children(err)) { + MemoryBufferRef mbref = + CHECK(c.getMemoryBufferRef(), + mb.getBufferIdentifier() + + ": could not get the buffer for a child of the archive"); + v.push_back(mbref); + } + if (err) + fatal(mb.getBufferIdentifier() + + ": Archive::children failed: " + toString(std::move(err))); + + return v; +} + +static void forceLoadArchive(StringRef path) { + if (Optional buffer = readFile(path)) + for (MemoryBufferRef member : getArchiveMembers(*buffer)) + inputFiles.push_back(make(member)); +} + static std::array archNames{"arm", "arm64", "i386", "x86_64", "ppc", "ppc64"}; static bool isArchString(StringRef s) { @@ -465,6 +495,9 @@ case OPT_filelist: addFileList(arg->getValue()); break; + case OPT_force_load: + forceLoadArchive(arg->getValue()); + break; case OPT_l: { StringRef name = arg->getValue(); if (Optional path = findLibrary(name)) { diff --git a/lld/test/MachO/force-load.s b/lld/test/MachO/force-load.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/force-load.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t +# RUN: echo ".section __TEXT,archive; .globl _foo; .weak_definition _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/archive-foo.o +# RUN: rm -f %t/foo.a +# RUN: llvm-ar rcs %t/foo.a %t/archive-foo.o +# RUN: echo ".section __TEXT,obj; .globl _foo; .weak_definition _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/foo.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o + +# RUN: lld -flavor darwinnew -force_load %t/foo.a %t/foo.o %t/test.o -o %t/test-force-load-first +# FORCE-LOAD-FIRST: __TEXT,archive _foo +# RUN: llvm-objdump --syms %t/test-force-load-first | FileCheck %s --check-prefix=FORCE-LOAD-FIRST + +# RUN: lld -flavor darwinnew %t/foo.o -force_load %t/foo.a %t/test.o -o %t/test-force-load-second +# RUN: llvm-objdump --syms %t/test-force-load-second | FileCheck %s --check-prefix=FORCE-LOAD-SECOND +# FORCE-LOAD-SECOND: __TEXT,obj _foo + +.globl _main +_main: + ret diff --git a/lld/test/MachO/invalid/bad-archive.s b/lld/test/MachO/invalid/bad-archive.s --- a/lld/test/MachO/invalid/bad-archive.s +++ b/lld/test/MachO/invalid/bad-archive.s @@ -4,6 +4,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o # RUN: not lld -flavor darwinnew %t.o %t.a -o /dev/null 2>&1 | FileCheck -DFILE=%t.a %s +# RUN: not lld -flavor darwinnew %t.o -force_load %t.a -o /dev/null 2>&1 | FileCheck -DFILE=%t.a %s # CHECK: error: [[FILE]]: failed to parse archive: truncated or malformed archive (remaining size of archive too small for next archive member header at offset 8) .global _main