[lld] 31d5885 - [lld-macho] Partial support for weak definitions
Jez Ng via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 24 16:16:29 PDT 2020
Author: Jez Ng
Date: 2020-07-24T15:55:25-07:00
New Revision: 31d58858425f6021d380eff879dd8983e25a5715
URL: https://github.com/llvm/llvm-project/commit/31d58858425f6021d380eff879dd8983e25a5715
DIFF: https://github.com/llvm/llvm-project/commit/31d58858425f6021d380eff879dd8983e25a5715.diff
LOG: [lld-macho] Partial support for weak definitions
This diff adds support for weak definitions, though it doesn't handle weak
symbols in dylibs quite correctly -- we need to emit binding opcodes for them
in the weak binding section rather than the lazy binding section.
What *is* covered in this diff:
1. Reading the weak flag from symbol table / export trie, and writing it to the
export trie
2. Refining the symbol table's rules for choosing one symbol definition over
another. Wrote a few dozen test cases to make sure we were matching ld64's
behavior.
We can now link basic C++ programs.
Reviewed By: #lld-macho, compnerd
Differential Revision: https://reviews.llvm.org/D83532
Added:
lld/test/MachO/weak-definition-direct-fetch.s
lld/test/MachO/weak-definition-indirect-fetch.s
lld/test/MachO/weak-definition-order.s
lld/test/MachO/weak-definition-over-dysym.s
Modified:
lld/MachO/Arch/X86_64.cpp
lld/MachO/ExportTrie.cpp
lld/MachO/InputFiles.cpp
lld/MachO/SymbolTable.cpp
lld/MachO/SymbolTable.h
lld/MachO/Symbols.h
lld/MachO/SyntheticSections.cpp
Removed:
################################################################################
diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 36f686ca2f1d..458dad805b4a 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -218,6 +218,7 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol &sym,
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<DylibSymbol>(&sym))
in.stubs->addEntry(*dysym);
break;
diff --git a/lld/MachO/ExportTrie.cpp b/lld/MachO/ExportTrie.cpp
index 7cc81bcfd5f1..993a55243532 100644
--- a/lld/MachO/ExportTrie.cpp
+++ b/lld/MachO/ExportTrie.cpp
@@ -59,6 +59,10 @@ struct Edge {
struct ExportInfo {
uint64_t address;
+ uint8_t flags;
+ explicit 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 @@ bool TrieNode::updateOffset(size_t &nextOffset) {
// 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 @@ void TrieNode::writeTo(uint8_t *buf) const {
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 @@ void TrieBuilder::sortAndBuild(MutableArrayRef<const Symbol *> vec,
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);
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 46fe82f98822..f1afc187aca2 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -228,10 +228,9 @@ void InputFile::parseSymbols(ArrayRef<structs::nlist_64> nList,
StringRef name = strtab + sym.n_strx;
if (sym.n_type & N_EXT)
// Global defined symbol
- return symtab->addDefined(name, isec, value);
- else
- // Local defined symbol
- return make<Defined>(name, isec, value);
+ return symtab->addDefined(name, isec, value, sym.n_desc & N_WEAK_DEF);
+ // Local defined symbol
+ return make<Defined>(name, isec, value, sym.n_desc & N_WEAK_DEF);
};
for (size_t i = 0, n = nList.size(); i < n; ++i) {
@@ -351,7 +350,9 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella)
auto *c = reinterpret_cast<const dyld_info_command *>(cmd);
parseTrie(buf + c->export_off, c->export_size,
[&](const Twine &name, uint64_t flags) {
- symbols.push_back(symtab->addDylib(saver.save(name), umbrella));
+ bool isWeakDef = flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+ symbols.push_back(
+ symtab->addDylib(saver.save(name), umbrella, isWeakDef));
});
} else {
error("LC_DYLD_INFO_ONLY not found in " + getName());
@@ -390,10 +391,11 @@ DylibFile::DylibFile(std::shared_ptr<llvm::MachO::InterfaceFile> interface,
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.cpp b/lld/MachO/SymbolTable.cpp
index 80e870d79890..061642d73f44 100644
--- a/lld/MachO/SymbolTable.cpp
+++ b/lld/MachO/SymbolTable.cpp
@@ -37,15 +37,23 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
}
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<Defined>(s))
- error("duplicate symbol: " + name);
-
- replaceSymbol<Defined>(s, name, isec, value);
+ if (!wasInserted) {
+ if (auto *defined = dyn_cast<Defined>(s)) {
+ if (isWeakDef)
+ return s;
+ if (!defined->isWeakDef())
+ error("duplicate symbol: " + name);
+ }
+ // Defined symbols take priority over other types of symbols, so in case
+ // of a name conflict, we fall through to the replaceSymbol() call below.
+ }
+
+ replaceSymbol<Defined>(s, name, isec, value, isWeakDef);
return s;
}
@@ -61,13 +69,15 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
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<Undefined>(s))
- replaceSymbol<DylibSymbol>(s, file, name);
+ if (wasInserted || isa<Undefined>(s) ||
+ (isa<DylibSymbol>(s) && !isWeakDef && s->isWeakDef()))
+ replaceSymbol<DylibSymbol>(s, file, name, isWeakDef);
+
return s;
}
@@ -79,7 +89,7 @@ Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file,
if (wasInserted)
replaceSymbol<LazySymbol>(s, file, sym);
- else if (isa<Undefined>(s))
+ else if (isa<Undefined>(s) || (isa<DylibSymbol>(s) && s->isWeakDef()))
file->fetch(sym);
return s;
}
diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h
index 2379008db56d..088b0e97c840 100644
--- a/lld/MachO/SymbolTable.h
+++ b/lld/MachO/SymbolTable.h
@@ -22,13 +22,20 @@ class DylibFile;
class InputSection;
class Symbol;
+/*
+ * Note that the SymbolTable handles name collisions by calling
+ * replaceSymbol(), which does an in-place update of the Symbol via `placement
+ * new`. Therefore, there is no need to update any relocations that hold
+ * pointers the "old" Symbol -- they will automatically point to the new one.
+ */
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/Symbols.h b/lld/MachO/Symbols.h
index 63748ee48324..2dcccd03a8d0 100644
--- a/lld/MachO/Symbols.h
+++ b/lld/MachO/Symbols.h
@@ -39,6 +39,8 @@ class Symbol {
LazyKind,
};
+ virtual ~Symbol() {}
+
Kind kind() const { return static_cast<Kind>(symbolKind); }
StringRef getName() const { return {name.data, name.size}; }
@@ -47,6 +49,8 @@ class Symbol {
uint64_t getFileOffset() const;
+ virtual bool isWeakDef() const { llvm_unreachable("cannot be weak"); }
+
uint32_t gotIndex = UINT32_MAX;
protected:
@@ -58,13 +62,19 @@ class Symbol {
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), isec(isec), value(value),
+ weakDef(isWeakDef) {}
+
+ bool isWeakDef() const override { return weakDef; }
+
+ static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }
InputSection *isec;
uint32_t value;
- static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }
+private:
+ const bool weakDef;
};
class Undefined : public Symbol {
@@ -76,14 +86,19 @@ class Undefined : public Symbol {
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), file(file), weakDef(isWeakDef) {}
+
+ bool isWeakDef() const override { return weakDef; }
static bool classof(const Symbol *s) { return s->kind() == DylibKind; }
DylibFile *file;
uint32_t stubsIndex = UINT32_MAX;
uint32_t lazyBindOffset = UINT32_MAX;
+
+private:
+ const bool weakDef;
};
class LazySymbol : public Symbol {
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index cc0d5a93c40d..a2d8bf42e9ed 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -264,7 +264,8 @@ void StubHelperSection::setup() {
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
index 000000000000..04c022e9c086
--- /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 --format=darwin rcs %t/foo.a %t/foo.o
+# RUN: rm -f %t/weakfoo.a
+# RUN: llvm-ar --format=darwin 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 -lfoo -lweakfoo %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
diff erent 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
index 000000000000..d22e0a370d5e
--- /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 member 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: _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: _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weakfoo.o
+
+# RUN: rm -f %t/foo.a
+# RUN: llvm-ar --format=darwin rcs %t/foo.a %t/foo.o
+# RUN: rm -f %t/weakfoo.a
+# RUN: llvm-ar --format=darwin 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
index 000000000000..6770a5f76b39
--- /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
index 000000000000..e3cf030b7149
--- /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: _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: _foo:" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/weakfoo.o
+
+# RUN: rm -f %t/foo.a
+# RUN: llvm-ar --format=darwin rcs %t/foo.a %t/foo.o
+# RUN: rm -f %t/weakfoo.a
+# RUN: llvm-ar --format=darwin 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
More information about the llvm-commits
mailing list