[comp.sys.sgi] More Dynamic Loading and Stuff.

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