[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