diff --git a/src/lj_clib.c b/src/lj_clib.c index d7721860..7b9b6c1a 100644 --- a/src/lj_clib.c +++ b/src/lj_clib.c @@ -22,6 +22,7 @@ #if LJ_TARGET_DLOPEN #include +#include #if defined(RTLD_DEFAULT) #define CLIB_DEFHANDLE RTLD_DEFAULT @@ -59,11 +60,41 @@ static const char *clib_extname(lua_State *L, const char *name) return name; } +/* Quick and dirty solution to resolve shared library name from ld script. */ +static const char *clib_resolve_lds(lua_State *L, const char *name) +{ + FILE *fp = fopen(name, "r"); + if (fp) { + char *p, *e, buf[256]; + if (fgets(buf, sizeof(buf), fp) && !strncmp(buf, "/* GNU ld script", 16)) { + while (fgets(buf, sizeof(buf), fp)) { + if (!strncmp(buf, "GROUP", 5) && (p = strchr(buf, '('))) { + while (*++p == ' ') ; + for (e = p; *e && *e != ' ' && *e != ')'; e++) ; + fclose(fp); + return strdata(lj_str_new(L, p, e-p)); + } + } + } + fclose(fp); + } + return NULL; +} + static void *clib_loadlib(lua_State *L, const char *name, int global) { void *h = dlopen(clib_extname(L, name), RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); - if (!h) clib_error_(L); + if (!h) { + const char *e, *err = dlerror(); + if (*err == '/' && (e = strchr(err, ':')) && + (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) { + h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); + if (h) return h; + err = dlerror(); + } + lj_err_callermsg(L, err); + } return h; }