More Dynamic Loading and Stuff.
Jeff P. M. Hultquist
hultquis at nas.nasa.gov
Tue May 14 15:45:39 AEST 1991
>>> rpaul at 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 at nas.nasa.gov
NASA - Ames Research Center (415) 604-4970
Disclaimer: "I am not a rocket scientist."
More information about the Comp.sys.sgi
mailing list