root/lj_clib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clib_error_
  2. clib_extname
  3. clib_check_lds
  4. clib_resolve_lds
  5. clib_loadlib
  6. clib_unloadlib
  7. clib_getsym
  8. clib_error
  9. clib_needext
  10. clib_extname
  11. clib_loadlib
  12. clib_unloadlib
  13. clib_getsym
  14. clib_error
  15. clib_loadlib
  16. clib_unloadlib
  17. clib_getsym
  18. clib_func_argsize
  19. clib_extsym
  20. lj_clib_index
  21. clib_new
  22. lj_clib_load
  23. lj_clib_unload
  24. lj_clib_default

   1 /*
   2 ** FFI C library loader.
   3 ** Copyright (C) 2005-2017 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 #include <stdio.h>
  26 
  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)
  31 #else
  32 #define CLIB_DEFHANDLE  NULL
  33 #endif
  34 
  35 LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
  36 {
  37   lj_err_callermsg(L, dlerror());
  38 }
  39 
  40 #define clib_error(L, fmt, name)        clib_error_(L)
  41 
  42 #if LJ_TARGET_CYGWIN
  43 #define CLIB_SOPREFIX   "cyg"
  44 #else
  45 #define CLIB_SOPREFIX   "lib"
  46 #endif
  47 
  48 #if LJ_TARGET_OSX
  49 #define CLIB_SOEXT      "%s.dylib"
  50 #elif LJ_TARGET_CYGWIN
  51 #define CLIB_SOEXT      "%s.dll"
  52 #else
  53 #define CLIB_SOEXT      "%s.so"
  54 #endif
  55 
  56 static const char *clib_extname(lua_State *L, const char *name)
  57 {
  58   if (!strchr(name, '/')
  59 #if LJ_TARGET_CYGWIN
  60       && !strchr(name, '\\')
  61 #endif
  62      ) {
  63     if (!strchr(name, '.')) {
  64       name = lj_str_pushf(L, CLIB_SOEXT, name);
  65       L->top--;
  66 #if LJ_TARGET_CYGWIN
  67     } else {
  68       return name;
  69 #endif
  70     }
  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);
  74       L->top--;
  75     }
  76   }
  77   return name;
  78 }
  79 
  80 /* Check for a recognized ld script line. */
  81 static const char *clib_check_lds(lua_State *L, const char *buf)
  82 {
  83   char *p, *e;
  84   if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
  85       (p = strchr(buf, '('))) {
  86     while (*++p == ' ') ;
  87     for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
  88     return strdata(lj_str_new(L, p, e-p));
  89   }
  90   return NULL;
  91 }
  92 
  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)
  95 {
  96   FILE *fp = fopen(name, "r");
  97   const char *p = NULL;
  98   if (fp) {
  99     char buf[256];
 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);
 104           if (p) break;
 105         }
 106       } else {  /* Otherwise check only the first line. */
 107         p = clib_check_lds(L, buf);
 108       }
 109     }
 110     fclose(fp);
 111   }
 112   return p;
 113 }
 114 
 115 static void *clib_loadlib(lua_State *L, const char *name, int global)
 116 {
 117   void *h = dlopen(clib_extname(L, name),
 118                    RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
 119   if (!h) {
 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));
 124       if (h) return h;
 125       err = dlerror();
 126     }
 127     lj_err_callermsg(L, err);
 128   }
 129   return h;
 130 }
 131 
 132 static void clib_unloadlib(CLibrary *cl)
 133 {
 134   if (cl->handle && cl->handle != CLIB_DEFHANDLE)
 135     dlclose(cl->handle);
 136 }
 137 
 138 static void *clib_getsym(CLibrary *cl, const char *name)
 139 {
 140   void *p = dlsym(cl->handle, name);
 141   return p;
 142 }
 143 
 144 #elif LJ_TARGET_WINDOWS
 145 
 146 #define WIN32_LEAN_AND_MEAN
 147 #include <windows.h>
 148 
 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*);
 153 #endif
 154 
 155 #define CLIB_DEFHANDLE  ((void *)-1)
 156 
 157 /* Default libraries. */
 158 enum {
 159   CLIB_HANDLE_EXE,
 160   CLIB_HANDLE_DLL,
 161   CLIB_HANDLE_CRT,
 162   CLIB_HANDLE_KERNEL32,
 163   CLIB_HANDLE_USER32,
 164   CLIB_HANDLE_GDI32,
 165   CLIB_HANDLE_MAX
 166 };
 167 
 168 static void *clib_def_handle[CLIB_HANDLE_MAX];
 169 
 170 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
 171                                             const char *name)
 172 {
 173   DWORD err = GetLastError();
 174   char buf[128];
 175   if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
 176                       NULL, err, 0, buf, sizeof(buf), NULL))
 177     buf[0] = '\0';
 178   lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
 179 }
 180 
 181 static int clib_needext(const char *s)
 182 {
 183   while (*s) {
 184     if (*s == '/' || *s == '\\' || *s == '.') return 0;
 185     s++;
 186   }
 187   return 1;
 188 }
 189 
 190 static const char *clib_extname(lua_State *L, const char *name)
 191 {
 192   if (clib_needext(name)) {
 193     name = lj_str_pushf(L, "%s.dll", name);
 194     L->top--;
 195   }
 196   return name;
 197 }
 198 
 199 static void *clib_loadlib(lua_State *L, const char *name, int global)
 200 {
 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);
 205   UNUSED(global);
 206   return h;
 207 }
 208 
 209 static void clib_unloadlib(CLibrary *cl)
 210 {
 211   if (cl->handle == CLIB_DEFHANDLE) {
 212     MSize i;
 213     for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
 214       void *h = clib_def_handle[i];
 215       if (h) {
 216         clib_def_handle[i] = NULL;
 217         FreeLibrary((HINSTANCE)h);
 218       }
 219     }
 220   } else if (cl->handle) {
 221     FreeLibrary((HINSTANCE)cl->handle);
 222   }
 223 }
 224 
 225 static void *clib_getsym(CLibrary *cl, const char *name)
 226 {
 227   void *p = NULL;
 228   if (cl->handle == CLIB_DEFHANDLE) {  /* Search default libraries. */
 229     MSize i;
 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). */
 233         switch (i) {
 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);
 238           break;
 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);
 242           break;
 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;
 246         }
 247         if (!h) continue;
 248         clib_def_handle[i] = (void *)h;
 249       }
 250       p = (void *)GetProcAddress(h, name);
 251       if (p) break;
 252     }
 253   } else {
 254     p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
 255   }
 256   return p;
 257 }
 258 
 259 #else
 260 
 261 #define CLIB_DEFHANDLE  NULL
 262 
 263 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
 264                                             const char *name)
 265 {
 266   lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
 267 }
 268 
 269 static void *clib_loadlib(lua_State *L, const char *name, int global)
 270 {
 271   lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
 272   UNUSED(name); UNUSED(global);
 273   return NULL;
 274 }
 275 
 276 static void clib_unloadlib(CLibrary *cl)
 277 {
 278   UNUSED(cl);
 279 }
 280 
 281 static void *clib_getsym(CLibrary *cl, const char *name)
 282 {
 283   UNUSED(cl); UNUSED(name);
 284   return NULL;
 285 }
 286 
 287 #endif
 288 
 289 /* -- C library indexing -------------------------------------------------- */
 290 
 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)
 294 {
 295   CTSize n = 0;
 296   while (ct->sib) {
 297     CType *d;
 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);
 302     }
 303   }
 304   return n;
 305 }
 306 #endif
 307 
 308 /* Get redirected or mangled external symbol. */
 309 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
 310 {
 311   if (ct->sib) {
 312     CType *ctf = ctype_get(cts, ct->sib);
 313     if (ctype_isxattrib(ctf->info, CTA_REDIR))
 314       return strdata(gco2str(gcref(ctf->name)));
 315   }
 316   return strdata(name);
 317 }
 318 
 319 /* Index a C library by name. */
 320 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
 321 {
 322   TValue *tv = lj_tab_setstr(L, cl->cache, name);
 323   if (LJ_UNLIKELY(tvisnil(tv))) {
 324     CTState *cts = ctype_cts(L);
 325     CType *ct;
 326     CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
 327     if (!id)
 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);
 334       else
 335         setintV(tv, (int32_t)ct->size);
 336     } else {
 337       const char *sym = clib_extsym(cts, ct, name);
 338 #if LJ_TARGET_WINDOWS
 339       DWORD oldwerr = GetLastError();
 340 #endif
 341       void *p = clib_getsym(cl, sym);
 342       GCcdata *cd;
 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",
 352                                sym, sz);
 353           L->top--;
 354           p = clib_getsym(cl, symd);
 355         }
 356       }
 357 #endif
 358       if (!p)
 359         clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
 360 #if LJ_TARGET_WINDOWS
 361       SetLastError(oldwerr);
 362 #endif
 363       cd = lj_cdata_new(cts, id, CTSIZE_PTR);
 364       *(void **)cdataptr(cd) = p;
 365       setcdataV(L, tv, cd);
 366     }
 367   }
 368   return tv;
 369 }
 370 
 371 /* -- C library management ------------------------------------------------ */
 372 
 373 /* Create a new CLibrary object and push it on the stack. */
 374 static CLibrary *clib_new(lua_State *L, GCtab *mt)
 375 {
 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);
 379   cl->cache = t;
 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);
 384   return cl;
 385 }
 386 
 387 /* Load a C library. */
 388 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
 389 {
 390   void *handle = clib_loadlib(L, strdata(name), global);
 391   CLibrary *cl = clib_new(L, mt);
 392   cl->handle = handle;
 393 }
 394 
 395 /* Unload a C library. */
 396 void lj_clib_unload(CLibrary *cl)
 397 {
 398   clib_unloadlib(cl);
 399   cl->handle = NULL;
 400 }
 401 
 402 /* Create the default C library object. */
 403 void lj_clib_default(lua_State *L, GCtab *mt)
 404 {
 405   CLibrary *cl = clib_new(L, mt);
 406   cl->handle = CLIB_DEFHANDLE;
 407 }
 408 
 409 #endif

/* [<][>][^][v][top][bottom][index][help] */