summaryrefslogtreecommitdiff
path: root/src/lj_clib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_clib.c')
-rw-r--r--src/lj_clib.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/lj_clib.c b/src/lj_clib.c
new file mode 100644
index 00000000..91309eb2
--- /dev/null
+++ b/src/lj_clib.c
@@ -0,0 +1,294 @@
1/*
2** FFI C library loader.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#include "lj_obj.h"
7
8#if LJ_HASFFI
9
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
20/* -- OS-specific functions ----------------------------------------------- */
21
22#if LJ_TARGET_DLOPEN
23
24#include <dlfcn.h>
25
26#if defined(RTLD_DEFAULT)
27#define CLIB_DEFHANDLE RTLD_DEFAULT
28#elif LJ_TARGET_OSX || LJ_TARGET_BSD
29#define CLIB_DEFHANDLE ((void *)-2)
30#else
31#define CLIB_DEFHANDLE NULL
32#endif
33
34LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L)
35{
36 lj_err_callermsg(L, dlerror());
37}
38
39#if LJ_TARGET_OSX
40#define CLIB_SOEXT "%s.dylib"
41#else
42#define CLIB_SOEXT "%s.so"
43#endif
44
45static const char *clib_extname(lua_State *L, GCstr *name)
46{
47 const char *s = strdata(name);
48 if (!strchr(s, '/')) {
49 if (!strchr(s, '.')) {
50 s = lj_str_pushf(L, CLIB_SOEXT, s);
51 L->top--;
52 }
53 if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) {
54 s = lj_str_pushf(L, "lib%s", s);
55 L->top--;
56 }
57 }
58 return s;
59}
60
61static void *clib_loadlib(lua_State *L, GCstr *name, int global)
62{
63 void *h = dlopen(clib_extname(L, name),
64 RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
65 if (!h) clib_error(L);
66 return h;
67}
68
69static void clib_unloadlib(CLibrary *cl)
70{
71 if (!cl->handle && cl->handle != CLIB_DEFHANDLE)
72 dlclose(cl->handle);
73}
74
75static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
76{
77 void *p = dlsym(cl->handle, strdata(name));
78 if (!p) clib_error(L);
79 return p;
80}
81
82#elif LJ_TARGET_WINDOWS
83
84#define WIN32_LEAN_AND_MEAN
85#ifndef WINVER
86#define WINVER 0x0500
87#endif
88#include <windows.h>
89
90#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
91#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
92BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
93#endif
94
95#define CLIB_DEFHANDLE ((void *)-1)
96
97/* Default libraries. */
98enum {
99 CLIB_HANDLE_EXE,
100 CLIB_HANDLE_DLL,
101 CLIB_HANDLE_CRT,
102 CLIB_HANDLE_KERNEL32,
103 CLIB_HANDLE_USER32,
104 CLIB_HANDLE_GDI32,
105 CLIB_HANDLE_MAX
106};
107
108static void *clib_def_handle[CLIB_HANDLE_MAX];
109
110LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
111 const char *name)
112{
113 DWORD err = GetLastError();
114 char buf[128];
115 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
116 NULL, err, 0, buf, sizeof(buf), NULL))
117 buf[0] = '\0';
118 lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
119}
120
121static int clib_needext(const char *s)
122{
123 while (*s) {
124 if (*s == '/' || *s == '\\' || *s == '.') return 0;
125 s++;
126 }
127 return 1;
128}
129
130static const char *clib_extname(lua_State *L, GCstr *name)
131{
132 const char *s = strdata(name);
133 if (clib_needext(s)) {
134 s = lj_str_pushf(L, "%s.dll", s);
135 L->top--;
136 }
137 return s;
138}
139
140static void *clib_loadlib(lua_State *L, GCstr *name, int global)
141{
142 void *h = (void *)LoadLibraryA(clib_extname(L, name));
143 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name));
144 UNUSED(global);
145 return h;
146}
147
148static void clib_unloadlib(CLibrary *cl)
149{
150 if (cl->handle == CLIB_DEFHANDLE) {
151 MSize i;
152 for (i = 0; i < CLIB_HANDLE_MAX; i++)
153 if (clib_def_handle[i])
154 FreeLibrary((HINSTANCE)clib_def_handle[i]);
155 } else if (!cl->handle) {
156 FreeLibrary((HINSTANCE)cl->handle);
157 }
158}
159
160static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
161{
162 const char *sym = strdata(name);
163 void *p;
164 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */
165 MSize i;
166 for (i = 0; i < CLIB_HANDLE_MAX; i++) {
167 HINSTANCE h = (HINSTANCE)clib_def_handle[i];
168 if (!(void *)h) { /* Resolve default library handles (once). */
169 switch (i) {
170 case CLIB_HANDLE_EXE: GetModuleHandleExA(0, NULL, &h); break;
171 case CLIB_HANDLE_DLL:
172 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
173 (const char *)clib_def_handle, &h);
174 break;
175 case CLIB_HANDLE_CRT:
176 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
177 (const char *)&_fmode, &h);
178 break;
179 case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
180 case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
181 case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
182 }
183 if (!h) continue;
184 clib_def_handle[i] = (void *)h;
185 }
186 p = (void *)GetProcAddress(h, sym);
187 if (p) break;
188 }
189 } else {
190 p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym);
191 }
192 if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
193 return p;
194}
195
196#else
197
198#define CLIB_DEFHANDLE NULL
199
200static void *clib_loadlib(lua_State *L, GCstr *name, int global)
201{
202 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
203 UNUSED(name); UNUSED(global);
204 return NULL;
205}
206
207static void clib_unloadlib(CLibrary *cl)
208{
209 UNUSED(cl);
210}
211
212static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name)
213{
214 lj_err_callermsg(L, "no support for resolving symbols for this OS");
215 UNUSED(cl); UNUSED(name);
216 return NULL;
217}
218
219#endif
220
221/* -- C library indexing -------------------------------------------------- */
222
223/* Namespace for C library indexing. */
224#define CLNS_INDEX \
225 ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL))
226
227/* Index a C library by name. */
228TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
229{
230 TValue *tv = lj_tab_setstr(L, cl->cache, name);
231 if (LJ_UNLIKELY(tvisnil(tv))) {
232 CTState *cts = ctype_cts(L);
233 CType *ct;
234 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
235 if (!id)
236 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
237 if (ctype_isconstval(ct->info)) {
238 CType *ctt = ctype_child(cts, ct);
239 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
240 if ((ctt->info & CTF_UNSIGNED) && ctt->size == 4)
241 setnumV(tv, (lua_Number)(uint32_t)ct->size);
242 else
243 setnumV(tv, (lua_Number)(int32_t)ct->size);
244 } else {
245 void *p = clib_getsym(L, cl, name);
246 GCcdata *cd;
247 lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
248 cd = lj_cdata_new(cts, id, CTSIZE_PTR);
249 *(void **)cdataptr(cd) = p;
250 setcdataV(L, tv, cd);
251 }
252 }
253 return tv;
254}
255
256/* -- C library management ------------------------------------------------ */
257
258/* Create a new CLibrary object and push it on the stack. */
259static CLibrary *clib_new(lua_State *L, GCtab *mt)
260{
261 GCtab *t = lj_tab_new(L, 0, 0);
262 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
263 CLibrary *cl = (CLibrary *)uddata(ud);
264 cl->cache = t;
265 ud->udtype = UDTYPE_FFI_CLIB;
266 /* NOBARRIER: The GCudata is new (marked white). */
267 setgcref(ud->metatable, obj2gco(mt));
268 setudataV(L, L->top++, ud);
269 return cl;
270}
271
272/* Load a C library. */
273void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
274{
275 void *handle = clib_loadlib(L, name, global);
276 CLibrary *cl = clib_new(L, mt);
277 cl->handle = handle;
278}
279
280/* Unload a C library. */
281void lj_clib_unload(CLibrary *cl)
282{
283 clib_unloadlib(cl);
284 cl->handle = NULL;
285}
286
287/* Create the default C library object. */
288void lj_clib_default(lua_State *L, GCtab *mt)
289{
290 CLibrary *cl = clib_new(L, mt);
291 cl->handle = CLIB_DEFHANDLE;
292}
293
294#endif