lj_clib.c (11057B)
1 /* 2 ** FFI C library loader. 3 ** Copyright (C) 2005-2016 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 #include "lj_strfmt.h" 20 21 /* -- OS-specific functions ----------------------------------------------- */ 22 23 #if LJ_TARGET_DLOPEN 24 25 #include <dlfcn.h> 26 #include <stdio.h> 27 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 35 36 LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L) 37 { 38 lj_err_callermsg(L, dlerror()); 39 } 40 41 #define clib_error(L, fmt, name) clib_error_(L) 42 43 #if defined(__CYGWIN__) 44 #define CLIB_SOPREFIX "cyg" 45 #else 46 #define CLIB_SOPREFIX "lib" 47 #endif 48 49 #define CLIB_FMT "%s" 50 51 #if LJ_TARGET_OSX 52 #define CLIB_SOEXT ".dylib" 53 #elif defined(__CYGWIN__) 54 #define CLIB_SOEXT ".dll" 55 #else 56 #define CLIB_SOEXT ".so" 57 #endif 58 59 static const char *clib_extname(lua_State *L, const char *name) 60 { 61 if (!strchr(name, '/') 62 #ifdef __CYGWIN__ 63 && !strchr(name, '\\') 64 #endif 65 ) { 66 int n = strlen(name); 67 if ((n < (sizeof(CLIB_SOEXT) - 1)) || 68 (strcmp(name + n - sizeof(CLIB_SOEXT) + 1, CLIB_SOEXT))) { 69 name = lj_strfmt_pushf(L, CLIB_FMT CLIB_SOEXT, name); 70 L->top--; 71 #ifdef __CYGWIN__ 72 } else { 73 return name; 74 #endif 75 } 76 if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] && 77 name[2] == CLIB_SOPREFIX[2])) { 78 name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name); 79 L->top--; 80 } 81 } 82 return name; 83 } 84 85 /* Check for a recognized ld script line. */ 86 static const char *clib_check_lds(lua_State *L, const char *buf) 87 { 88 char *p, *e; 89 if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) && 90 (p = strchr(buf, '('))) { 91 while (*++p == ' ') ; 92 for (e = p; *e && *e != ' ' && *e != ')'; e++) ; 93 return strdata(lj_str_new(L, p, e-p)); 94 } 95 return NULL; 96 } 97 98 /* Quick and dirty solution to resolve shared library name from ld script. */ 99 static const char *clib_resolve_lds(lua_State *L, const char *name) 100 { 101 FILE *fp = fopen(name, "r"); 102 const char *p = NULL; 103 if (fp) { 104 char buf[256]; 105 if (fgets(buf, sizeof(buf), fp)) { 106 if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */ 107 while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */ 108 p = clib_check_lds(L, buf); 109 if (p) break; 110 } 111 } else { /* Otherwise check only the first line. */ 112 p = clib_check_lds(L, buf); 113 } 114 } 115 fclose(fp); 116 } 117 return p; 118 } 119 120 static void *clib_loadlib(lua_State *L, const char *name, int global) 121 { 122 void *h = dlopen(clib_extname(L, name), 123 RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); 124 if (!h) { 125 const char *e, *err = dlerror(); 126 if (*err == '/' && (e = strchr(err, ':')) && 127 (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) { 128 h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); 129 if (h) return h; 130 err = dlerror(); 131 } 132 lj_err_callermsg(L, err); 133 } 134 return h; 135 } 136 137 static void clib_unloadlib(CLibrary *cl) 138 { 139 if (cl->handle && cl->handle != CLIB_DEFHANDLE) 140 dlclose(cl->handle); 141 } 142 143 static void *clib_getsym(CLibrary *cl, const char *name) 144 { 145 void *p = dlsym(cl->handle, name); 146 #ifdef __MSYS__ 147 if (!p && cl->system) 148 p = dlsym(NULL, name); 149 #endif 150 return p; 151 } 152 153 #elif LJ_TARGET_WINDOWS 154 155 #define WIN32_LEAN_AND_MEAN 156 #include <windows.h> 157 158 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 159 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 160 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 161 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); 162 #endif 163 164 #define CLIB_DEFHANDLE ((void *)-1) 165 166 /* Default libraries. */ 167 enum { 168 CLIB_HANDLE_EXE, 169 CLIB_HANDLE_DLL, 170 CLIB_HANDLE_CRT, 171 CLIB_HANDLE_KERNEL32, 172 CLIB_HANDLE_USER32, 173 CLIB_HANDLE_GDI32, 174 CLIB_HANDLE_MAX 175 }; 176 177 static void *clib_def_handle[CLIB_HANDLE_MAX]; 178 179 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, 180 const char *name) 181 { 182 DWORD err = GetLastError(); 183 #if LJ_TARGET_XBOXONE 184 wchar_t wbuf[128]; 185 char buf[128*2]; 186 if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, 187 NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) || 188 !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL)) 189 #else 190 char buf[128]; 191 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, 192 NULL, err, 0, buf, sizeof(buf), NULL)) 193 #endif 194 buf[0] = '\0'; 195 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf)); 196 } 197 198 static int clib_needext(const char *s) 199 { 200 while (*s) { 201 if (*s == '/' || *s == '\\' || *s == '.') return 0; 202 s++; 203 } 204 return 1; 205 } 206 207 static const char *clib_extname(lua_State *L, const char *name) 208 { 209 if (clib_needext(name)) { 210 name = lj_strfmt_pushf(L, "%s.dll", name); 211 L->top--; 212 } 213 return name; 214 } 215 216 static void *clib_loadlib(lua_State *L, const char *name, int global) 217 { 218 DWORD oldwerr = GetLastError(); 219 void *h = (void *)LoadLibraryExA(clib_extname(L, name), NULL, 0); 220 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name); 221 SetLastError(oldwerr); 222 UNUSED(global); 223 return h; 224 } 225 226 static void clib_unloadlib(CLibrary *cl) 227 { 228 if (cl->handle == CLIB_DEFHANDLE) { 229 MSize i; 230 for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) { 231 void *h = clib_def_handle[i]; 232 if (h) { 233 clib_def_handle[i] = NULL; 234 FreeLibrary((HINSTANCE)h); 235 } 236 } 237 } else if (cl->handle) { 238 FreeLibrary((HINSTANCE)cl->handle); 239 } 240 } 241 242 static void *clib_getsym(CLibrary *cl, const char *name) 243 { 244 void *p = NULL; 245 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ 246 MSize i; 247 for (i = 0; i < CLIB_HANDLE_MAX; i++) { 248 HINSTANCE h = (HINSTANCE)clib_def_handle[i]; 249 if (!(void *)h) { /* Resolve default library handles (once). */ 250 switch (i) { 251 case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break; 252 case CLIB_HANDLE_DLL: 253 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 254 (const char *)clib_def_handle, &h); 255 break; 256 case CLIB_HANDLE_CRT: 257 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 258 (const char *)&_fmode, &h); 259 break; 260 case CLIB_HANDLE_KERNEL32: h = LoadLibraryExA("kernel32.dll", NULL, 0); break; 261 case CLIB_HANDLE_USER32: h = LoadLibraryExA("user32.dll", NULL, 0); break; 262 case CLIB_HANDLE_GDI32: h = LoadLibraryExA("gdi32.dll", NULL, 0); break; 263 } 264 if (!h) continue; 265 clib_def_handle[i] = (void *)h; 266 } 267 p = (void *)GetProcAddress(h, name); 268 if (p) break; 269 } 270 } else { 271 p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); 272 } 273 return p; 274 } 275 276 #else 277 278 #define CLIB_DEFHANDLE NULL 279 280 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, 281 const char *name) 282 { 283 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS")); 284 } 285 286 static void *clib_loadlib(lua_State *L, const char *name, int global) 287 { 288 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); 289 UNUSED(name); UNUSED(global); 290 return NULL; 291 } 292 293 static void clib_unloadlib(CLibrary *cl) 294 { 295 UNUSED(cl); 296 } 297 298 static void *clib_getsym(CLibrary *cl, const char *name) 299 { 300 UNUSED(cl); UNUSED(name); 301 return NULL; 302 } 303 304 #endif 305 306 /* -- C library indexing -------------------------------------------------- */ 307 308 #if LJ_TARGET_X86 && LJ_ABI_WIN 309 /* Compute argument size for fastcall/stdcall functions. */ 310 static CTSize clib_func_argsize(CTState *cts, CType *ct) 311 { 312 CTSize n = 0; 313 while (ct->sib) { 314 CType *d; 315 ct = ctype_get(cts, ct->sib); 316 if (ctype_isfield(ct->info)) { 317 d = ctype_rawchild(cts, ct); 318 n += ((d->size + 3) & ~3); 319 } 320 } 321 return n; 322 } 323 #endif 324 325 /* Get redirected or mangled external symbol. */ 326 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name) 327 { 328 if (ct->sib) { 329 CType *ctf = ctype_get(cts, ct->sib); 330 if (ctype_isxattrib(ctf->info, CTA_REDIR)) 331 return strdata(gco2str(gcref(ctf->name))); 332 } 333 return strdata(name); 334 } 335 336 /* Index a C library by name. */ 337 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) 338 { 339 TValue *tv = lj_tab_setstr(L, cl->cache, name); 340 if (LJ_UNLIKELY(tvisnil(tv))) { 341 CTState *cts = ctype_cts(L); 342 CType *ct; 343 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); 344 if (!id) 345 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); 346 if (ctype_isconstval(ct->info)) { 347 CType *ctt = ctype_child(cts, ct); 348 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); 349 if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) 350 setnumV(tv, (lua_Number)(uint32_t)ct->size); 351 else 352 setintV(tv, (int32_t)ct->size); 353 } else { 354 const char *sym = clib_extsym(cts, ct, name); 355 #if LJ_TARGET_WINDOWS 356 DWORD oldwerr = GetLastError(); 357 #endif 358 void *p = clib_getsym(cl, sym); 359 GCcdata *cd; 360 lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); 361 #if LJ_TARGET_X86 && LJ_ABI_WIN 362 /* Retry with decorated name for fastcall/stdcall functions. */ 363 if (!p && ctype_isfunc(ct->info)) { 364 CTInfo cconv = ctype_cconv(ct->info); 365 if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { 366 CTSize sz = clib_func_argsize(cts, ct); 367 const char *symd = lj_strfmt_pushf(L, 368 cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", 369 sym, sz); 370 L->top--; 371 p = clib_getsym(cl, symd); 372 } 373 } 374 #endif 375 if (!p) 376 clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); 377 #if LJ_TARGET_WINDOWS 378 SetLastError(oldwerr); 379 #endif 380 cd = lj_cdata_new(cts, id, CTSIZE_PTR); 381 *(void **)cdataptr(cd) = p; 382 setcdataV(L, tv, cd); 383 } 384 } 385 return tv; 386 } 387 388 /* -- C library management ------------------------------------------------ */ 389 390 /* Create a new CLibrary object and push it on the stack. */ 391 static CLibrary *clib_new(lua_State *L, GCtab *mt) 392 { 393 GCtab *t = lj_tab_new(L, 0, 0); 394 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t); 395 CLibrary *cl = (CLibrary *)uddata(ud); 396 cl->cache = t; 397 ud->udtype = UDTYPE_FFI_CLIB; 398 /* NOBARRIER: The GCudata is new (marked white). */ 399 setgcref(ud->metatable, obj2gco(mt)); 400 setudataV(L, L->top++, ud); 401 return cl; 402 } 403 404 /* Load a C library. */ 405 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) 406 { 407 void *handle = clib_loadlib(L, strdata(name), global); 408 CLibrary *cl = clib_new(L, mt); 409 cl->handle = handle; 410 } 411 412 /* Unload a C library. */ 413 void lj_clib_unload(CLibrary *cl) 414 { 415 clib_unloadlib(cl); 416 cl->handle = NULL; 417 } 418 419 /* Create the default C library object. */ 420 void lj_clib_default(lua_State *L, GCtab *mt) 421 { 422 CLibrary *cl = clib_new(L, mt); 423 #if __MSYS__ 424 cl->handle = dlopen("msys-2.0.dll", RTLD_LOCAL); 425 cl->system = 1; 426 lua_assert(cl->handle); 427 #else 428 cl->handle = CLIB_DEFHANDLE; 429 #endif 430 } 431 432 #endif