lld: initial pass at supporting TBD

Add support to lld to use Text Based API stubs for linking.  This is
support is incomplete not filtering out platforms.  It also does not
account for architecture specific API handling and potentially does not
correctly handle trees of re-exports with inlined libraries being
treated as direct children of the top level library.
This commit is contained in:
Saleem Abdulrasool 2020-06-05 11:18:33 -07:00
parent 48c28d58c6
commit 6fe27b5fed
8 changed files with 141 additions and 4 deletions

View File

@ -75,19 +75,20 @@ opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
}
static Optional<std::string> 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 @@ static void addFile(StringRef path) {
case file_magic::macho_dynamically_linked_shared_lib:
inputFiles.push_back(make<DylibFile>(mbref));
break;
case file_magic::tapi_file: {
llvm::Expected<std::unique_ptr<llvm::MachO::InterfaceFile>> result =
TextAPIReader::get(mbref);
if (!result)
return;
std::unique_ptr<llvm::MachO::InterfaceFile> interface{std::move(*result)};
inputFiles.push_back(make<DylibFile>(std::move(interface)));
break;
}
default:
error(path + ": unhandled file type");
}

View File

@ -378,6 +378,25 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella)
}
}
DylibFile::DylibFile(std::shared_ptr<llvm::MachO::InterfaceFile> 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<DylibFile>(document, umbrella));
}
DylibFile::DylibFile() : InputFile(DylibKind, MemoryBufferRef()) {}
DylibFile *DylibFile::createLibSystemMock() {

View File

@ -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 <map>
#include <vector>
@ -73,6 +75,9 @@ public:
// .dylib file
class DylibFile : public InputFile {
public:
explicit DylibFile(std::shared_ptr<llvm::MachO::InterfaceFile> 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 @@ public:
// 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(),

View File

@ -251,7 +251,7 @@ private:
void Writer::scanRelocations() {
for (InputSection *isec : inputSections) {
for (Reloc &r : isec->relocs) {
if (auto *s = r.target.dyn_cast<Symbol *>()) {
if (auto *s = r.target.dyn_cast<lld::macho::Symbol *>()) {
if (isa<Undefined>(s))
error("undefined symbol " + s->getName() + ", referenced from " +
sys::path::filename(isec->file->getName()));
@ -329,7 +329,7 @@ static DenseMap<const InputSection *, size_t> buildInputSectionPriorities() {
// TODO: Make sure this handles weak symbols correctly.
for (InputFile *file : inputFiles)
if (isa<ObjFile>(file) || isa<ArchiveFile>(file))
for (Symbol *sym : file->symbols)
for (lld::macho::Symbol *sym : file->symbols)
if (auto *d = dyn_cast<Defined>(sym))
addSym(*d);

View File

@ -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 ]
...

View File

@ -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 ]
...

View File

@ -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

View File

@ -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