stk/Src/dynload.c

245 lines
7.1 KiB
C

/*
*
* d y n l o a d . c -- All the stuff dealing with
* dynamic loading
*
* Copyright © 1993-1996 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
*
*
* Permission to use, copy, and/or distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that both the above copyright notice and this permission notice appear in
* all copies and derived works. Fees for distribution or use of this
* software or derived works may only be charged with express written
* permission of the copyright holder.
* This software is provided ``as is'' without express or implied warranty.
*
* This software is a derivative work of other copyrighted softwares; the
* copyright notices of these softwares are placed in the file COPYRIGHTS
*
*
* Author: Erick Gallesio [eg@kaolin.unice.fr]
* Creation date: 23-Jan-1994 19:09
* Last file update: 21-Jul-1996 21:24
*/
/* Support for HPUX is due to Dipankar Gupta <dg@hplb.hpl.hp.com> */
/* Support for NETBSD is from Franke Ruediger (Ruediger.Franke@rz.tu-ilmenau.de) */
/* Support for FreeBsD is due to Amancio Hasty Jr (hasty@netcom.com) */
/* Support for Linux is inspired from Patrick Nguyen (pnguyen@elde.epfl.ch) */
#if defined(SUNOS4) || defined(SUNOS5) || defined(IRIX5) || defined(OSF1)
#include <dlfcn.h>
#endif
#if defined(LINUX_DLD)
#include <dld.h>
#endif
#if defined(NETBSD1)
#include <sys/types.h>
#include <nlist.h>
#include <link.h>
#define dlerror() "dlerror" /* dlerror() isn't implemented in NetBSD 1.0 */
#endif
#ifdef HPUX
#include <dl.h>
#endif
#include "stk.h"
#ifdef USE_DYNLOAD
static SCM list_of_files = NULL;
#if defined(SUNOS4) || defined(SUNOS5) || defined(NETBSD1) || defined(FREEBSD) || defined(IRIX5) || defined(OSF1) ||defined(LINUX_ELF)
static void load_and_call(char *path, char *fct_name)
{
static void *self_handle= NULL;
void *handle;
void (*init_fct)();
SCM str;
/* Test if fct_name is already defined in the core interpreter
/* Don't do a dlopen with NULL more than one time since it seems to break
/* Solaris 2.3. (Moises Lejter <mlm@cs.brown.edu>) */
if (self_handle == NULL)
if ((self_handle = (void *) dlopen(NULL,1)) == NULL)
Err("Cannot open myself !!!", NIL);
if ((init_fct = (void (*)()) dlsym(self_handle, fct_name)) != NULL)
Err("Module is already (statically) loaded", STk_makestring(path));
/* Try to avoid multiple loading */
if (!list_of_files) {
STk_gc_protect(&list_of_files);
list_of_files = NIL;
}
str = STk_makestring(path);
if (STk_member(str, list_of_files) != Ntruth) {
Err("Module is already (dynamically) loaded", str);
}
/* Load file */
if ((handle = (void *) dlopen(path, 1)) == NULL) {
char msg[MAX_PATH_LENGTH];
#ifdef FREEBSD
sprintf(msg, "Cannot open object file");
#else
sprintf(msg, "Cannot open object file (%s)", dlerror());
#endif
Err(msg, str);
}
if ((init_fct = (void (*)()) dlsym(handle, fct_name)) == NULL) {
char msg[MAX_PATH_LENGTH];
sprintf(msg, "Cannot find function \"%s\" in object file", fct_name);
Err(msg, NIL);
}
/* Call the init code */
(*init_fct)();
list_of_files = Cons(str, list_of_files);
}
#endif
#if defined(LINUX_DLD)
/*
* This code is for Linux, using the dld package. This code should not be used
* anymore when ELF will be completely accepted under Linux. In the meanwhile...
*
* This code is inspired from a code sent by Patrick Nguyen pnguyen@elde.epfl.ch.
*
*/
static void load_and_call(char *path, char *fct_name)
{
void *handle;
void (*init_fct)();
SCM str;
static dld_already_initialized = FALSE;
/* Try to avoid multiple loading */
if (!list_of_files) {
STk_gc_protect(&list_of_files);
list_of_files = NIL;
}
str = STk_makestring(path);
if (STk_member(str, list_of_files) != Ntruth) {
Err("Module is already (dynamically) loaded", str);
}
/* Dld must be initialized at first call */
if(!dld_already_initialized) {
if (dld_init (dld_find_executable (STk_Argv0)))
dld_perror("dld: failed to init dld");
else
dld_already_initialized = TRUE;
}
/* Load file */
if (dld_link(path)) dld_perror("dld: cannot link");
/* And get a pointer on function "fct_name" */
init_fct = (void (*) ()) dld_get_func(fct_name);
if (init_fct) {
/* When loading a function. It can induce some unresolved references
* Most of the time, the unresolved references come from fucntions
* which are in the libc but which are not used by the core interpreter.
* For instance, if loaded module uses fork, which is not loaded in
* the interpreter, we will have an unresolve reference for _fork.
* To avoid this problem, we make again a link against standard libc
* Note: in general situation is more complicated than this, unresolved
* symbols could be elsewhere than the libc....
* Those situation are not handled by current code, but I hope that ELF
* will supplant this way of doing dynamic loading soon...
*/
if (dld_function_executable_p (fct_name))
/* Call the init code */
(*init_fct) ();
else {
/* Function is notexecutable = we have unresolved references */
if (dld_link("/usr/lib/libc.a") && dld_link("/usr/lib/libc.sa"))
dld_perror("dld: cannot link");
if (dld_function_executable_p (fct_name)) {
init_fct = (void (*) ()) dld_get_func(fct_name);
(*init_fct) ();
}
else {
char **unresolved;
extern int dld_undefined_sym_count;
int i;
fprintf(STk_stderr, "dld: function %s not executable!\n", fct_name);
fprintf(STk_stderr, "Unresolved symbols are:\n");
unresolved= dld_list_undefined_sym();
for (i = 0; i < dld_undefined_sym_count; i++)
fprintf(STk_stderr, "\t%s\n",unresolved[i]);
free(unresolved);
Err("dld: link aborted", NIL);
}
}
}
else {
char msg[MAX_PATH_LENGTH];
sprintf(msg, "Cannot find function \"%s\" in object file", fct_name);
Err(msg, NIL);
}
list_of_files = Cons(str, list_of_files);
}
#endif /* LINUX_DLD */
#ifdef HPUX
static void load_and_call(char *path, char *fct_name)
{
shl_t handle;
void (*init_fct)();
if ((handle = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L)) == NULL)
Err("Cannot open file", STk_makestring(path));
handle = NULL;
if (shl_findsym(&handle, fct_name, TYPE_PROCEDURE, &init_fct) == -1) {
char msg[MAX_PATH_LENGTH];
sprintf(msg, "Cannot find function %s in object file", fct_name);
Err(msg, NIL);
}
/* Call the init code */
(*init_fct)();
}
#endif
void STk_load_object_file(char *path)
{
char fct_name[1024], *p, *slash, *dot;
/* Load the file as an object one */
for (p = path, slash = p-1; *p; p++) /* Find position of last '/' */
if (*p == '/') slash = p;
#if defined(NETBSD1) || defined(FREEBSD)
sprintf(fct_name, "_STk_init_%s", slash + 1);
#else
sprintf(fct_name, "STk_init_%s", slash + 1);
#endif
for (p = fct_name; *p; p++) /* Delete suffix it it exists */
if (*p == '.') { *p = '\0'; break; }
load_and_call(path, fct_name);
}
#else /* not DYNLOAD */
void STk_load_object_file(char *path)
{
Err("load: Loading of object file is not defined on this architecture", NIL);
}
#endif