diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -54,7 +54,8 @@ // Check for both libfoo.dylib and libfoo.tbd (in that order). llvm::Optional resolveDylibPath(llvm::StringRef path); -DylibFile *loadDylib(llvm::MemoryBufferRef mbref, DylibFile *umbrella = nullptr, +DylibFile *loadDylib(llvm::MemoryBufferRef mbref, bool forceWeakImport, + DylibFile *umbrella = nullptr, bool isBundleLoader = false); void resetLoadedDylibs(); diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -249,7 +249,8 @@ static DenseMap loadedArchives; static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive, - bool isExplicit = true, bool isBundleLoader = false) { + bool isExplicit = true, bool isBundleLoader = false, + bool forceWeakImport = false) { Optional buffer = readFile(path); if (!buffer) return nullptr; @@ -324,7 +325,7 @@ case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamically_linked_shared_lib_stub: case file_magic::tapi_file: - if (DylibFile *dylibFile = loadDylib(mbref)) { + if (DylibFile *dylibFile = loadDylib(mbref, forceWeakImport)) { if (isExplicit) dylibFile->explicitlyLinked = true; newFile = dylibFile; @@ -339,7 +340,8 @@ // as a bundle loader. if (!isBundleLoader) error(path + ": unhandled file type"); - if (DylibFile *dylibFile = loadDylib(mbref, nullptr, isBundleLoader)) + if (DylibFile *dylibFile = + loadDylib(mbref, forceWeakImport, nullptr, isBundleLoader)) newFile = dylibFile; break; default: @@ -360,11 +362,13 @@ ForceLoad forceLoadArchive) { if (Optional path = findLibrary(name)) { if (auto *dylibFile = dyn_cast_or_null( - addFile(*path, forceLoadArchive, isExplicit))) { + addFile(*path, forceLoadArchive, isExplicit, + /*isBundleLoader=*/false, isWeak))) { + + if (isWeak) + assert(dylibFile->forceWeakImport); if (isNeeded) dylibFile->forceNeeded = true; - if (isWeak) - dylibFile->forceWeakImport = true; if (isReexport) { config->hasReexports = true; dylibFile->reexport = true; @@ -380,11 +384,11 @@ ForceLoad forceLoadArchive) { if (Optional path = findFramework(name)) { if (auto *dylibFile = dyn_cast_or_null( - addFile(*path, forceLoadArchive, isExplicit))) { + addFile(*path, forceLoadArchive, isExplicit, false, isWeak))) { if (isNeeded) dylibFile->forceNeeded = true; if (isWeak) - dylibFile->forceWeakImport = true; + assert(dylibFile->forceWeakImport); if (isReexport) { config->hasReexports = true; dylibFile->reexport = true; diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -204,12 +204,14 @@ // especially if it's a commonly re-exported core library. static DenseMap loadedDylibs; -DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella, - bool isBundleLoader) { +DylibFile *macho::loadDylib(MemoryBufferRef mbref, bool forceWeakImport, + DylibFile *umbrella, bool isBundleLoader) { CachedHashStringRef path(mbref.getBufferIdentifier()); DylibFile *&file = loadedDylibs[path]; - if (file) + if (file) { + file->forceWeakImport |= forceWeakImport; return file; + } DylibFile *newFile; file_magic magic = identify_magic(mbref.getBuffer()); @@ -243,6 +245,7 @@ if (newFile->exportingFile) newFile->parseLoadCommands(mbref); } + newFile->forceWeakImport = forceWeakImport; return newFile; } diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -150,6 +150,7 @@ std::tie(s, wasInserted) = insert(name, file); RefState refState = RefState::Unreferenced; + bool wasForceWeak = false; if (!wasInserted) { if (auto *defined = dyn_cast(s)) { if (isWeakDef && !defined->isWeakDef()) @@ -158,14 +159,19 @@ refState = undefined->refState; } else if (auto *dysym = dyn_cast(s)) { refState = dysym->getRefState(); + if (DylibFile *prevFile = dysym->getFile()) + wasForceWeak = prevFile->forceWeakImport; } } bool isDynamicLookup = file == nullptr; - if (wasInserted || isa(s) || - (isa(s) && - ((!isWeakDef && s->isWeakDef()) || - (!isDynamicLookup && cast(s)->isDynamicLookup())))) { + if (!isDynamicLookup && !wasInserted && file->forceWeakImport && + !wasForceWeak) + replaceSymbol(s, file, name, isWeakDef, refState, isTlv); + else if (wasInserted || isa(s) || + (isa(s) && + ((!isWeakDef && s->isWeakDef()) || + (!isDynamicLookup && cast(s)->isDynamicLookup())))) { if (auto *dynsym = dyn_cast(s)) dynsym->unreference(); replaceSymbol(s, file, name, isWeakDef, refState, isTlv); diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -228,15 +228,20 @@ public: DylibSymbol(DylibFile *file, StringRefZ name, bool isWeakDef, RefState refState, bool isTlv) - : Symbol(DylibKind, name, file), refState(refState), weakDef(isWeakDef), - tlv(isTlv) { + : Symbol(DylibKind, name, file), refState(refState), + weakDef(isWeakDef || (file && file->forceWeakImport)), tlv(isTlv) { if (file && refState > RefState::Unreferenced) file->numReferencedSymbols++; } uint64_t getVA() const override; - bool isWeakDef() const override { return weakDef; } - bool isWeakRef() const override { return refState == RefState::Weak; } + bool isWeakDef() const override { + return weakDef || (file && dyn_cast(file)->forceWeakImport); + } + bool isWeakRef() const override { + return refState == RefState::Weak || + (file && dyn_cast(file)->forceWeakImport); + } bool isReferenced() const { return refState != RefState::Unreferenced; } bool isTlv() const override { return tlv; } bool isDynamicLookup() const { return file == nullptr; } diff --git a/lld/test/MachO/weak-import.s b/lld/test/MachO/weak-import.s --- a/lld/test/MachO/weak-import.s +++ b/lld/test/MachO/weak-import.s @@ -22,6 +22,11 @@ # RUN: %lld -lSystem -dylib %t/libfoo.dylib %t/mixed-ref.o -o %t/mixed-ref # RUN: llvm-objdump --macho --all-headers %t/mixed-ref | FileCheck %s -DDIR=%t --check-prefixes=SYS,FOO +# RUN: %lld -framework CoreFoundation %t/test.o -weak_framework CoreFoundation -o %t/strong_weak_import.out +# RUN: %lld -weak_framework CoreFoundation %t/test.o -framework CoreFoundation -o %t/weak_strong_import.out +# RUN: llvm-objdump --macho --bind %t/strong_weak_import.out | FileCheck %s --check-prefix=WEAK-IMP +# RUN: llvm-objdump --macho --bind %t/weak_strong_import.out | FileCheck %s --check-prefix=WEAK-IMP + # WEAK-SYS: cmd LC_LOAD_WEAK_DYLIB # WEAK-SYS-NEXT: cmdsize # WEAK-SYS-NEXT: name /usr/lib/libSystem.dylib @@ -42,6 +47,7 @@ # FOO-NEXT: cmdsize # FOO-NEXT: name [[DIR]]/libfoo.dylib +# WEAK-IMP: {{.+}} pointer 0 CoreFoundation __CFBigNumGetInt128 (weak_import) #--- foo.s .globl _foo _foo: @@ -69,4 +75,5 @@ #--- test.s .globl _main _main: + movq __CFBigNumGetInt128@GOTPCREL(%rip), %rax ret