From 1f1928a6a00f09cfd457f369cca8a747b3cefb5b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 27 Nov 2012 16:52:27 -0500 Subject: [PATCH] include the soname-lookup functionality of OpenLib in the compiler close #949 close #450 ccall functions can now be specified as (:lib, :name), without dlopen/dlsym the names can be symbols or strings ccalls are now generated by symbol name instead of by address makes disassembly more readable, and needed for static compilation add "julia_" prefix to generated functions to avoid conflicts in the process symbol table add warning for conflicts among library symbol names --- src/ccall.cpp | 155 +++++++++++++++++++++++++++++++++++++++++------- src/codegen.cpp | 11 +++- src/dlload.c | 11 +++- 3 files changed, 153 insertions(+), 24 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index ae0f8b566b202..d112c6c49b393 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1,5 +1,81 @@ // --- the ccall intrinsic --- +// --- library symbol lookup --- + +// map from "libX" to full soname "libX.so.ver" +static std::map sonameMap; +static bool got_sonames = false; + +static void read_sonames() +{ + char *line=NULL; + size_t sz=0; + FILE *ldc = popen("/sbin/ldconfig -p", "r"); + + while (!feof(ldc)) { + ssize_t n = getline(&line, &sz, ldc); + if (n == -1) + break; + if (n > 2 && isspace(line[0])) { + int i=0; + while (isspace(line[++i])) ; + char *name = &line[i]; + char *dot = strchr(name, '.'); + char *nxt = strchr(name, ' '); + std::string pfx(name, dot - name); + std::string soname(name, nxt - name); + sonameMap[pfx] = soname; + } + } + + free(line); + pclose(ldc); +} + +extern "C" const char *jl_lookup_soname(char *pfx, size_t n) +{ + if (!got_sonames) { + read_sonames(); + got_sonames = true; + } + std::string str(pfx, n); + if (sonameMap.find(str) != sonameMap.end()) { + return sonameMap[str].c_str(); + } + return NULL; +} + +// map from user-specified lib names to handles +static std::map libMap; + +static void *add_library_sym(char *name, char *lib) +{ + void *hnd; + if (lib == NULL) { + hnd = jl_dl_handle; + } + else { + hnd = libMap[lib]; + if (hnd == NULL) { + hnd = jl_load_dynamic_library(lib); + libMap[lib] = hnd; + } + } + // add a symbol->address mapping for the JIT + void *sval = jl_dlsym_e((uv_lib_t*)hnd, name); + if (lib != NULL && hnd != jl_dl_handle) { + void *exist = sys::DynamicLibrary::SearchForAddressOfSymbol(name); + if (exist != NULL && exist != sval) { + ios_printf(ios_stderr, "Warning: Possible conflict in library symbol %s\n", name); + } + if (exist == NULL) + sys::DynamicLibrary::AddSymbol(name, sval); + } + return sval; +} + +// --- argument passing and scratch space utilities --- + static Function *value_to_pointer_func; // TODO: per-thread @@ -170,6 +246,8 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, false); } +// --- code generator for ccall itself --- + // ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { @@ -190,33 +268,62 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); - void *fptr; - if (jl_is_symbol(ptr)) { + void *fptr=NULL; + char *f_name=NULL, *f_lib=NULL; + if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) { + ptr = jl_tupleref(ptr,0); + } + if (jl_is_symbol(ptr)) + f_name = ((jl_sym_t*)ptr)->name; + else if (jl_is_byte_string(ptr)) + f_name = jl_string_data(ptr); + if (f_name != NULL) { // just symbol, default to JuliaDLHandle #ifdef __WIN32__ - - fptr = jl_dlsym_e(jl_dl_handle, ((jl_sym_t*)ptr)->name); - if(!fptr) { - fptr = jl_dlsym_e(jl_kernel32_handle, ((jl_sym_t*)ptr)->name); - if(!fptr) { - fptr = jl_dlsym_e(jl_ntdll_handle, ((jl_sym_t*)ptr)->name); - if(!fptr) { - fptr = jl_dlsym_e(jl_crtdll_handle, ((jl_sym_t*)ptr)->name); - if(!fptr) { - fptr = jl_dlsym(jl_winsock_handle, ((jl_sym_t*)ptr)->name); + fptr = jl_dlsym_e(jl_dl_handle, f_name); + if (!fptr) { + fptr = jl_dlsym_e(jl_kernel32_handle, f_name); + if (!fptr) { + fptr = jl_dlsym_e(jl_ntdll_handle, f_name); + if (!fptr) { + fptr = jl_dlsym_e(jl_crtdll_handle, f_name); + if (!fptr) { + fptr = jl_dlsym(jl_winsock_handle, f_name); } } } } + else { + // available in process symbol table + fptr = NULL; + } #else - fptr = jl_dlsym(jl_dl_handle, ((jl_sym_t*)ptr)->name); + // will look in process symbol table #endif } + else if (jl_is_cpointer_type(jl_typeof(ptr))) { + fptr = *(void**)jl_bits_data(ptr); + } + else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) { + jl_value_t *t0 = jl_tupleref(ptr,0); + jl_value_t *t1 = jl_tupleref(ptr,1); + if (jl_is_symbol(t0)) + f_name = ((jl_sym_t*)t0)->name; + else if (jl_is_byte_string(t0)) + f_name = jl_string_data(t0); + else + JL_TYPECHK(ccall, symbol, t0); + if (jl_is_symbol(t1)) + f_lib = ((jl_sym_t*)t1)->name; + else if (jl_is_byte_string(t1)) + f_lib = jl_string_data(t1); + else + JL_TYPECHK(ccall, symbol, t1); + } else { JL_TYPECHK(ccall, pointer, ptr); - fptr = *(void**)jl_bits_data(ptr); } - if (fptr == NULL) { + if (f_name == NULL && fptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); @@ -291,11 +398,19 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } // make LLVM function object for the target - Function *llvmf = - Function::Create(FunctionType::get(lrt, fargt_sig, isVa), - Function::ExternalLinkage, - "ccall_", jl_Module); - jl_ExecutionEngine->addGlobalMapping(llvmf, fptr); + Function *llvmf; + FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); + + if (fptr != NULL) { + llvmf = Function::Create(functype, Function::ExternalLinkage, + "ccall_", jl_Module); + jl_ExecutionEngine->addGlobalMapping(llvmf, fptr); + } + else { + if (f_lib != NULL) + add_library_sym(f_name, f_lib); + llvmf = (Function*)jl_Module->getOrInsertFunction(f_name, functype); + } // save temp argument area stack pointer Value *saveloc=NULL; diff --git a/src/codegen.cpp b/src/codegen.cpp index 764ff6e7e468b..99ac75016e467 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/IRBuilder.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Config/llvm-config.h" #include #include @@ -1730,7 +1731,7 @@ extern "C" jl_tuple_t *jl_tuple_tvars_to_symbols(jl_tuple_t *t); static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) { Function *w = Function::Create(jl_func_sig, Function::ExternalLinkage, - lam->name->name, jl_Module); + f->getName(), jl_Module); Function::arg_iterator AI = w->arg_begin(); AI++; //const Argument &fArg = *AI++; Value *argArray = AI++; @@ -1869,6 +1870,10 @@ static Function *emit_function(jl_lambda_info_t *lam) specsig = true; } + std::string funcName = lam->name->name; + // try to avoid conflicts in the global symbol table + funcName = "julia_" + funcName; + if (specsig) { std::vector fsig(0); for(size_t i=0; i < lam->specTypes->length; i++) { @@ -1877,7 +1882,7 @@ static Function *emit_function(jl_lambda_info_t *lam) jl_value_t *jlrettype = ast_rettype((jl_value_t*)ast); Type *rt = (jlrettype == (jl_value_t*)jl_nothing->type ? T_void : julia_type_to_llvm(jlrettype)); f = Function::Create(FunctionType::get(rt, fsig, false), - Function::ExternalLinkage, lam->name->name, jl_Module); + Function::ExternalLinkage, funcName, jl_Module); if (lam->functionObject == NULL) { lam->cFunctionObject = (void*)f; lam->functionObject = (void*)gen_jlcall_wrapper(lam, f); @@ -1885,7 +1890,7 @@ static Function *emit_function(jl_lambda_info_t *lam) } else { f = Function::Create(jl_func_sig, Function::ExternalLinkage, - lam->name->name, jl_Module); + funcName, jl_Module); if (lam->functionObject == NULL) { lam->functionObject = (void*)f; } diff --git a/src/dlload.c b/src/dlload.c index cf7f4a9578c5d..12be1a10444ab 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -31,6 +31,8 @@ static char *extensions[] = { ".so", "" }; extern char *julia_home; +char *jl_lookup_soname(char *pfx, size_t n); + int jl_uv_dlopen(const char* filename, uv_lib_t* lib) { #ifdef RTLD_DEEPBIND @@ -91,7 +93,8 @@ uv_lib_t *jl_load_dynamic_library(char *modname) struct stat sbuf; if (stat(path, &sbuf) != -1) { //JL_PRINTF(JL_STDERR, "could not load module %s (%d): %s\n", modname, error, uv_dlerror(handle)); - jl_errorf("could not load module %s: %s", modname, uv_dlerror(handle)); + //jl_errorf("could not load module %s: %s", modname, uv_dlerror(handle)); + goto error; } } } @@ -100,7 +103,13 @@ uv_lib_t *jl_load_dynamic_library(char *modname) error = jl_uv_dlopen(path, handle); if (!error) goto done; } +#if !defined(__APPLE__) && !defined(_WIN32) + char *soname = jl_lookup_soname(modname, strlen(modname)); + error = jl_uv_dlopen(soname, handle); + if (!error) goto done; +#endif +error: //JL_PRINTF(JL_STDERR, "could not load module %s (%d): %s\n", modname, error, uv_dlerror(handle)); jl_errorf("could not load module %s: %s", modname, uv_dlerror(handle)); uv_dlclose(handle);