[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