Mercurial
comparison third_party/luajit/src/lj_clib.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** FFI C library loader. | |
| 3 ** Copyright (C) 2005-2023 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) && !defined(NO_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 && *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 if (!err) err = "dlopen failed"; | |
| 129 lj_err_callermsg(L, err); | |
| 130 } | |
| 131 return h; | |
| 132 } | |
| 133 | |
| 134 static void clib_unloadlib(CLibrary *cl) | |
| 135 { | |
| 136 if (cl->handle && cl->handle != CLIB_DEFHANDLE) | |
| 137 dlclose(cl->handle); | |
| 138 } | |
| 139 | |
| 140 static void *clib_getsym(CLibrary *cl, const char *name) | |
| 141 { | |
| 142 void *p = dlsym(cl->handle, name); | |
| 143 return p; | |
| 144 } | |
| 145 | |
| 146 #elif LJ_TARGET_WINDOWS | |
| 147 | |
| 148 #define WIN32_LEAN_AND_MEAN | |
| 149 #include <windows.h> | |
| 150 | |
| 151 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | |
| 152 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 | |
| 153 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 | |
| 154 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); | |
| 155 #endif | |
| 156 | |
| 157 #define CLIB_DEFHANDLE ((void *)-1) | |
| 158 | |
| 159 /* Default libraries. */ | |
| 160 enum { | |
| 161 CLIB_HANDLE_EXE, | |
| 162 #if !LJ_TARGET_UWP | |
| 163 CLIB_HANDLE_DLL, | |
| 164 CLIB_HANDLE_CRT, | |
| 165 CLIB_HANDLE_KERNEL32, | |
| 166 CLIB_HANDLE_USER32, | |
| 167 CLIB_HANDLE_GDI32, | |
| 168 #endif | |
| 169 CLIB_HANDLE_MAX | |
| 170 }; | |
| 171 | |
| 172 static void *clib_def_handle[CLIB_HANDLE_MAX]; | |
| 173 | |
| 174 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, | |
| 175 const char *name) | |
| 176 { | |
| 177 DWORD err = GetLastError(); | |
| 178 #if LJ_TARGET_XBOXONE | |
| 179 wchar_t wbuf[128]; | |
| 180 char buf[128*2]; | |
| 181 if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, | |
| 182 NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) || | |
| 183 !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL)) | |
| 184 #else | |
| 185 char buf[128]; | |
| 186 if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, | |
| 187 NULL, err, 0, buf, sizeof(buf), NULL)) | |
| 188 #endif | |
| 189 buf[0] = '\0'; | |
| 190 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf)); | |
| 191 } | |
| 192 | |
| 193 static int clib_needext(const char *s) | |
| 194 { | |
| 195 while (*s) { | |
| 196 if (*s == '/' || *s == '\\' || *s == '.') return 0; | |
| 197 s++; | |
| 198 } | |
| 199 return 1; | |
| 200 } | |
| 201 | |
| 202 static const char *clib_extname(lua_State *L, const char *name) | |
| 203 { | |
| 204 if (clib_needext(name)) { | |
| 205 name = lj_strfmt_pushf(L, "%s.dll", name); | |
| 206 L->top--; | |
| 207 } | |
| 208 return name; | |
| 209 } | |
| 210 | |
| 211 static void *clib_loadlib(lua_State *L, const char *name, int global) | |
| 212 { | |
| 213 DWORD oldwerr = GetLastError(); | |
| 214 void *h = LJ_WIN_LOADLIBA(clib_extname(L, name)); | |
| 215 if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name); | |
| 216 SetLastError(oldwerr); | |
| 217 UNUSED(global); | |
| 218 return h; | |
| 219 } | |
| 220 | |
| 221 static void clib_unloadlib(CLibrary *cl) | |
| 222 { | |
| 223 if (cl->handle == CLIB_DEFHANDLE) { | |
| 224 #if !LJ_TARGET_UWP | |
| 225 MSize i; | |
| 226 for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) { | |
| 227 void *h = clib_def_handle[i]; | |
| 228 if (h) { | |
| 229 clib_def_handle[i] = NULL; | |
| 230 FreeLibrary((HINSTANCE)h); | |
| 231 } | |
| 232 } | |
| 233 #endif | |
| 234 } else if (cl->handle) { | |
| 235 FreeLibrary((HINSTANCE)cl->handle); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 #if LJ_TARGET_UWP | |
| 240 EXTERN_C IMAGE_DOS_HEADER __ImageBase; | |
| 241 #endif | |
| 242 | |
| 243 static void *clib_getsym(CLibrary *cl, const char *name) | |
| 244 { | |
| 245 void *p = NULL; | |
| 246 if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ | |
| 247 MSize i; | |
| 248 for (i = 0; i < CLIB_HANDLE_MAX; i++) { | |
| 249 HINSTANCE h = (HINSTANCE)clib_def_handle[i]; | |
| 250 if (!(void *)h) { /* Resolve default library handles (once). */ | |
| 251 #if LJ_TARGET_UWP | |
| 252 h = (HINSTANCE)&__ImageBase; | |
| 253 #else | |
| 254 switch (i) { | |
| 255 case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break; | |
| 256 case CLIB_HANDLE_DLL: | |
| 257 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | |
| 258 (const char *)clib_def_handle, &h); | |
| 259 break; | |
| 260 case CLIB_HANDLE_CRT: | |
| 261 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | |
| 262 (const char *)&_fmode, &h); | |
| 263 break; | |
| 264 case CLIB_HANDLE_KERNEL32: h = LJ_WIN_LOADLIBA("kernel32.dll"); break; | |
| 265 case CLIB_HANDLE_USER32: h = LJ_WIN_LOADLIBA("user32.dll"); break; | |
| 266 case CLIB_HANDLE_GDI32: h = LJ_WIN_LOADLIBA("gdi32.dll"); break; | |
| 267 } | |
| 268 if (!h) continue; | |
| 269 #endif | |
| 270 clib_def_handle[i] = (void *)h; | |
| 271 } | |
| 272 p = (void *)GetProcAddress(h, name); | |
| 273 if (p) break; | |
| 274 } | |
| 275 } else { | |
| 276 p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); | |
| 277 } | |
| 278 return p; | |
| 279 } | |
| 280 | |
| 281 #else | |
| 282 | |
| 283 #define CLIB_DEFHANDLE NULL | |
| 284 | |
| 285 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, | |
| 286 const char *name) | |
| 287 { | |
| 288 lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS")); | |
| 289 } | |
| 290 | |
| 291 static void *clib_loadlib(lua_State *L, const char *name, int global) | |
| 292 { | |
| 293 lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); | |
| 294 UNUSED(name); UNUSED(global); | |
| 295 return NULL; | |
| 296 } | |
| 297 | |
| 298 static void clib_unloadlib(CLibrary *cl) | |
| 299 { | |
| 300 UNUSED(cl); | |
| 301 } | |
| 302 | |
| 303 static void *clib_getsym(CLibrary *cl, const char *name) | |
| 304 { | |
| 305 UNUSED(cl); UNUSED(name); | |
| 306 return NULL; | |
| 307 } | |
| 308 | |
| 309 #endif | |
| 310 | |
| 311 /* -- C library indexing -------------------------------------------------- */ | |
| 312 | |
| 313 #if LJ_TARGET_X86 && LJ_ABI_WIN | |
| 314 /* Compute argument size for fastcall/stdcall functions. */ | |
| 315 static CTSize clib_func_argsize(CTState *cts, CType *ct) | |
| 316 { | |
| 317 CTSize n = 0; | |
| 318 while (ct->sib) { | |
| 319 CType *d; | |
| 320 ct = ctype_get(cts, ct->sib); | |
| 321 if (ctype_isfield(ct->info)) { | |
| 322 d = ctype_rawchild(cts, ct); | |
| 323 n += ((d->size + 3) & ~3); | |
| 324 } | |
| 325 } | |
| 326 return n; | |
| 327 } | |
| 328 #endif | |
| 329 | |
| 330 /* Get redirected or mangled external symbol. */ | |
| 331 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name) | |
| 332 { | |
| 333 if (ct->sib) { | |
| 334 CType *ctf = ctype_get(cts, ct->sib); | |
| 335 if (ctype_isxattrib(ctf->info, CTA_REDIR)) | |
| 336 return strdata(gco2str(gcref(ctf->name))); | |
| 337 } | |
| 338 return strdata(name); | |
| 339 } | |
| 340 | |
| 341 /* Index a C library by name. */ | |
| 342 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) | |
| 343 { | |
| 344 TValue *tv = lj_tab_setstr(L, cl->cache, name); | |
| 345 if (LJ_UNLIKELY(tvisnil(tv))) { | |
| 346 CTState *cts = ctype_cts(L); | |
| 347 CType *ct; | |
| 348 CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); | |
| 349 if (!id) | |
| 350 lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); | |
| 351 if (ctype_isconstval(ct->info)) { | |
| 352 CType *ctt = ctype_child(cts, ct); | |
| 353 lj_assertCTS(ctype_isinteger(ctt->info) && ctt->size <= 4, | |
| 354 "only 32 bit const supported"); /* NYI */ | |
| 355 if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) | |
| 356 setnumV(tv, (lua_Number)(uint32_t)ct->size); | |
| 357 else | |
| 358 setintV(tv, (int32_t)ct->size); | |
| 359 } else { | |
| 360 const char *sym = clib_extsym(cts, ct, name); | |
| 361 #if LJ_TARGET_WINDOWS | |
| 362 DWORD oldwerr = GetLastError(); | |
| 363 #endif | |
| 364 void *p = clib_getsym(cl, sym); | |
| 365 GCcdata *cd; | |
| 366 lj_assertCTS(ctype_isfunc(ct->info) || ctype_isextern(ct->info), | |
| 367 "unexpected ctype %08x in clib", ct->info); | |
| 368 #if LJ_TARGET_X86 && LJ_ABI_WIN | |
| 369 /* Retry with decorated name for fastcall/stdcall functions. */ | |
| 370 if (!p && ctype_isfunc(ct->info)) { | |
| 371 CTInfo cconv = ctype_cconv(ct->info); | |
| 372 if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { | |
| 373 CTSize sz = clib_func_argsize(cts, ct); | |
| 374 const char *symd = lj_strfmt_pushf(L, | |
| 375 cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", | |
| 376 sym, sz); | |
| 377 L->top--; | |
| 378 p = clib_getsym(cl, symd); | |
| 379 } | |
| 380 } | |
| 381 #endif | |
| 382 if (!p) | |
| 383 clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); | |
| 384 #if LJ_TARGET_WINDOWS | |
| 385 SetLastError(oldwerr); | |
| 386 #endif | |
| 387 cd = lj_cdata_new(cts, id, CTSIZE_PTR); | |
| 388 *(void **)cdataptr(cd) = p; | |
| 389 setcdataV(L, tv, cd); | |
| 390 lj_gc_anybarriert(L, cl->cache); | |
| 391 } | |
| 392 } | |
| 393 return tv; | |
| 394 } | |
| 395 | |
| 396 /* -- C library management ------------------------------------------------ */ | |
| 397 | |
| 398 /* Create a new CLibrary object and push it on the stack. */ | |
| 399 static CLibrary *clib_new(lua_State *L, GCtab *mt) | |
| 400 { | |
| 401 GCtab *t = lj_tab_new(L, 0, 0); | |
| 402 GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t); | |
| 403 CLibrary *cl = (CLibrary *)uddata(ud); | |
| 404 cl->cache = t; | |
| 405 ud->udtype = UDTYPE_FFI_CLIB; | |
| 406 /* NOBARRIER: The GCudata is new (marked white). */ | |
| 407 setgcref(ud->metatable, obj2gco(mt)); | |
| 408 setudataV(L, L->top++, ud); | |
| 409 return cl; | |
| 410 } | |
| 411 | |
| 412 /* Load a C library. */ | |
| 413 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) | |
| 414 { | |
| 415 void *handle = clib_loadlib(L, strdata(name), global); | |
| 416 CLibrary *cl = clib_new(L, mt); | |
| 417 cl->handle = handle; | |
| 418 } | |
| 419 | |
| 420 /* Unload a C library. */ | |
| 421 void lj_clib_unload(CLibrary *cl) | |
| 422 { | |
| 423 clib_unloadlib(cl); | |
| 424 cl->handle = NULL; | |
| 425 } | |
| 426 | |
| 427 /* Create the default C library object. */ | |
| 428 void lj_clib_default(lua_State *L, GCtab *mt) | |
| 429 { | |
| 430 CLibrary *cl = clib_new(L, mt); | |
| 431 cl->handle = CLIB_DEFHANDLE; | |
| 432 } | |
| 433 | |
| 434 #endif |