2 ** FFI C library loader.
3 ** Copyright (C) 2005-2017 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)
43 #define CLIB_SOPREFIX "cyg"
45 #define CLIB_SOPREFIX "lib"
49 #define CLIB_SOEXT "%s.dylib"
50 #elif LJ_TARGET_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
149 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
150 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
151 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
152 BOOL WINAPI
GetModuleHandleExA(DWORD
, LPCSTR
, HMODULE
*);
155 #define CLIB_DEFHANDLE ((void *)-1)
157 /* Default libraries. */
162 CLIB_HANDLE_KERNEL32
,
168 static void *clib_def_handle
[CLIB_HANDLE_MAX
];
170 LJ_NORET LJ_NOINLINE
static void clib_error(lua_State
*L
, const char *fmt
,
173 DWORD err
= GetLastError();
175 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS
|FORMAT_MESSAGE_FROM_SYSTEM
,
176 NULL
, err
, 0, buf
, sizeof(buf
), NULL
))
178 lj_err_callermsg(L
, lj_str_pushf(L
, fmt
, name
, buf
));
181 static int clib_needext(const char *s
)
184 if (*s
== '/' || *s
== '\\' || *s
== '.') return 0;
190 static const char *clib_extname(lua_State
*L
, const char *name
)
192 if (clib_needext(name
)) {
193 name
= lj_str_pushf(L
, "%s.dll", name
);
199 static void *clib_loadlib(lua_State
*L
, const char *name
, int global
)
201 DWORD oldwerr
= GetLastError();
202 void *h
= (void *)LoadLibraryA(clib_extname(L
, name
));
203 if (!h
) clib_error(L
, "cannot load module " LUA_QS
": %s", name
);
204 SetLastError(oldwerr
);
209 static void clib_unloadlib(CLibrary
*cl
)
211 if (cl
->handle
== CLIB_DEFHANDLE
) {
213 for (i
= CLIB_HANDLE_KERNEL32
; i
< CLIB_HANDLE_MAX
; i
++) {
214 void *h
= clib_def_handle
[i
];
216 clib_def_handle
[i
] = NULL
;
217 FreeLibrary((HINSTANCE
)h
);
220 } else if (cl
->handle
) {
221 FreeLibrary((HINSTANCE
)cl
->handle
);
225 static void *clib_getsym(CLibrary
*cl
, const char *name
)
228 if (cl
->handle
== CLIB_DEFHANDLE
) { /* Search default libraries. */
230 for (i
= 0; i
< CLIB_HANDLE_MAX
; i
++) {
231 HINSTANCE h
= (HINSTANCE
)clib_def_handle
[i
];
232 if (!(void *)h
) { /* Resolve default library handles (once). */
234 case CLIB_HANDLE_EXE
: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
, NULL
, &h
); break;
235 case CLIB_HANDLE_DLL
:
236 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
237 (const char *)clib_def_handle
, &h
);
239 case CLIB_HANDLE_CRT
:
240 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
241 (const char *)&_fmode
, &h
);
243 case CLIB_HANDLE_KERNEL32
: h
= LoadLibraryA("kernel32.dll"); break;
244 case CLIB_HANDLE_USER32
: h
= LoadLibraryA("user32.dll"); break;
245 case CLIB_HANDLE_GDI32
: h
= LoadLibraryA("gdi32.dll"); break;
248 clib_def_handle
[i
] = (void *)h
;
250 p
= (void *)GetProcAddress(h
, name
);
254 p
= (void *)GetProcAddress((HINSTANCE
)cl
->handle
, name
);
261 #define CLIB_DEFHANDLE NULL
263 LJ_NORET LJ_NOINLINE
static void clib_error(lua_State
*L
, const char *fmt
,
266 lj_err_callermsg(L
, lj_str_pushf(L
, fmt
, name
, "no support for this OS"));
269 static void *clib_loadlib(lua_State
*L
, const char *name
, int global
)
271 lj_err_callermsg(L
, "no support for loading dynamic libraries for this OS");
272 UNUSED(name
); UNUSED(global
);
276 static void clib_unloadlib(CLibrary
*cl
)
281 static void *clib_getsym(CLibrary
*cl
, const char *name
)
283 UNUSED(cl
); UNUSED(name
);
289 /* -- C library indexing -------------------------------------------------- */
291 #if LJ_TARGET_X86 && LJ_ABI_WIN
292 /* Compute argument size for fastcall/stdcall functions. */
293 static CTSize
clib_func_argsize(CTState
*cts
, CType
*ct
)
298 ct
= ctype_get(cts
, ct
->sib
);
299 if (ctype_isfield(ct
->info
)) {
300 d
= ctype_rawchild(cts
, ct
);
301 n
+= ((d
->size
+ 3) & ~3);
308 /* Get redirected or mangled external symbol. */
309 static const char *clib_extsym(CTState
*cts
, CType
*ct
, GCstr
*name
)
312 CType
*ctf
= ctype_get(cts
, ct
->sib
);
313 if (ctype_isxattrib(ctf
->info
, CTA_REDIR
))
314 return strdata(gco2str(gcref(ctf
->name
)));
316 return strdata(name
);
319 /* Index a C library by name. */
320 TValue
*lj_clib_index(lua_State
*L
, CLibrary
*cl
, GCstr
*name
)
322 TValue
*tv
= lj_tab_setstr(L
, cl
->cache
, name
);
323 if (LJ_UNLIKELY(tvisnil(tv
))) {
324 CTState
*cts
= ctype_cts(L
);
326 CTypeID id
= lj_ctype_getname(cts
, &ct
, name
, CLNS_INDEX
);
328 lj_err_callerv(L
, LJ_ERR_FFI_NODECL
, strdata(name
));
329 if (ctype_isconstval(ct
->info
)) {
330 CType
*ctt
= ctype_child(cts
, ct
);
331 lua_assert(ctype_isinteger(ctt
->info
) && ctt
->size
<= 4);
332 if ((ctt
->info
& CTF_UNSIGNED
) && (int32_t)ct
->size
< 0)
333 setnumV(tv
, (lua_Number
)(uint32_t)ct
->size
);
335 setintV(tv
, (int32_t)ct
->size
);
337 const char *sym
= clib_extsym(cts
, ct
, name
);
338 #if LJ_TARGET_WINDOWS
339 DWORD oldwerr
= GetLastError();
341 void *p
= clib_getsym(cl
, sym
);
343 lua_assert(ctype_isfunc(ct
->info
) || ctype_isextern(ct
->info
));
344 #if LJ_TARGET_X86 && LJ_ABI_WIN
345 /* Retry with decorated name for fastcall/stdcall functions. */
346 if (!p
&& ctype_isfunc(ct
->info
)) {
347 CTInfo cconv
= ctype_cconv(ct
->info
);
348 if (cconv
== CTCC_FASTCALL
|| cconv
== CTCC_STDCALL
) {
349 CTSize sz
= clib_func_argsize(cts
, ct
);
350 const char *symd
= lj_str_pushf(L
,
351 cconv
== CTCC_FASTCALL
? "@%s@%d" : "_%s@%d",
354 p
= clib_getsym(cl
, symd
);
359 clib_error(L
, "cannot resolve symbol " LUA_QS
": %s", sym
);
360 #if LJ_TARGET_WINDOWS
361 SetLastError(oldwerr
);
363 cd
= lj_cdata_new(cts
, id
, CTSIZE_PTR
);
364 *(void **)cdataptr(cd
) = p
;
365 setcdataV(L
, tv
, cd
);
371 /* -- C library management ------------------------------------------------ */
373 /* Create a new CLibrary object and push it on the stack. */
374 static CLibrary
*clib_new(lua_State
*L
, GCtab
*mt
)
376 GCtab
*t
= lj_tab_new(L
, 0, 0);
377 GCudata
*ud
= lj_udata_new(L
, sizeof(CLibrary
), t
);
378 CLibrary
*cl
= (CLibrary
*)uddata(ud
);
380 ud
->udtype
= UDTYPE_FFI_CLIB
;
381 /* NOBARRIER: The GCudata is new (marked white). */
382 setgcref(ud
->metatable
, obj2gco(mt
));
383 setudataV(L
, L
->top
++, ud
);
387 /* Load a C library. */
388 void lj_clib_load(lua_State
*L
, GCtab
*mt
, GCstr
*name
, int global
)
390 void *handle
= clib_loadlib(L
, strdata(name
), global
);
391 CLibrary
*cl
= clib_new(L
, mt
);
395 /* Unload a C library. */
396 void lj_clib_unload(CLibrary
*cl
)
402 /* Create the default C library object. */
403 void lj_clib_default(lua_State
*L
, GCtab
*mt
)
405 CLibrary
*cl
= clib_new(L
, mt
);
406 cl
->handle
= CLIB_DEFHANDLE
;