From eea0a81bc57597d58ef72d01ea0f9ccdd236158f Mon Sep 17 00:00:00 2001 From: midipix Date: Sat, 28 Oct 2017 12:42:47 -0400 Subject: ldso: implemented dlopen(). --- src/ldso/nt32/dynlink.c | 107 ++++++++++++++++++++++++++++++++++++++++++++---- src/ldso/nt64/dynlink.c | 107 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 196 insertions(+), 18 deletions(-) (limited to 'src/ldso') diff --git a/src/ldso/nt32/dynlink.c b/src/ldso/nt32/dynlink.c index c1fab74..4115178 100644 --- a/src/ldso/nt32/dynlink.c +++ b/src/ldso/nt32/dynlink.c @@ -1,11 +1,108 @@ #define _BSD_SOURCE #include +#include #include #include "psxglue.h" #include "pthread_impl.h" -extern struct __ldso_vtbl * __ldso_vtbl; +extern const struct __ldso_vtbl * __ldso_vtbl; +extern const struct __psx_vtbl * __psx_vtbl; + +static pthread_rwlock_t __ldso_lock; + +void * dlopen(const char * file, int mode) +{ + int status; + void * base; + int cs; + char * ch; + char * next; + char * epath; + char * lpath; + const char ** lpathv; + const char ** epathv; + char lpathbuf[2048]; + const char * lpathvbuf[64]; + int i; + + /* prolog */ + if (!file) + return __ldso_vtbl->dlopen(0,mode,0,&status); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + pthread_rwlock_wrlock(&__ldso_lock); + __inhibit_ptc(); + + /* loader path environment variable to loader path vector */ + if ((epath = getenv("LD_LIBRARY_PATH"))) { + lpath = (strncpy(lpathbuf,epath,2048) < &lpathbuf[2048]) + ? lpathbuf + : strdup(epath); + + if ((i = !!lpath)) + for (ch=lpath; *ch; ch++) + if (*ch == ':') + i++; + + lpathv = (++i < 64) + ? lpathvbuf + : calloc(++i,sizeof(char *)); + } else { + lpath = lpathbuf; + lpathv = lpathvbuf; + lpath[0] = 0; + } + + if (lpath && lpathv) { + ch = lpath; + next = *ch ? ch : 0; + epathv = lpathv; + + for (; next; ) { + *epathv++ = (*next == ':') + ? "." + : next; + + ch = &next[1]; + + for (; *ch; ) { + if (*ch == ':') { + *ch = 0; + ch = 0; + } else { + ch++; + } + } + + next = *ch ? ch : 0; + } + + *epathv = 0; + } + + /* dlopen */ + base = (lpath && lpathv) + ? __ldso_vtbl->dlopen(file,mode,lpathv,&status) + : 0; + + /* epilog */ + if (lpath && (lpath != lpathbuf)) + free(lpath); + + if (lpathv && (lpathv != lpathvbuf)) + free(lpathv); + + __release_ptc(); + pthread_rwlock_unlock(&__ldso_lock); + + if (base) + __psx_vtbl->do_global_ctors_fn(); + + pthread_setcancelstate(cs, 0); + + return base; +} int __dladdr(const void * addr, Dl_info * info) { @@ -22,14 +119,6 @@ void *__dlsym(void * restrict p, const char * restrict s, void * restrict ra) return __ldso_vtbl->dlsym(p,s,ra); } -void * dlopen(const char * file, int mode) -{ - return __ldso_vtbl->dlopen( - file,mode, - getenv("LD_LIBRARY_PATH"), - 0); -} - int dlclose(void *p) { return __ldso_vtbl->dlclose(p); diff --git a/src/ldso/nt64/dynlink.c b/src/ldso/nt64/dynlink.c index c1fab74..4115178 100644 --- a/src/ldso/nt64/dynlink.c +++ b/src/ldso/nt64/dynlink.c @@ -1,11 +1,108 @@ #define _BSD_SOURCE #include +#include #include #include "psxglue.h" #include "pthread_impl.h" -extern struct __ldso_vtbl * __ldso_vtbl; +extern const struct __ldso_vtbl * __ldso_vtbl; +extern const struct __psx_vtbl * __psx_vtbl; + +static pthread_rwlock_t __ldso_lock; + +void * dlopen(const char * file, int mode) +{ + int status; + void * base; + int cs; + char * ch; + char * next; + char * epath; + char * lpath; + const char ** lpathv; + const char ** epathv; + char lpathbuf[2048]; + const char * lpathvbuf[64]; + int i; + + /* prolog */ + if (!file) + return __ldso_vtbl->dlopen(0,mode,0,&status); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + pthread_rwlock_wrlock(&__ldso_lock); + __inhibit_ptc(); + + /* loader path environment variable to loader path vector */ + if ((epath = getenv("LD_LIBRARY_PATH"))) { + lpath = (strncpy(lpathbuf,epath,2048) < &lpathbuf[2048]) + ? lpathbuf + : strdup(epath); + + if ((i = !!lpath)) + for (ch=lpath; *ch; ch++) + if (*ch == ':') + i++; + + lpathv = (++i < 64) + ? lpathvbuf + : calloc(++i,sizeof(char *)); + } else { + lpath = lpathbuf; + lpathv = lpathvbuf; + lpath[0] = 0; + } + + if (lpath && lpathv) { + ch = lpath; + next = *ch ? ch : 0; + epathv = lpathv; + + for (; next; ) { + *epathv++ = (*next == ':') + ? "." + : next; + + ch = &next[1]; + + for (; *ch; ) { + if (*ch == ':') { + *ch = 0; + ch = 0; + } else { + ch++; + } + } + + next = *ch ? ch : 0; + } + + *epathv = 0; + } + + /* dlopen */ + base = (lpath && lpathv) + ? __ldso_vtbl->dlopen(file,mode,lpathv,&status) + : 0; + + /* epilog */ + if (lpath && (lpath != lpathbuf)) + free(lpath); + + if (lpathv && (lpathv != lpathvbuf)) + free(lpathv); + + __release_ptc(); + pthread_rwlock_unlock(&__ldso_lock); + + if (base) + __psx_vtbl->do_global_ctors_fn(); + + pthread_setcancelstate(cs, 0); + + return base; +} int __dladdr(const void * addr, Dl_info * info) { @@ -22,14 +119,6 @@ void *__dlsym(void * restrict p, const char * restrict s, void * restrict ra) return __ldso_vtbl->dlsym(p,s,ra); } -void * dlopen(const char * file, int mode) -{ - return __ldso_vtbl->dlopen( - file,mode, - getenv("LD_LIBRARY_PATH"), - 0); -} - int dlclose(void *p) { return __ldso_vtbl->dlclose(p); -- cgit v1.2.3