diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -75,19 +75,20 @@ } static Optional findLibrary(StringRef name) { + std::string stub = (llvm::Twine("lib") + name + ".tbd").str(); std::string shared = (llvm::Twine("lib") + name + ".dylib").str(); std::string archive = (llvm::Twine("lib") + name + ".a").str(); llvm::SmallString<260> location; for (StringRef dir : config->searchPaths) { - for (StringRef library : {shared, archive}) { + for (StringRef library : {stub, shared, archive}) { location = dir; llvm::sys::path::append(location, library); if (fs::exists(location)) return location.str().str(); } } - return None; + return {}; } static TargetInfo *createTargetInfo(opt::InputArgList &args) { @@ -135,6 +136,16 @@ case file_magic::macho_dynamically_linked_shared_lib: inputFiles.push_back(make(mbref)); break; + case file_magic::tapi_file: { + llvm::Expected> result = + TextAPIReader::get(mbref); + if (!result) + return; + + std::unique_ptr interface{std::move(*result)}; + inputFiles.push_back(make(std::move(interface))); + break; + } default: error(path + ": unhandled file type"); } diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -16,6 +16,8 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/Object/Archive.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include "llvm/TextAPI/MachO/TextAPIReader.h" #include #include @@ -73,6 +75,9 @@ // .dylib file class DylibFile : public InputFile { public: + explicit DylibFile(std::shared_ptr interface, + DylibFile *umbrella = nullptr); + // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the // symbols in those sub-libraries will be available under the umbrella // library's namespace. Those sub-libraries can also have their own @@ -81,6 +86,7 @@ // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr); + static bool classof(const InputFile *f) { return f->kind() == DylibKind; } // Do not use this constructor!! This is meant only for createLibSystemMock(), diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -378,6 +378,25 @@ } } +DylibFile::DylibFile(std::shared_ptr interface, + DylibFile *umbrella) + : InputFile(DylibKind, MemoryBufferRef()) { + if (umbrella == nullptr) + umbrella = this; + + dylibName = saver.save(interface->getInstallName()); + // TODO(compnerd) filter out symbols based on the target platform + for (const auto symbol : interface->symbols()) + if (symbol->getArchitectures().has(config->arch)) + symbols.push_back( + symtab->addDylib(saver.save(symbol->getName()), umbrella)); + // TODO(compnerd) properly represent the hierarchy of the documents as it is + // in theory possible to have re-exported dylibs from re-exported dylibs which + // should be parent'ed to the child. + for (auto document : interface->documents()) + reexported.push_back(make(document, umbrella)); +} + DylibFile::DylibFile() : InputFile(DylibKind, MemoryBufferRef()) {} DylibFile *DylibFile::createLibSystemMock() { diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -251,7 +251,7 @@ void Writer::scanRelocations() { for (InputSection *isec : inputSections) { for (Reloc &r : isec->relocs) { - if (auto *s = r.target.dyn_cast()) { + if (auto *s = r.target.dyn_cast()) { if (isa(s)) error("undefined symbol " + s->getName() + ", referenced from " + sys::path::filename(isec->file->getName())); @@ -329,7 +329,7 @@ // TODO: Make sure this handles weak symbols correctly. for (InputFile *file : inputFiles) if (isa(file) || isa(file)) - for (Symbol *sym : file->symbols) + for (lld::macho::Symbol *sym : file->symbols) if (auto *d = dyn_cast(sym)) addSym(*d); diff --git a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd @@ -0,0 +1,42 @@ +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000000' ] +platform: macosx +install-name: '/usr/lib/libSystem.B.dylib' +current-version: 0001.001.1 +exports: + - archs: [ 'x86_64' ] + re-exports: [ '/usr/lib/system/libdyld.dylib', + '/usr/lib/system/libsystem_c.dylib', + '/usr/lib/system/libsystem_m.dylib' ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: macosx +install-name: '/usr/lib/libdyld.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ dyld_stub_binder ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000002' ] +platform: macosx +install-name: '/usr/lib/libsystem_c.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000003' ] +platform: macosx +install-name: '/usr/lib/libsystem_m.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ ___nan ] +... diff --git a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd @@ -0,0 +1,23 @@ +--- !tapi-tbd-v3 +archs: [ i386, x86_64 ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: ios +install-name: '/usr/lib/libSystem.B.dylib' +current-version: 1281 +exports: + - archs: [ i386, x86_64 ] + re-exports: [ '/usr/lib/system/libcache.dylib' ] + symbols: [ __crashreporter_info__ ] +--- !tapi-tbd-v3 +archs: [ i386, x86_64 ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000002', 'x86_64: 00000000-0000-0000-0000-000000000003' ] +platform: ios +install-name: '/usr/lib/libcache.dylib' +current-version: 83 +parent-umbrella: System +exports: + - archs: [ i386 ] + symbols: [ __cache_handle_memory_pressure_event ] + - archs: [ i386, x86_64 ] + symbols: [ _cache_create, _cache_destroy, _cache_get ] +... diff --git a/lld/test/MachO/invalid/stub-link.s b/lld/test/MachO/invalid/stub-link.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid/stub-link.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: mkdir -p %t +# +# RUN: llvm-mc -filetype obj -triple x86_64-apple-ios %s -o %t/test.o +# RUN: not lld -flavor darwinnew -o %t/test -Z -L%S/../Inputs/iPhoneSimulator.sdk/usr/lib -lSystem %t/test.o 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol __cache_handle_memory_pressure_event + +.section __TEXT,__text +.global _main + +_main: + movq __cache_handle_memory_pressure_event@GOTPCREL(%rip), %rax + ret diff --git a/lld/test/MachO/stub-link.s b/lld/test/MachO/stub-link.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/stub-link.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# RUN: mkdir -p %t +# +# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/test.o +# RUN: lld -flavor darwinnew -o %t/test -Z -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem %t/test.o +# +# RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/test | FileCheck %s + +# CHECK: Disassembly of section __TEXT,__text: +# CHECK: movq {{.*}} # [[ADDR:[0-9a-f]+]] + +# CHECK: Bind table: +# CHECK: __DATA_CONST __got 0x[[ADDR]] pointer 0 libSystem ___nan + +.section __TEXT,__text +.global _main + +_main: + movq ___nan@GOTPCREL(%rip), %rax + ret