src/lj_clib.c - luajit-2.0-src

Global variables defined

Functions defined

Macros defined

Source code

  1. /*
  2. ** FFI C library loader.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. #include "lj_obj.h"

  6. #if LJ_HASFFI

  7. #include "lj_gc.h"
  8. #include "lj_err.h"
  9. #include "lj_tab.h"
  10. #include "lj_str.h"
  11. #include "lj_udata.h"
  12. #include "lj_ctype.h"
  13. #include "lj_cconv.h"
  14. #include "lj_cdata.h"
  15. #include "lj_clib.h"
  16. #include "lj_strfmt.h"

  17. /* -- OS-specific functions ----------------------------------------------- */

  18. #if LJ_TARGET_DLOPEN

  19. #include <dlfcn.h>
  20. #include <stdio.h>

  21. #if defined(RTLD_DEFAULT)
  22. #define CLIB_DEFHANDLE        RTLD_DEFAULT
  23. #elif LJ_TARGET_OSX || LJ_TARGET_BSD
  24. #define CLIB_DEFHANDLE        ((void *)(intptr_t)-2)
  25. #else
  26. #define CLIB_DEFHANDLE        NULL
  27. #endif

  28. LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
  29. {
  30.   lj_err_callermsg(L, dlerror());
  31. }

  32. #define clib_error(L, fmt, name)        clib_error_(L)

  33. #if defined(__CYGWIN__)
  34. #define CLIB_SOPREFIX        "cyg"
  35. #else
  36. #define CLIB_SOPREFIX        "lib"
  37. #endif

  38. #if LJ_TARGET_OSX
  39. #define CLIB_SOEXT        "%s.dylib"
  40. #elif defined(__CYGWIN__)
  41. #define CLIB_SOEXT        "%s.dll"
  42. #else
  43. #define CLIB_SOEXT        "%s.so"
  44. #endif

  45. static const char *clib_extname(lua_State *L, const char *name)
  46. {
  47.   if (!strchr(name, '/')
  48. #ifdef __CYGWIN__
  49.       && !strchr(name, '\\')
  50. #endif
  51.      ) {
  52.     if (!strchr(name, '.')) {
  53.       name = lj_strfmt_pushf(L, CLIB_SOEXT, name);
  54.       L->top--;
  55. #ifdef __CYGWIN__
  56.     } else {
  57.       return name;
  58. #endif
  59.     }
  60.     if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
  61.           name[2] == CLIB_SOPREFIX[2])) {
  62.       name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name);
  63.       L->top--;
  64.     }
  65.   }
  66.   return name;
  67. }

  68. /* Check for a recognized ld script line. */
  69. static const char *clib_check_lds(lua_State *L, const char *buf)
  70. {
  71.   char *p, *e;
  72.   if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
  73.       (p = strchr(buf, '('))) {
  74.     while (*++p == ' ') ;
  75.     for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
  76.     return strdata(lj_str_new(L, p, e-p));
  77.   }
  78.   return NULL;
  79. }

  80. /* Quick and dirty solution to resolve shared library name from ld script. */
  81. static const char *clib_resolve_lds(lua_State *L, const char *name)
  82. {
  83.   FILE *fp = fopen(name, "r");
  84.   const char *p = NULL;
  85.   if (fp) {
  86.     char buf[256];
  87.     if (fgets(buf, sizeof(buf), fp)) {
  88.       if (!strncmp(buf, "/* GNU ld script", 16)) {  /* ld script magic? */
  89.         while (fgets(buf, sizeof(buf), fp)) {  /* Check all lines. */
  90.           p = clib_check_lds(L, buf);
  91.           if (p) break;
  92.         }
  93.       } else/* Otherwise check only the first line. */
  94.         p = clib_check_lds(L, buf);
  95.       }
  96.     }
  97.     fclose(fp);
  98.   }
  99.   return p;
  100. }

  101. static void *clib_loadlib(lua_State *L, const char *name, int global)
  102. {
  103.   void *h = dlopen(clib_extname(L, name),
  104.                    RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
  105.   if (!h) {
  106.     const char *e, *err = dlerror();
  107.     if (*err == '/' && (e = strchr(err, ':')) &&
  108.         (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
  109.       h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
  110.       if (h) return h;
  111.       err = dlerror();
  112.     }
  113.     lj_err_callermsg(L, err);
  114.   }
  115.   return h;
  116. }

  117. static void clib_unloadlib(CLibrary *cl)
  118. {
  119.   if (cl->handle && cl->handle != CLIB_DEFHANDLE)
  120.     dlclose(cl->handle);
  121. }

  122. static void *clib_getsym(CLibrary *cl, const char *name)
  123. {
  124.   void *p = dlsym(cl->handle, name);
  125.   return p;
  126. }

  127. #elif LJ_TARGET_WINDOWS

  128. #define WIN32_LEAN_AND_MEAN
  129. #include <windows.h>

  130. #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
  131. #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS        4
  132. #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT        2
  133. BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
  134. #endif

  135. #define CLIB_DEFHANDLE        ((void *)-1)

  136. /* Default libraries. */
  137. enum {
  138.   CLIB_HANDLE_EXE,
  139.   CLIB_HANDLE_DLL,
  140.   CLIB_HANDLE_CRT,
  141.   CLIB_HANDLE_KERNEL32,
  142.   CLIB_HANDLE_USER32,
  143.   CLIB_HANDLE_GDI32,
  144.   CLIB_HANDLE_MAX
  145. };

  146. static void *clib_def_handle[CLIB_HANDLE_MAX];

  147. LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
  148.                                             const char *name)
  149. {
  150.   DWORD err = GetLastError();
  151.   char buf[128];
  152.   if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
  153.                       NULL, err, 0, buf, sizeof(buf), NULL))
  154.     buf[0] = '\0';
  155.   lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf));
  156. }

  157. static int clib_needext(const char *s)
  158. {
  159.   while (*s) {
  160.     if (*s == '/' || *s == '\\' || *s == '.') return 0;
  161.     s++;
  162.   }
  163.   return 1;
  164. }

  165. static const char *clib_extname(lua_State *L, const char *name)
  166. {
  167.   if (clib_needext(name)) {
  168.     name = lj_strfmt_pushf(L, "%s.dll", name);
  169.     L->top--;
  170.   }
  171.   return name;
  172. }

  173. static void *clib_loadlib(lua_State *L, const char *name, int global)
  174. {
  175.   DWORD oldwerr = GetLastError();
  176.   void *h = (void *)LoadLibraryA(clib_extname(L, name));
  177.   if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
  178.   SetLastError(oldwerr);
  179.   UNUSED(global);
  180.   return h;
  181. }

  182. static void clib_unloadlib(CLibrary *cl)
  183. {
  184.   if (cl->handle == CLIB_DEFHANDLE) {
  185.     MSize i;
  186.     for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
  187.       void *h = clib_def_handle[i];
  188.       if (h) {
  189.         clib_def_handle[i] = NULL;
  190.         FreeLibrary((HINSTANCE)h);
  191.       }
  192.     }
  193.   } else if (cl->handle) {
  194.     FreeLibrary((HINSTANCE)cl->handle);
  195.   }
  196. }

  197. static void *clib_getsym(CLibrary *cl, const char *name)
  198. {
  199.   void *p = NULL;
  200.   if (cl->handle == CLIB_DEFHANDLE) {  /* Search default libraries. */
  201.     MSize i;
  202.     for (i = 0; i < CLIB_HANDLE_MAX; i++) {
  203.       HINSTANCE h = (HINSTANCE)clib_def_handle[i];
  204.       if (!(void *)h) {  /* Resolve default library handles (once). */
  205.         switch (i) {
  206.         case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
  207.         case CLIB_HANDLE_DLL:
  208.           GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
  209.                              (const char *)clib_def_handle, &h);
  210.           break;
  211.         case CLIB_HANDLE_CRT:
  212.           GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
  213.                              (const char *)&_fmode, &h);
  214.           break;
  215.         case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
  216.         case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
  217.         case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
  218.         }
  219.         if (!h) continue;
  220.         clib_def_handle[i] = (void *)h;
  221.       }
  222.       p = (void *)GetProcAddress(h, name);
  223.       if (p) break;
  224.     }
  225.   } else {
  226.     p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
  227.   }
  228.   return p;
  229. }

  230. #else

  231. #define CLIB_DEFHANDLE        NULL

  232. LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
  233.                                             const char *name)
  234. {
  235.   lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS"));
  236. }

  237. static void *clib_loadlib(lua_State *L, const char *name, int global)
  238. {
  239.   lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
  240.   UNUSED(name); UNUSED(global);
  241.   return NULL;
  242. }

  243. static void clib_unloadlib(CLibrary *cl)
  244. {
  245.   UNUSED(cl);
  246. }

  247. static void *clib_getsym(CLibrary *cl, const char *name)
  248. {
  249.   UNUSED(cl); UNUSED(name);
  250.   return NULL;
  251. }

  252. #endif

  253. /* -- C library indexing -------------------------------------------------- */

  254. #if LJ_TARGET_X86 && LJ_ABI_WIN
  255. /* Compute argument size for fastcall/stdcall functions. */
  256. static CTSize clib_func_argsize(CTState *cts, CType *ct)
  257. {
  258.   CTSize n = 0;
  259.   while (ct->sib) {
  260.     CType *d;
  261.     ct = ctype_get(cts, ct->sib);
  262.     if (ctype_isfield(ct->info)) {
  263.       d = ctype_rawchild(cts, ct);
  264.       n += ((d->size + 3) & ~3);
  265.     }
  266.   }
  267.   return n;
  268. }
  269. #endif

  270. /* Get redirected or mangled external symbol. */
  271. static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
  272. {
  273.   if (ct->sib) {
  274.     CType *ctf = ctype_get(cts, ct->sib);
  275.     if (ctype_isxattrib(ctf->info, CTA_REDIR))
  276.       return strdata(gco2str(gcref(ctf->name)));
  277.   }
  278.   return strdata(name);
  279. }

  280. /* Index a C library by name. */
  281. TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
  282. {
  283.   TValue *tv = lj_tab_setstr(L, cl->cache, name);
  284.   if (LJ_UNLIKELY(tvisnil(tv))) {
  285.     CTState *cts = ctype_cts(L);
  286.     CType *ct;
  287.     CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
  288.     if (!id)
  289.       lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
  290.     if (ctype_isconstval(ct->info)) {
  291.       CType *ctt = ctype_child(cts, ct);
  292.       lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
  293.       if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
  294.         setnumV(tv, (lua_Number)(uint32_t)ct->size);
  295.       else
  296.         setintV(tv, (int32_t)ct->size);
  297.     } else {
  298.       const char *sym = clib_extsym(cts, ct, name);
  299. #if LJ_TARGET_WINDOWS
  300.       DWORD oldwerr = GetLastError();
  301. #endif
  302.       void *p = clib_getsym(cl, sym);
  303.       GCcdata *cd;
  304.       lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
  305. #if LJ_TARGET_X86 && LJ_ABI_WIN
  306.       /* Retry with decorated name for fastcall/stdcall functions. */
  307.       if (!p && ctype_isfunc(ct->info)) {
  308.         CTInfo cconv = ctype_cconv(ct->info);
  309.         if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
  310.           CTSize sz = clib_func_argsize(cts, ct);
  311.           const char *symd = lj_strfmt_pushf(L,
  312.                                cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
  313.                                sym, sz);
  314.           L->top--;
  315.           p = clib_getsym(cl, symd);
  316.         }
  317.       }
  318. #endif
  319.       if (!p)
  320.         clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
  321. #if LJ_TARGET_WINDOWS
  322.       SetLastError(oldwerr);
  323. #endif
  324.       cd = lj_cdata_new(cts, id, CTSIZE_PTR);
  325.       *(void **)cdataptr(cd) = p;
  326.       setcdataV(L, tv, cd);
  327.     }
  328.   }
  329.   return tv;
  330. }

  331. /* -- C library management ------------------------------------------------ */

  332. /* Create a new CLibrary object and push it on the stack. */
  333. static CLibrary *clib_new(lua_State *L, GCtab *mt)
  334. {
  335.   GCtab *t = lj_tab_new(L, 0, 0);
  336.   GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
  337.   CLibrary *cl = (CLibrary *)uddata(ud);
  338.   cl->cache = t;
  339.   ud->udtype = UDTYPE_FFI_CLIB;
  340.   /* NOBARRIER: The GCudata is new (marked white). */
  341.   setgcref(ud->metatable, obj2gco(mt));
  342.   setudataV(L, L->top++, ud);
  343.   return cl;
  344. }

  345. /* Load a C library. */
  346. void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
  347. {
  348.   void *handle = clib_loadlib(L, strdata(name), global);
  349.   CLibrary *cl = clib_new(L, mt);
  350.   cl->handle = handle;
  351. }

  352. /* Unload a C library. */
  353. void lj_clib_unload(CLibrary *cl)
  354. {
  355.   clib_unloadlib(cl);
  356.   cl->handle = NULL;
  357. }

  358. /* Create the default C library object. */
  359. void lj_clib_default(lua_State *L, GCtab *mt)
  360. {
  361.   CLibrary *cl = clib_new(L, mt);
  362.   cl->handle = CLIB_DEFHANDLE;
  363. }

  364. #endif