FFI: Lookup decorated name for fastcall/stdcall functions.

This commit is contained in:
Mike Pall 2011-01-11 03:08:54 +01:00
parent 87a6c8a980
commit a54843bb51

View File

@ -31,38 +31,39 @@
#define CLIB_DEFHANDLE NULL #define CLIB_DEFHANDLE NULL
#endif #endif
LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L) LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
{ {
lj_err_callermsg(L, dlerror()); lj_err_callermsg(L, dlerror());
} }
#define clib_error(L, fmt, name) clib_error_(L)
#if LJ_TARGET_OSX #if LJ_TARGET_OSX
#define CLIB_SOEXT "%s.dylib" #define CLIB_SOEXT "%s.dylib"
#else #else
#define CLIB_SOEXT "%s.so" #define CLIB_SOEXT "%s.so"
#endif #endif
static const char *clib_extname(lua_State *L, GCstr *name) static const char *clib_extname(lua_State *L, const char *name)
{ {
const char *s = strdata(name); if (!strchr(name, '/')) {
if (!strchr(s, '/')) { if (!strchr(name, '.')) {
if (!strchr(s, '.')) { name = lj_str_pushf(L, CLIB_SOEXT, name);
s = lj_str_pushf(L, CLIB_SOEXT, s);
L->top--; L->top--;
} }
if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) { if (!(name[0] == 'l' && name[1] == 'i' && name[2] == 'b')) {
s = lj_str_pushf(L, "lib%s", s); name = lj_str_pushf(L, "lib%s", name);
L->top--; L->top--;
} }
} }
return s; return name;
} }
static void *clib_loadlib(lua_State *L, GCstr *name, int global) static void *clib_loadlib(lua_State *L, const char *name, int global)
{ {
void *h = dlopen(clib_extname(L, name), void *h = dlopen(clib_extname(L, name),
RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
if (!h) clib_error(L); if (!h) clib_error_(L);
return h; return h;
} }
@ -72,10 +73,9 @@ static void clib_unloadlib(CLibrary *cl)
dlclose(cl->handle); dlclose(cl->handle);
} }
static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) static void *clib_getsym(CLibrary *cl, const char *name)
{ {
void *p = dlsym(cl->handle, strdata(name)); void *p = dlsym(cl->handle, name);
if (!p) clib_error(L);
return p; return p;
} }
@ -127,17 +127,16 @@ static int clib_needext(const char *s)
return 1; return 1;
} }
static const char *clib_extname(lua_State *L, GCstr *name) static const char *clib_extname(lua_State *L, const char *name)
{ {
const char *s = strdata(name); if (clib_needext(name)) {
if (clib_needext(s)) { name = lj_str_pushf(L, "%s.dll", name);
s = lj_str_pushf(L, "%s.dll", s);
L->top--; L->top--;
} }
return s; return name;
} }
static void *clib_loadlib(lua_State *L, GCstr *name, int global) static void *clib_loadlib(lua_State *L, const char *name, int global)
{ {
void *h = (void *)LoadLibraryA(clib_extname(L, name)); void *h = (void *)LoadLibraryA(clib_extname(L, name));
if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name));
@ -157,9 +156,8 @@ static void clib_unloadlib(CLibrary *cl)
} }
} }
static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) static void *clib_getsym(CLibrary *cl, const char *name)
{ {
const char *sym = strdata(name);
void *p; void *p;
if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
MSize i; MSize i;
@ -183,13 +181,12 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
if (!h) continue; if (!h) continue;
clib_def_handle[i] = (void *)h; clib_def_handle[i] = (void *)h;
} }
p = (void *)GetProcAddress(h, sym); p = (void *)GetProcAddress(h, name);
if (p) break; if (p) break;
} }
} else { } else {
p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym); p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
} }
if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
return p; return p;
} }
@ -197,7 +194,13 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
#define CLIB_DEFHANDLE NULL #define CLIB_DEFHANDLE NULL
static void *clib_loadlib(lua_State *L, GCstr *name, int global) LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
const char *name)
{
lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
}
static void *clib_loadlib(lua_State *L, const char *name, int global)
{ {
lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
UNUSED(name); UNUSED(global); UNUSED(name); UNUSED(global);
@ -209,9 +212,8 @@ static void clib_unloadlib(CLibrary *cl)
UNUSED(cl); UNUSED(cl);
} }
static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) static void *clib_getsym(CLibrary *cl, const char *name)
{ {
lj_err_callermsg(L, "no support for resolving symbols for this OS");
UNUSED(cl); UNUSED(name); UNUSED(cl); UNUSED(name);
return NULL; return NULL;
} }
@ -224,6 +226,22 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
#define CLNS_INDEX \ #define CLNS_INDEX \
((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL))
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Compute argument size for fastcall/stdcall functions. */
static CTSize clib_func_argsize(CTState *cts, CType *ct)
{
CTSize n = 0;
while (ct->sib) {
CType *d;
ct = ctype_get(cts, ct->sib);
lua_assert(ctype_isfield(ct->info));
d = ctype_rawchild(cts, ct);
n += ((d->size + 3) & ~3);
}
return n;
}
#endif
/* Index a C library by name. */ /* Index a C library by name. */
TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
{ {
@ -242,9 +260,24 @@ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
else else
setnumV(tv, (lua_Number)(int32_t)ct->size); setnumV(tv, (lua_Number)(int32_t)ct->size);
} else { } else {
void *p = clib_getsym(L, cl, name); void *p = clib_getsym(cl, strdata(name));
GCcdata *cd; GCcdata *cd;
lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Retry with decorated name for fastcall/stdcall functions. */
if (!p && ctype_isfunc(ct->info)) {
CTInfo cconv = ctype_cconv(ct->info);
if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
CTSize sz = clib_func_argsize(cts, ct);
const char *sym = lj_str_pushf(L,
cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", strdata(name), sz);
L->top--;
p = clib_getsym(cl, sym);
}
}
#endif
if (!p)
clib_error(L, "cannot resolve symbol " LUA_QS ": %s", strdata(name));
cd = lj_cdata_new(cts, id, CTSIZE_PTR); cd = lj_cdata_new(cts, id, CTSIZE_PTR);
*(void **)cdataptr(cd) = p; *(void **)cdataptr(cd) = p;
setcdataV(L, tv, cd); setcdataV(L, tv, cd);
@ -272,7 +305,7 @@ static CLibrary *clib_new(lua_State *L, GCtab *mt)
/* Load a C library. */ /* Load a C library. */
void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
{ {
void *handle = clib_loadlib(L, name, global); void *handle = clib_loadlib(L, strdata(name), global);
CLibrary *cl = clib_new(L, mt); CLibrary *cl = clib_new(L, mt);
cl->handle = handle; cl->handle = handle;
} }