diff --git a/libs/libc/dllfcn/Kconfig b/libs/libc/dllfcn/Kconfig index 33e017246ad..5f52993d035 100644 --- a/libs/libc/dllfcn/Kconfig +++ b/libs/libc/dllfcn/Kconfig @@ -17,4 +17,16 @@ config LIBC_DLLFCN A work in progress, hence, marked EXPERIMENTAL +if LIBC_DLLFCN + +config LDPATH_INITIAL + string "Initial LD_LIBRARY_PATH Value" + default "" + depends on LIB_ENVPATH + ---help--- + The initial value of the LD_LIBRARY_PATH variable. This is the + colon-separated list of absolute paths. E.g., "/lib:/usr/lib:/system/lib" + +endif + # endmenu # Shared Library Support diff --git a/libs/libc/dllfcn/lib_dlopen.c b/libs/libc/dllfcn/lib_dlopen.c index bfd15ec8ccc..2e1c020f345 100644 --- a/libs/libc/dllfcn/lib_dlopen.c +++ b/libs/libc/dllfcn/lib_dlopen.c @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -161,6 +162,14 @@ static void dldump_initializer(mod_initializer_t initializer, ****************************************************************************/ #ifdef CONFIG_BUILD_PROTECTED +/* The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * must be two copies of the module logic: One residing in kernel + * space and using the kernel symbol table and one residing in user space + * using the user space symbol table. + * + * dlinsert() is essentially a clone of insmod(). + */ + static inline FAR void *dlinsert(FAR const char *filename) { struct mod_loadinfo_s loadinfo; @@ -257,6 +266,50 @@ errout_with_lock: set_errno(-ret); return NULL; } +#elif defined(CONFIG_BUILD_FLAT) +/* In the FLAT build, a shared library is essentially the same as a kernel + * module. + * + * REVIST: Missing functionality: + * - No automatic binding of symbols + * - No dependencies + * - mode is ignored. + */ + +static inline FAR void *dlinsert(FAR const char *filename) +{ + FAR void *handle; + FAR char *name; + + DEBUGASSERT(filename != NULL); + + name = strdup(filename); + if (name == NULL) + { + return NULL; + } + + /* Then install the file using the basename of the file as the module name. */ + + handle = insmod(filename, basename(name)); + free(name); + return handle; +} +#else /* if defined(CONFIG_BUILD_KERNEL) */ +/* The KERNEL build is considerably more complex: In order to be shared, + * the .text portion of the module must be (1) build for PIC/PID operation + * and (2) must like in a shared memory region accessible from all + * processes. The .data/.bss portion of the module must be allocated in + * the user space of each process, but must lie at the same virtual address + * so that it can be referenced from the one copy of the text in the shared + * memory region. + */ + +static inline FAR void *dlinsert(FAR const char *filename) +{ +#warning Missing logic + return NULL; +} #endif /**************************************************************************** @@ -365,61 +418,58 @@ errout_with_lock: FAR void *dlopen(FAR const char *file, int mode) { -#if defined(CONFIG_BUILD_FLAT) - FAR void *handle; - FAR char *name; + FAR void *handle = NULL; - DEBUGASSERT(file != NULL); - - /* In the FLAT build, a shared library is essentially the same as a kernel - * module. - * - * REVIST: Missing functionality: - * - No automatic binding of symbols - * - No dependencies - * - mode is ignored. - */ - - /* Use the basename of the file as the module name. - * REVISIT: This places an non-standard restriction. We cannot install - * two modules of the same name event though they lie in different - * directories. - */ - - name = strdup(file); - if (name == NULL) +#ifdef CONFIG_LIB_ENVPATH + if (file[0] != '/') { - return NULL; + FAR const char *relpath; + FAR char *fullpath; + ENVPATH_HANDLE env; + + /* Set aside the relative path */ + + relpath = file; + + /* Initialize to traverse the LD_LIBRARY_PATH variable */ + + env = envpath_init("LD_LIBRARY_PATH"); + if (env) + { + /* Get the next absolute file path */ + + while ((fullpath = envpath_next(env, relpath)) != NULL) + { + /* Try to load the file at this path */ + + handle = dlinsert(fullpath); + + /* Free the allocated fullpath */ + + lib_free(fullpath); + + /* Break out of the loop with handle != NULL on success */ + + if (handle != NULL) + { + break; + } + } + + /* Release the traversal handle */ + + envpath_release(env); + } + } + else +#endif + { + /* We already have the one and only absolute path to the file to + * be loaded. + */ + + handle = dlinsert(file); } - /* Then install the file using the basename of the file as the module name. */ - - handle = insmod(file, basename(name)); - free(name); return handle; - -#elif defined(CONFIG_BUILD_PROTECTED) - /* The PROTECTED build is equivalent to the FLAT build EXCEPT that there - * must be two copies of the module logic: One residing in kernel - * space and using the kernel symbol table and one residing in user space - * using the user space symbol table. - * - * dlinsert() is essentially a clone of insmod(). - */ - - return dlinsert(file); - -#else /* if defined(CONFIG_BUILD_KERNEL) */ - /* The KERNEL build is considerably more complex: In order to be shared, - * the .text portion of the module must be (1) build for PIC/PID operation - * and (2) must like in a shared memory region accessible from all - * processes. The .data/.bss portion of the module must be allocated in - * the user space of each process, but must lie at the same virtual address - * so that it can be referenced from the one copy of the text in the shared - * memory region. - */ - -#warning Missing logic - return NULL; -#endif } diff --git a/sched/init/os_bringup.c b/sched/init/os_bringup.c index 4f5532b175e..ffd13dc3d87 100644 --- a/sched/init/os_bringup.c +++ b/sched/init/os_bringup.c @@ -436,6 +436,10 @@ int os_bringup(void) (void)setenv("PATH", CONFIG_PATH_INITIAL, 1); #endif +#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_LDPATH_INITIAL) + (void)setenv("LD_LIBRARY_PATH", CONFIG_LDPATH_INITIAL, 1); +#endif + /* Start the page fill worker kernel thread that will resolve page faults. * This should always be the first thread started because it may have to * resolve page faults in other threads @@ -458,7 +462,7 @@ int os_bringup(void) /* We an save a few bytes by discarding the IDLE thread's environment. */ -#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL) +#if !defined(CONFIG_DISABLE_ENVIRON) && (defined(CONFIG_PATH_INITIAL) || defined(CONFIG_LDPATH_INITIAL)) (void)clearenv(); #endif