[lld] e263287 - [lld-macho] Implement weak binding for branch relocations

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 17:44:39 PDT 2020


Author: Jez Ng
Date: 2020-08-27T17:44:15-07:00
New Revision: e263287c797f7d143cf2f38e2df1d5fcee94f9b0

URL: https://github.com/llvm/llvm-project/commit/e263287c797f7d143cf2f38e2df1d5fcee94f9b0
DIFF: https://github.com/llvm/llvm-project/commit/e263287c797f7d143cf2f38e2df1d5fcee94f9b0.diff

LOG: [lld-macho] Implement weak binding for branch relocations

Since there is no "weak lazy" lookup, function calls to weak symbols are
always non-lazily bound. We emit both regular non-lazy bindings as well
as weak bindings, in order that the weak bindings may overwrite the
non-lazy bindings if an appropriate symbol is found at runtime. However,
the bound addresses will still be written (non-lazily) into the
LazyPointerSection.

Reviewed By: #lld-macho, smeenai

Differential Revision: https://reviews.llvm.org/D86573

Added: 
    

Modified: 
    lld/MachO/Arch/X86_64.cpp
    lld/MachO/Symbols.h
    lld/MachO/SyntheticSections.cpp
    lld/MachO/SyntheticSections.h
    lld/MachO/Target.h
    lld/MachO/Writer.cpp
    lld/test/MachO/weak-binding.s
    lld/test/MachO/weak-definition-order.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 41c797513014..354a47bf0465 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -29,7 +29,7 @@ struct X86_64 : TargetInfo {
                              const relocation_info &) const override;
   void relocateOne(uint8_t *loc, const Reloc &, uint64_t val) const override;
 
-  void writeStub(uint8_t *buf, const DylibSymbol &) const override;
+  void writeStub(uint8_t *buf, const macho::Symbol &) const override;
   void writeStubHelperHeader(uint8_t *buf) const override;
   void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
                             uint64_t entryAddr) const override;
@@ -182,7 +182,7 @@ static constexpr uint8_t stub[] = {
     0xff, 0x25, 0, 0, 0, 0, // jmpq *__la_symbol_ptr(%rip)
 };
 
-void X86_64::writeStub(uint8_t *buf, const DylibSymbol &sym) const {
+void X86_64::writeStub(uint8_t *buf, const macho::Symbol &sym) const {
   memcpy(buf, stub, 2); // just copy the two nonzero bytes
   uint64_t stubAddr = in.stubs->addr + sym.stubsIndex * sizeof(stub);
   writeRipRelative(buf, stubAddr, sizeof(stub),
@@ -231,9 +231,23 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol *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);
+    if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
+      if (in.stubs->addEntry(dysym)) {
+        if (sym->isWeakDef()) {
+          in.binding->addEntry(dysym, in.lazyPointers,
+                               sym->stubsIndex * WordSize);
+          in.weakBinding->addEntry(sym, in.lazyPointers,
+                                   sym->stubsIndex * WordSize);
+        } else {
+          in.lazyBinding->addEntry(dysym);
+        }
+      }
+    } else if (auto *defined = dyn_cast<Defined>(sym)) {
+      if (defined->isWeakDef() && defined->isExternal())
+        if (in.stubs->addEntry(sym))
+          in.weakBinding->addEntry(sym, in.lazyPointers,
+                                   sym->stubsIndex * WordSize);
+    }
     break;
   }
   case X86_64_RELOC_UNSIGNED: {
@@ -277,10 +291,11 @@ uint64_t X86_64::resolveSymbolVA(uint8_t *buf, const lld::macho::Symbol &sym,
   case X86_64_RELOC_GOT_LOAD:
   case X86_64_RELOC_GOT:
     return in.got->addr + sym.gotIndex * WordSize;
-  case X86_64_RELOC_BRANCH:
-    if (auto *dysym = dyn_cast<DylibSymbol>(&sym))
-      return in.stubs->addr + dysym->stubsIndex * sizeof(stub);
+  case X86_64_RELOC_BRANCH: {
+    if (sym.isInStubs())
+      return in.stubs->addr + sym.stubsIndex * sizeof(stub);
     return sym.getVA();
+  }
   case X86_64_RELOC_UNSIGNED:
   case X86_64_RELOC_SIGNED:
   case X86_64_RELOC_SIGNED_1:

diff  --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h
index 90fdd5e01eea..a8b8540378d7 100644
--- a/lld/MachO/Symbols.h
+++ b/lld/MachO/Symbols.h
@@ -60,11 +60,16 @@ class Symbol {
   // Whether this symbol is in the GOT or TLVPointer sections.
   bool isInGot() const { return gotIndex != UINT32_MAX; }
 
+  // Whether this symbol is in the StubsSection.
+  bool isInStubs() const { return stubsIndex != UINT32_MAX; }
+
   // The index of this symbol in the GOT or the TLVPointer section, depending
   // on whether it is a thread-local. A given symbol cannot be referenced by
   // both these sections at once.
   uint32_t gotIndex = UINT32_MAX;
 
+  uint32_t stubsIndex = UINT32_MAX;
+
 protected:
   Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {}
 
@@ -114,13 +119,13 @@ class DylibSymbol : public Symbol {
       : Symbol(DylibKind, name), file(file), weakDef(isWeakDef), tlv(isTlv) {}
 
   bool isWeakDef() const override { return weakDef; }
-
   bool isTlv() const override { return tlv; }
+  bool hasStubsHelper() const { return stubsHelperIndex != UINT32_MAX; }
 
   static bool classof(const Symbol *s) { return s->kind() == DylibKind; }
 
   DylibFile *file;
-  uint32_t stubsIndex = UINT32_MAX;
+  uint32_t stubsHelperIndex = UINT32_MAX;
   uint32_t lazyBindOffset = UINT32_MAX;
 
 private:

diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 2b46a45c34e2..35a76e002dc2 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -277,15 +277,17 @@ uint64_t StubsSection::getSize() const {
 
 void StubsSection::writeTo(uint8_t *buf) const {
   size_t off = 0;
-  for (const DylibSymbol *sym : in.stubs->getEntries()) {
+  for (const Symbol *sym : entries) {
     target->writeStub(buf + off, *sym);
     off += target->stubSize;
   }
 }
 
-void StubsSection::addEntry(DylibSymbol *sym) {
-  if (entries.insert(sym))
+bool StubsSection::addEntry(Symbol *sym) {
+  bool inserted = entries.insert(sym);
+  if (inserted)
     sym->stubsIndex = entries.size() - 1;
+  return inserted;
 }
 
 StubHelperSection::StubHelperSection()
@@ -293,17 +295,15 @@ StubHelperSection::StubHelperSection()
 
 uint64_t StubHelperSection::getSize() const {
   return target->stubHelperHeaderSize +
-         in.stubs->getEntries().size() * target->stubHelperEntrySize;
+         in.lazyBinding->getEntries().size() * target->stubHelperEntrySize;
 }
 
-bool StubHelperSection::isNeeded() const {
-  return !in.stubs->getEntries().empty();
-}
+bool StubHelperSection::isNeeded() const { return in.lazyBinding->isNeeded(); }
 
 void StubHelperSection::writeTo(uint8_t *buf) const {
   target->writeStubHelperHeader(buf);
   size_t off = target->stubHelperHeaderSize;
-  for (const DylibSymbol *sym : in.stubs->getEntries()) {
+  for (const DylibSymbol *sym : in.lazyBinding->getEntries()) {
     target->writeStubHelperEntry(buf + off, *sym, addr + off);
     off += target->stubHelperEntrySize;
   }
@@ -347,10 +347,17 @@ bool LazyPointerSection::isNeeded() const {
 
 void LazyPointerSection::writeTo(uint8_t *buf) const {
   size_t off = 0;
-  for (const DylibSymbol *sym : in.stubs->getEntries()) {
-    uint64_t stubHelperOffset = target->stubHelperHeaderSize +
-                                sym->stubsIndex * target->stubHelperEntrySize;
-    write64le(buf + off, in.stubHelper->addr + stubHelperOffset);
+  for (const Symbol *sym : in.stubs->getEntries()) {
+    if (const auto *dysym = dyn_cast<DylibSymbol>(sym)) {
+      if (dysym->hasStubsHelper()) {
+        uint64_t stubHelperOffset =
+            target->stubHelperHeaderSize +
+            dysym->stubsHelperIndex * target->stubHelperEntrySize;
+        write64le(buf + off, in.stubHelper->addr + stubHelperOffset);
+      }
+    } else {
+      write64le(buf + off, sym->getVA());
+    }
     off += WordSize;
   }
 }
@@ -358,12 +365,10 @@ void LazyPointerSection::writeTo(uint8_t *buf) const {
 LazyBindingSection::LazyBindingSection()
     : LinkEditSection(segment_names::linkEdit, section_names::lazyBinding) {}
 
-bool LazyBindingSection::isNeeded() const { return in.stubs->isNeeded(); }
-
 void LazyBindingSection::finalizeContents() {
   // TODO: Just precompute output size here instead of writing to a temporary
   // buffer
-  for (DylibSymbol *sym : in.stubs->getEntries())
+  for (DylibSymbol *sym : entries)
     sym->lazyBindOffset = encode(*sym);
 }
 
@@ -371,6 +376,11 @@ void LazyBindingSection::writeTo(uint8_t *buf) const {
   memcpy(buf, contents.data(), contents.size());
 }
 
+void LazyBindingSection::addEntry(DylibSymbol *dysym) {
+  if (entries.insert(dysym))
+    dysym->stubsHelperIndex = entries.size() - 1;
+}
+
 // Unlike the non-lazy binding section, the bind opcodes in this section aren't
 // interpreted all at once. Rather, dyld will start interpreting opcodes at a
 // given offset, typically only binding a single symbol before it finds a

diff  --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 1c393eb3f874..c1e938809c8a 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -222,13 +222,15 @@ void addNonLazyBindingEntries(const Symbol *, SectionPointerUnion,
 // The following sections implement lazy symbol binding -- very similar to the
 // PLT mechanism in ELF.
 //
-// ELF's .plt section is broken up into two sections in Mach-O: StubsSection and
-// StubHelperSection. Calls to functions in dylibs will end up calling into
+// ELF's .plt section is broken up into two sections in Mach-O: StubsSection
+// and StubHelperSection. Calls to functions in dylibs will end up calling into
 // StubsSection, which contains indirect jumps to addresses stored in the
 // LazyPointerSection (the counterpart to ELF's .plt.got).
 //
-// Initially, the LazyPointerSection contains addresses that point into one of
-// the entry points in the middle of the StubHelperSection. The code in
+// We will first describe how non-weak symbols are handled.
+//
+// At program start, the LazyPointerSection contains addresses that point into
+// one of the entry points in the middle of the StubHelperSection. The code in
 // StubHelperSection will push on the stack an offset into the
 // LazyBindingSection. The push is followed by a jump to the beginning of the
 // StubHelperSection (similar to PLT0), which then calls into dyld_stub_binder.
@@ -236,10 +238,17 @@ void addNonLazyBindingEntries(const Symbol *, SectionPointerUnion,
 // the GOT.
 //
 // The stub binder will look up the bind opcodes in the LazyBindingSection at
-// the given offset. The bind opcodes will tell the binder to update the address
-// in the LazyPointerSection to point to the symbol, so that subsequent calls
-// don't have to redo the symbol resolution. The binder will then jump to the
-// resolved symbol.
+// the given offset. The bind opcodes will tell the binder to update the
+// address in the LazyPointerSection to point to the symbol, so that subsequent
+// calls don't have to redo the symbol resolution. The binder will then jump to
+// the resolved symbol.
+//
+// With weak symbols, the situation is slightly 
diff erent. Since there is no
+// "weak lazy" lookup, function calls to weak symbols are always non-lazily
+// bound. We emit both regular non-lazy bindings as well as weak bindings, in
+// order that the weak bindings may overwrite the non-lazy bindings if an
+// appropriate symbol is found at runtime. However, the bound addresses will
+// still be written (non-lazily) into the LazyPointerSection.
 
 class StubsSection : public SyntheticSection {
 public:
@@ -247,13 +256,13 @@ class StubsSection : public SyntheticSection {
   uint64_t getSize() const override;
   bool isNeeded() const override { return !entries.empty(); }
   void writeTo(uint8_t *buf) const override;
-
-  const llvm::SetVector<DylibSymbol *> &getEntries() const { return entries; }
-
-  void addEntry(DylibSymbol *sym);
+  const llvm::SetVector<Symbol *> &getEntries() const { return entries; }
+  // Returns whether the symbol was added. Note that every stubs entry will
+  // have a corresponding entry in the LazyPointerSection.
+  bool addEntry(Symbol *);
 
 private:
-  llvm::SetVector<DylibSymbol *> entries;
+  llvm::SetVector<Symbol *> entries;
 };
 
 class StubHelperSection : public SyntheticSection {
@@ -278,6 +287,8 @@ class ImageLoaderCacheSection : public InputSection {
   uint64_t getSize() const override { return WordSize; }
 };
 
+// Note that this section may also be targeted by non-lazy bindings. In
+// particular, this happens when branch relocations target weak symbols.
 class LazyPointerSection : public SyntheticSection {
 public:
   LazyPointerSection();
@@ -291,15 +302,21 @@ class LazyBindingSection : public LinkEditSection {
   LazyBindingSection();
   void finalizeContents();
   uint64_t getRawSize() const override { return contents.size(); }
-  uint32_t encode(const DylibSymbol &);
   // Like other sections in __LINKEDIT, the lazy binding section is special: its
   // offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
   // section headers.
   bool isHidden() const override { return true; }
-  bool isNeeded() const override;
+  bool isNeeded() const override { return !entries.empty(); }
   void writeTo(uint8_t *buf) const override;
+  // Note that every entry here will by referenced by a corresponding entry in
+  // the StubHelperSection.
+  void addEntry(DylibSymbol *dysym);
+  const llvm::SetVector<DylibSymbol *> &getEntries() const { return entries; }
 
 private:
+  uint32_t encode(const DylibSymbol &);
+
+  llvm::SetVector<DylibSymbol *> entries;
   SmallVector<char, 128> contents;
   llvm::raw_svector_ostream os{contents};
 };
@@ -368,6 +385,7 @@ struct InStruct {
   MachHeaderSection *header = nullptr;
   BindingSection *binding = nullptr;
   WeakBindingSection *weakBinding = nullptr;
+  LazyBindingSection *lazyBinding = nullptr;
   GotSection *got = nullptr;
   TlvPointerSection *tlvPointers = nullptr;
   LazyPointerSection *lazyPointers = nullptr;

diff  --git a/lld/MachO/Target.h b/lld/MachO/Target.h
index a2efe506864d..d80da011e286 100644
--- a/lld/MachO/Target.h
+++ b/lld/MachO/Target.h
@@ -44,7 +44,7 @@ class TargetInfo {
 
   // Write code for lazy binding. See the comments on StubsSection for more
   // details.
-  virtual void writeStub(uint8_t *buf, const DylibSymbol &) const = 0;
+  virtual void writeStub(uint8_t *buf, const Symbol &) const = 0;
   virtual void writeStubHelperHeader(uint8_t *buf) const = 0;
   virtual void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
                                     uint64_t entryAddr) const = 0;

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 923c0407fa6e..437852cf4fbf 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -55,7 +55,6 @@ class Writer {
   uint64_t addr = 0;
   uint64_t fileOff = 0;
   MachHeaderSection *header = nullptr;
-  LazyBindingSection *lazyBindingSection = nullptr;
   ExportSection *exportSection = nullptr;
   StringTableSection *stringTableSection = nullptr;
   SymtabSection *symtabSection = nullptr;
@@ -327,8 +326,8 @@ void Writer::scanRelocations() {
 }
 
 void Writer::createLoadCommands() {
-  in.header->addLoadCommand(make<LCDyldInfo>(
-      in.binding, in.weakBinding, lazyBindingSection, exportSection));
+  in.header->addLoadCommand(make<LCDyldInfo>(in.binding, in.weakBinding,
+                                             in.lazyBinding, exportSection));
   in.header->addLoadCommand(make<LCSymtab>(symtabSection, stringTableSection));
   in.header->addLoadCommand(make<LCDysymtab>());
   for (StringRef path : config->runtimePaths)
@@ -473,7 +472,6 @@ static void sortSegmentsAndSections() {
 
 void Writer::createOutputSections() {
   // First, create hidden sections
-  lazyBindingSection = make<LazyBindingSection>();
   stringTableSection = make<StringTableSection>();
   symtabSection = make<SymtabSection>(*stringTableSection);
   exportSection = make<ExportSection>();
@@ -585,7 +583,7 @@ void Writer::run() {
   // Fill __LINKEDIT contents.
   in.binding->finalizeContents();
   in.weakBinding->finalizeContents();
-  lazyBindingSection->finalizeContents();
+  in.lazyBinding->finalizeContents();
   exportSection->finalizeContents();
   symtabSection->finalizeContents();
 
@@ -609,6 +607,7 @@ void macho::createSyntheticSections() {
   in.header = make<MachHeaderSection>();
   in.binding = make<BindingSection>();
   in.weakBinding = make<WeakBindingSection>();
+  in.lazyBinding = make<LazyBindingSection>();
   in.got = make<GotSection>();
   in.tlvPointers = make<TlvPointerSection>();
   in.lazyPointers = make<LazyPointerSection>();

diff  --git a/lld/test/MachO/weak-binding.s b/lld/test/MachO/weak-binding.s
index e8b0e1785ffa..6f5c559994e8 100644
--- a/lld/test/MachO/weak-binding.s
+++ b/lld/test/MachO/weak-binding.s
@@ -4,13 +4,18 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
 # RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -dylib %t/libfoo.o -o %t/libfoo.dylib
 # RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk %t/test.o -L%t -lfoo -o %t/test -lSystem
-# RUN: llvm-objdump -d --no-show-raw-insn --bind --weak-bind --full-contents %t/test | \
+# RUN: llvm-objdump -d --no-show-raw-insn --bind --lazy-bind --weak-bind --full-contents %t/test | \
 # RUN:   FileCheck %s
 
+# CHECK:      Contents of section __la_symbol_ptr:
+## Check that this section contains a nonzero pointer. It should point to
+## _weak_external_fn, but we don't have a good way of testing the exact value as
+## the bytes here are in little-endian order.
+# CHECK-NEXT: {{[0-9a-f]+}} {{[0-9a-f ]*[1-9a-f]+[0-9a-f ]*}}
+
 # CHECK:      Contents of section __got:
 ## Check that this section contains a nonzero pointer. It should point to
-## _weak_external_for_gotpcrel, but we don't have a good way of testing the exact
-## value as the bytes here are in little-endian order.
+## _weak_external_for_gotpcrel.
 # CHECK-NEXT: {{[0-9a-f]+}} {{[0-9a-f ]*[1-9a-f]+[0-9a-f ]*}}
 
 # CHECK:      <_main>:
@@ -19,28 +24,39 @@
 # CHECK-NEXT: movq	[[#]](%rip), %rax  # [[#%X,WEAK_TLV_ADDR:]]
 # CHECK-NEXT: movq	[[#]](%rip), %rax  # [[#%X,WEAK_DY_TLV_ADDR:]]
 # CHECK-NEXT: movq	[[#]](%rip), %rax  # [[#%X,WEAK_INT_TLV_ADDR:]]
+# CHECK-NEXT: callq 0x{{[0-9a-f]*}}
+# CHECK-NEXT: callq 0x{{[0-9a-f]*}}
+# CHECK-NEXT: callq 0x{{[0-9a-f]*}}
 
 # CHECK-LABEL: Bind table:
-# CHECK-DAG:   __DATA        __data        0x[[#%x,WEAK_DY:]]      pointer 0 libfoo    _weak_dysym
-# CHECK-DAG:   __DATA        __thread_vars 0x{{[0-9a-f]*}}         pointer 0 libSystem __tlv_bootstrap
-# CHECK-DAG:   __DATA        __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]] pointer 0 libfoo    _weak_dysym_tlv
-# CHECK-DAG:   __DATA_CONST  __got         0x[[#WEAK_DY_GOT_ADDR]] pointer 0 libfoo    _weak_dysym_for_gotpcrel
+# CHECK-DAG:   __DATA        __data          0x[[#%x,WEAK_DY:]]      pointer 0 libfoo    _weak_dysym
+# CHECK-DAG:   __DATA        __thread_vars   0x{{[0-9a-f]*}}         pointer 0 libSystem __tlv_bootstrap
+# CHECK-DAG:   __DATA        __thread_ptrs   0x[[#WEAK_DY_TLV_ADDR]] pointer 0 libfoo    _weak_dysym_tlv
+# CHECK-DAG:   __DATA_CONST  __got           0x[[#WEAK_DY_GOT_ADDR]] pointer 0 libfoo    _weak_dysym_for_gotpcrel
+# CHECK-DAG:   __DATA        __la_symbol_ptr 0x[[#%x,WEAK_DY_FN:]]   pointer 0 libfoo    _weak_dysym_fn
 ## Check that we don't have any other bindings
 # CHECK-NOT:   pointer
 
+# CHECK-LABEL: Lazy bind table:
+## Verify that we have no lazy bindings
+# CHECK-NOT:   pointer
+
 # CHECK-LABEL: Weak bind table:
-# CHECK-DAG:   __DATA_CONST __got         0x[[#WEAK_DY_GOT_ADDR]]   pointer 0 _weak_dysym_for_gotpcrel
-# CHECK-DAG:   __DATA_CONST __got         0x[[#WEAK_EXT_GOT_ADDR]]  pointer 0 _weak_external_for_gotpcrel
-# CHECK-DAG:   __DATA       __data        0x[[#WEAK_DY]]            pointer 0 _weak_dysym
-# CHECK-DAG:   __DATA       __thread_ptrs 0x[[#WEAK_TLV_ADDR]]      pointer 0 _weak_tlv
-# CHECK-DAG:   __DATA       __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]]   pointer 0 _weak_dysym_tlv
-# CHECK-DAG:   __DATA       __data        0x{{[0-9a-f]*}}           pointer 2 _weak_external
+# CHECK-DAG:   __DATA_CONST __got           0x[[#WEAK_DY_GOT_ADDR]]   pointer 0 _weak_dysym_for_gotpcrel
+# CHECK-DAG:   __DATA_CONST __got           0x[[#WEAK_EXT_GOT_ADDR]]  pointer 0 _weak_external_for_gotpcrel
+# CHECK-DAG:   __DATA       __data          0x[[#WEAK_DY]]            pointer 0 _weak_dysym
+# CHECK-DAG:   __DATA       __thread_ptrs   0x[[#WEAK_TLV_ADDR]]      pointer 0 _weak_tlv
+# CHECK-DAG:   __DATA       __thread_ptrs   0x[[#WEAK_DY_TLV_ADDR]]   pointer 0 _weak_dysym_tlv
+# CHECK-DAG:   __DATA       __data          0x{{[0-9a-f]*}}           pointer 2 _weak_external
+# CHECK-DAG:   __DATA       __la_symbol_ptr 0x[[#WEAK_DY_FN]]         pointer 0 _weak_dysym_fn
+# CHECK-DAG:   __DATA       __la_symbol_ptr 0x{{[0-9a-f]*}}           pointer 0 _weak_external_fn
 ## Check that we don't have any other bindings
 # CHECK-NOT:   pointer
 
 ## Weak internal symbols don't get bindings
-# RUN: llvm-objdump --macho --bind --weak-bind %t/test | FileCheck %s --check-prefix=WEAK-INTERNAL
+# RUN: llvm-objdump --macho --bind --lazy-bind --weak-bind %t/test | FileCheck %s --check-prefix=WEAK-INTERNAL
 # WEAK-INTERNAL-NOT: _weak_internal
+# WEAK-INTERNAL-NOT: _weak_internal_fn
 # WEAK-INTERNAL-NOT: _weak_internal_tlv
 
 #--- libfoo.s
@@ -55,6 +71,11 @@ _weak_dysym:
 _weak_dysym_for_gotpcrel:
   .quad 0x1234
 
+.globl _weak_dysym_fn
+.weak_definition _weak_dysym_fn
+_weak_dysym_fn:
+  ret
+
 .section __DATA,__thread_vars,thread_local_variables
 
 .globl _weak_dysym_tlv
@@ -64,8 +85,8 @@ _weak_dysym_tlv:
 
 #--- test.s
 
-.globl _main, _weak_external, _weak_external_for_gotpcrel
-.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_internal
+.globl _main, _weak_external, _weak_external_for_gotpcrel, _weak_external_fn
+.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_external_fn, _weak_internal, _weak_internal_fn
 
 _main:
   mov _weak_dysym_for_gotpcrel at GOTPCREL(%rip), %rax
@@ -73,6 +94,9 @@ _main:
   mov _weak_tlv at TLVP(%rip), %rax
   mov _weak_dysym_tlv at TLVP(%rip), %rax
   mov _weak_internal_tlv at TLVP(%rip), %rax
+  callq _weak_dysym_fn
+  callq _weak_external_fn
+  callq _weak_internal_fn
   mov $0, %rax
   ret
 
@@ -82,9 +106,15 @@ _weak_external:
 _weak_external_for_gotpcrel:
   .quad 0x1234
 
+_weak_external_fn:
+  ret
+
 _weak_internal:
   .quad 0x1234
 
+_weak_internal_fn:
+  ret
+
 .data
   .quad _weak_dysym
   .quad _weak_external + 2

diff  --git a/lld/test/MachO/weak-definition-order.s b/lld/test/MachO/weak-definition-order.s
index 6770a5f76b39..b3b23c816bba 100644
--- a/lld/test/MachO/weak-definition-order.s
+++ b/lld/test/MachO/weak-definition-order.s
@@ -23,12 +23,11 @@
 # 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: llvm-objdump --macho --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
+# RUN: llvm-objdump --macho --bind %t/dylib21 | FileCheck %s --check-prefix=DYLIB2
+# DYLIB1: __DATA   __la_symbol_ptr    0x{{[0-9a-f]*}} pointer 0 libweak1         _foo
+# DYLIB2: __DATA   __la_symbol_ptr    0x{{[0-9a-f]*}} pointer 0 libweak2         _foo
 
 .globl _main
 _main:


        


More information about the llvm-commits mailing list