[lld] cbe2731 - [lld-macho] Implement weak bindings for GOT/TLV

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 19:27:02 PDT 2020


Author: Jez Ng
Date: 2020-08-26T19:21:09-07:00
New Revision: cbe27316efce6fe1854f2c5b3428c6a74946877f

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

LOG: [lld-macho] Implement weak bindings for GOT/TLV

Previously, we were only emitting regular bindings to weak
dynamic symbols; this diff adds support for the weak bindings too, which
can overwrite the regular bindings at runtime. We also treat weak
defined global symbols similarly -- since they can also be interposed at
runtime, they need to be treated as potentially dynamic symbols.

Note that weak bindings differ from regular bindings in that they do not
specify the dylib to do the lookup in (i.e. weak symbol lookup happens
in a flat namespace.)

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

Added: 
    lld/test/MachO/weak-binding.s

Modified: 
    lld/MachO/Arch/X86_64.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/SymbolTable.cpp
    lld/MachO/Symbols.h
    lld/MachO/SyntheticSections.cpp
    lld/MachO/SyntheticSections.h
    lld/MachO/Writer.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 0c5abd6cc4f5..41c797513014 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -222,12 +222,14 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol *sym,
   switch (r.type) {
   case X86_64_RELOC_GOT_LOAD:
     // TODO: implement mov -> lea relaxation for non-dynamic symbols
-  case X86_64_RELOC_GOT:
+  case X86_64_RELOC_GOT: {
     in.got->addEntry(sym);
+
     if (sym->isTlv())
       error("found GOT relocation referencing thread-local variable in " +
             toString(isec));
     break;
+  }
   case X86_64_RELOC_BRANCH: {
     // TODO: weak dysyms should go into the weak binding section instead
     if (auto *dysym = dyn_cast<DylibSymbol>(sym))
@@ -241,31 +243,26 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol *sym,
               dysym->getName() + " must have r_length = 3");
         return;
       }
-      in.binding->addEntry(dysym, isec, r.offset, r.addend);
     }
+    addNonLazyBindingEntries(sym, isec, r.offset, r.addend);
     break;
   }
   case X86_64_RELOC_SIGNED:
   case X86_64_RELOC_SIGNED_1:
   case X86_64_RELOC_SIGNED_2:
   case X86_64_RELOC_SIGNED_4:
+    // TODO: warn if they refer to a weak global
     break;
-  case X86_64_RELOC_TLV:
-    if (isa<DylibSymbol>(sym)) {
+  case X86_64_RELOC_TLV: {
+    if (sym->isWeakDef() || isa<DylibSymbol>(sym))
       in.tlvPointers->addEntry(sym);
-    } else {
-      assert(isa<Defined>(sym));
-      // TLV relocations on x86_64 are always used with a movq opcode, which
-      // can be converted to leaq opcodes if they reference a defined symbol.
-      // (This is in contrast to GOT relocations, which can be used with
-      // non-movq opcodes.) As such, there is no need to add an entry to
-      // tlvPointers here.
-    }
+
     if (!sym->isTlv())
       error(
           "found X86_64_RELOC_TLV referencing a non-thread-local variable in " +
           toString(isec));
     break;
+  }
   case X86_64_RELOC_SUBTRACTOR:
     fatal("TODO: handle relocation type " + std::to_string(r.type));
     break;
@@ -291,7 +288,7 @@ uint64_t X86_64::resolveSymbolVA(uint8_t *buf, const lld::macho::Symbol &sym,
   case X86_64_RELOC_SIGNED_4:
     return sym.getVA();
   case X86_64_RELOC_TLV: {
-    if (isa<DylibSymbol>(&sym))
+    if (sym.isInGot())
       return in.tlvPointers->addr + sym.gotIndex * WordSize;
 
     // Convert the movq to a leaq.

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 2fc8cee0bae4..d19654306be5 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -236,7 +236,8 @@ void InputFile::parseSymbols(ArrayRef<structs::nlist_64> nList,
       // Global defined symbol
       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);
+    return make<Defined>(name, isec, value, sym.n_desc & N_WEAK_DEF,
+                         /*isExternal=*/false);
   };
 
   for (size_t i = 0, n = nList.size(); i < n; ++i) {

diff  --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp
index bd10a2c56989..2072b914fa83 100644
--- a/lld/MachO/SymbolTable.cpp
+++ b/lld/MachO/SymbolTable.cpp
@@ -53,7 +53,7 @@ Symbol *SymbolTable::addDefined(StringRef name, InputSection *isec,
     // of a name conflict, we fall through to the replaceSymbol() call below.
   }
 
-  replaceSymbol<Defined>(s, name, isec, value, isWeakDef);
+  replaceSymbol<Defined>(s, name, isec, value, isWeakDef, /*isExternal=*/true);
   return s;
 }
 

diff  --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h
index 4ccb87e18335..90fdd5e01eea 100644
--- a/lld/MachO/Symbols.h
+++ b/lld/MachO/Symbols.h
@@ -57,6 +57,9 @@ class Symbol {
 
   virtual bool isTlv() const { llvm_unreachable("cannot be TLV"); }
 
+  // Whether this symbol is in the GOT or TLVPointer sections.
+  bool isInGot() const { return gotIndex != 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.
@@ -71,14 +74,17 @@ class Symbol {
 
 class Defined : public Symbol {
 public:
-  Defined(StringRefZ name, InputSection *isec, uint32_t value, bool isWeakDef)
-      : Symbol(DefinedKind, name), isec(isec), value(value),
-        weakDef(isWeakDef) {}
+  Defined(StringRefZ name, InputSection *isec, uint32_t value, bool isWeakDef,
+          bool isExternal)
+      : Symbol(DefinedKind, name), isec(isec), value(value), weakDef(isWeakDef),
+        external(isExternal) {}
 
   bool isWeakDef() const override { return weakDef; }
 
   bool isTlv() const override { return isThreadLocalVariables(isec->flags); }
 
+  bool isExternal() const { return external; }
+
   static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }
 
   uint64_t getVA() const override { return isec->getVA() + value; }
@@ -92,6 +98,7 @@ class Defined : public Symbol {
 
 private:
   const bool weakDef;
+  const bool external;
 };
 
 class Undefined : public Symbol {

diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index c5c9bf3ea414..2b46a45c34e2 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -91,11 +91,10 @@ NonLazyPointerSectionBase::NonLazyPointerSectionBase(const char *segname,
 
 void NonLazyPointerSectionBase::addEntry(Symbol *sym) {
   if (entries.insert(sym)) {
-    assert(sym->gotIndex == UINT32_MAX);
+    assert(!sym->isInGot());
     sym->gotIndex = entries.size() - 1;
 
-    if (auto *dysym = dyn_cast<DylibSymbol>(sym))
-      in.binding->addEntry(dysym, this, sym->gotIndex * WordSize);
+    addNonLazyBindingEntries(sym, this, sym->gotIndex * WordSize);
   }
 }
 
@@ -117,13 +116,13 @@ struct Binding {
 };
 } // namespace
 
-// Encode a sequence of opcodes that tell dyld to write the address of dysym +
+// Encode a sequence of opcodes that tell dyld to write the address of symbol +
 // addend at osec->addr + outSecOff.
 //
 // The bind opcode "interpreter" remembers the values of each binding field, so
 // we only need to encode the 
diff erences between bindings. Hence the use of
 // lastBinding.
-static void encodeBinding(const DylibSymbol *dysym, const OutputSection *osec,
+static void encodeBinding(const Symbol *sym, const OutputSection *osec,
                           uint64_t outSecOff, int64_t addend,
                           Binding &lastBinding, raw_svector_ostream &os) {
   using namespace llvm::MachO;
@@ -141,17 +140,6 @@ static void encodeBinding(const DylibSymbol *dysym, const OutputSection *osec,
     lastBinding.offset = offset;
   }
 
-  if (lastBinding.ordinal != dysym->file->ordinal) {
-    if (dysym->file->ordinal <= BIND_IMMEDIATE_MASK) {
-      os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
-                                 dysym->file->ordinal);
-    } else {
-      os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-      encodeULEB128(dysym->file->ordinal, os);
-    }
-    lastBinding.ordinal = dysym->file->ordinal;
-  }
-
   if (lastBinding.addend != addend) {
     os << static_cast<uint8_t>(BIND_OPCODE_SET_ADDEND_SLEB);
     encodeSLEB128(addend, os);
@@ -159,18 +147,33 @@ static void encodeBinding(const DylibSymbol *dysym, const OutputSection *osec,
   }
 
   os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
-     << dysym->getName() << '\0'
+     << sym->getName() << '\0'
      << static_cast<uint8_t>(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
      << static_cast<uint8_t>(BIND_OPCODE_DO_BIND);
   // DO_BIND causes dyld to both perform the binding and increment the offset
   lastBinding.offset += WordSize;
 }
 
-uint64_t BindingEntry::getVA() const {
+// Non-weak bindings need to have their dylib ordinal encoded as well.
+static void encodeDylibOrdinal(const DylibSymbol *dysym, Binding &lastBinding,
+                               raw_svector_ostream &os) {
+  using namespace llvm::MachO;
+  if (lastBinding.ordinal != dysym->file->ordinal) {
+    if (dysym->file->ordinal <= BIND_IMMEDIATE_MASK) {
+      os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+                                 dysym->file->ordinal);
+    } else {
+      os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+      encodeULEB128(dysym->file->ordinal, os);
+    }
+    lastBinding.ordinal = dysym->file->ordinal;
+  }
+}
+
+uint64_t BindingTarget::getVA() const {
   if (auto *isec = section.dyn_cast<const InputSection *>())
     return isec->getVA() + offset;
-  auto *osec = section.get<const OutputSection *>();
-  return osec->addr + offset;
+  return section.get<const OutputSection *>()->addr + offset;
 }
 
 // Emit bind opcodes, which are a stream of byte-sized opcodes that dyld
@@ -194,15 +197,17 @@ void BindingSection::finalizeContents() {
   // result. Note that sorting by address alone ensures that bindings for the
   // same segment / section are located together.
   llvm::sort(bindings, [](const BindingEntry &a, const BindingEntry &b) {
-    return a.getVA() < b.getVA();
+    return a.target.getVA() < b.target.getVA();
   });
   for (const BindingEntry &b : bindings) {
-    if (auto *isec = b.section.dyn_cast<const InputSection *>()) {
-      encodeBinding(b.dysym, isec->parent, isec->outSecOff + b.offset, b.addend,
-                    lastBinding, os);
+    encodeDylibOrdinal(b.dysym, lastBinding, os);
+    if (auto *isec = b.target.section.dyn_cast<const InputSection *>()) {
+      encodeBinding(b.dysym, isec->parent, isec->outSecOff + b.target.offset,
+                    b.target.addend, lastBinding, os);
     } else {
-      auto *osec = b.section.get<const OutputSection *>();
-      encodeBinding(b.dysym, osec, b.offset, b.addend, lastBinding, os);
+      auto *osec = b.target.section.get<const OutputSection *>();
+      encodeBinding(b.dysym, osec, b.target.offset, b.target.addend,
+                    lastBinding, os);
     }
   }
   if (!bindings.empty())
@@ -213,6 +218,56 @@ void BindingSection::writeTo(uint8_t *buf) const {
   memcpy(buf, contents.data(), contents.size());
 }
 
+WeakBindingSection::WeakBindingSection()
+    : LinkEditSection(segment_names::linkEdit, section_names::weakBinding) {}
+
+void WeakBindingSection::finalizeContents() {
+  raw_svector_ostream os{contents};
+  Binding lastBinding;
+
+  // Since bindings are delta-encoded, sorting them allows for a more compact
+  // result.
+  llvm::sort(bindings,
+             [](const WeakBindingEntry &a, const WeakBindingEntry &b) {
+               return a.target.getVA() < b.target.getVA();
+             });
+  for (const WeakBindingEntry &b : bindings) {
+    if (auto *isec = b.target.section.dyn_cast<const InputSection *>()) {
+      encodeBinding(b.symbol, isec->parent, isec->outSecOff + b.target.offset,
+                    b.target.addend, lastBinding, os);
+    } else {
+      auto *osec = b.target.section.get<const OutputSection *>();
+      encodeBinding(b.symbol, osec, b.target.offset, b.target.addend,
+                    lastBinding, os);
+    }
+  }
+  if (!bindings.empty())
+    os << static_cast<uint8_t>(MachO::BIND_OPCODE_DONE);
+}
+
+void WeakBindingSection::writeTo(uint8_t *buf) const {
+  memcpy(buf, contents.data(), contents.size());
+}
+
+void macho::addNonLazyBindingEntries(const Symbol *sym,
+                                     SectionPointerUnion section,
+                                     uint64_t offset, int64_t addend) {
+  if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
+    in.binding->addEntry(dysym, section, offset, addend);
+    if (dysym->isWeakDef())
+      in.weakBinding->addEntry(sym, section, offset, addend);
+  } else if (auto *defined = dyn_cast<Defined>(sym)) {
+    if (defined->isWeakDef() && defined->isExternal())
+      in.weakBinding->addEntry(sym, section, offset, addend);
+  } else if (isa<DSOHandle>(sym)) {
+    error("cannot bind to " + DSOHandle::name);
+  } else {
+    // Undefined symbols are filtered out in scanRelocations(); we should never
+    // get here
+    llvm_unreachable("cannot bind to an undefined symbol");
+  }
+}
+
 StubsSection::StubsSection()
     : SyntheticSection(segment_names::text, "__stubs") {}
 

diff  --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 9918fbcb432e..1c393eb3f874 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -28,6 +28,7 @@ namespace section_names {
 constexpr const char pageZero[] = "__pagezero";
 constexpr const char header[] = "__mach_header";
 constexpr const char binding[] = "__binding";
+constexpr const char weakBinding[] = "__weak_binding";
 constexpr const char lazyBinding[] = "__lazy_binding";
 constexpr const char export_[] = "__export";
 constexpr const char symbolTable[] = "__symbol_table";
@@ -140,19 +141,24 @@ class TlvPointerSection : public NonLazyPointerSectionBase {
 using SectionPointerUnion =
     llvm::PointerUnion<const InputSection *, const OutputSection *>;
 
-struct BindingEntry {
-  const DylibSymbol *dysym;
+struct BindingTarget {
   SectionPointerUnion section;
   uint64_t offset;
   int64_t addend;
 
-  BindingEntry(const DylibSymbol *dysym, SectionPointerUnion section,
-               uint64_t offset, int64_t addend)
-      : dysym(dysym), section(section), offset(offset), addend(addend) {}
+  BindingTarget(SectionPointerUnion section, uint64_t offset, int64_t addend)
+      : section(section), offset(offset), addend(addend) {}
 
   uint64_t getVA() const;
 };
 
+struct BindingEntry {
+  const DylibSymbol *dysym;
+  BindingTarget target;
+  BindingEntry(const DylibSymbol *dysym, BindingTarget target)
+      : dysym(dysym), target(std::move(target)) {}
+};
+
 // Stores bind opcodes for telling dyld which symbols to load non-lazily.
 class BindingSection : public LinkEditSection {
 public:
@@ -168,7 +174,7 @@ class BindingSection : public LinkEditSection {
 
   void addEntry(const DylibSymbol *dysym, SectionPointerUnion section,
                 uint64_t offset, int64_t addend = 0) {
-    bindings.emplace_back(dysym, section, offset, addend);
+    bindings.emplace_back(dysym, BindingTarget(section, offset, addend));
   }
 
 private:
@@ -176,6 +182,43 @@ class BindingSection : public LinkEditSection {
   SmallVector<char, 128> contents;
 };
 
+struct WeakBindingEntry {
+  const Symbol *symbol;
+  BindingTarget target;
+  WeakBindingEntry(const Symbol *symbol, BindingTarget target)
+      : symbol(symbol), target(std::move(target)) {}
+};
+
+// Stores bind opcodes for telling dyld which weak symbols to load. Note that
+// the bind opcodes will only refer to these symbols by name, but will not
+// specify which dylib to load them from.
+class WeakBindingSection : public LinkEditSection {
+public:
+  WeakBindingSection();
+  void finalizeContents();
+  uint64_t getRawSize() const override { return contents.size(); }
+  // Like other sections in __LINKEDIT, the 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 { return !bindings.empty(); }
+
+  void writeTo(uint8_t *buf) const override;
+
+  void addEntry(const Symbol *symbol, SectionPointerUnion section,
+                uint64_t offset, int64_t addend = 0) {
+    bindings.emplace_back(symbol, BindingTarget(section, offset, addend));
+  }
+
+private:
+  std::vector<WeakBindingEntry> bindings;
+  SmallVector<char, 128> contents;
+};
+
+// Add bindings for symbols that need weak or non-lazy bindings.
+void addNonLazyBindingEntries(const Symbol *, SectionPointerUnion,
+                              uint64_t offset, int64_t addend = 0);
+
 // The following sections implement lazy symbol binding -- very similar to the
 // PLT mechanism in ELF.
 //
@@ -324,6 +367,7 @@ class SymtabSection : public SyntheticSection {
 struct InStruct {
   MachHeaderSection *header = nullptr;
   BindingSection *binding = nullptr;
+  WeakBindingSection *weakBinding = nullptr;
   GotSection *got = nullptr;
   TlvPointerSection *tlvPointers = nullptr;
   LazyPointerSection *lazyPointers = nullptr;

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 5a56762450a1..923c0407fa6e 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -65,10 +65,11 @@ class Writer {
 class LCDyldInfo : public LoadCommand {
 public:
   LCDyldInfo(BindingSection *bindingSection,
+             WeakBindingSection *weakBindingSection,
              LazyBindingSection *lazyBindingSection,
              ExportSection *exportSection)
-      : bindingSection(bindingSection), lazyBindingSection(lazyBindingSection),
-        exportSection(exportSection) {}
+      : bindingSection(bindingSection), weakBindingSection(weakBindingSection),
+        lazyBindingSection(lazyBindingSection), exportSection(exportSection) {}
 
   uint32_t getSize() const override { return sizeof(dyld_info_command); }
 
@@ -80,6 +81,10 @@ class LCDyldInfo : public LoadCommand {
       c->bind_off = bindingSection->fileOff;
       c->bind_size = bindingSection->getFileSize();
     }
+    if (weakBindingSection->isNeeded()) {
+      c->weak_bind_off = weakBindingSection->fileOff;
+      c->weak_bind_size = weakBindingSection->getFileSize();
+    }
     if (lazyBindingSection->isNeeded()) {
       c->lazy_bind_off = lazyBindingSection->fileOff;
       c->lazy_bind_size = lazyBindingSection->getFileSize();
@@ -91,6 +96,7 @@ class LCDyldInfo : public LoadCommand {
   }
 
   BindingSection *bindingSection;
+  WeakBindingSection *weakBindingSection;
   LazyBindingSection *lazyBindingSection;
   ExportSection *exportSection;
 };
@@ -321,8 +327,8 @@ void Writer::scanRelocations() {
 }
 
 void Writer::createLoadCommands() {
-  in.header->addLoadCommand(
-      make<LCDyldInfo>(in.binding, lazyBindingSection, exportSection));
+  in.header->addLoadCommand(make<LCDyldInfo>(
+      in.binding, in.weakBinding, lazyBindingSection, exportSection));
   in.header->addLoadCommand(make<LCSymtab>(symtabSection, stringTableSection));
   in.header->addLoadCommand(make<LCDysymtab>());
   for (StringRef path : config->runtimePaths)
@@ -414,7 +420,8 @@ static int sectionOrder(OutputSection *osec) {
       return -1;
   } else if (segname == segment_names::linkEdit) {
     return StringSwitch<int>(osec->name)
-        .Case(section_names::binding, -5)
+        .Case(section_names::binding, -6)
+        .Case(section_names::weakBinding, -5)
         .Case(section_names::lazyBinding, -4)
         .Case(section_names::export_, -3)
         .Case(section_names::symbolTable, -2)
@@ -577,6 +584,7 @@ void Writer::run() {
 
   // Fill __LINKEDIT contents.
   in.binding->finalizeContents();
+  in.weakBinding->finalizeContents();
   lazyBindingSection->finalizeContents();
   exportSection->finalizeContents();
   symtabSection->finalizeContents();
@@ -600,6 +608,7 @@ void macho::writeResult() { Writer().run(); }
 void macho::createSyntheticSections() {
   in.header = make<MachHeaderSection>();
   in.binding = make<BindingSection>();
+  in.weakBinding = make<WeakBindingSection>();
   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
new file mode 100644
index 000000000000..e8b0e1785ffa
--- /dev/null
+++ b/lld/test/MachO/weak-binding.s
@@ -0,0 +1,108 @@
+# REQUIRES: x86
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+# 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:   FileCheck %s
+
+# 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.
+# CHECK-NEXT: {{[0-9a-f]+}} {{[0-9a-f ]*[1-9a-f]+[0-9a-f ]*}}
+
+# CHECK:      <_main>:
+# CHECK-NEXT: movq	[[#]](%rip), %rax  # [[#%X,WEAK_DY_GOT_ADDR:]]
+# CHECK-NEXT: movq	[[#]](%rip), %rax  # [[#%X,WEAK_EXT_GOT_ADDR:]]
+# 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-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 that we don't have any other 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 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
+# WEAK-INTERNAL-NOT: _weak_internal
+# WEAK-INTERNAL-NOT: _weak_internal_tlv
+
+#--- libfoo.s
+
+.globl _weak_dysym
+.weak_definition _weak_dysym
+_weak_dysym:
+  .quad 0x1234
+
+.globl _weak_dysym_for_gotpcrel
+.weak_definition _weak_dysym_for_gotpcrel
+_weak_dysym_for_gotpcrel:
+  .quad 0x1234
+
+.section __DATA,__thread_vars,thread_local_variables
+
+.globl _weak_dysym_tlv
+.weak_definition _weak_dysym_tlv
+_weak_dysym_tlv:
+  .quad 0x1234
+
+#--- test.s
+
+.globl _main, _weak_external, _weak_external_for_gotpcrel
+.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_internal
+
+_main:
+  mov _weak_dysym_for_gotpcrel at GOTPCREL(%rip), %rax
+  mov _weak_external_for_gotpcrel at GOTPCREL(%rip), %rax
+  mov _weak_tlv at TLVP(%rip), %rax
+  mov _weak_dysym_tlv at TLVP(%rip), %rax
+  mov _weak_internal_tlv at TLVP(%rip), %rax
+  mov $0, %rax
+  ret
+
+_weak_external:
+  .quad 0x1234
+
+_weak_external_for_gotpcrel:
+  .quad 0x1234
+
+_weak_internal:
+  .quad 0x1234
+
+.data
+  .quad _weak_dysym
+  .quad _weak_external + 2
+  .quad _weak_internal
+
+.tbss _weak_tlv$tlv$init, 4, 2
+.tbss _weak_internal_tlv$tlv$init, 4, 2
+
+.section __DATA,__thread_vars,thread_local_variables
+.globl _weak_tlv
+.weak_definition  _weak_tlv, _weak_internal_tlv
+
+_weak_tlv:
+  .quad __tlv_bootstrap
+  .quad 0
+  .quad _weak_tlv$tlv$init
+
+_weak_internal_tlv:
+  .quad __tlv_bootstrap
+  .quad 0
+  .quad _weak_internal_tlv$tlv$init


        


More information about the llvm-commits mailing list