diff options
author | Mike Pall <mike> | 2011-01-11 03:08:54 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2011-01-11 03:08:54 +0100 |
commit | a54843bb510d4f51e4ce404fe2d42ba80fc74a04 (patch) | |
tree | 3c21e52606aefeba6f2f7a16d836f9f462876355 /src | |
parent | 87a6c8a980edf4bd8ba6b2126269400a925b4d05 (diff) | |
download | luajit-a54843bb510d4f51e4ce404fe2d42ba80fc74a04.tar.gz luajit-a54843bb510d4f51e4ce404fe2d42ba80fc74a04.tar.bz2 luajit-a54843bb510d4f51e4ce404fe2d42ba80fc74a04.zip |
FFI: Lookup decorated name for fastcall/stdcall functions.
Diffstat (limited to 'src')
-rw-r--r-- | src/lj_clib.c | 93 |
1 files changed, 63 insertions, 30 deletions
diff --git a/src/lj_clib.c b/src/lj_clib.c index 91309eb2..3fc91a72 100644 --- a/src/lj_clib.c +++ b/src/lj_clib.c | |||
@@ -31,38 +31,39 @@ | |||
31 | #define CLIB_DEFHANDLE NULL | 31 | #define CLIB_DEFHANDLE NULL |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L) | 34 | LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L) |
35 | { | 35 | { |
36 | lj_err_callermsg(L, dlerror()); | 36 | lj_err_callermsg(L, dlerror()); |
37 | } | 37 | } |
38 | 38 | ||
39 | #define clib_error(L, fmt, name) clib_error_(L) | ||
40 | |||
39 | #if LJ_TARGET_OSX | 41 | #if LJ_TARGET_OSX |
40 | #define CLIB_SOEXT "%s.dylib" | 42 | #define CLIB_SOEXT "%s.dylib" |
41 | #else | 43 | #else |
42 | #define CLIB_SOEXT "%s.so" | 44 | #define CLIB_SOEXT "%s.so" |
43 | #endif | 45 | #endif |
44 | 46 | ||
45 | static const char *clib_extname(lua_State *L, GCstr *name) | 47 | static const char *clib_extname(lua_State *L, const char *name) |
46 | { | 48 | { |
47 | const char *s = strdata(name); | 49 | if (!strchr(name, '/')) { |
48 | if (!strchr(s, '/')) { | 50 | if (!strchr(name, '.')) { |
49 | if (!strchr(s, '.')) { | 51 | name = lj_str_pushf(L, CLIB_SOEXT, name); |
50 | s = lj_str_pushf(L, CLIB_SOEXT, s); | ||
51 | L->top--; | 52 | L->top--; |
52 | } | 53 | } |
53 | if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) { | 54 | if (!(name[0] == 'l' && name[1] == 'i' && name[2] == 'b')) { |
54 | s = lj_str_pushf(L, "lib%s", s); | 55 | name = lj_str_pushf(L, "lib%s", name); |
55 | L->top--; | 56 | L->top--; |
56 | } | 57 | } |
57 | } | 58 | } |
58 | return s; | 59 | return name; |
59 | } | 60 | } |
60 | 61 | ||
61 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 62 | static void *clib_loadlib(lua_State *L, const char *name, int global) |
62 | { | 63 | { |
63 | void *h = dlopen(clib_extname(L, name), | 64 | void *h = dlopen(clib_extname(L, name), |
64 | RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); | 65 | RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); |
65 | if (!h) clib_error(L); | 66 | if (!h) clib_error_(L); |
66 | return h; | 67 | return h; |
67 | } | 68 | } |
68 | 69 | ||
@@ -72,10 +73,9 @@ static void clib_unloadlib(CLibrary *cl) | |||
72 | dlclose(cl->handle); | 73 | dlclose(cl->handle); |
73 | } | 74 | } |
74 | 75 | ||
75 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 76 | static void *clib_getsym(CLibrary *cl, const char *name) |
76 | { | 77 | { |
77 | void *p = dlsym(cl->handle, strdata(name)); | 78 | void *p = dlsym(cl->handle, name); |
78 | if (!p) clib_error(L); | ||
79 | return p; | 79 | return p; |
80 | } | 80 | } |
81 | 81 | ||
@@ -127,17 +127,16 @@ static int clib_needext(const char *s) | |||
127 | return 1; | 127 | return 1; |
128 | } | 128 | } |
129 | 129 | ||
130 | static const char *clib_extname(lua_State *L, GCstr *name) | 130 | static const char *clib_extname(lua_State *L, const char *name) |
131 | { | 131 | { |
132 | const char *s = strdata(name); | 132 | if (clib_needext(name)) { |
133 | if (clib_needext(s)) { | 133 | name = lj_str_pushf(L, "%s.dll", name); |
134 | s = lj_str_pushf(L, "%s.dll", s); | ||
135 | L->top--; | 134 | L->top--; |
136 | } | 135 | } |
137 | return s; | 136 | return name; |
138 | } | 137 | } |
139 | 138 | ||
140 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 139 | static void *clib_loadlib(lua_State *L, const char *name, int global) |
141 | { | 140 | { |
142 | void *h = (void *)LoadLibraryA(clib_extname(L, name)); | 141 | void *h = (void *)LoadLibraryA(clib_extname(L, name)); |
143 | if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); | 142 | if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); |
@@ -157,9 +156,8 @@ static void clib_unloadlib(CLibrary *cl) | |||
157 | } | 156 | } |
158 | } | 157 | } |
159 | 158 | ||
160 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 159 | static void *clib_getsym(CLibrary *cl, const char *name) |
161 | { | 160 | { |
162 | const char *sym = strdata(name); | ||
163 | void *p; | 161 | void *p; |
164 | if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ | 162 | if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ |
165 | MSize i; | 163 | MSize i; |
@@ -183,13 +181,12 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
183 | if (!h) continue; | 181 | if (!h) continue; |
184 | clib_def_handle[i] = (void *)h; | 182 | clib_def_handle[i] = (void *)h; |
185 | } | 183 | } |
186 | p = (void *)GetProcAddress(h, sym); | 184 | p = (void *)GetProcAddress(h, name); |
187 | if (p) break; | 185 | if (p) break; |
188 | } | 186 | } |
189 | } else { | 187 | } else { |
190 | p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym); | 188 | p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); |
191 | } | 189 | } |
192 | if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); | ||
193 | return p; | 190 | return p; |
194 | } | 191 | } |
195 | 192 | ||
@@ -197,7 +194,13 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
197 | 194 | ||
198 | #define CLIB_DEFHANDLE NULL | 195 | #define CLIB_DEFHANDLE NULL |
199 | 196 | ||
200 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 197 | LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, |
198 | const char *name) | ||
199 | { | ||
200 | lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS")); | ||
201 | } | ||
202 | |||
203 | static void *clib_loadlib(lua_State *L, const char *name, int global) | ||
201 | { | 204 | { |
202 | lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); | 205 | lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); |
203 | UNUSED(name); UNUSED(global); | 206 | UNUSED(name); UNUSED(global); |
@@ -209,9 +212,8 @@ static void clib_unloadlib(CLibrary *cl) | |||
209 | UNUSED(cl); | 212 | UNUSED(cl); |
210 | } | 213 | } |
211 | 214 | ||
212 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 215 | static void *clib_getsym(CLibrary *cl, const char *name) |
213 | { | 216 | { |
214 | lj_err_callermsg(L, "no support for resolving symbols for this OS"); | ||
215 | UNUSED(cl); UNUSED(name); | 217 | UNUSED(cl); UNUSED(name); |
216 | return NULL; | 218 | return NULL; |
217 | } | 219 | } |
@@ -224,6 +226,22 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
224 | #define CLNS_INDEX \ | 226 | #define CLNS_INDEX \ |
225 | ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) | 227 | ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) |
226 | 228 | ||
229 | #if LJ_TARGET_X86 && LJ_ABI_WIN | ||
230 | /* Compute argument size for fastcall/stdcall functions. */ | ||
231 | static CTSize clib_func_argsize(CTState *cts, CType *ct) | ||
232 | { | ||
233 | CTSize n = 0; | ||
234 | while (ct->sib) { | ||
235 | CType *d; | ||
236 | ct = ctype_get(cts, ct->sib); | ||
237 | lua_assert(ctype_isfield(ct->info)); | ||
238 | d = ctype_rawchild(cts, ct); | ||
239 | n += ((d->size + 3) & ~3); | ||
240 | } | ||
241 | return n; | ||
242 | } | ||
243 | #endif | ||
244 | |||
227 | /* Index a C library by name. */ | 245 | /* Index a C library by name. */ |
228 | TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) | 246 | TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) |
229 | { | 247 | { |
@@ -242,9 +260,24 @@ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) | |||
242 | else | 260 | else |
243 | setnumV(tv, (lua_Number)(int32_t)ct->size); | 261 | setnumV(tv, (lua_Number)(int32_t)ct->size); |
244 | } else { | 262 | } else { |
245 | void *p = clib_getsym(L, cl, name); | 263 | void *p = clib_getsym(cl, strdata(name)); |
246 | GCcdata *cd; | 264 | GCcdata *cd; |
247 | lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); | 265 | lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); |
266 | #if LJ_TARGET_X86 && LJ_ABI_WIN | ||
267 | /* Retry with decorated name for fastcall/stdcall functions. */ | ||
268 | if (!p && ctype_isfunc(ct->info)) { | ||
269 | CTInfo cconv = ctype_cconv(ct->info); | ||
270 | if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { | ||
271 | CTSize sz = clib_func_argsize(cts, ct); | ||
272 | const char *sym = lj_str_pushf(L, | ||
273 | cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", strdata(name), sz); | ||
274 | L->top--; | ||
275 | p = clib_getsym(cl, sym); | ||
276 | } | ||
277 | } | ||
278 | #endif | ||
279 | if (!p) | ||
280 | clib_error(L, "cannot resolve symbol " LUA_QS ": %s", strdata(name)); | ||
248 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); | 281 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); |
249 | *(void **)cdataptr(cd) = p; | 282 | *(void **)cdataptr(cd) = p; |
250 | setcdataV(L, tv, cd); | 283 | setcdataV(L, tv, cd); |
@@ -272,7 +305,7 @@ static CLibrary *clib_new(lua_State *L, GCtab *mt) | |||
272 | /* Load a C library. */ | 305 | /* Load a C library. */ |
273 | void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) | 306 | void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) |
274 | { | 307 | { |
275 | void *handle = clib_loadlib(L, name, global); | 308 | void *handle = clib_loadlib(L, strdata(name), global); |
276 | CLibrary *cl = clib_new(L, mt); | 309 | CLibrary *cl = clib_new(L, mt); |
277 | cl->handle = handle; | 310 | cl->handle = handle; |
278 | } | 311 | } |