[pkg-d-commits] [ldc] 91/211: Shared library support for OS X (#1705)

Matthias Klumpp mak at moszumanska.debian.org
Sun Apr 23 22:36:12 UTC 2017


This is an automated email from the git hooks/post-receive script.

mak pushed a commit to annotated tag v1.1.0
in repository ldc.

commit bb2b648d8e286c82cc55219a2d2ac067e361d432
Author: David Nadlinger <code at klickverbot.at>
Date:   Sat Oct 15 16:17:39 2016 +0100

    Shared library support for OS X (#1705)
---
 .travis.yml            |   3 +
 gen/modules.cpp        | 208 ++++++++++++++++++++++++++++++++++++-------------
 gen/runtime.cpp        |  39 +++-------
 runtime/CMakeLists.txt |  18 +++--
 runtime/druntime       |   2 +-
 5 files changed, 180 insertions(+), 90 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 7d8d3af..36b2d99 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,6 +21,9 @@ matrix:
     - os: osx
       d: ldc
       env: LLVM_CONFIG="llvm-config-3.8"
+    - os: osx
+      d: ldc
+      env: LLVM_CONFIG="llvm-config-3.8" OPTS="-DBUILD_SHARED_LIBS=ON"
   allow_failures:
     #- env: LLVM_VERSION=3.9
 
diff --git a/gen/modules.cpp b/gen/modules.cpp
index bf35db0..c29999f 100644
--- a/gen/modules.cpp
+++ b/gen/modules.cpp
@@ -95,9 +95,52 @@ void Module::makeObjectFilenameUnique() {
 }
 
 namespace {
+/// Ways the druntime module registry system can be implemented.
+enum class RegistryStyle {
+  /// Modules are inserted into a linked list starting at the _Dmodule_ref
+  /// global.
+  legacyLinkedList,
+
+  /// Module references are emitted into the .minfo section, bracketed with
+  /// extra sections to access the .minfo range. Global constructors/
+  /// destructors make sure _d_dso_registry is invoked once per ELF object.
+  sectionELF,
+
+  /// Module references are emitted into the .minfo section. Global
+  /// constructors/destructors make sure _d_dso_registry is invoked once per
+  /// shared object. A "TLS anchor" function to identify the TLS range
+  /// corresponding to this image is also passed to druntime.
+  sectionDarwin
+};
+
+/// Returns the module registry style to use for the current target triple.
+RegistryStyle getModuleRegistryStyle() {
+  const auto t = global.params.targetTriple;
+
+  if (t->isMacOSX()) {
+    return RegistryStyle::sectionDarwin;
+  }
+
+  if ((t->isOSLinux() && t->getEnvironment() != llvm::Triple::Android) ||
+      t->isOSFreeBSD() ||
+#if LDC_LLVM_VER > 305
+      t->isOSNetBSD() || t->isOSOpenBSD() || t->isOSDragonFly()
+#else
+      t->getOS() == llvm::Triple::NetBSD ||
+      t->getOS() == llvm::Triple::OpenBSD ||
+      t->getOS() == llvm::Triple::DragonFly
+#endif
+          ) {
+    return RegistryStyle::sectionELF;
+  }
+
+  return RegistryStyle::legacyLinkedList;
+}
 
-// build ModuleReference and register function, to register the module info in
-// the global linked list
+/// Build ModuleReference and register function, to register the module info in
+/// the global linked list.
+///
+/// Implements getModuleRegistryStyle() == RegistryStyle::legacyLinkedList.
 LLFunction *build_module_reference_and_ctor(const char *moduleMangle,
                                             LLConstant *moduleinfo) {
   // build ctor type
@@ -170,17 +213,49 @@ LLFunction *build_module_reference_and_ctor(const char *moduleMangle,
   return ctor;
 }
 
-/// Builds the body for the ldc.dso_ctor and ldc.dso_dtor functions.
+/// Builds a void*() function with hidden visibility that returns the address of
+/// a dummy TLS global (also with hidden visibility).
+///
+/// The global is non-zero-initialised and aligned to 16 bytes.
+llvm::Function *buildGetTLSAnchor() {
+  // Create a dummmy TLS global private to this module.
+  const auto one =
+      llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 1);
+  const auto anchor = getOrCreateGlobal(
+      Loc(), gIR->module, one->getType(), false,
+      llvm::GlobalValue::LinkOnceODRLinkage, one, "ldc.tls_anchor", true);
+  anchor->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  anchor->setAlignment(16);
+
+  const auto getAnchor =
+      llvm::Function::Create(llvm::FunctionType::get(getVoidPtrType(), false),
+                             llvm::GlobalValue::LinkOnceODRLinkage,
+                             "ldc.get_tls_anchor", &gIR->module);
+  getAnchor->setVisibility(llvm::GlobalValue::HiddenVisibility);
+
+  IRBuilder<> builder(llvm::BasicBlock::Create(gIR->context(), "", getAnchor));
+  builder.CreateRet(anchor);
+
+  return getAnchor;
+}
+
+/// Builds the ldc.register_dso function, which is called by the global
+/// {c, d}tors to invoke _d_dso_registry.
 ///
 /// Pseudocode:
 /// void ldc.register_dso(bool isShutdown, void* minfoUsedPointer) {
 ///   if (dsoInitialized == isShutdown) {
 ///     dsoInitialized = !isShutdown;
-///     auto record = {1, dsoSlot, minfoBeg, minfoEnd, minfoUsedPointer};
+///     auto record = {1, dsoSlot, minfoBeg, minfoEnd[, getTlsAnchor],
+///       minfoUsedPointer};
 ///     _d_dso_registry(cast(CompilerDSOData*)&record);
 ///   }
 /// }
-llvm::Function *buildRegisterDSO(llvm::Value *dsoInitialized,
+///
+/// On Darwin platforms, the record contains an extra pointer to a function
+/// which returns the address of a TLS global.
+llvm::Function *buildRegisterDSO(RegistryStyle style,
+                                 llvm::Value *dsoInitialized,
                                  llvm::Value *dsoSlot, llvm::Value *minfoBeg,
                                  llvm::Value *minfoEnd) {
   llvm::Type *argTypes[] = {llvm::Type::getInt1Ty(gIR->context()),
@@ -206,6 +281,11 @@ llvm::Function *buildRegisterDSO(llvm::Value *dsoInitialized,
       getRuntimeFunction(Loc(), gIR->module, "_d_dso_registry");
   const auto recordPtrTy = dsoRegistry->getFunctionType()->getContainedType(1);
 
+  llvm::Function *getTlsAnchorPtr;
+  if (style == RegistryStyle::sectionDarwin) {
+    getTlsAnchorPtr = buildGetTLSAnchor();
+  }
+
   const auto entryBB = llvm::BasicBlock::Create(gIR->context(), "", fn);
   const auto initBB = llvm::BasicBlock::Create(gIR->context(), "init", fn);
   const auto endBB = llvm::BasicBlock::Create(gIR->context(), "end", fn);
@@ -223,24 +303,38 @@ llvm::Function *buildRegisterDSO(llvm::Value *dsoInitialized,
     b.CreateStore(b.CreateZExt(newFlag, b.getInt8Ty()), dsoInitialized);
 
     llvm::Constant *version = DtoConstSize_t(1);
-    llvm::Type *memberTypes[] = {version->getType(), dsoSlot->getType(),
-                                 minfoBeg->getType(), minfoEnd->getType(),
-                                 minfoUsedPointer->getType()};
+    llvm::SmallVector<llvm::Type *, 6> memberTypes;
+    memberTypes.push_back(version->getType());
+    memberTypes.push_back(dsoSlot->getType());
+    memberTypes.push_back(minfoBeg->getType());
+    memberTypes.push_back(minfoEnd->getType());
+    if (style == RegistryStyle::sectionDarwin) {
+      memberTypes.push_back(getTlsAnchorPtr->getType());
+    }
+    memberTypes.push_back(minfoUsedPointer->getType());
     llvm::StructType *stype =
         llvm::StructType::get(gIR->context(), memberTypes, false);
     llvm::Value *record = b.CreateAlloca(stype);
+
+    unsigned i = 0;
 #if LDC_LLVM_VER >= 307
-    b.CreateStore(version, b.CreateStructGEP(stype, record, 0)); // version
-    b.CreateStore(dsoSlot, b.CreateStructGEP(stype, record, 1)); // slot
-    b.CreateStore(minfoBeg, b.CreateStructGEP(stype, record, 2));
-    b.CreateStore(minfoEnd, b.CreateStructGEP(stype, record, 3));
-    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(stype, record, 4));
+    b.CreateStore(version, b.CreateStructGEP(stype, record, i++));
+    b.CreateStore(dsoSlot, b.CreateStructGEP(stype, record, i++));
+    b.CreateStore(minfoBeg, b.CreateStructGEP(stype, record, i++));
+    b.CreateStore(minfoEnd, b.CreateStructGEP(stype, record, i++));
+    if (style == RegistryStyle::sectionDarwin) {
+      b.CreateStore(getTlsAnchorPtr, b.CreateStructGEP(stype, record, i++));
+    }
+    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(stype, record, i++));
 #else
-    b.CreateStore(version, b.CreateStructGEP(record, 0)); // version
-    b.CreateStore(dsoSlot, b.CreateStructGEP(record, 1)); // slot
-    b.CreateStore(minfoBeg, b.CreateStructGEP(record, 2));
-    b.CreateStore(minfoEnd, b.CreateStructGEP(record, 3));
-    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(record, 4));
+    b.CreateStore(version, b.CreateStructGEP(record, i++));
+    b.CreateStore(dsoSlot, b.CreateStructGEP(record, i++));
+    b.CreateStore(minfoBeg, b.CreateStructGEP(record, i++));
+    b.CreateStore(minfoEnd, b.CreateStructGEP(record, i++));
+    if (style == RegistryStyle::sectionDarwin) {
+      b.CreateStore(getTlsAnchorPtr, b.CreateStructGEP(record, i++));
+    }
+    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(record, i++));
 #endif
 
     b.CreateCall(dsoRegistry, b.CreateBitCast(record, recordPtrTy));
@@ -254,8 +348,10 @@ llvm::Function *buildRegisterDSO(llvm::Value *dsoInitialized,
   return fn;
 }
 
-void build_module_ref(std::string moduleMangle,
-                      llvm::Constant *thisModuleInfo) {
+void emitModuleRefToSection(RegistryStyle style, std::string moduleMangle,
+                            llvm::Constant *thisModuleInfo) {
+  assert(style == RegistryStyle::sectionELF ||
+         style == RegistryStyle::sectionDarwin);
   // Only for the first D module to be emitted into this llvm::Module we need to
   // create the _minfo_beg/_minfo_end symbols and the global ctors/dtors. For
   // all subsequent ones, we just need to emit an additional reference into the
@@ -265,18 +361,24 @@ void build_module_ref(std::string moduleMangle,
 
   llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type);
 
-  // Order is important here: We must create the symbols in the
+  // Order is important here: For ELF, we must create the symbols in the
   // bracketing sections right before/after the ModuleInfo reference
   // so that they end up in the correct order in the object file.
   llvm::GlobalVariable *minfoBeg;
   if (isFirst) {
-    minfoBeg = new llvm::GlobalVariable(
-        gIR->module, moduleInfoPtrTy,
-        false, // FIXME: mRelocModel != llvm::Reloc::PIC_
-        llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy),
-        "_minfo_beg");
-    minfoBeg->setSection(".minfo_beg");
-    minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility);
+    if (style == RegistryStyle::sectionDarwin) {
+      minfoBeg =
+          new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false,
+                                   llvm::GlobalValue::ExternalLinkage, nullptr,
+                                   "\1section$start$__DATA$.minfo");
+    } else {
+      minfoBeg =
+          new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false,
+                                   llvm::GlobalValue::LinkOnceODRLinkage,
+                                   getNullPtr(moduleInfoPtrTy), "_minfo_beg");
+      minfoBeg->setSection(".minfo_beg");
+      minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility);
+    }
   }
 
   std::string thismrefname = "_D";
@@ -287,7 +389,8 @@ void build_module_ref(std::string moduleMangle,
       false, // FIXME: mRelocModel != llvm::Reloc::PIC_
       llvm::GlobalValue::LinkOnceODRLinkage,
       DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname);
-  thismref->setSection(".minfo");
+  thismref->setSection((style == RegistryStyle::sectionDarwin) ? "__DATA,.minfo"
+                                                               : ".minfo");
   gIR->usedArray.push_back(thismref);
 
   if (!isFirst) {
@@ -295,13 +398,19 @@ void build_module_ref(std::string moduleMangle,
     return;
   }
 
-  auto minfoEnd =
-      new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy,
-                               false, // FIXME: mRelocModel != llvm::Reloc::PIC_
-                               llvm::GlobalValue::LinkOnceODRLinkage,
-                               getNullPtr(moduleInfoPtrTy), "_minfo_end");
-  minfoEnd->setSection(".minfo_end");
-  minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  llvm::GlobalVariable *minfoEnd;
+  if (style == RegistryStyle::sectionDarwin) {
+    minfoEnd = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false,
+                                        llvm::GlobalValue::ExternalLinkage,
+                                        nullptr, "\1section$end$__DATA$.minfo");
+  } else {
+    minfoEnd =
+        new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false,
+                                 llvm::GlobalValue::LinkOnceODRLinkage,
+                                 getNullPtr(moduleInfoPtrTy), "_minfo_end");
+    minfoEnd->setSection(".minfo_end");
+    minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  }
 
   // Build the ctor to invoke _d_dso_registry.
 
@@ -356,7 +465,7 @@ void build_module_ref(std::string moduleMangle,
   llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType());
 
   const auto registerDSO =
-      buildRegisterDSO(dsoInitialized, dsoSlot, minfoBeg, minfoEnd);
+      buildRegisterDSO(style, dsoInitialized, dsoSlot, minfoBeg, minfoEnd);
 
   std::string ctorName = "ldc.dso_ctor.";
   ctorName += moduleMangle;
@@ -604,26 +713,13 @@ void loadInstrProfileData(IRState *irs) {
 
 void registerModuleInfo(Module *m) {
   const auto moduleInfoSym = genModuleInfo(m);
-
-  if ((global.params.targetTriple->isOSLinux() &&
-       global.params.targetTriple->getEnvironment() != llvm::Triple::Android) ||
-      global.params.targetTriple->isOSFreeBSD() ||
-#if LDC_LLVM_VER > 305
-      global.params.targetTriple->isOSNetBSD() ||
-      global.params.targetTriple->isOSOpenBSD() ||
-      global.params.targetTriple->isOSDragonFly()
-#else
-      global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
-      global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
-      global.params.targetTriple->getOS() == llvm::Triple::DragonFly
-#endif
-          ) {
-    build_module_ref(mangle(m), moduleInfoSym);
-  } else {
-    // build the modulereference and ctor for registering it
-    LLFunction *mictor =
+  const auto style = getModuleRegistryStyle();
+  if (style == RegistryStyle::legacyLinkedList) {
+    const auto miCtor =
         build_module_reference_and_ctor(mangle(m), moduleInfoSym);
-    AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true);
+    AppendFunctionToLLVMGlobalCtorsDtors(miCtor, 65535, true);
+  } else {
+    emitModuleRefToSection(style, mangle(m), moduleInfoSym);
   }
 }
 }
diff --git a/gen/runtime.cpp b/gen/runtime.cpp
index 1d03f57..a680a9f 100644
--- a/gen/runtime.cpp
+++ b/gen/runtime.cpp
@@ -677,29 +677,14 @@ static void buildRuntimeModule() {
   //////////////////////////////////////////////////////////////////////////////
 
   // void invariant._d_invariant(Object o)
-  createFwdDecl(
-      LINKd, voidTy,
-      {gABI->mangleFunctionForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)},
-      {objectTy});
-
-  // void _d_dso_registry(CompilerDSOData* data)
-  llvm::StringRef fname("_d_dso_registry");
-
-  LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
-  LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
-  LLType *moduleInfoPtrPtrTy =
-      getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));
-
-  llvm::StructType *dsoDataTy =
-      llvm::StructType::get(DtoSize_t(),        // version
-                            LLvoidPtrPtrTy,     // slot
-                            moduleInfoPtrPtrTy, // _minfo_beg
-                            moduleInfoPtrPtrTy, // _minfo_end
-                            NULL);
+  createFwdDecl(LINKd, voidTy,
+                {gABI->mangleFunctionForLLVM(
+                    "_D9invariant12_d_invariantFC6ObjectZv", LINKd)},
+                {objectTy});
 
-  llvm::Type *types[] = {getPtrToType(dsoDataTy)};
-  llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
-  llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
+  // void _d_dso_registry(void* data)
+  // (the argument is really a pointer to rt.sections_elf_shared.CompilerDSOData)
+  createFwdDecl(LINKc, voidTy, {"_d_dso_registry"}, {voidPtrTy});
 
   //////////////////////////////////////////////////////////////////////////////
   //////////////////////////////////////////////////////////////////////////////
@@ -717,9 +702,9 @@ static void buildRuntimeModule() {
 
     // The types of these functions don't really matter because they are always
     // bitcast to correct signature before calling.
-    Type* objectPtrTy = voidPtrTy;
-    Type* selectorPtrTy = voidPtrTy;
-    Type* realTy = Type::tfloat80;
+    Type *objectPtrTy = voidPtrTy;
+    Type *selectorPtrTy = voidPtrTy;
+    Type *realTy = Type::tfloat80;
 
     // id objc_msgSend(id self, SEL op, ...)
     // Function called early and/or often, so lazy binding isn't worthwhile.
@@ -732,13 +717,13 @@ static void buildRuntimeModule() {
       // creal objc_msgSend_fp2ret(id self, SEL op, ...)
       createFwdDecl(LINKc, Type::tcomplex80, {"objc_msgSend_fp2ret"},
                     {objectPtrTy, selectorPtrTy});
-      // fall-thru
+    // fall-thru
     case llvm::Triple::x86:
       // x86_64 real return only,  x86 float, double, real return
       // real objc_msgSend_fpret(id self, SEL op, ...)
       createFwdDecl(LINKc, realTy, {"objc_msgSend_fpret"},
                     {objectPtrTy, selectorPtrTy});
-      // fall-thru
+    // fall-thru
     case llvm::Triple::arm:
     case llvm::Triple::thumb:
       // used when return value is aggregate via a hidden sret arg
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index 841e2f9..50faf8f 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -37,8 +37,10 @@ else()
 endif()
 
 if(BUILD_SHARED_LIBS)
-    if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
-        message(FATAL_ERROR "Shared libraries (BUILD_SHARED_LIBS) are only supported on Linux and FreeBSD for the time being.")
+    if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND
+       NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND
+       NOT APPLE)
+        message(FATAL_ERROR "Shared libraries (BUILD_SHARED_LIBS) are only supported on Linux, macOS and FreeBSD for the time being.")
     endif()
 
     list(APPEND D_FLAGS -relocation-model=pic)
@@ -422,10 +424,10 @@ macro(build_runtime d_flags c_flags ld_flags lib_suffix path_suffix outlist_targ
     # C executables.
 
     if(BUILD_SHARED_LIBS)
-        if(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-            set(dso_system_libs "m" "pthread")
-        else()
+        if(${CMAKE_SYSTEM} MATCHES "Linux")
             set(dso_system_libs "m" "pthread" "rt" "dl")
+        else()
+            set(dso_system_libs "m" "pthread")
         endif()
         target_link_libraries(druntime-ldc${target_suffix} ${dso_system_libs})
     endif()
@@ -638,6 +640,10 @@ macro(build_test_runner name_suffix d_flags c_flags)
             add_test(build-${l} "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${l})
         endforeach()
 
+        if(NOT APPLE)
+            list(APPEND flags -L--no-as-needed)
+        endif()
+
         set(libarg "druntime-ldc-unittest${name_suffix}")
         add_test(NAME build-druntime-test-runner${name_suffix}
             COMMAND ${LDC_EXE_FULL}
@@ -653,7 +659,7 @@ macro(build_test_runner name_suffix d_flags c_flags)
             add_test(NAME build-phobos2-test-runner${name_suffix}
                 COMMAND ${LDC_EXE_FULL}
                     -of${PROJECT_BINARY_DIR}/phobos2-test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX}
-                    -L--no-as-needed -defaultlib=${libarg} -debuglib=${libarg}
+                    -defaultlib=${libarg} -debuglib=${libarg}
                     -singleobj ${flags} ${RUNTIME_DIR}/src/test_runner.d
             )
             set_tests_properties(build-phobos2-test-runner${name_suffix} PROPERTIES
diff --git a/runtime/druntime b/runtime/druntime
index 17a94d6..cf95c49 160000
--- a/runtime/druntime
+++ b/runtime/druntime
@@ -1 +1 @@
-Subproject commit 17a94d64b47fcc4a41a158e05217a66a9db357e4
+Subproject commit cf95c49d685b78c6ba6f811ca210d243faf0d4d7

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git



More information about the pkg-d-commits mailing list