beta-0.89.2
[luatex.git] / source / libs / luajit / LuaJIT-src / src / lj_clib.c
blob1e927ebe99eb0179236146cfadede167f87acad7
1 /*
2 ** FFI C library loader.
3 ** Copyright (C) 2005-2015 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"
19 #include "lj_strfmt.h"
21 /* -- OS-specific functions ----------------------------------------------- */
23 #if LJ_TARGET_DLOPEN
25 #include <dlfcn.h>
26 #include <stdio.h>
28 #if defined(RTLD_DEFAULT)
29 #define CLIB_DEFHANDLE RTLD_DEFAULT
30 #elif LJ_TARGET_OSX || LJ_TARGET_BSD
31 #define CLIB_DEFHANDLE ((void *)(intptr_t)-2)
32 #else
33 #define CLIB_DEFHANDLE NULL
34 #endif
36 LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
38 lj_err_callermsg(L, dlerror());
41 #define clib_error(L, fmt, name) clib_error_(L)
43 #if defined(__CYGWIN__)
44 #define CLIB_SOPREFIX "cyg"
45 #else
46 #define CLIB_SOPREFIX "lib"
47 #endif
49 #if LJ_TARGET_OSX
50 #define CLIB_SOEXT "%s.dylib"
51 #elif defined(__CYGWIN__)
52 #define CLIB_SOEXT "%s.dll"
53 #else
54 #define CLIB_SOEXT "%s.so"
55 #endif
57 static const char *clib_extname(lua_State *L, const char *name)
59 if (!strchr(name, '/')
60 #ifdef __CYGWIN__
61 && !strchr(name, '\\')
62 #endif
63 ) {
64 if (!strchr(name, '.')) {
65 name = lj_strfmt_pushf(L, CLIB_SOEXT, name);
66 L->top--;
67 #ifdef __CYGWIN__
68 } else {
69 return name;
70 #endif
72 if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
73 name[2] == CLIB_SOPREFIX[2])) {
74 name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name);
75 L->top--;
78 return name;
81 /* Check for a recognized ld script line. */
82 static const char *clib_check_lds(lua_State *L, const char *buf)
84 char *p, *e;
85 if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
86 (p = strchr(buf, '('))) {
87 while (*++p == ' ') ;
88 for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
89 return strdata(lj_str_new(L, p, e-p));
91 return NULL;
94 /* Quick and dirty solution to resolve shared library name from ld script. */
95 static const char *clib_resolve_lds(lua_State *L, const char *name)
97 FILE *fp = fopen(name, "r");
98 const char *p = NULL;
99 if (fp) {
100 char buf[256];
101 if (fgets(buf, sizeof(buf), fp)) {
102 if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */
103 while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */
104 p = clib_check_lds(L, buf);
105 if (p) break;
107 } else { /* Otherwise check only the first line. */
108 p = clib_check_lds(L, buf);
111 fclose(fp);
113 return p;
116 static void *clib_loadlib(lua_State *L, const char *name, int global)
118 void *h = dlopen(clib_extname(L, name),
119 RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
120 if (!h) {
121 const char *e, *err = dlerror();
122 if (*err == '/' && (e = strchr(err, ':')) &&
123 (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
124 h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
125 if (h) return h;
126 err = dlerror();
128 lj_err_callermsg(L, err);
130 return h;
133 static void clib_unloadlib(CLibrary *cl)
135 if (cl->handle && cl->handle != CLIB_DEFHANDLE)
136 dlclose(cl->handle);
139 static void *clib_getsym(CLibrary *cl, const char *name)
141 void *p = dlsym(cl->handle, name);
142 return p;
145 #elif LJ_TARGET_WINDOWS
147 #define WIN32_LEAN_AND_MEAN
148 #include <windows.h>
150 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
151 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
152 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
153 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
154 #endif
156 #define CLIB_DEFHANDLE ((void *)-1)
158 /* Default libraries. */
159 enum {
160 CLIB_HANDLE_EXE,
161 CLIB_HANDLE_DLL,
162 CLIB_HANDLE_CRT,
163 CLIB_HANDLE_KERNEL32,
164 CLIB_HANDLE_USER32,
165 CLIB_HANDLE_GDI32,
166 CLIB_HANDLE_MAX
169 static void *clib_def_handle[CLIB_HANDLE_MAX];
171 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
172 const char *name)
174 DWORD err = GetLastError();
175 #if LJ_TARGET_XBOXONE
176 wchar_t wbuf[128];
177 char buf[128*2];
178 if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
179 NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) ||
180 !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL))
181 #else
182 char buf[128];
183 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
184 NULL, err, 0, buf, sizeof(buf), NULL))
185 #endif
186 buf[0] = '\0';
187 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf));
190 static int clib_needext(const char *s)
192 while (*s) {
193 if (*s == '/' || *s == '\\' || *s == '.') return 0;
194 s++;
196 return 1;
199 static const char *clib_extname(lua_State *L, const char *name)
201 if (clib_needext(name)) {
202 name = lj_strfmt_pushf(L, "%s.dll", name);
203 L->top--;
205 return name;
208 static void *clib_loadlib(lua_State *L, const char *name, int global)
210 DWORD oldwerr = GetLastError();
211 void *h = (void *)LoadLibraryExA(clib_extname(L, name), NULL, 0);
212 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
213 SetLastError(oldwerr);
214 UNUSED(global);
215 return h;
218 static void clib_unloadlib(CLibrary *cl)
220 if (cl->handle == CLIB_DEFHANDLE) {
221 MSize i;
222 for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
223 void *h = clib_def_handle[i];
224 if (h) {
225 clib_def_handle[i] = NULL;
226 FreeLibrary((HINSTANCE)h);
229 } else if (cl->handle) {
230 FreeLibrary((HINSTANCE)cl->handle);
234 static void *clib_getsym(CLibrary *cl, const char *name)
236 void *p = NULL;
237 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
238 MSize i;
239 for (i = 0; i < CLIB_HANDLE_MAX; i++) {
240 HINSTANCE h = (HINSTANCE)clib_def_handle[i];
241 if (!(void *)h) { /* Resolve default library handles (once). */
242 switch (i) {
243 case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
244 case CLIB_HANDLE_DLL:
245 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
246 (const char *)clib_def_handle, &h);
247 break;
248 case CLIB_HANDLE_CRT:
249 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
250 (const char *)&_fmode, &h);
251 break;
252 case CLIB_HANDLE_KERNEL32: h = LoadLibraryExA("kernel32.dll", NULL, 0); break;
253 case CLIB_HANDLE_USER32: h = LoadLibraryExA("user32.dll", NULL, 0); break;
254 case CLIB_HANDLE_GDI32: h = LoadLibraryExA("gdi32.dll", NULL, 0); break;
256 if (!h) continue;
257 clib_def_handle[i] = (void *)h;
259 p = (void *)GetProcAddress(h, name);
260 if (p) break;
262 } else {
263 p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
265 return p;
268 #else
270 #define CLIB_DEFHANDLE NULL
272 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
273 const char *name)
275 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS"));
278 static void *clib_loadlib(lua_State *L, const char *name, int global)
280 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
281 UNUSED(name); UNUSED(global);
282 return NULL;
285 static void clib_unloadlib(CLibrary *cl)
287 UNUSED(cl);
290 static void *clib_getsym(CLibrary *cl, const char *name)
292 UNUSED(cl); UNUSED(name);
293 return NULL;
296 #endif
298 /* -- C library indexing -------------------------------------------------- */
300 #if LJ_TARGET_X86 && LJ_ABI_WIN
301 /* Compute argument size for fastcall/stdcall functions. */
302 static CTSize clib_func_argsize(CTState *cts, CType *ct)
304 CTSize n = 0;
305 while (ct->sib) {
306 CType *d;
307 ct = ctype_get(cts, ct->sib);
308 if (ctype_isfield(ct->info)) {
309 d = ctype_rawchild(cts, ct);
310 n += ((d->size + 3) & ~3);
313 return n;
315 #endif
317 /* Get redirected or mangled external symbol. */
318 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
320 if (ct->sib) {
321 CType *ctf = ctype_get(cts, ct->sib);
322 if (ctype_isxattrib(ctf->info, CTA_REDIR))
323 return strdata(gco2str(gcref(ctf->name)));
325 return strdata(name);
328 /* Index a C library by name. */
329 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
331 TValue *tv = lj_tab_setstr(L, cl->cache, name);
332 if (LJ_UNLIKELY(tvisnil(tv))) {
333 CTState *cts = ctype_cts(L);
334 CType *ct;
335 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
336 if (!id)
337 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
338 if (ctype_isconstval(ct->info)) {
339 CType *ctt = ctype_child(cts, ct);
340 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
341 if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
342 setnumV(tv, (lua_Number)(uint32_t)ct->size);
343 else
344 setintV(tv, (int32_t)ct->size);
345 } else {
346 const char *sym = clib_extsym(cts, ct, name);
347 #if LJ_TARGET_WINDOWS
348 DWORD oldwerr = GetLastError();
349 #endif
350 void *p = clib_getsym(cl, sym);
351 GCcdata *cd;
352 lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
353 #if LJ_TARGET_X86 && LJ_ABI_WIN
354 /* Retry with decorated name for fastcall/stdcall functions. */
355 if (!p && ctype_isfunc(ct->info)) {
356 CTInfo cconv = ctype_cconv(ct->info);
357 if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
358 CTSize sz = clib_func_argsize(cts, ct);
359 const char *symd = lj_strfmt_pushf(L,
360 cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
361 sym, sz);
362 L->top--;
363 p = clib_getsym(cl, symd);
366 #endif
367 if (!p)
368 clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
369 #if LJ_TARGET_WINDOWS
370 SetLastError(oldwerr);
371 #endif
372 cd = lj_cdata_new(cts, id, CTSIZE_PTR);
373 *(void **)cdataptr(cd) = p;
374 setcdataV(L, tv, cd);
377 return tv;
380 /* -- C library management ------------------------------------------------ */
382 /* Create a new CLibrary object and push it on the stack. */
383 static CLibrary *clib_new(lua_State *L, GCtab *mt)
385 GCtab *t = lj_tab_new(L, 0, 0);
386 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
387 CLibrary *cl = (CLibrary *)uddata(ud);
388 cl->cache = t;
389 ud->udtype = UDTYPE_FFI_CLIB;
390 /* NOBARRIER: The GCudata is new (marked white). */
391 setgcref(ud->metatable, obj2gco(mt));
392 setudataV(L, L->top++, ud);
393 return cl;
396 /* Load a C library. */
397 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
399 void *handle = clib_loadlib(L, strdata(name), global);
400 CLibrary *cl = clib_new(L, mt);
401 cl->handle = handle;
404 /* Unload a C library. */
405 void lj_clib_unload(CLibrary *cl)
407 clib_unloadlib(cl);
408 cl->handle = NULL;
411 /* Create the default C library object. */
412 void lj_clib_default(lua_State *L, GCtab *mt)
414 CLibrary *cl = clib_new(L, mt);
415 cl->handle = CLIB_DEFHANDLE;
418 #endif