diff options
| -rw-r--r-- | src/lj_clib.c | 93 |
1 files changed, 63 insertions, 30 deletions
diff --git a/src/lj_clib.c b/src/lj_clib.c index 91309eb2..3fc91a72 100644 --- a/src/lj_clib.c +++ b/src/lj_clib.c | |||
| @@ -31,38 +31,39 @@ | |||
| 31 | #define CLIB_DEFHANDLE NULL | 31 | #define CLIB_DEFHANDLE NULL |
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
| 34 | LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L) | 34 | LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L) |
| 35 | { | 35 | { |
| 36 | lj_err_callermsg(L, dlerror()); | 36 | lj_err_callermsg(L, dlerror()); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | #define clib_error(L, fmt, name) clib_error_(L) | ||
| 40 | |||
| 39 | #if LJ_TARGET_OSX | 41 | #if LJ_TARGET_OSX |
| 40 | #define CLIB_SOEXT "%s.dylib" | 42 | #define CLIB_SOEXT "%s.dylib" |
| 41 | #else | 43 | #else |
| 42 | #define CLIB_SOEXT "%s.so" | 44 | #define CLIB_SOEXT "%s.so" |
| 43 | #endif | 45 | #endif |
| 44 | 46 | ||
| 45 | static const char *clib_extname(lua_State *L, GCstr *name) | 47 | static const char *clib_extname(lua_State *L, const char *name) |
| 46 | { | 48 | { |
| 47 | const char *s = strdata(name); | 49 | if (!strchr(name, '/')) { |
| 48 | if (!strchr(s, '/')) { | 50 | if (!strchr(name, '.')) { |
| 49 | if (!strchr(s, '.')) { | 51 | name = lj_str_pushf(L, CLIB_SOEXT, name); |
| 50 | s = lj_str_pushf(L, CLIB_SOEXT, s); | ||
| 51 | L->top--; | 52 | L->top--; |
| 52 | } | 53 | } |
| 53 | if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) { | 54 | if (!(name[0] == 'l' && name[1] == 'i' && name[2] == 'b')) { |
| 54 | s = lj_str_pushf(L, "lib%s", s); | 55 | name = lj_str_pushf(L, "lib%s", name); |
| 55 | L->top--; | 56 | L->top--; |
| 56 | } | 57 | } |
| 57 | } | 58 | } |
| 58 | return s; | 59 | return name; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 62 | static void *clib_loadlib(lua_State *L, const char *name, int global) |
| 62 | { | 63 | { |
| 63 | void *h = dlopen(clib_extname(L, name), | 64 | void *h = dlopen(clib_extname(L, name), |
| 64 | RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); | 65 | RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); |
| 65 | if (!h) clib_error(L); | 66 | if (!h) clib_error_(L); |
| 66 | return h; | 67 | return h; |
| 67 | } | 68 | } |
| 68 | 69 | ||
| @@ -72,10 +73,9 @@ static void clib_unloadlib(CLibrary *cl) | |||
| 72 | dlclose(cl->handle); | 73 | dlclose(cl->handle); |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 76 | static void *clib_getsym(CLibrary *cl, const char *name) |
| 76 | { | 77 | { |
| 77 | void *p = dlsym(cl->handle, strdata(name)); | 78 | void *p = dlsym(cl->handle, name); |
| 78 | if (!p) clib_error(L); | ||
| 79 | return p; | 79 | return p; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| @@ -127,17 +127,16 @@ static int clib_needext(const char *s) | |||
| 127 | return 1; | 127 | return 1; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static const char *clib_extname(lua_State *L, GCstr *name) | 130 | static const char *clib_extname(lua_State *L, const char *name) |
| 131 | { | 131 | { |
| 132 | const char *s = strdata(name); | 132 | if (clib_needext(name)) { |
| 133 | if (clib_needext(s)) { | 133 | name = lj_str_pushf(L, "%s.dll", name); |
| 134 | s = lj_str_pushf(L, "%s.dll", s); | ||
| 135 | L->top--; | 134 | L->top--; |
| 136 | } | 135 | } |
| 137 | return s; | 136 | return name; |
| 138 | } | 137 | } |
| 139 | 138 | ||
| 140 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 139 | static void *clib_loadlib(lua_State *L, const char *name, int global) |
| 141 | { | 140 | { |
| 142 | void *h = (void *)LoadLibraryA(clib_extname(L, name)); | 141 | void *h = (void *)LoadLibraryA(clib_extname(L, name)); |
| 143 | if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); | 142 | if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); |
| @@ -157,9 +156,8 @@ static void clib_unloadlib(CLibrary *cl) | |||
| 157 | } | 156 | } |
| 158 | } | 157 | } |
| 159 | 158 | ||
| 160 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 159 | static void *clib_getsym(CLibrary *cl, const char *name) |
| 161 | { | 160 | { |
| 162 | const char *sym = strdata(name); | ||
| 163 | void *p; | 161 | void *p; |
| 164 | if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ | 162 | if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ |
| 165 | MSize i; | 163 | MSize i; |
| @@ -183,13 +181,12 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
| 183 | if (!h) continue; | 181 | if (!h) continue; |
| 184 | clib_def_handle[i] = (void *)h; | 182 | clib_def_handle[i] = (void *)h; |
| 185 | } | 183 | } |
| 186 | p = (void *)GetProcAddress(h, sym); | 184 | p = (void *)GetProcAddress(h, name); |
| 187 | if (p) break; | 185 | if (p) break; |
| 188 | } | 186 | } |
| 189 | } else { | 187 | } else { |
| 190 | p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym); | 188 | p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); |
| 191 | } | 189 | } |
| 192 | if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); | ||
| 193 | return p; | 190 | return p; |
| 194 | } | 191 | } |
| 195 | 192 | ||
| @@ -197,7 +194,13 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
| 197 | 194 | ||
| 198 | #define CLIB_DEFHANDLE NULL | 195 | #define CLIB_DEFHANDLE NULL |
| 199 | 196 | ||
| 200 | static void *clib_loadlib(lua_State *L, GCstr *name, int global) | 197 | LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, |
| 198 | const char *name) | ||
| 199 | { | ||
| 200 | lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS")); | ||
| 201 | } | ||
| 202 | |||
| 203 | static void *clib_loadlib(lua_State *L, const char *name, int global) | ||
| 201 | { | 204 | { |
| 202 | lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); | 205 | lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); |
| 203 | UNUSED(name); UNUSED(global); | 206 | UNUSED(name); UNUSED(global); |
| @@ -209,9 +212,8 @@ static void clib_unloadlib(CLibrary *cl) | |||
| 209 | UNUSED(cl); | 212 | UNUSED(cl); |
| 210 | } | 213 | } |
| 211 | 214 | ||
| 212 | static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | 215 | static void *clib_getsym(CLibrary *cl, const char *name) |
| 213 | { | 216 | { |
| 214 | lj_err_callermsg(L, "no support for resolving symbols for this OS"); | ||
| 215 | UNUSED(cl); UNUSED(name); | 217 | UNUSED(cl); UNUSED(name); |
| 216 | return NULL; | 218 | return NULL; |
| 217 | } | 219 | } |
| @@ -224,6 +226,22 @@ static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) | |||
| 224 | #define CLNS_INDEX \ | 226 | #define CLNS_INDEX \ |
| 225 | ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) | 227 | ((1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) |
| 226 | 228 | ||
| 229 | #if LJ_TARGET_X86 && LJ_ABI_WIN | ||
| 230 | /* Compute argument size for fastcall/stdcall functions. */ | ||
| 231 | static CTSize clib_func_argsize(CTState *cts, CType *ct) | ||
| 232 | { | ||
| 233 | CTSize n = 0; | ||
| 234 | while (ct->sib) { | ||
| 235 | CType *d; | ||
| 236 | ct = ctype_get(cts, ct->sib); | ||
| 237 | lua_assert(ctype_isfield(ct->info)); | ||
| 238 | d = ctype_rawchild(cts, ct); | ||
| 239 | n += ((d->size + 3) & ~3); | ||
| 240 | } | ||
| 241 | return n; | ||
| 242 | } | ||
| 243 | #endif | ||
| 244 | |||
| 227 | /* Index a C library by name. */ | 245 | /* Index a C library by name. */ |
| 228 | TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) | 246 | TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) |
| 229 | { | 247 | { |
| @@ -242,9 +260,24 @@ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) | |||
| 242 | else | 260 | else |
| 243 | setnumV(tv, (lua_Number)(int32_t)ct->size); | 261 | setnumV(tv, (lua_Number)(int32_t)ct->size); |
| 244 | } else { | 262 | } else { |
| 245 | void *p = clib_getsym(L, cl, name); | 263 | void *p = clib_getsym(cl, strdata(name)); |
| 246 | GCcdata *cd; | 264 | GCcdata *cd; |
| 247 | lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); | 265 | lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); |
| 266 | #if LJ_TARGET_X86 && LJ_ABI_WIN | ||
| 267 | /* Retry with decorated name for fastcall/stdcall functions. */ | ||
| 268 | if (!p && ctype_isfunc(ct->info)) { | ||
| 269 | CTInfo cconv = ctype_cconv(ct->info); | ||
| 270 | if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { | ||
| 271 | CTSize sz = clib_func_argsize(cts, ct); | ||
| 272 | const char *sym = lj_str_pushf(L, | ||
| 273 | cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", strdata(name), sz); | ||
| 274 | L->top--; | ||
| 275 | p = clib_getsym(cl, sym); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | #endif | ||
| 279 | if (!p) | ||
| 280 | clib_error(L, "cannot resolve symbol " LUA_QS ": %s", strdata(name)); | ||
| 248 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); | 281 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); |
| 249 | *(void **)cdataptr(cd) = p; | 282 | *(void **)cdataptr(cd) = p; |
| 250 | setcdataV(L, tv, cd); | 283 | setcdataV(L, tv, cd); |
| @@ -272,7 +305,7 @@ static CLibrary *clib_new(lua_State *L, GCtab *mt) | |||
| 272 | /* Load a C library. */ | 305 | /* Load a C library. */ |
| 273 | void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) | 306 | void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) |
| 274 | { | 307 | { |
| 275 | void *handle = clib_loadlib(L, name, global); | 308 | void *handle = clib_loadlib(L, strdata(name), global); |
| 276 | CLibrary *cl = clib_new(L, mt); | 309 | CLibrary *cl = clib_new(L, mt); |
| 277 | cl->handle = handle; | 310 | cl->handle = handle; |
| 278 | } | 311 | } |
