2 ** FFI C library loader.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
20 /* -- OS-specific functions ----------------------------------------------- */
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)
32 #define CLIB_DEFHANDLE NULL
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"
45 #define CLIB_SOPREFIX "lib"
49 #define CLIB_SOEXT "%s.dylib"
50 #elif defined(__CYGWIN__)
51 #define CLIB_SOEXT "%s.dll"
53 #define CLIB_SOEXT "%s.so"
56 static const char *clib_extname(lua_State
*L
, const char *name
)
58 if (!strchr(name
, '/')
60 && !strchr(name
, '\\')
63 if (!strchr(name
, '.')) {
64 name
= lj_str_pushf(L
, CLIB_SOEXT
, name
);
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
);
80 /* Check for a recognized ld script line. */
81 static const char *clib_check_lds(lua_State
*L
, const char *buf
)
84 if ((!strncmp(buf
, "GROUP", 5) || !strncmp(buf
, "INPUT", 5)) &&
85 (p
= strchr(buf
, '('))) {
87 for (e
= p
; *e
&& *e
!= ' ' && *e
!= ')'; e
++) ;
88 return strdata(lj_str_new(L
, p
, e
-p
));
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");
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
);
106 } else { /* Otherwise check only the first line. */
107 p
= clib_check_lds(L
, buf
);
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
));
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
));
127 lj_err_callermsg(L
, err
);
132 static void clib_unloadlib(CLibrary
*cl
)
134 if (cl
->handle
&& cl
->handle
!= CLIB_DEFHANDLE
)
138 static void *clib_getsym(CLibrary
*cl
, const char *name
)
140 void *p
= dlsym(cl
->handle
, name
);
144 #elif LJ_TARGET_WINDOWS
146 #define WIN32_LEAN_AND_MEAN
148 #define WINVER 0x0500
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
*);
158 #define CLIB_DEFHANDLE ((void *)-1)
160 /* Default libraries. */
165 CLIB_HANDLE_KERNEL32
,
171 static void *clib_def_handle
[CLIB_HANDLE_MAX
];
173 LJ_NORET LJ_NOINLINE
static void clib_error(lua_State
*L
, const char *fmt
,
176 DWORD err
= GetLastError();
178 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS
|FORMAT_MESSAGE_FROM_SYSTEM
,
179 NULL
, err
, 0, buf
, sizeof(buf
), NULL
))
181 lj_err_callermsg(L
, lj_str_pushf(L
, fmt
, name
, buf
));
184 static int clib_needext(const char *s
)
187 if (*s
== '/' || *s
== '\\' || *s
== '.') return 0;
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
);
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
);
212 static void clib_unloadlib(CLibrary
*cl
)
214 if (cl
->handle
== CLIB_DEFHANDLE
) {
216 for (i
= 0; i
< CLIB_HANDLE_MAX
; i
++) {
217 void *h
= clib_def_handle
[i
];
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
)
231 DWORD oldwerr
= GetLastError();
232 if (cl
->handle
== CLIB_DEFHANDLE
) { /* Search default libraries. */
234 for (i
= 0; i
< CLIB_HANDLE_MAX
; i
++) {
235 HINSTANCE h
= (HINSTANCE
)clib_def_handle
[i
];
236 if (!(void *)h
) { /* Resolve default library handles (once). */
238 case CLIB_HANDLE_EXE
: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
, NULL
, &h
); break;
239 case CLIB_HANDLE_DLL
:
240 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
241 (const char *)clib_def_handle
, &h
);
243 case CLIB_HANDLE_CRT
:
244 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
245 (const char *)&_fmode
, &h
);
247 case CLIB_HANDLE_KERNEL32
: h
= LoadLibraryA("kernel32.dll"); break;
248 case CLIB_HANDLE_USER32
: h
= LoadLibraryA("user32.dll"); break;
249 case CLIB_HANDLE_GDI32
: h
= LoadLibraryA("gdi32.dll"); break;
252 clib_def_handle
[i
] = (void *)h
;
254 p
= (void *)GetProcAddress(h
, name
);
258 p
= (void *)GetProcAddress((HINSTANCE
)cl
->handle
, name
);
260 SetLastError(oldwerr
);
266 #define CLIB_DEFHANDLE NULL
268 LJ_NORET LJ_NOINLINE
static void clib_error(lua_State
*L
, const char *fmt
,
271 lj_err_callermsg(L
, lj_str_pushf(L
, fmt
, name
, "no support for this OS"));
274 static void *clib_loadlib(lua_State
*L
, const char *name
, int global
)
276 lj_err_callermsg(L
, "no support for loading dynamic libraries for this OS");
277 UNUSED(name
); UNUSED(global
);
281 static void clib_unloadlib(CLibrary
*cl
)
286 static void *clib_getsym(CLibrary
*cl
, const char *name
)
288 UNUSED(cl
); UNUSED(name
);
294 /* -- C library indexing -------------------------------------------------- */
296 #if LJ_TARGET_X86 && LJ_ABI_WIN
297 /* Compute argument size for fastcall/stdcall functions. */
298 static CTSize
clib_func_argsize(CTState
*cts
, CType
*ct
)
303 ct
= ctype_get(cts
, ct
->sib
);
304 if (ctype_isfield(ct
->info
)) {
305 d
= ctype_rawchild(cts
, ct
);
306 n
+= ((d
->size
+ 3) & ~3);
313 /* Get redirected or mangled external symbol. */
314 static const char *clib_extsym(CTState
*cts
, CType
*ct
, GCstr
*name
)
317 CType
*ctf
= ctype_get(cts
, ct
->sib
);
318 if (ctype_isxattrib(ctf
->info
, CTA_REDIR
))
319 return strdata(gco2str(gcref(ctf
->name
)));
321 return strdata(name
);
324 /* Index a C library by name. */
325 TValue
*lj_clib_index(lua_State
*L
, CLibrary
*cl
, GCstr
*name
)
327 TValue
*tv
= lj_tab_setstr(L
, cl
->cache
, name
);
328 if (LJ_UNLIKELY(tvisnil(tv
))) {
329 CTState
*cts
= ctype_cts(L
);
331 CTypeID id
= lj_ctype_getname(cts
, &ct
, name
, CLNS_INDEX
);
333 lj_err_callerv(L
, LJ_ERR_FFI_NODECL
, strdata(name
));
334 if (ctype_isconstval(ct
->info
)) {
335 CType
*ctt
= ctype_child(cts
, ct
);
336 lua_assert(ctype_isinteger(ctt
->info
) && ctt
->size
<= 4);
337 if ((ctt
->info
& CTF_UNSIGNED
) && (int32_t)ct
->size
< 0)
338 setnumV(tv
, (lua_Number
)(uint32_t)ct
->size
);
340 setintV(tv
, (int32_t)ct
->size
);
342 const char *sym
= clib_extsym(cts
, ct
, name
);
343 void *p
= clib_getsym(cl
, sym
);
345 lua_assert(ctype_isfunc(ct
->info
) || ctype_isextern(ct
->info
));
346 #if LJ_TARGET_X86 && LJ_ABI_WIN
347 /* Retry with decorated name for fastcall/stdcall functions. */
348 if (!p
&& ctype_isfunc(ct
->info
)) {
349 CTInfo cconv
= ctype_cconv(ct
->info
);
350 if (cconv
== CTCC_FASTCALL
|| cconv
== CTCC_STDCALL
) {
351 CTSize sz
= clib_func_argsize(cts
, ct
);
352 sym
= lj_str_pushf(L
, cconv
== CTCC_FASTCALL
? "@%s@%d" : "_%s@%d",
355 p
= clib_getsym(cl
, sym
);
360 clib_error(L
, "cannot resolve symbol " LUA_QS
": %s", strdata(name
));
361 cd
= lj_cdata_new(cts
, id
, CTSIZE_PTR
);
362 *(void **)cdataptr(cd
) = p
;
363 setcdataV(L
, tv
, cd
);
369 /* -- C library management ------------------------------------------------ */
371 /* Create a new CLibrary object and push it on the stack. */
372 static CLibrary
*clib_new(lua_State
*L
, GCtab
*mt
)
374 GCtab
*t
= lj_tab_new(L
, 0, 0);
375 GCudata
*ud
= lj_udata_new(L
, sizeof(CLibrary
), t
);
376 CLibrary
*cl
= (CLibrary
*)uddata(ud
);
378 ud
->udtype
= UDTYPE_FFI_CLIB
;
379 /* NOBARRIER: The GCudata is new (marked white). */
380 setgcref(ud
->metatable
, obj2gco(mt
));
381 setudataV(L
, L
->top
++, ud
);
385 /* Load a C library. */
386 void lj_clib_load(lua_State
*L
, GCtab
*mt
, GCstr
*name
, int global
)
388 void *handle
= clib_loadlib(L
, strdata(name
), global
);
389 CLibrary
*cl
= clib_new(L
, mt
);
393 /* Unload a C library. */
394 void lj_clib_unload(CLibrary
*cl
)
400 /* Create the default C library object. */
401 void lj_clib_default(lua_State
*L
, GCtab
*mt
)
403 CLibrary
*cl
= clib_new(L
, mt
);
404 cl
->handle
= CLIB_DEFHANDLE
;