diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -31,8 +31,10 @@ uint64_t X86_64::getImplicitAddend(const uint8_t *loc, uint8_t type) const { switch (type) { + case X86_64_RELOC_BRANCH: case X86_64_RELOC_SIGNED: case X86_64_RELOC_GOT_LOAD: + case X86_64_RELOC_SIGNED_1: return read32le(loc); default: error("TODO: Unhandled relocation type " + std::to_string(type)); @@ -42,10 +44,14 @@ void X86_64::relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const { switch (type) { + case X86_64_RELOC_BRANCH: case X86_64_RELOC_SIGNED: case X86_64_RELOC_GOT_LOAD: // These types are only used for pc-relative relocations, so offset by 4 // since the RIP has advanced by 4 at this point. + case X86_64_RELOC_SIGNED_1: + // This type is only used for pc-relative relocations, so offset by 4 since + // the RIP has advanced by 4 at this point. write32le(loc, val - 4); break; default: diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -103,6 +103,12 @@ MemoryBufferRef mbref = *buffer; switch (identify_magic(mbref.getBuffer())) { + case file_magic::archive: { + std::unique_ptr file = CHECK( + object::Archive::create(mbref), path + ": failed to parse archive"); + inputFiles.push_back(make(file)); + break; + } case file_magic::macho_object: inputFiles.push_back(make(mbref)); break; @@ -160,7 +166,7 @@ // Initialize InputSections. for (InputFile *file : inputFiles) - for (InputSection *sec : file->sections) + for (InputSection *sec : file->getInputSections()) inputSections.push_back(sec); // Write to an output file. diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -28,15 +28,16 @@ enum Kind { ObjKind, DylibKind, + ArchiveKind, }; virtual ~InputFile() = default; Kind kind() const { return fileKind; } StringRef getName() const { return mb.getBufferIdentifier(); } + virtual std::vector const getInputSections() = 0; MemoryBufferRef mb; std::vector symbols; - std::vector sections; protected: InputFile(Kind kind, MemoryBufferRef mb) : mb(mb), fileKind(kind) {} @@ -55,6 +56,10 @@ public: explicit ObjFile(MemoryBufferRef mb); static bool classof(const InputFile *f) { return f->kind() == ObjKind; } + std::vector const getInputSections() { return sections; } + +private: + std::vector sections; }; // .dylib file @@ -62,9 +67,26 @@ public: explicit DylibFile(MemoryBufferRef mb); static bool classof(const InputFile *f) { return f->kind() == DylibKind; } + std::vector const getInputSections() { return sections; } StringRef dylibName; uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel + +private: + std::vector sections; +}; + +// .a file +class ArchiveFile : public InputFile { +public: + explicit ArchiveFile(std::unique_ptr &file); + static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } + std::vector const getInputSections(); + InputFile *fetch(const llvm::object::Archive::Symbol &sym); + +private: + llvm::DenseSet seen; + std::vector resolvedInputs; }; extern std::vector inputFiles; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -239,6 +239,40 @@ } } +ArchiveFile::ArchiveFile(std::unique_ptr &f) + : InputFile(ArchiveKind, f->getMemoryBufferRef()) { + for (const object::Archive::Symbol &sym : f->symbols()) + symtab->addLazy(sym.getName(), this, sym); +} + +std::vector const ArchiveFile::getInputSections() { + std::vector sections; + for (InputFile *input : resolvedInputs) { + auto inputSections = input->getInputSections(); + sections.insert(sections.end(), inputSections.begin(), inputSections.end()); + } + return sections; +} + +InputFile *ArchiveFile::fetch(const object::Archive::Symbol &sym) { + object::Archive::Child c = + CHECK(sym.getMember(), toString(this) + + ": could not get the member for symbol " + + sym.getName()); + + if (!seen.insert(c.getChildOffset()).second) + return nullptr; + + MemoryBufferRef mb = + CHECK(c.getMemoryBufferRef(), + toString(this) + + ": could not get the buffer for the member defining symbol " + + sym.getName()); + auto file = make(mb); + resolvedInputs.push_back(file); + return file; +} + // Returns "" or "baz.o". std::string lld::toString(const InputFile *file) { return file ? std::string(file->getName()) : ""; diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -28,6 +28,8 @@ Symbol *addUndefined(StringRef name); Symbol *addDylib(StringRef name, DylibFile *file); + Symbol *addLazy(StringRef name, ArchiveFile *file, + const llvm::object::Archive::Symbol sym); ArrayRef getSymbols() const { return symVector; } Symbol *find(StringRef name); diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -69,4 +69,17 @@ return s; } +Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file, + const llvm::object::Archive::Symbol sym) { + Symbol *s; + bool wasInserted; + std::tie(s, wasInserted) = insert(name); + + if (wasInserted) + replaceSymbol(s, file, sym); + else if (isa(s)) + file->fetch(sym); + return s; +} + SymbolTable *macho::symtab; diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -35,6 +35,7 @@ DefinedKind, UndefinedKind, DylibKind, + LazyKind, }; Kind kind() const { return static_cast(symbolKind); } @@ -79,6 +80,20 @@ uint32_t gotIndex = UINT32_MAX; }; +class LazySymbol : public Symbol { +public: + LazySymbol(InputFile *file, const llvm::object::Archive::Symbol sym) + : Symbol(LazyKind, sym.getName()), file(file), sym(sym) {} + + static bool classof(const Symbol *s) { return s->kind() == LazyKind; } + + InputFile *fetch(); + +private: + InputFile *file; + const llvm::object::Archive::Symbol sym; +}; + inline uint64_t Symbol::getVA() const { if (auto *d = dyn_cast(this)) return d->isec->getVA() + d->value - ImageBase; @@ -89,6 +104,7 @@ alignas(Defined) char a[sizeof(Defined)]; alignas(Undefined) char b[sizeof(Undefined)]; alignas(DylibSymbol) char c[sizeof(DylibSymbol)]; + alignas(LazySymbol) char d[sizeof(LazySymbol)]; }; template diff --git a/lld/MachO/Symbols.cpp b/lld/MachO/Symbols.cpp --- a/lld/MachO/Symbols.cpp +++ b/lld/MachO/Symbols.cpp @@ -15,6 +15,8 @@ using namespace lld; using namespace lld::macho; +InputFile *LazySymbol::fetch() { return cast(file)->fetch(sym); } + // Returns a symbol for an error message. std::string lld::toString(const Symbol &sym) { if (Optional s = demangleItanium(sym.getName())) diff --git a/lld/test/MachO/Inputs/archive.s b/lld/test/MachO/Inputs/archive.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/archive.s @@ -0,0 +1,6 @@ +.global _main +_main: + callq _boo + callq _bar + mov $0, %rax + ret diff --git a/lld/test/MachO/Inputs/archive2.s b/lld/test/MachO/Inputs/archive2.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/archive2.s @@ -0,0 +1,4 @@ +.global _boo +_boo: + mov $2, %rax + ret diff --git a/lld/test/MachO/Inputs/archive3.s b/lld/test/MachO/Inputs/archive3.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/archive3.s @@ -0,0 +1,4 @@ +.global _bar +_bar: + mov $3, %rax + ret diff --git a/lld/test/MachO/Inputs/archive4.s b/lld/test/MachO/Inputs/archive4.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/archive4.s @@ -0,0 +1,4 @@ +.global _lonely +_alone: + mov $5, %rax + ret diff --git a/lld/test/MachO/archive.s b/lld/test/MachO/archive.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/archive.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %S/Inputs/archive.s -o %t.main +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %S/Inputs/archive2.s -o %t2 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %S/Inputs/archive3.s -o %t3 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %S/Inputs/archive4.s -o %t4 + +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %t2 %t3 %t4 + +# RUN: lld -flavor darwinnew %t.main %t.a -o %t.out +# RUN: llvm-nm %t.out | FileCheck %s + +# CHECK: T _bar +# CHECK-NEXT: T _boo +# CHECK-NEXT: T _main