Skip to content

Commit

Permalink
include the soname-lookup functionality of OpenLib in the compiler
Browse files Browse the repository at this point in the history
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
  • Loading branch information
JeffBezanson committed Nov 27, 2012
1 parent c9ae93a commit 1f1928a
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 24 deletions.
155 changes: 135 additions & 20 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,81 @@
// --- the ccall intrinsic ---

// --- library symbol lookup ---

// map from "libX" to full soname "libX.so.ver"
static std::map<std::string, std::string> 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<std::string, void*> 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
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 8 additions & 3 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <setjmp.h>
#include <string>
Expand Down Expand Up @@ -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++;
Expand Down Expand Up @@ -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<Type*> fsig(0);
for(size_t i=0; i < lam->specTypes->length; i++) {
Expand All @@ -1877,15 +1882,15 @@ 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);
}
}
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;
}
Expand Down
11 changes: 10 additions & 1 deletion src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
}
}
Expand All @@ -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);
Expand Down

2 comments on commit 1f1928a

@StefanKarpinski
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to go through and change any ccalls or are you already doing that?

@JeffBezanson
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll do the rest

Please sign in to comment.