/* "dynl.c" dynamically link&load object files. * Copyright (C) 1990-1999 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include "scm.h" #ifndef STDC_HEADERS int free (); /* P((char *ptr)) */ #endif /* linkpath holds the filename which just got linked. Scheme *loadpath* will get set to linkpath and then restored around the initialization call */ /* static SCM linkpath; */ #ifdef DLD # include "dld.h" void listundefs() { int i; char **undefs = dld_list_undefined_sym(); puts(" undefs:"); for (i = dld_undefined_sym_count;i--;) { putc('"', stdout); fputs(undefs[i], stdout); puts("\""); } free(undefs); } static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { int status; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); DEFER_INTS; status = dld_link(CHARS(fname)); ALLOW_INTS; if (!status) {/* linkpath = fname; */ return fname;} if (DLD_ENOFILE==status) return BOOL_F; if (DLD_EBADOBJECT==status) return BOOL_F; dld_perror("DLD"); return BOOL_F; } SCM l_dyn_call(symb, shl) SCM symb, shl; { int i; void (*func)() = 0; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); DEFER_INTS; if ((i = dld_function_executable_p(CHARS(symb)))) func = (void (*) ()) dld_get_func(CHARS(symb)); else dld_perror("DLDP"); ALLOW_INTS; if (!i) listundefs(); if (!func) { dld_perror("DLD"); return BOOL_F; } /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)(int argc, const char **argv) = 0; const char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); DEFER_INTS; argv = makargvfrmstrs(args, s_main_call); if ((i = dld_function_executable_p(CHARS(symb)))) func = (int (*) (int argc, const char **argv)) dld_get_func(CHARS(symb)); else dld_perror("DLDP"); if (!i) listundefs(); if (!func) { must_free_argv(argv); ALLOW_INTS; dld_perror("DLD"); return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(fname) SCM fname; { int status; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_unlink); DEFER_INTS; status = dld_unlink_by_file(CHARS(fname), 1); ALLOW_INTS; if (!status) return BOOL_T; dld_perror("DLD"); return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { /* if (!execpath) execpath = scm_find_execpath(); */ if ((!execpath) || dld_init(execpath)) { dld_perror("DLD:"); return; } if (!dumped) { init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("dld"); # ifdef DLD_DYNCM add_feature("dld:dyncm"); # endif } } #else # ifdef hpux # include "dl.h" # define P_SHL(obj) ((shl_t*)(&CDR(obj))) # define SHL(obj) (*P_SHL(obj)) int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, free0, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { SCM z; shl_t shl; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; shl = shl_load(CHARS(fname), BIND_DEFERRED , 0L); if (NULL==shl) { ALLOW_INTS; return BOOL_F; } SETCHARS(z, shl); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; int i; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; if ((i = shl_findsym(P_SHL(shl), CHARS(symb), TYPE_PROCEDURE, &func)) != 0) { puts(" undef:"); puts(CHARS(symb)); } ALLOW_INTS; if (i != 0) return BOOL_F; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; const char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; if ((i = shl_findsym(P_SHL(shl), CHARS(symb), TYPE_PROCEDURE, &func)) != 0) { puts(" undef:"); puts(CHARS(symb)); } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; if (i != 0) return BOOL_F; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { int status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = shl_unload(SHL(shl)); ALLOW_INTS; if (!status) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("shl"); } } # endif #endif #ifdef vms /* This permits dynamic linking. For example, the procedure of 0 arguments from a file could be the initialization procedure. (vms:dynamic-link-call "MYDISK:[MYDIR].EXE" "foo" "INIT_FOO") The first argument specifies the directory where the file specified by the second argument resides. The current directory would be "SYS$DISK:[].EXE". The second argument cannot contain any punctuation. The third argument probably needs to be uppercased to mimic the VMS linker. */ # include # include # include struct dsc$descriptor *descriptorize(x, buff) struct dsc$descriptor *x; SCM buff; {(*x).dsc$w_length = LENGTH(buff); (*x).dsc$a_pointer = CHARS(buff); (*x).dsc$b_class = DSC$K_CLASS_S; (*x).dsc$b_dtype = DSC$K_DTYPE_T; return(x);} static char s_dynl[] = "vms:dynamic-link-call"; SCM dynl(dir, symbol, fname) SCM dir, symbol, fname; { struct dsc$descriptor fnamed, symbold, dird; void (*fcn)(); long retval; ASRTER(IMP(dir) || STRINGP(dir), dir, ARG1, s_dynl); ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG2, s_dynl); ASRTER(NIMP(symbol) && STRINGP(symbol), symbol, ARG3, s_dynl); descriptorize(&fnamed, fname); descriptorize(&symbold, symbol); DEFER_INTS; retval = lib$find_image_symbol(&fnamed, &symbold, &fcn, IMP(dir) ? 0 : descriptorize(&dird, dir)); if (SS$_NORMAL != retval) { /* wta(MAKINUM(retval), "vms error", s_dynl); */ ALLOW_INTS; return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = dir; */ (*fcn)(); /* *loc_loadpath = oloadpath; */ return BOOL_T; } void init_dynl() { if (!dumped) { make_subr(s_dynl, tc7_subr_3, dynl); } } #endif #ifdef SUN_DL # include # define SHL(obj) ((void*)CDR(obj)) # ifdef RTLD_GLOBAL # define DLOPEN_MODE (RTLD_NOW | RTLD_GLOBAL) # else # ifdef RTLD_LAZY /* This is here out of conservatism, not because it's known to be right. */ # define DLOPEN_MODE RTLD_LAZY # else # define DLOPEN_MODE 1 /* Thats what it says in the man page. */ # endif # endif sizet frshl(ptr) CELLPTR ptr; { # if 0 /* Should freeing a shl close and possibly unmap the object file it */ /* refers to? */ if (SHL(ptr)) dlclose(SHL(ptr)); # endif return 0; } int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, frshl, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { SCM z; void *handle; if (FALSEP(fname)) return fname; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; handle = dlopen(CHARS(fname), DLOPEN_MODE); if (NULL==handle) { if (scm_verbose > 1) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_link, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); }} return BOOL_F; } SETCHARS(z, handle); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; func = dlsym(SHL(shl), CHARS(symb)); if (!func) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_call, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); } return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; char **argv; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; func = dlsym(SHL(shl), CHARS(symb)); if (!func) { char *dlr = dlerror(); ALLOW_INTS; if (dlr) { lputs(s_main_call, cur_errp); lputs(": ", cur_errp); lputs(dlr, cur_errp); scm_newline(cur_errp); } return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), (const char**)argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { int status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = dlclose(SHL(shl)); SETCHARS(shl, NULL); ALLOW_INTS; if (!status) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("sun-dl"); } } #endif /* SUN_DL */ #ifdef macintosh # include # include # define SHL(obj) ((void*)CDR(obj)) sizet frshl(ptr) CELLPTR ptr; { # if 0 /* Should freeing a shl close and possibly unmap the object file it */ /* refers to? */ if (SHL(ptr)) dlclose(SHL(ptr)); # endif return 0; } int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, frshl, prinshl}; static char s_link[] = "dyn:link", s_call[] = "dyn:call"; SCM l_dyn_link(fname) SCM fname; { OSErr err; SCM z; void *handle; Str63 libName; CFragConnectionID connID; Ptr mainAddr; Str255 errMessage; if (FALSEP(fname)) return fname; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; strcpy((char *)libName, CHARS(fname)); c2pstr((char *)libName); err = GetSharedLibrary (libName, kCompiledCFragArch, kReferenceCFrag, &connID, &mainAddr, errMessage); if (err!=noErr) { ALLOW_INTS; return BOOL_F; } SETCHARS(z, (void *)connID); CAR(z) = tc16_shl; ALLOW_INTS; /* linkpath = fname; */ return z; } SCM l_dyn_call(symb, shl) SCM symb, shl; { void (*func)() = 0; OSErr err; CFragSymbolClass symClass; Str255 symName; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; strcpy((char *)symName, CHARS(symb)); c2pstr((char *)symName); err = FindSymbol((CFragConnectionID)SHL(shl), symName, (Ptr *)&func, &symClass); if (err!=noErr /* || symClass != kCodeCFragSymbol */) { ALLOW_INTS; if (err == cfragConnectionIDErr) puts("Invalid library connection."); if (err == cfragNoSymbolErr) puts("Symbol not found."); return BOOL_F; } ALLOW_INTS; /* *loc_loadpath = linkpath; */ (*func) (); /* *loc_loadpath = oloadpath; */ return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM l_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; int (*func)P((int argc, const char **argv)) = 0; const char **argv; OSErr err; CFragSymbolClass symClass; Str255 symName; /* SCM oloadpath = *loc_loadpath; */ ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; strcpy((char *)symName, CHARS(symb)); c2pstr((char *)symName); err = FindSymbol((CFragConnectionID)SHL(shl), symName, (Ptr *)&func, &symClass); if (err!=noErr || symClass != kCodeCFragSymbol) { ALLOW_INTS; if (err == cfragConnectionIDErr) puts("Invalid library connection."); if (err == cfragNoSymbolErr) puts("Symbol not found."); return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; /* *loc_loadpath = linkpath; */ i = (*func) ((int)ilength(args), argv); /* *loc_loadpath = oloadpath; */ DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static char s_unlink[] = "dyn:unlink"; SCM l_dyn_unlink(shl) SCM shl; { OSErr status; CFragConnectionID connID; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; connID = (CFragConnectionID)SHL(shl); status = CloseConnection(&connID); SETCHARS(shl, NULL); ALLOW_INTS; if (status!=noErr) return BOOL_T; return BOOL_F; } static iproc subr1s[] = { {s_link, l_dyn_link}, {s_unlink, l_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, l_dyn_call); make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); add_feature("mac-dl"); } } #endif /* MACOS */ #ifdef _WIN32 # include # define SHL(obj) ((HINSTANCE)(CDR(obj))) int prinshl(exp, port, writing) SCM exp; SCM port; int writing; { lputs("#', port); return 1; } int tc16_shl; static smobfuns shlsmob = {mark0, free0, prinshl}; static char s_link[] = "dyn:link"; SCM scm_dyn_link(fname) SCM fname; { SCM z, shl = BOOL_F; HINSTANCE hshl; ASRTER(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); NEWCELL(z); DEFER_INTS; hshl = LoadLibrary(CHARS(fname)); if (hshl) { SETCHARS(z, hshl); CAR(z) = tc16_shl; shl = z; } ALLOW_INTS; return shl; } static char s_unlink[] = "dyn:unlink"; SCM scm_dyn_unlink(shl) SCM shl; { BOOL status; ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); DEFER_INTS; status = FreeLibrary(SHL(shl)); ALLOW_INTS; return status ? BOOL_T : BOOL_F; } static char s_call[] = "dyn:call"; SCM scm_dyn_call(symb, shl) SCM symb, shl; { FARPROC func; int i; ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); DEFER_INTS; func = GetProcAddress(SHL(shl), CHARS(symb)); ALLOW_INTS; if (!func) return BOOL_F; (*func) (); return BOOL_T; } static char s_main_call[] = "dyn:main-call"; SCM scm_dyn_main_call(symb, shl, args) SCM symb, shl, args; { int i; FARPROC func; const char **argv; ASRTER(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); ASRTER(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); DEFER_INTS; func = GetProcAddress(SHL(shl), CHARS(symb)); if (!func) { ALLOW_INTS; return BOOL_F; } argv = makargvfrmstrs(args, s_main_call); ALLOW_INTS; i = (*func) ((int)ilength(args), argv); DEFER_INTS; must_free_argv(argv); ALLOW_INTS; return MAKINUM(0L+i); } static iproc subr1s[] = { {s_link, scm_dyn_link}, {s_unlink, scm_dyn_unlink}, {0, 0}}; void init_dynl() { if (!dumped) { tc16_shl = newsmob(&shlsmob); init_iprocs(subr1s, tc7_subr_1); make_subr(s_call, tc7_subr_2, scm_dyn_call); make_subr(s_main_call, tc7_lsubr_2, scm_dyn_main_call); add_feature("win32-dl"); } } #endif