Cleanup various endianess issues in assembler backend.
[luajit-2.0.git] / src / lj_clib.c
blobff576d35c01c08ed40ad16ed64438055504d769a
1 /*
2 ** FFI C library loader.
3 ** Copyright (C) 2005-2011 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 LJ_TARGET_OSX
43 #define CLIB_SOEXT "%s.dylib"
44 #else
45 #define CLIB_SOEXT "%s.so"
46 #endif
48 static const char *clib_extname(lua_State *L, const char *name)
50 if (!strchr(name, '/')) {
51 if (!strchr(name, '.')) {
52 name = lj_str_pushf(L, CLIB_SOEXT, name);
53 L->top--;
55 if (!(name[0] == 'l' && name[1] == 'i' && name[2] == 'b')) {
56 name = lj_str_pushf(L, "lib%s", name);
57 L->top--;
60 return name;
63 /* Quick and dirty solution to resolve shared library name from ld script. */
64 static const char *clib_resolve_lds(lua_State *L, const char *name)
66 FILE *fp = fopen(name, "r");
67 if (fp) {
68 char *p, *e, buf[256];
69 if (fgets(buf, sizeof(buf), fp) && !strncmp(buf, "/* GNU ld script", 16)) {
70 while (fgets(buf, sizeof(buf), fp)) {
71 if (!strncmp(buf, "GROUP", 5) && (p = strchr(buf, '('))) {
72 while (*++p == ' ') ;
73 for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
74 fclose(fp);
75 return strdata(lj_str_new(L, p, e-p));
79 fclose(fp);
81 return NULL;
84 static void *clib_loadlib(lua_State *L, const char *name, int global)
86 void *h = dlopen(clib_extname(L, name),
87 RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
88 if (!h) {
89 const char *e, *err = dlerror();
90 if (*err == '/' && (e = strchr(err, ':')) &&
91 (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
92 h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
93 if (h) return h;
94 err = dlerror();
96 lj_err_callermsg(L, err);
98 return h;
101 static void clib_unloadlib(CLibrary *cl)
103 if (!cl->handle && cl->handle != CLIB_DEFHANDLE)
104 dlclose(cl->handle);
107 static void *clib_getsym(CLibrary *cl, const char *name)
109 void *p = dlsym(cl->handle, name);
110 return p;
113 #elif LJ_TARGET_WINDOWS
115 #define WIN32_LEAN_AND_MEAN
116 #ifndef WINVER
117 #define WINVER 0x0500
118 #endif
119 #include <windows.h>
121 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
122 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
123 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
124 #endif
126 #define CLIB_DEFHANDLE ((void *)-1)
128 /* Default libraries. */
129 enum {
130 CLIB_HANDLE_EXE,
131 CLIB_HANDLE_DLL,
132 CLIB_HANDLE_CRT,
133 CLIB_HANDLE_KERNEL32,
134 CLIB_HANDLE_USER32,
135 CLIB_HANDLE_GDI32,
136 CLIB_HANDLE_MAX
139 static void *clib_def_handle[CLIB_HANDLE_MAX];
141 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
142 const char *name)
144 DWORD err = GetLastError();
145 char buf[128];
146 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
147 NULL, err, 0, buf, sizeof(buf), NULL))
148 buf[0] = '\0';
149 lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
152 static int clib_needext(const char *s)
154 while (*s) {
155 if (*s == '/' || *s == '\\' || *s == '.') return 0;
156 s++;
158 return 1;
161 static const char *clib_extname(lua_State *L, const char *name)
163 if (clib_needext(name)) {
164 name = lj_str_pushf(L, "%s.dll", name);
165 L->top--;
167 return name;
170 static void *clib_loadlib(lua_State *L, const char *name, int global)
172 void *h = (void *)LoadLibraryA(clib_extname(L, name));
173 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
174 UNUSED(global);
175 return h;
178 static void clib_unloadlib(CLibrary *cl)
180 if (cl->handle == CLIB_DEFHANDLE) {
181 MSize i;
182 for (i = 0; i < CLIB_HANDLE_MAX; i++) {
183 void *h = clib_def_handle[i];
184 if (h) {
185 clib_def_handle[i] = NULL;
186 FreeLibrary((HINSTANCE)h);
189 } else if (!cl->handle) {
190 FreeLibrary((HINSTANCE)cl->handle);
194 static void *clib_getsym(CLibrary *cl, const char *name)
196 void *p = NULL;
197 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
198 MSize i;
199 for (i = 0; i < CLIB_HANDLE_MAX; i++) {
200 HINSTANCE h = (HINSTANCE)clib_def_handle[i];
201 if (!(void *)h) { /* Resolve default library handles (once). */
202 switch (i) {
203 case CLIB_HANDLE_EXE: GetModuleHandleExA(0, NULL, &h); break;
204 case CLIB_HANDLE_DLL:
205 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
206 (const char *)clib_def_handle, &h);
207 break;
208 case CLIB_HANDLE_CRT:
209 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
210 (const char *)&_fmode, &h);
211 break;
212 case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
213 case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
214 case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
216 if (!h) continue;
217 clib_def_handle[i] = (void *)h;
219 p = (void *)GetProcAddress(h, name);
220 if (p) break;
222 } else {
223 p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
225 return p;
228 #else
230 #define CLIB_DEFHANDLE NULL
232 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
233 const char *name)
235 lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
238 static void *clib_loadlib(lua_State *L, const char *name, int global)
240 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
241 UNUSED(name); UNUSED(global);
242 return NULL;
245 static void clib_unloadlib(CLibrary *cl)
247 UNUSED(cl);
250 static void *clib_getsym(CLibrary *cl, const char *name)
252 UNUSED(cl); UNUSED(name);
253 return NULL;
256 #endif
258 /* -- C library indexing -------------------------------------------------- */
260 #if LJ_TARGET_X86 && LJ_ABI_WIN
261 /* Compute argument size for fastcall/stdcall functions. */
262 static CTSize clib_func_argsize(CTState *cts, CType *ct)
264 CTSize n = 0;
265 while (ct->sib) {
266 CType *d;
267 ct = ctype_get(cts, ct->sib);
268 lua_assert(ctype_isfield(ct->info));
269 d = ctype_rawchild(cts, ct);
270 n += ((d->size + 3) & ~3);
272 return n;
274 #endif
276 /* Get redirected or mangled external symbol. */
277 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
279 if (ct->sib) {
280 CType *ctf = ctype_get(cts, ct->sib);
281 if (ctype_isxattrib(ctf->info, CTA_REDIR))
282 return strdata(gco2str(gcref(ctf->name)));
284 return strdata(name);
287 /* Index a C library by name. */
288 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
290 TValue *tv = lj_tab_setstr(L, cl->cache, name);
291 if (LJ_UNLIKELY(tvisnil(tv))) {
292 CTState *cts = ctype_cts(L);
293 CType *ct;
294 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
295 if (!id)
296 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
297 if (ctype_isconstval(ct->info)) {
298 CType *ctt = ctype_child(cts, ct);
299 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
300 if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
301 setnumV(tv, (lua_Number)(uint32_t)ct->size);
302 else
303 setintV(tv, (int32_t)ct->size);
304 } else {
305 const char *sym = clib_extsym(cts, ct, name);
306 void *p = clib_getsym(cl, sym);
307 GCcdata *cd;
308 lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
309 #if LJ_TARGET_X86 && LJ_ABI_WIN
310 /* Retry with decorated name for fastcall/stdcall functions. */
311 if (!p && ctype_isfunc(ct->info)) {
312 CTInfo cconv = ctype_cconv(ct->info);
313 if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
314 CTSize sz = clib_func_argsize(cts, ct);
315 sym = lj_str_pushf(L, cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
316 sym, sz);
317 L->top--;
318 p = clib_getsym(cl, sym);
321 #endif
322 if (!p)
323 clib_error(L, "cannot resolve symbol " LUA_QS ": %s", strdata(name));
324 cd = lj_cdata_new(cts, id, CTSIZE_PTR);
325 *(void **)cdataptr(cd) = p;
326 setcdataV(L, tv, cd);
329 return tv;
332 /* -- C library management ------------------------------------------------ */
334 /* Create a new CLibrary object and push it on the stack. */
335 static CLibrary *clib_new(lua_State *L, GCtab *mt)
337 GCtab *t = lj_tab_new(L, 0, 0);
338 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
339 CLibrary *cl = (CLibrary *)uddata(ud);
340 cl->cache = t;
341 ud->udtype = UDTYPE_FFI_CLIB;
342 /* NOBARRIER: The GCudata is new (marked white). */
343 setgcref(ud->metatable, obj2gco(mt));
344 setudataV(L, L->top++, ud);
345 return cl;
348 /* Load a C library. */
349 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
351 void *handle = clib_loadlib(L, strdata(name), global);
352 CLibrary *cl = clib_new(L, mt);
353 cl->handle = handle;
356 /* Unload a C library. */
357 void lj_clib_unload(CLibrary *cl)
359 clib_unloadlib(cl);
360 cl->handle = NULL;
363 /* Create the default C library object. */
364 void lj_clib_default(lua_State *L, GCtab *mt)
366 CLibrary *cl = clib_new(L, mt);
367 cl->handle = CLIB_DEFHANDLE;
370 #endif