[mod.sources] dynamic loading code for 4.2bsd

sources-request@genrad.UUCP (05/17/85)

From: Stephen Daniel <decvax!mcnc!swd>

Having recieved the usual numerouse requests for this code,
I am submitting it.

This is a fast but simple dynamic loader for 4.2bsd.
It handles everything except making linkages between
the code being loaded and the running process image (sorry).

	Stephen Daniel
	decvax!mcnc!swd
	swd@mcnc (csnet)


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	Makefile
#	dyload.c
#	main.c
#	test.c
# This archive created: Thu May 16 14:01:14 1985
echo shar: extracting README '(282 characters)'
sed 's/^XX//' << \SHAR_EOF > README
XXThese files contain a dynamic loading routine (dyload.c)
XXand a test program (main.c and test.c).
XX
XXTo run things, type make and then foo.
XXYou should get
XX	Hello World
XX	routine returns 17
XXas output.
XX
XXThis dynamic loading code pretends to work under
XXBerkeley Unix versions 4.1 and 4.2.
SHAR_EOF
if test 282 -ne "`wc -c README`"
then
echo shar: error transmitting README '(should have been 282 characters)'
fi
echo shar: extracting Makefile '(217 characters)'
sed 's/^XX//' << \SHAR_EOF > Makefile
XXCFLAGS=
XX
XXall : foo test
XX
XXfoo : main.o dyload.o
XX	cc -o foo main.o dyload.o
XX
XX#
XX# Note: on a vax this line can be replaced by just "mv test.o test"
XX#
XXtest: test.o
XX	ld -r -d -o test test.o -lc
XX
XXclean:
XX	rm -f *.o test foo
SHAR_EOF
if test 217 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 217 characters)'
fi
echo shar: extracting dyload.c '(5168 characters)'
sed 's/^XX//' << \SHAR_EOF > dyload.c
XX/*
XX
XX		DISCLAIMER AND NOTIFICATION OF RIGHTS
XX			May 16, 1985
XX
XX	This code was written by Phil Smith, Bert Sacks, and
XX	Stephen Daniel of the Microelectronics Center of NC.
XX
XX	It appears to us that it works, but there are no
XX	guarentees of any kind expressed or implied.
XX
XX	The Microelectronics Center of North Carolina
XX	hereby places this code into the public domain.
XX
XX	We request that you keep this comment associated with
XX	this code.
XX
XX*/
XX
XX
XX/*
XX * Dynamic loading routine.
XX */
XX
XX#include <stdio.h>
XX#include <a.out.h>
XX#include <setjmp.h>
XX
XXtypedef int (*pfi_t)();	/* pointer to function returning integer. */
XX
XXstatic FILE *input;
XXstatic char *f_name;
XXstatic long string_offset;
XXjmp_buf blow_out;
XX
XXpfi_t
XXload_function(file_name)
XX  char *file_name;
XX{
XX	int size;
XX	int *data;
XX	struct exec header;
XX	char *ok_calloc();
XX	FILE *fopen();
XX
XX	/*
XX	 * Set up an error exit.
XX	 */
XX	f_name = file_name;
XX	if (setjmp(blow_out))
XX		return ((pfi_t)0);
XX
XX	/*
XX	 *	Open the file:  return if unopened.
XX	 */
XX	if ((input = fopen(file_name, "r")) == NULL)
XX		error("cannot open file\n");
XX
XX	ok_fread (&header, sizeof(header), 1, input);
XX	ok_fseek (input, (long) N_TXTOFF(header), 0);
XX
XX	string_offset = N_STROFF(header);
XX	size = header.a_text + header.a_data;
XX
XX	/*
XX	 *	Read in the text and data segments
XX	 *	Use ok_calloc() to make sure bss segment zero'ed
XX	 */
XX	data = (int *)ok_calloc(size + header.a_bss, 1);
XX
XX	ok_fread ((char *)data, 1, size, input);
XX
XX	if (header.a_trsize + header.a_drsize > 0)
XX		relocate (header, data);
XX
XX	fclose (input);
XX	return((pfi_t ) data);
XX}
XX
XX/*
XX *	Relocate text and data
XX */
XXstatic
XXrelocate (header, text)
XXstruct exec header;
XXchar *text;
XX{
XX	int i; 
XX	char *data;
XX	unsigned long	no_reloc_items,
XX			no_reloc_text_items,
XX			no_reloc_data_items,
XX			no_symbols;
XX	struct relocation_info *rp, *relocate;
XX	struct nlist *symtab;
XX	char *ok_malloc();
XX
XX	data = text + header.a_text;
XX
XX	/*
XX	 *	Read in the relocation information
XX	 */
XX	no_reloc_text_items = (header.a_trsize / sizeof (struct relocation_info));
XX	no_reloc_data_items = (header.a_drsize / sizeof (struct relocation_info));
XX	no_reloc_items = no_reloc_text_items + no_reloc_data_items;
XX
XX	relocate = (struct relocation_info *) ok_malloc
XX				(header.a_trsize + header.a_drsize);
XX	ok_fread (relocate, sizeof (struct relocation_info), no_reloc_items, input);
XX
XX	/*
XX	 *	Read in the symbol table
XX	 */
XX	symtab = (struct nlist *) ok_malloc (header.a_syms);
XX	no_symbols = header.a_syms / (sizeof (struct nlist));
XX	ok_fread (symtab, sizeof (struct nlist), no_symbols, input);
XX
XX	/*
XX	 *	Relocate text
XX	 */
XX	for (i = 0, rp = relocate; i < no_reloc_text_items; i++, rp++) 
XX		adjust(text+rp->r_address, rp, symtab, text);
XX
XX	/*
XX	 *	Relocate data
XX	 */
XX	for (i = 0; i < no_reloc_data_items; i++, rp++) 
XX		adjust(data+rp->r_address, rp, symtab, text);
XX
XX	ok_free(symtab);
XX}
XX
XX/*
XX *	Add the offset to relocated items
XX */
XXstatic
XXadjust (word, reloc, symtab, text)
XXchar *word;
XXstruct relocation_info *reloc;
XXstruct nlist *symtab;
XXchar *text;
XX{
XX	long reloc_item;
XX	struct nlist *sp;
XX
XX	if (reloc->r_length == 0) 
XX		reloc_item = *(char *) word;
XX	else if (reloc->r_length == 1) 
XX		reloc_item = *(short *) word;
XX	else if (reloc->r_length == 2) 
XX		reloc_item = *(long *) word;
XX	else
XX		error("INTERNAL ERROR: bad r_length\n");
XX
XX	/*
XX	 *	Relocate a text or data item 
XX	 */
XX	if (reloc->r_extern) {
XX		sp = symtab + reloc->r_symbolnum;
XX		if ((sp->n_type & N_TYPE) == N_UNDF) {
XX			warn("undefined symbol: ");
XX			print_symbol_name(sp->n_un.n_strx);
XX		} else 
XX			reloc_item += sp->n_value;
XX
XX	} else if (!reloc->r_pcrel)
XX		switch (reloc->r_symbolnum & N_TYPE) {
XX			case N_TEXT:
XX			case N_DATA:
XX			case N_BSS:
XX				reloc_item += (long)text;
XX				break;
XX			case N_ABS:
XX				break;
XX			default:
XX				error("INTERNAL ERROR: bad n_type\n");
XX		}
XX
XX	if (reloc->r_length == 0)
XX		*(char *) word = reloc_item;
XX	else if (reloc->r_length == 1)
XX		*(short *) word = reloc_item;
XX	else if (reloc->r_length == 2)
XX		*(long *) word = reloc_item;
XX	else
XX		error("INTERNAL ERROR: bad r_length\n");
XX}
XX
XXstatic
XXprint_symbol_name(which)
XXlong which;
XX{
XX	int c;
XX
XX	if (which) {
XX		ok_fseek(input, string_offset + which, 0);
XX		while ((c = getc(input)) != '\0')
XX			putchar(c);
XX		putchar ('\n');
XX	} else 
XX		puts ("name undetermined");
XX}
XX
XXstatic
XXok_fread(ptr, size, nitems, stream)
XXchar *ptr;
XXint size, nitems;
XXFILE *stream;
XX{
XX	if (fread(ptr, size, nitems, stream) != nitems ||
XX	    feof(stream) || ferror(stream))
XX		error("error while reading disk file\n");
XX}
XX
XXstatic
XXok_fseek(stream, offset, ptrname)
XXFILE *stream;
XXlong offset;
XXint ptrname;
XX{
XX	if (fseek(stream, offset, ptrname) < 0)
XX		error("error while seeking on disk file\n");
XX}
XX
XXstatic char *
XXok_calloc(nelem, elsize)
XXint nelem, elsize;
XX{
XX	register char *ret;
XX	char *calloc();
XX
XX	if ((ret = calloc((unsigned)nelem, (unsigned)elsize)) == (char *)0)
XX		error("insufficient memory\n");
XX	return(ret);
XX}
XX
XXstatic char *
XXok_malloc(n)
XXint n;
XX{
XX	register char *ret;
XX	char *malloc();
XX
XX	if ((ret = malloc((unsigned)n)) == (char *)0)
XX		error("insufficient memory\n");
XX	return(ret);
XX}
XX
XXstatic
XXok_free(s)
XXchar *s;
XX{
XX	free(s);
XX}
XX
XXstatic
XXerror(s)
XXchar *s;
XX{
XX	warn(s);
XX	longjmp(blow_out, 1);
XX}
XX
XX
XXstatic
XXwarn(s)
XXchar *s;
XX{
XX	fprintf(stderr, "load_function(%s): %s", f_name, s);
XX}
SHAR_EOF
if test 5168 -ne "`wc -c dyload.c`"
then
echo shar: error transmitting dyload.c '(should have been 5168 characters)'
fi
echo shar: extracting main.c '(437 characters)'
sed 's/^XX//' << \SHAR_EOF > main.c
XX#include <stdio.h>
XX
XXtypedef int (*pfi_t)();	/* pointer to function returning integer. */
XX
XXmain(argc, argv)
XXint argc;
XXchar **argv;
XX{
XX	int ret;
XX	char *f_name;
XX	pfi_t routine, load_function();
XX	int printf();
XX
XX	if (argc > 1)
XX		f_name = argv[1];
XX	else
XX		f_name = "test";
XX	
XX	if (!(routine = load_function(f_name))) {
XX		fprintf(stderr, "Cannot load %s\n", f_name);
XX		exit(1);
XX	}
XX
XX	ret = routine(printf);
XX	printf("routine returns %d\n", ret);
XX}
SHAR_EOF
if test 437 -ne "`wc -c main.c`"
then
echo shar: error transmitting main.c '(should have been 437 characters)'
fi
echo shar: extracting test.c '(110 characters)'
sed 's/^XX//' << \SHAR_EOF > test.c
XX/*
XX * routine that gets called by main().
XX */
XX
XXfoo(pf)
XXint (*pf)();
XX{
XX	(*pf)("Hello World\n");
XX	return(17);
XX}
SHAR_EOF
if test 110 -ne "`wc -c test.c`"
then
echo shar: error transmitting test.c '(should have been 110 characters)'
fi
#	End of shell archive
exit 0