[lld-macho] Allow the entry symbol to be dynamically bound
authorJez Ng <jezng@fb.com>
Thu, 17 Sep 2020 17:20:16 +0000 (10:20 -0700)
committerJez Ng <jezng@fb.com>
Fri, 25 Sep 2020 18:28:33 +0000 (11:28 -0700)
Apparently this is used in real programs. I've handled this by reusing
the logic we already have for branch (function call) relocations.

Reviewed By: #lld-macho, smeenai

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

lld/MachO/Arch/X86_64.cpp
lld/MachO/Driver.cpp
lld/MachO/SyntheticSections.cpp
lld/MachO/SyntheticSections.h
lld/MachO/Writer.cpp
lld/test/MachO/entry-symbol.s

index 8e07ee4..19e62a9 100644 (file)
@@ -238,28 +238,7 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol *sym,
     break;
   }
   case X86_64_RELOC_BRANCH: {
-    // TODO: factor this logic out so it can be reused for different
-    // architectures
-    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.rebase->addEntry(in.lazyPointers, sym->stubsIndex * WordSize);
-          in.weakBinding->addEntry(sym, in.lazyPointers,
-                                   sym->stubsIndex * WordSize);
-        }
-      }
-    }
+    prepareBranchTarget(sym);
     break;
   }
   case X86_64_RELOC_UNSIGNED: {
index 4991966..7a8215b 100644 (file)
@@ -697,7 +697,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
   if (!orderFile.empty())
     parseOrderFile(orderFile);
 
-  if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
+  if (config->outputType == MH_EXECUTE && isa<Undefined>(config->entry)) {
     error("undefined symbol: " + config->entry->getName());
     return false;
   }
index a243a05..e40b832 100644 (file)
@@ -529,6 +529,29 @@ uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
   return opstreamOffset;
 }
 
+void macho::prepareBranchTarget(Symbol *sym) {
+  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.rebase->addEntry(in.lazyPointers, sym->stubsIndex * WordSize);
+        in.weakBinding->addEntry(sym, in.lazyPointers,
+                                 sym->stubsIndex * WordSize);
+      }
+    }
+  }
+}
+
 ExportSection::ExportSection()
     : LinkEditSection(segment_names::linkEdit, section_names::export_) {}
 
index 3bd4e11..1736b6a 100644 (file)
@@ -364,6 +364,10 @@ private:
   llvm::raw_svector_ostream os{contents};
 };
 
+// Adds stubs and bindings where necessary (e.g. if the symbol is a
+// DylibSymbol.)
+void prepareBranchTarget(Symbol *);
+
 // Stores a trie that describes the set of exported symbols.
 class ExportSection : public LinkEditSection {
 public:
index 4572c52..c47b878 100644 (file)
@@ -194,7 +194,13 @@ class LCMain : public LoadCommand {
     auto *c = reinterpret_cast<entry_point_command *>(buf);
     c->cmd = LC_MAIN;
     c->cmdsize = getSize();
-    c->entryoff = config->entry->getFileOffset();
+
+    if (config->entry->isInStubs())
+      c->entryoff =
+          in.stubs->fileOff + config->entry->stubsIndex * target->stubSize;
+    else
+      c->entryoff = config->entry->getFileOffset();
+
     c->stacksize = 0;
   }
 };
@@ -617,6 +623,7 @@ void Writer::run() {
   OutputSegment *linkEditSegment =
       getOrCreateOutputSegment(segment_names::linkEdit);
 
+  prepareBranchTarget(config->entry);
   scanRelocations();
   if (in.stubHelper->isNeeded())
     in.stubHelper->setup();
index 159c7c5..d24d4e6 100644 (file)
@@ -1,7 +1,11 @@
 # REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
-# RUN: lld -flavor darwinnew -o %t %t.o -e _not_main
-# RUN: llvm-objdump --macho --all-headers --syms %t | FileCheck %s
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/not-main.s -o %t/not-main.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 -lSystem -dylib %t/libfoo.o -o %t/libfoo.dylib
+
+# RUN: lld -flavor darwinnew -o %t/not-main %t/not-main.o -e _not_main
+# RUN: llvm-objdump --macho --all-headers --syms %t/not-main | FileCheck %s
 # CHECK-LABEL: SYMBOL TABLE
 # CHECK-NEXT: {{0*}}[[#%x, ENTRY_ADDR:]] {{.*}} __TEXT,__text _not_main
 # CHECK:      cmd  LC_MAIN
 # CHECK-NEXT: size
 # CHECK-NEXT: offset [[#ENTRYOFF]]
 
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -o %t/dysym-main %t/not-main.o %t/libfoo.dylib -e _dysym_main
+# RUN: llvm-objdump --macho --all-headers --indirect-symbols --lazy-bind %t/dysym-main | FileCheck %s --check-prefix=DYSYM
+# DYSYM-LABEL: Indirect symbols for (__TEXT,__stubs) 1 entries
+# DYSYM-NEXT:  address                      index  name
+# DYSYM-NEXT:  0x[[#%x,DYSYM_ENTRY_ADDR:]]  [[#]]  _dysym_main
+# DYSYM-LABEL: cmd  LC_MAIN
+# DYSYM-NEXT:  cmdsize  24
+# DYSYM-NEXT:  entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]]
+# DYSYM-LABEL: Lazy bind table:
+# DYSYM-NEXT:  segment  section            address     dylib            symbol
+# DYSYM-NEXT:  __DATA   __la_symbol_ptr    {{.*}}      libfoo       _dysym_main
+
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -o %t/weak-dysym-main %t/not-main.o %t/libfoo.dylib -e _weak_dysym_main
+# RUN: llvm-objdump --macho --all-headers --indirect-symbols --bind --weak-bind %t/weak-dysym-main | FileCheck %s --check-prefix=WEAK-DYSYM
+# WEAK-DYSYM-LABEL: Indirect symbols for (__TEXT,__stubs) 1 entries
+# WEAK-DYSYM-NEXT:  address                      index  name
+# WEAK-DYSYM-NEXT:  0x[[#%x,DYSYM_ENTRY_ADDR:]]  [[#]]  _weak_dysym_main
+# WEAK-DYSYM:       cmd  LC_MAIN
+# WEAK-DYSYM-NEXT:  cmdsize  24
+# WEAK-DYSYM-NEXT:  entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]]
+# WEAK-DYSYM-LABEL: Bind table:
+# WEAK-DYSYM-NEXT:  segment  section          address  type     addend  dylib      symbol
+# WEAK-DYSYM:       __DATA   __la_symbol_ptr  {{.*}}   pointer       0  libfoo _weak_dysym_main
+# WEAK-DYSYM-LABEL: Weak bind table:
+# WEAK-DYSYM-NEXT:  segment  section          address  type     addend  symbol
+# WEAK-DYSYM-NEXT:  __DATA   __la_symbol_ptr  {{.*}}   pointer       0  _weak_dysym_main
 
-# RUN: not lld -flavor darwinnew -o /dev/null %t.o -e _missing 2>&1 | FileCheck %s --check-prefix=UNDEFINED
+# RUN: not lld -flavor darwinnew -o /dev/null %t/not-main.o -e _missing 2>&1 | FileCheck %s --check-prefix=UNDEFINED
 # UNDEFINED: error: undefined symbol: _missing
-# RUN: not lld -flavor darwinnew -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY
+# RUN: not lld -flavor darwinnew -o /dev/null %t/not-main.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY
 # DEFAULT-ENTRY: error: undefined symbol: _main
 
+#--- libfoo.s
+.text
+.global _dysym_main, _weak_dysym_main
+.weak_definition _weak_dysym_main
+_dysym_main:
+  ret
+
+_weak_dysym_main:
+  ret
+
+#--- not-main.s
 .text
 .global _not_main
 _not_main:
-  movq $0, %rax
-  retq
+  ret