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 @@ -218,6 +218,7 @@ in.got->addEntry(sym); break; case X86_64_RELOC_BRANCH: { + // TODO: weak dysyms should go into the weak binding section instead if (auto *dysym = dyn_cast(&sym)) in.stubs->addEntry(*dysym); break; diff --git a/lld/MachO/ExportTrie.h b/lld/MachO/ExportTrie.h --- a/lld/MachO/ExportTrie.h +++ b/lld/MachO/ExportTrie.h @@ -37,7 +37,7 @@ }; using TrieEntryCallback = - llvm::function_ref; + llvm::function_ref; void parseTrie(const uint8_t *buf, size_t size, const TrieEntryCallback &); diff --git a/lld/MachO/ExportTrie.cpp b/lld/MachO/ExportTrie.cpp --- a/lld/MachO/ExportTrie.cpp +++ b/lld/MachO/ExportTrie.cpp @@ -59,6 +59,10 @@ struct ExportInfo { uint64_t address; + uint8_t flags; + ExportInfo(const Symbol &sym) + : address(sym.getVA()), + flags(sym.isWeakDef ? EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION : 0) {} // TODO: Add proper support for re-exports & stub-and-resolver flags. }; @@ -83,9 +87,8 @@ // node. size_t nodeSize; if (info) { - uint64_t flags = 0; uint32_t terminalSize = - getULEB128Size(flags) + getULEB128Size(info->address); + getULEB128Size(info->flags) + getULEB128Size(info->address); // Overall node size so far is the uleb128 size of the length of the symbol // info + the symbol info itself. nodeSize = terminalSize + getULEB128Size(terminalSize); @@ -110,11 +113,10 @@ buf += offset; if (info) { // TrieNodes with Symbol info: size, flags address - uint64_t flags = 0; // TODO: emit proper flags uint32_t terminalSize = - getULEB128Size(flags) + getULEB128Size(info->address); + getULEB128Size(info->flags) + getULEB128Size(info->address); buf += encodeULEB128(terminalSize, buf); - buf += encodeULEB128(flags, buf); + buf += encodeULEB128(info->flags, buf); buf += encodeULEB128(info->address, buf); } else { // TrieNode with no Symbol info. @@ -194,7 +196,7 @@ if (isTerminal) { assert(j - i == 1); // no duplicate symbols - node->info = {pivotSymbol->getVA()}; + node->info = ExportInfo(*pivotSymbol); } else { // This is the tail-call-optimized version of the following: // sortAndBuild(vec.slice(i, j - i), node, lastPos, pos + 1); @@ -260,7 +262,7 @@ size_t offset; if (terminalSize != 0) { flags = decodeULEB128(buf, &ulebSize); - callback(cumulativeString, flags); + callback(cumulativeString, flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION); } buf += terminalSize; uint8_t numEdges = *buf++; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -226,12 +226,12 @@ auto createDefined = [&](const structs::nlist_64 &sym, InputSection *isec, uint32_t value) -> Symbol * { StringRef name = strtab + sym.n_strx; - if (sym.n_type & N_EXT) + if (sym.n_type & N_EXT) { // Global defined symbol - return symtab->addDefined(name, isec, value); - else + return symtab->addDefined(name, isec, value, sym.n_desc & N_WEAK_DEF); + } else // Local defined symbol - return make(name, isec, value); + return make(name, isec, value, sym.n_desc & N_WEAK_DEF); }; for (size_t i = 0, n = nList.size(); i < n; ++i) { @@ -350,8 +350,9 @@ if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) { auto *c = reinterpret_cast(cmd); parseTrie(buf + c->export_off, c->export_size, - [&](const Twine &name, uint64_t flags) { - symbols.push_back(symtab->addDylib(saver.save(name), umbrella)); + [&](const Twine &name, bool isWeakDef) { + symbols.push_back( + symtab->addDylib(saver.save(name), umbrella, isWeakDef)); }); } else { error("LC_DYLD_INFO_ONLY not found in " + getName()); @@ -390,10 +391,11 @@ dylibName = saver.save(interface->getInstallName()); // TODO(compnerd) filter out symbols based on the target platform + // TODO: handle weak defs for (const auto symbol : interface->symbols()) if (symbol->getArchitectures().has(config->arch)) - symbols.push_back( - symtab->addDylib(saver.save(symbol->getName()), umbrella)); + symbols.push_back(symtab->addDylib(saver.save(symbol->getName()), + umbrella, /*isWeakDef*/ false)); // 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. diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -24,11 +24,12 @@ class SymbolTable { public: - Symbol *addDefined(StringRef name, InputSection *isec, uint32_t value); + Symbol *addDefined(StringRef name, InputSection *isec, uint32_t value, + bool isWeakDef); Symbol *addUndefined(StringRef name); - Symbol *addDylib(StringRef name, DylibFile *file); + Symbol *addDylib(StringRef name, DylibFile *file, bool isWeakDef); Symbol *addLazy(StringRef name, ArchiveFile *file, const llvm::object::Archive::Symbol &sym); diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -37,15 +37,21 @@ } Symbol *SymbolTable::addDefined(StringRef name, InputSection *isec, - uint32_t value) { + uint32_t value, bool isWeakDef) { Symbol *s; bool wasInserted; std::tie(s, wasInserted) = insert(name); - if (!wasInserted && isa(s)) - error("duplicate symbol: " + name); + if (!wasInserted) { + if (auto *defined = dyn_cast(s)) { + if (isWeakDef) + return s; + if (!defined->isWeakDef) + error("duplicate symbol: " + name); + } + } - replaceSymbol(s, name, isec, value); + replaceSymbol(s, name, isec, value, isWeakDef); return s; } @@ -61,13 +67,15 @@ return s; } -Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file) { +Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef) { Symbol *s; bool wasInserted; std::tie(s, wasInserted) = insert(name); - if (wasInserted || isa(s)) - replaceSymbol(s, file, name); + if (wasInserted || isa(s) || + (isa(s) && !isWeakDef && s->isWeakDef)) + replaceSymbol(s, file, name, isWeakDef); + return s; } @@ -79,7 +87,7 @@ if (wasInserted) replaceSymbol(s, file, sym); - else if (isa(s)) + else if (isa(s) || (isa(s) && s->isWeakDef)) file->fetch(sym); return s; } diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -49,8 +49,12 @@ uint32_t gotIndex = UINT32_MAX; + // This bool is only meaningful for Defineds and DylibSymbols. + const bool isWeakDef; + protected: - Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {} + Symbol(Kind k, StringRefZ name, bool isWeakDef) + : isWeakDef(isWeakDef), symbolKind(k), name(name) {} Kind symbolKind; StringRefZ name; @@ -58,8 +62,8 @@ class Defined : public Symbol { public: - Defined(StringRefZ name, InputSection *isec, uint32_t value) - : Symbol(DefinedKind, name), isec(isec), value(value) {} + Defined(StringRefZ name, InputSection *isec, uint32_t value, bool isWeakDef) + : Symbol(DefinedKind, name, isWeakDef), isec(isec), value(value) {} InputSection *isec; uint32_t value; @@ -69,15 +73,16 @@ class Undefined : public Symbol { public: - Undefined(StringRefZ name) : Symbol(UndefinedKind, name) {} + Undefined(StringRefZ name) + : Symbol(UndefinedKind, name, /*isWeakDef*/ true) {} static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } }; class DylibSymbol : public Symbol { public: - DylibSymbol(DylibFile *file, StringRefZ name) - : Symbol(DylibKind, name), file(file) {} + DylibSymbol(DylibFile *file, StringRefZ name, bool isWeakDef) + : Symbol(DylibKind, name, isWeakDef), file(file) {} static bool classof(const Symbol *s) { return s->kind() == DylibKind; } @@ -89,7 +94,7 @@ class LazySymbol : public Symbol { public: LazySymbol(ArchiveFile *file, const llvm::object::Archive::Symbol &sym) - : Symbol(LazyKind, sym.getName()), file(file), sym(sym) {} + : Symbol(LazyKind, sym.getName(), false), file(file), sym(sym) {} static bool classof(const Symbol *s) { return s->kind() == LazyKind; } diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -264,7 +264,8 @@ in.got->addEntry(*stubBinder); inputSections.push_back(in.imageLoaderCache); - symtab->addDefined("__dyld_private", in.imageLoaderCache, 0); + symtab->addDefined("__dyld_private", in.imageLoaderCache, 0, + /*isWeakDef*/ false); } ImageLoaderCacheSection::ImageLoaderCacheSection() { diff --git a/lld/test/MachO/weak-definition-direct-fetch.s b/lld/test/MachO/weak-definition-direct-fetch.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/weak-definition-direct-fetch.s @@ -0,0 +1,90 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t + +## This test exercises the various possible combinations of weak and non-weak +## symbols that get referenced directly by a relocation in an object file. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: echo ".globl _foo; .section __TEXT,nonweak; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/foo.o +# RUN: echo ".globl _foo; .weak_definition _foo; .section __TEXT,weak; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weakfoo.o + +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libfoo.dylib %t/foo.o -o %t/libfoo.dylib +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libweakfoo.dylib %t/weakfoo.o -o %t/libweakfoo.dylib + +# RUN: llvm-objdump --macho --exports-trie %t/libweakfoo.dylib | FileCheck %s --check-prefix WEAK-DYLIB-CHECK +# WEAK-DYLIB-CHECK: _foo [weak_def] + +## Make sure we are using the export trie and not the symbol table when linking +## against these dylibs. +# RUN: llvm-strip %t/libfoo.dylib +# RUN: llvm-strip %t/libweakfoo.dylib +# RUN: llvm-nm %t/libfoo.dylib 2>&1 | FileCheck %s --check-prefix=NOSYM +# RUN: llvm-nm %t/libweakfoo.dylib 2>&1 | FileCheck %s --check-prefix=NOSYM +# NOSYM: no symbols + +# RUN: rm -f %t/foo.a +# RUN: llvm-ar rcs %t/foo.a %t/foo.o +# RUN: rm -f %t/weakfoo.a +# RUN: llvm-ar rcs %t/weakfoo.a %t/weakfoo.o + +## End of input file setup. The following lines check which symbol "wins" when +## there are multiple definitions. + +# PREFER-NONWEAK-DYLIB: __DATA __la_symbol_ptr 0x{{[0-9a-f]+}} libfoo _foo +# PREFER-WEAK-OBJECT: O __TEXT,weak _foo +# PREFER-NONWEAK-OBJECT: O __TEXT,nonweak _foo + +## First, we test the cases where the symbols are of the same type (both from a +## dylib, or both from an archive, etc.) +## +## For dylibs and object files, the non-weak symbol always wins. But the weak +## flag has no effect when we are dealing with two archive symbols. + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-nonweak-dylibs -Z -L%t -lweakfoo -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-nonweak-dylibs | FileCheck %s --check-prefix=PREFER-NONWEAK-DYLIB +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-weak-dylibs -Z -L%t -lweakfoo -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-weak-dylibs | FileCheck %s --check-prefix=PREFER-NONWEAK-DYLIB + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-nonweak-objs -Z -L%t %t/weakfoo.o %t/foo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-nonweak-objs | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-weak-objs -Z -L%t %t/foo.o %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-weak-objs | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-nonweak-archives -Z -L%t %t/weakfoo.a %t/foo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-nonweak-archives | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-weak-archives -Z -L%t %t/foo.a %t/weakfoo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-weak-archives | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT + +## The remaining lines test symbol pairs of different types. + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-dylib-weak-ar -Z -L%t -lweakfoo %t/weakfoo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-dylib-weak-ar | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-ar-weak-dylib -Z -L%t %t/weakfoo.a -lweakfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-ar-weak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-ar-nonweak-dylib -Z -L%t %t/weakfoo.a -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-ar-nonweak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-dylib-weak-ar -Z -L%t -lfoo %t/weakfoo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-dylib-weak-ar | FileCheck %s --check-prefix=PREFER-NONWEAK-DYLIB + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-dylib-weak-obj -Z -L%t -lweakfoo %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-dylib-weak-obj | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-obj-weak-dylib -Z -L%t %t/weakfoo.o -lweakfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-obj-weak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-obj-nonweak-dylib -Z -L%t %t/weakfoo.o -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-obj-nonweak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-dylib-weak-obj -Z -L%t -lfoo %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-dylib-weak-obj | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-obj-nonweak-ar -Z -L%t %t/weakfoo.o %t/foo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-obj-nonweak-ar | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-ar-weak-obj -Z -L%t %t/foo.a %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-ar-weak-obj | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +.globl _main +_main: + callq _foo + ret diff --git a/lld/test/MachO/weak-definition-indirect-fetch.s b/lld/test/MachO/weak-definition-indirect-fetch.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/weak-definition-indirect-fetch.s @@ -0,0 +1,42 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t + +## This tests examines the effect of .weak_definition on symbols in an archive +## that are not referenced directly, but which are still loaded due to some +## other symbol in the archive being referenced. +## +## In this particular test, _foo isn't referenced directly, but both archives +## will be fetched when linking against the main test file due to its references +## to _bar and _baz. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: echo ".globl _foo, _bar; .section __TEXT,nonweak; _bar: callq _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/foo.o +# RUN: echo ".globl _foo, _baz; .weak_definition _foo; .section __TEXT,weak; _baz: callq _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weakfoo.o + +# RUN: rm -f %t/foo.a +# RUN: llvm-ar rcs %t/foo.a %t/foo.o +# RUN: rm -f %t/weakfoo.a +# RUN: llvm-ar rcs %t/weakfoo.a %t/weakfoo.o + +# PREFER-NONWEAK-OBJECT: O __TEXT,nonweak _foo + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-nonweak-archives -Z -L%t %t/weakfoo.a %t/foo.a %t/test.o +# RUN: llvm-objdump --syms %t/weak-nonweak-archives | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-weak-archives -Z -L%t %t/foo.a %t/weakfoo.a %t/test.o +# RUN: llvm-objdump --syms %t/nonweak-weak-archives | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-nonweak-objs -Z -L%t %t/weakfoo.o %t/foo.o %t/test.o +# RUN: llvm-objdump --syms %t/weak-nonweak-objs | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-weak-objs -Z -L%t %t/foo.o %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --syms %t/nonweak-weak-objs | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-obj-nonweak-ar -Z -L%t %t/weakfoo.o %t/foo.a %t/test.o +# RUN: llvm-objdump --syms %t/weak-obj-nonweak-ar | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-ar-weak-obj -Z -L%t %t/foo.a %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --syms %t/nonweak-ar-weak-obj | FileCheck %s --check-prefix=PREFER-NONWEAK-OBJECT + +.globl _main +_main: + callq _bar + callq _baz + ret diff --git a/lld/test/MachO/weak-definition-order.s b/lld/test/MachO/weak-definition-order.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/weak-definition-order.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t + +## This test demonstrates that when we have two weak symbols of the same type, +## we pick the one whose containing file appears earlier in the command-line +## invocation. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: echo ".globl _foo; .weak_definition _foo; .section __TEXT,weak1; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weak1.o +# RUN: echo ".globl _foo; .weak_definition _foo; .section __TEXT,weak2; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weak2.o + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/obj12 -Z -L%t %t/weak1.o %t/weak2.o %t/test.o +# RUN: llvm-objdump --syms %t/obj12 | FileCheck %s --check-prefix=WEAK1 +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/obj21 -Z -L%t %t/weak2.o %t/weak1.o %t/test.o +# RUN: llvm-objdump --syms %t/obj21 | FileCheck %s --check-prefix=WEAK2 + +# WEAK1: O __TEXT,weak1 _foo +# WEAK2: O __TEXT,weak2 _foo + +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libweak1.dylib %t/weak1.o -o %t/libweak1.dylib +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libweak2.dylib %t/weak2.o -o %t/libweak2.dylib + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/dylib12 -Z -L%t -lweak1 -lweak2 %t/test.o +# RUN: llvm-objdump --macho --lazy-bind %t/dylib12 | FileCheck %s --check-prefix=DYLIB1 +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/dylib21 -Z -L%t -lweak2 -lweak1 %t/test.o +# RUN: llvm-objdump --macho --lazy-bind %t/dylib21 | FileCheck %s --check-prefix=DYLIB2 +## TODO: these should really be in the weak binding section, not the lazy binding section +# DYLIB1: __DATA __la_symbol_ptr 0x{{[0-9a-f]*}} libweak1 _foo +# DYLIB2: __DATA __la_symbol_ptr 0x{{[0-9a-f]*}} libweak2 _foo + +.globl _main +_main: + callq _foo + ret diff --git a/lld/test/MachO/weak-definition-over-dysym.s b/lld/test/MachO/weak-definition-over-dysym.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/weak-definition-over-dysym.s @@ -0,0 +1,39 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t + +## This test demonstrates that when an archive file is fetched, its symbols +## always override any conflicting dylib symbols, regardless of any weak +## definition flags. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: echo ".globl _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/libfoo.o +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libfoo.dylib %t/libfoo.o -o %t/libfoo.dylib + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: echo ".globl _foo, _bar; .section __TEXT,nonweak; _bar: callq _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/foo.o +# RUN: echo ".globl _foo, _bar; .weak_definition _foo; .section __TEXT,weak; _bar: callq _foo; _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weakfoo.o + +# RUN: rm -f %t/foo.a +# RUN: llvm-ar rcs %t/foo.a %t/foo.o +# RUN: rm -f %t/weakfoo.a +# RUN: llvm-ar rcs %t/weakfoo.a %t/weakfoo.o + +# PREFER-WEAK-OBJECT: O __TEXT,weak _foo +# PREFER-NONWEAK-OBJECT: O __TEXT,nonweak _foo + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-dylib-weak-ar -Z -L%t -lfoo %t/weakfoo.a %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-dylib-weak-ar | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-ar-nonweak-dylib -Z -L%t %t/weakfoo.a -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-ar-nonweak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/weak-obj-nonweak-dylib -Z -L%t %t/weakfoo.o -lfoo %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/weak-obj-nonweak-dylib | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -o %t/nonweak-dylib-weak-obj -Z -L%t -lfoo %t/weakfoo.o %t/test.o +# RUN: llvm-objdump --macho --lazy-bind --syms %t/nonweak-dylib-weak-obj | FileCheck %s --check-prefix=PREFER-WEAK-OBJECT + +.globl _main +_main: + callq _foo + callq _bar + ret