hultquis@nas.nasa.gov (Jeff P. M. Hultquist) (05/14/91)
>>> rpaul@crow.UUCP (Rodian Paul) writes ... > > Has anybody else out there experimented with adding modules to an > application in a quazi dynamic way? i.e. it being possible to add > extras into an allready executing program other than using pipes and > stuff? Here is some stuff from a small LISP/C package I have been working on ... The first file is the top level command define which call a shell script to create an object file, and the calls 'load-object-file' to link this new code into the running app. Good luck. -- jeff -------------------------------------------------- ;;; dynload.scm (define (LOAD-C name #!optional ld-args) ;; (default ld-args "") (let ((mother "/u/wk/hultquis/flora/bin/flora.bin") (tmp-c "/tmp/fasl.c") (tmp-o "/tmp/fasl.o") (scratch "/tmp/scratch.o") (opts "-g -G 0") (defs "-DDO_PRIMS -DIRIS4D") (incs "-I$HOME/flora/src/c")) ;; (let ((filter (sprintf "$HOME/flora/etc/lcc %s > %s" name tmp-c)) (compile (sprintf "cc %s %s %s -o %s -c %s" opts defs incs tmp-o tmp-c))) ;; (let ((res (system:command filter))) (assert (zero? res))) (let ((res (system:command compile))) (assert (zero? res))) (load-object-file tmp-o mother ld-args scratch)))) ;;; end -------------------------------------------------- #!/bin/csh # lcc <file> # # This script takes a source file in which some of the routine names # have been declared as: # PRIMITIVE(c_name, scheme-name) # # These declarations are filtered out of the file and are turned into # commands of the form: # prim_install("scheme-name", c_name); # # The compiled file is linked and loaded into the running application, # and the first function is called. (!! We currently assume that the # first address of the linked data is the entry-point for the first # routine in the file.) This first routine is responsible for calling # the function `prim-install' for each new primitive. cat << _EOF_ /* begin */ static int init(); static int real_init(); static int init() { real_init(); return(0); } _EOF_ cat $1 # output the epilogue, including a sequence of # commands to install the new primitives into # the Scheme namespace (using prim_install). # cat << _EOF_ static int real_init() { _EOF_ sed -n -e 's/[(,)]/ /g' \ -e 's/PRIMITIVE//p' $1 |\ awk '{printf " prim_install(\"%s\", %s);\n", $2,$1}' cat << _EOF_ } /* end */ _EOF_ exit $status # end -------------------------------------------------- /* dynload.c */ #include <xscheme/xscheme.h> #include <stdio.h> #include <ctype.h> #include <a.out.h> struct headers { /* !! why is this here? */ struct filehdr fhdr; struct aouthdr aout; }; #define ASSERT(cond, msg) ((cond) ? 1 : xlfail(msg)) #define ALIGN 0xf typedef int (*PFI)(); PRIMITIVE(load_object_file_prim, LOAD-OBJECT-FILE) { PFI load_object_file(); PFI bootstrap; char *newobj = GET_STRING(); char *mother = GET_STRING(); char *ldargs = GET_STRING(); char *tmp = GET_STRING(); LAST_ARG(); bootstrap = load_object_file(newobj, mother, ldargs, tmp); if (bootstrap) { (*bootstrap)(); } return(true_lval); } static PFI load_object_file (char *newobj, /* a compiled object file */ char *mother, /* the image to link against */ char *ldargs, /* additional args and libraries */ char *tmp) /* scratch file */ { /* ** This takes an object file and resolves its dangling references ** with respect to some larger application. The linked object ** might be larger than was expected from simply checking the ** header data, and so we might be required to link this file ** twice until the linked image is small enough to fit in the ** image space that had been allocated for it. */ int guess_size; /* expected size of linked image */ int num_pass; /* counter of attempts to link */ void *bfr; /* pointer to malloc'd memory */ void *base; /* aligned pointer to loabable space */ char cmd[256]; /* command line to run the linker */ int res; /* result returned by linker */ FILE *fp; /* ptr to linked file */ int i; struct headers hdr; struct scnhdr sections[10]; int actual_size; /* total size of linked image */ guess_size = guess_code_size(newobj); for (num_pass=1; num_pass<4; num_pass++) { fprintf(stderr, " pass %d of linker ... ", num_pass); fflush(stderr); bfr = (void *) malloc(guess_size+ALIGN); ASSERT(bfr, "Couldn't allocate code space"); base = (void *) ((((int) bfr) + ALIGN) & ~ALIGN); sprintf(cmd, "ld -g -o %s -A %s -T %x -N %s %s", tmp, mother, base, newobj, ldargs); res = system(cmd); ASSERT(res>=0, "Running ld failed"); fp = fopen(tmp, "r"); ASSERT(fp, "Could not open linked file."); fread(&hdr, sizeof(hdr), 1, fp); for (i=0; i<hdr.fhdr.f_nscns; i++) { fread (&(sections[i]), sizeof(sections[i]), 1, fp); } for (actual_size=0, i=0; i<hdr.fhdr.f_nscns; i++) { actual_size += sections[i].s_size; } if (actual_size <= guess_size) { break; } else { guess_size = actual_size; fclose(fp); free(bfr); bfr = NULL; } } ASSERT(bfr, "Linked image is still larger than expected."); for (i=0; i<hdr.fhdr.f_nscns; i++) { fseek (fp, sections[i].s_scnptr, 0); fread (sections[i].s_vaddr, sections[i].s_size, 1, fp); } fclose(fp); return((PFI) ((char*) base)); /* "void and func ptrs not convertible" */ } static int guess_code_size (char *obj) { /* Read the header of the object file and guess how ** much memory will be needed to store the linked copy ** of this compiled data. */ FILE *fp; struct headers hdr; int guess; fp = fopen(obj, "r"); ASSERT(fp, "Couldn't open object file"); fread(&hdr, sizeof(struct headers), 1, fp); fclose(fp); guess = (hdr.aout.tsize + hdr.aout.dsize + hdr.aout.bsize + 512); /* FUDGE-FACTOR */ return(guess); } /* end */ -------------------------------------------------- -- -- Jeff Hultquist hultquis@nas.nasa.gov NASA - Ames Research Center (415) 604-4970 Disclaimer: "I am not a rocket scientist."
rpaul@crow.UUCP (Rodian Paul) (05/15/91)
It seems that the subject of Dynamic Loaders ain't too popular in this group, only got 1 reply (thanks Dan Karron). I guess it just isn't that easy. Anyway, in snooping around Showcase (trying to find out if it is possible to add fonts [no manuals, we didn't even get the software with our 35's, had to steal a copy]) I found the gizmos in /usr/lib/showcase. Rather an interesting approach. I don't know if the author(s) of Showcase read this mail/news group, but from what I can deduce, he/she/they are using regular file-descriptors to communicate with the main application. I was wondering if that approach was found to be a lot faster than say sockets or some similar network angle? Has anybody else out there experimented with adding modules to an application in a quazi dynamic way? i.e. it being possible to add extras into an allready executing program other than using pipes and stuff? BTW. I meant to say a while ago that I think Showcase is a pretty good product for a first realease. Cheers. ------------------------------------------------------------------------------- rpaul%crow@ccut.cc.u-tokyo.ac.jp phone: +81 (3) 5706-8357 ccut.cc.u-tokyo.ac.jp!crow!rpaul FAX: +81 (3) 5706-8437
srp@babar.mmwb.ucsf.edu (Scott R. Presnell) (05/16/91)
rpaul@crow.UUCP (Rodian Paul) writes: >It seems that the subject of Dynamic Loaders ain't too popular in this group, >only got 1 reply (thanks Dan Karron). I guess it just isn't that easy. >Has anybody else out there experimented with adding modules to an application >in a quazi dynamic way? i.e. it being possible to add extras into an allready >executing program other than using pipes and stuff? The statistical language 'S' from AT&T has a dynamic loading functionality. It seems to work for the most part (in tests atleast), but there are some limitiations and some requirements for specific load time options, etc. I can slam together some code fragments which encompass that part of the S language if enough people show interest. But I cannot answer detailed questions - I don't have the background. - Scott -- Scott Presnell +1 (415) 476-9890 Pharm. Chem., S-926 Internet: srp@cgl.ucsf.edu University of California UUCP: ...ucbvax!ucsfcgl!srp San Francisco, CA. 94143-0446 Bitnet: srp@ucsfcgl.bitnet