diff options
author | midipix <writeonce@midipix.org> | 2017-10-28 12:42:47 -0400 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2017-10-28 18:12:39 -0400 |
commit | eea0a81bc57597d58ef72d01ea0f9ccdd236158f (patch) | |
tree | eb385a4386af0364c2ab2583576559844d0d98cd /src/ldso/nt64 | |
parent | 03bf9aba6d06016ee4c01ba10ad19f6029c4056d (diff) | |
download | mmglue-eea0a81bc57597d58ef72d01ea0f9ccdd236158f.tar.bz2 mmglue-eea0a81bc57597d58ef72d01ea0f9ccdd236158f.tar.xz |
ldso: implemented dlopen().
Diffstat (limited to 'src/ldso/nt64')
-rw-r--r-- | src/ldso/nt64/dynlink.c | 107 |
1 files changed, 98 insertions, 9 deletions
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 <stdlib.h> +#include <string.h> #include <dlfcn.h> #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); |