RELEASE LuaJIT-2.0.0-rc1
[luajit-2.0/celess22.git] / src / lj_clib.c
blobedc513625d8d8b658a9c768dbcab373d01cc2eea
1 /*
2 ** FFI C library loader.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4 */
6 #include "lj_obj.h"
8 #if LJ_HASFFI
10 #include "lj_gc.h"
11 #include "lj_err.h"
12 #include "lj_tab.h"
13 #include "lj_str.h"
14 #include "lj_udata.h"
15 #include "lj_ctype.h"
16 #include "lj_cconv.h"
17 #include "lj_cdata.h"
18 #include "lj_clib.h"
20 /* -- OS-specific functions ----------------------------------------------- */
22 #if LJ_TARGET_DLOPEN
24 #include <dlfcn.h>
25 #include <stdio.h>
27 #if defined(RTLD_DEFAULT)
28 #define CLIB_DEFHANDLE RTLD_DEFAULT
29 #elif LJ_TARGET_OSX || LJ_TARGET_BSD
30 #define CLIB_DEFHANDLE ((void *)(intptr_t)-2)
31 #else
32 #define CLIB_DEFHANDLE NULL
33 #endif
35 LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
37 lj_err_callermsg(L, dlerror());
40 #define clib_error(L, fmt, name) clib_error_(L)
42 #if defined(__CYGWIN__)
43 #define CLIB_SOPREFIX "cyg"
44 #else
45 #define CLIB_SOPREFIX "lib"
46 #endif
48 #if LJ_TARGET_OSX
49 #define CLIB_SOEXT "%s.dylib"
50 #elif defined(__CYGWIN__)
51 #define CLIB_SOEXT "%s.dll"
52 #else
53 #define CLIB_SOEXT "%s.so"
54 #endif
56 static const char *clib_extname(lua_State *L, const char *name)
58 if (!strchr(name, '/')
59 #ifdef __CYGWIN__
60 && !strchr(name, '\\')
61 #endif
62 ) {
63 if (!strchr(name, '.')) {
64 name = lj_str_pushf(L, CLIB_SOEXT, name);
65 L->top--;
66 #ifdef __CYGWIN__
67 } else {
68 return name;
69 #endif
71 if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
72 name[2] == CLIB_SOPREFIX[2])) {
73 name = lj_str_pushf(L, CLIB_SOPREFIX "%s", name);
74 L->top--;
77 return name;
80 /* Check for a recognized ld script line. */
81 static const char *clib_check_lds(lua_State *L, const char *buf)
83 char *p, *e;
84 if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
85 (p = strchr(buf, '('))) {
86 while (*++p == ' ') ;
87 for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
88 return strdata(lj_str_new(L, p, e-p));
90 return NULL;
93 /* Quick and dirty solution to resolve shared library name from ld script. */
94 static const char *clib_resolve_lds(lua_State *L, const char *name)
96 FILE *fp = fopen(name, "r");
97 const char *p = NULL;
98 if (fp) {
99 char buf[256];
100 if (fgets(buf, sizeof(buf), fp)) {
101 if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */
102 while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */
103 p = clib_check_lds(L, buf);
104 if (p) break;
106 } else { /* Otherwise check only the first line. */
107 p = clib_check_lds(L, buf);
110 fclose(fp);
112 return p;
115 static void *clib_loadlib(lua_State *L, const char *name, int global)
117 void *h = dlopen(clib_extname(L, name),
118 RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
119 if (!h) {
120 const char *e, *err = dlerror();
121 if (*err == '/' && (e = strchr(err, ':')) &&
122 (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
123 h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
124 if (h) return h;
125 err = dlerror();
127 lj_err_callermsg(L, err);
129 return h;
132 static void clib_unloadlib(CLibrary *cl)
134 if (cl->handle && cl->handle != CLIB_DEFHANDLE)
135 dlclose(cl->handle);
138 static void *clib_getsym(CLibrary *cl, const char *name)
140 void *p = dlsym(cl->handle, name);
141 return p;
144 #elif LJ_TARGET_WINDOWS
146 #define WIN32_LEAN_AND_MEAN
147 #ifndef WINVER
148 #define WINVER 0x0500
149 #endif
150 #include <windows.h>
152 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
153 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
154 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
155 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
156 #endif
158 #define CLIB_DEFHANDLE ((void *)-1)
160 /* Default libraries. */
161 enum {
162 CLIB_HANDLE_EXE,
163 CLIB_HANDLE_DLL,
164 CLIB_HANDLE_CRT,
165 CLIB_HANDLE_KERNEL32,
166 CLIB_HANDLE_USER32,
167 CLIB_HANDLE_GDI32,
168 CLIB_HANDLE_MAX
171 static void *clib_def_handle[CLIB_HANDLE_MAX];
173 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
174 const char *name)
176 DWORD err = GetLastError();
177 char buf[128];
178 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
179 NULL, err, 0, buf, sizeof(buf), NULL))
180 buf[0] = '\0';
181 lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
184 static int clib_needext(const char *s)
186 while (*s) {
187 if (*s == '/' || *s == '\\' || *s == '.') return 0;
188 s++;
190 return 1;
193 static const char *clib_extname(lua_State *L, const char *name)
195 if (clib_needext(name)) {
196 name = lj_str_pushf(L, "%s.dll", name);
197 L->top--;
199 return name;
202 static void *clib_loadlib(lua_State *L, const char *name, int global)
204 DWORD oldwerr = GetLastError();
205 void *h = (void *)LoadLibraryA(clib_extname(L, name));
206 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
207 SetLastError(oldwerr);
208 UNUSED(global);
209 return h;
212 static void clib_unloadlib(CLibrary *cl)
214 if (cl->handle == CLIB_DEFHANDLE) {
215 MSize i;
216 for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
217 void *h = clib_def_handle[i];
218 if (h) {
219 clib_def_handle[i] = NULL;
220 FreeLibrary((HINSTANCE)h);
223 } else if (!cl->handle) {
224 FreeLibrary((HINSTANCE)cl->handle);
228 static void *clib_getsym(CLibrary *cl, const char *name)
230 void *p = NULL;
231 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
232 MSize i;
233 for (i = 0; i < CLIB_HANDLE_MAX; i++) {
234 HINSTANCE h = (HINSTANCE)clib_def_handle[i];
235 if (!(void *)h) { /* Resolve default library handles (once). */
236 switch (i) {
237 case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
238 case CLIB_HANDLE_DLL:
239 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
240 (const char *)clib_def_handle, &h);
241 break;
242 case CLIB_HANDLE_CRT:
243 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
244 (const char *)&_fmode, &h);
245 break;
246 case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
247 case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
248 case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
250 if (!h) continue;
251 clib_def_handle[i] = (void *)h;
253 p = (void *)GetProcAddress(h, name);
254 if (p) break;
256 } else {
257 p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
259 return p;
262 #else
264 #define CLIB_DEFHANDLE NULL
266 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
267 const char *name)
269 lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
272 static void *clib_loadlib(lua_State *L, const char *name, int global)
274 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
275 UNUSED(name); UNUSED(global);
276 return NULL;
279 static void clib_unloadlib(CLibrary *cl)
281 UNUSED(cl);
284 static void *clib_getsym(CLibrary *cl, const char *name)
286 UNUSED(cl); UNUSED(name);
287 return NULL;
290 #endif
292 /* -- C library indexing -------------------------------------------------- */
294 #if LJ_TARGET_X86 && LJ_ABI_WIN
295 /* Compute argument size for fastcall/stdcall functions. */
296 static CTSize clib_func_argsize(CTState *cts, CType *ct)
298 CTSize n = 0;
299 while (ct->sib) {
300 CType *d;
301 ct = ctype_get(cts, ct->sib);
302 if (ctype_isfield(ct->info)) {
303 d = ctype_rawchild(cts, ct);
304 n += ((d->size + 3) & ~3);
307 return n;
309 #endif
311 /* Get redirected or mangled external symbol. */
312 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
314 if (ct->sib) {
315 CType *ctf = ctype_get(cts, ct->sib);
316 if (ctype_isxattrib(ctf->info, CTA_REDIR))
317 return strdata(gco2str(gcref(ctf->name)));
319 return strdata(name);
322 /* Index a C library by name. */
323 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
325 TValue *tv = lj_tab_setstr(L, cl->cache, name);
326 if (LJ_UNLIKELY(tvisnil(tv))) {
327 CTState *cts = ctype_cts(L);
328 CType *ct;
329 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
330 if (!id)
331 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
332 if (ctype_isconstval(ct->info)) {
333 CType *ctt = ctype_child(cts, ct);
334 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
335 if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
336 setnumV(tv, (lua_Number)(uint32_t)ct->size);
337 else
338 setintV(tv, (int32_t)ct->size);
339 } else {
340 const char *sym = clib_extsym(cts, ct, name);
341 #if LJ_TARGET_WINDOWS
342 DWORD oldwerr = GetLastError();
343 #endif
344 void *p = clib_getsym(cl, sym);
345 GCcdata *cd;
346 lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
347 #if LJ_TARGET_X86 && LJ_ABI_WIN
348 /* Retry with decorated name for fastcall/stdcall functions. */
349 if (!p && ctype_isfunc(ct->info)) {
350 CTInfo cconv = ctype_cconv(ct->info);
351 if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
352 CTSize sz = clib_func_argsize(cts, ct);
353 const char *symd = lj_str_pushf(L,
354 cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
355 sym, sz);
356 L->top--;
357 p = clib_getsym(cl, symd);
360 #endif
361 if (!p)
362 clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
363 #if LJ_TARGET_WINDOWS
364 SetLastError(oldwerr);
365 #endif
366 cd = lj_cdata_new(cts, id, CTSIZE_PTR);
367 *(void **)cdataptr(cd) = p;
368 setcdataV(L, tv, cd);
371 return tv;
374 /* -- C library management ------------------------------------------------ */
376 /* Create a new CLibrary object and push it on the stack. */
377 static CLibrary *clib_new(lua_State *L, GCtab *mt)
379 GCtab *t = lj_tab_new(L, 0, 0);
380 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
381 CLibrary *cl = (CLibrary *)uddata(ud);
382 cl->cache = t;
383 ud->udtype = UDTYPE_FFI_CLIB;
384 /* NOBARRIER: The GCudata is new (marked white). */
385 setgcref(ud->metatable, obj2gco(mt));
386 setudataV(L, L->top++, ud);
387 return cl;
390 /* Load a C library. */
391 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
393 void *handle = clib_loadlib(L, strdata(name), global);
394 CLibrary *cl = clib_new(L, mt);
395 cl->handle = handle;
398 /* Unload a C library. */
399 void lj_clib_unload(CLibrary *cl)
401 clib_unloadlib(cl);
402 cl->handle = NULL;
405 /* Create the default C library object. */
406 void lj_clib_default(lua_State *L, GCtab *mt)
408 CLibrary *cl = clib_new(L, mt);
409 cl->handle = CLIB_DEFHANDLE;
412 #endif