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

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