head	1.19;
access;
symbols
	Version_2_1:1.16;
locks; strict;
comment	@ * @;


1.19
date	93.01.16.03.14.59;	author aoki;	state Exp;
branches;
next	1.18;

1.18
date	92.01.12.23.28.30;	author mao;	state Exp;
branches;
next	1.17;

1.17
date	91.12.15.02.01.34;	author glass;	state Exp;
branches;
next	1.16;

1.16
date	91.03.08.19.58.06;	author kemnitz;	state Exp;
branches;
next	1.15;

1.15
date	90.11.02.13.37.20;	author kemnitz;	state Exp;
branches;
next	1.14;

1.14
date	90.11.01.18.26.30;	author kemnitz;	state Exp;
branches;
next	1.13;

1.13
date	90.10.25.23.47.15;	author kemnitz;	state Exp;
branches;
next	1.12;

1.12
date	90.10.24.01.20.43;	author kemnitz;	state Exp;
branches;
next	1.11;

1.11
date	90.10.24.00.12.46;	author kemnitz;	state Exp;
branches;
next	1.10;

1.10
date	90.10.24.00.01.40;	author kemnitz;	state Exp;
branches;
next	1.9;

1.9
date	90.10.22.19.14.54;	author kemnitz;	state Exp;
branches;
next	1.8;

1.8
date	90.10.22.19.09.59;	author kemnitz;	state Exp;
branches;
next	1.7;

1.7
date	90.10.22.04.33.27;	author kemnitz;	state Exp;
branches;
next	1.6;

1.6
date	90.09.25.16.40.36;	author kemnitz;	state Exp;
branches;
next	1.5;

1.5
date	90.04.19.17.12.03;	author kemnitz;	state Exp;
branches;
next	1.4;

1.4
date	90.04.19.17.07.24;	author kemnitz;	state Exp;
branches;
next	1.3;

1.3
date	90.04.19.16.53.24;	author kemnitz;	state Exp;
branches;
next	1.2;

1.2
date	89.11.24.14.20.57;	author hirohama;	state Exp;
branches;
next	1.1;

1.1
date	89.09.17.23.23.56;	author dillon;	state Exp;
branches;
next	;


desc
@Just #include's the sun dynamic loader... but must be in a port
directory.  

q.
@


1.19
log
@removed references to utils/fmgr.h and parser/parse.h
@
text
@/*

!!!! Be sure that we close all open files up exit on the Sequent - the ld !!!!
     fails otherwise 

	 $Header: /home2/aoki/postgres/src/backend/port/seq/RCS/dynloader.c,v 1.18 1992/01/12 23:28:30 mao Exp aoki $
*/

#include <pwd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>

extern char pg_pathname[];

#include <a.out.h>

#include "tmp/c.h"
#include "fmgr.h"

/*
 * Allow extra space for "overruns" caused by the link.
 */

#define FUDGE 10000

static char *temp_file_name = NULL;
static char *path = "/usr/tmp/postgres";

DynamicFunctionList *
dynamic_file_load(err, filename, address, size)

char **err, *filename, **address;
long *size;

{
	extern char *valloc();

	int nread;
	struct exec ld_header, header;
	unsigned long image_size, true_image_size;
	char *load_address = NULL;
	FILE *temp_file = NULL;
	DynamicFunctionList *retval = NULL, *load_symbols();
	int fd;
	char foo[10];

	closeAllVfds(); /* We run out of open files in running on the Sequent */

	fd = open(filename, O_RDONLY);


	if (fd == -1)
	{
		*err = "error opening file";
		goto finish_up;
	}

	read(fd, &ld_header, sizeof(struct exec));

	image_size = ld_header.a_text + ld_header.a_data + ld_header.a_bss + FUDGE;

	close(fd); /* don't open it until the load is finished. */

	if (!(load_address = valloc(image_size)))
	{
		*err = "unable to allocate memory";
		goto finish_up;
	}

	if (temp_file_name == NULL)
	{
		sprintf(foo, "%d", getpid());
		temp_file_name = (char *)malloc(strlen(path) + strlen(foo) + 2);
		strcpy(temp_file_name, path);
		strcat(temp_file_name, foo);
	}

	if(execld(load_address, temp_file_name, filename))
	{
		*err = "link failed!";
		goto finish_up;
	}

	if(!(temp_file = fopen(temp_file_name,"r")))
	{
		*err = "unable to open tmp file";
		goto finish_up;
	}
	nread = fread(&header, sizeof(header), 1, temp_file);
	true_image_size = header.a_text + header.a_data + header.a_bss;

	if (true_image_size > image_size)
	{
		fclose(temp_file);
		free(load_address);
		load_address = valloc(true_image_size);

		if (execld(load_address, temp_file_name, filename))
		{
			*err = "ld failed!";
			goto finish_up;
		}
		temp_file = fopen(temp_file_name,"r");
		nread = fread(&header, sizeof(header), 1, temp_file);
	}

	fseek(temp_file, N_TXTOFF(header), 0);
	nread = fread(load_address, true_image_size,1,temp_file);

	retval = load_symbols(filename, &ld_header, load_address);

	fclose(temp_file);
	unlink(temp_file_name);
	*address = load_address;
	*size = image_size;

	temp_file = NULL;
	load_address = NULL;

finish_up:
	if (temp_file != NULL) fclose(temp_file);
	if (load_address != NULL) free(load_address);
	return retval;
}

DynamicFunctionList *
load_symbols(filename, hdr, entry_addr)

char *filename;
struct exec *hdr;
int entry_addr;

{
	int fd;
	char *strings, *symb_table, *p, *q;
	int symtab_offset, string_offset, string_size, nsyms, i;
	struct nlist *table_entry;
	int entering = 1;
	DynamicFunctionList *head, *scanner;

	symtab_offset = N_SYMOFF(*hdr);
	string_offset = N_STROFF(*hdr);

	fd = open(filename, O_RDONLY);

	lseek(fd, string_offset, 0);
	read(fd, &string_size, sizeof(string_size));
	strings = (char *) malloc(string_size - 4);
	read(fd, strings, string_size - 4);
	nsyms = hdr->a_syms / sizeof(struct nlist);
	lseek(fd, symtab_offset, 0);
	symb_table = (char *) malloc(hdr->a_syms);
	read(fd, symb_table, hdr->a_syms);

	p = symb_table;
	for (i = 0; i < nsyms; i++)
	{
		table_entry = (struct nlist *) p;
		p += sizeof(struct nlist);
	    if (! ((table_entry->n_type & N_EXT) == 0
			|| (table_entry->n_type & N_TYPE) != N_TEXT))
		{
			if (entering)
			{
				head = (DynamicFunctionList *)
					   malloc(sizeof(DynamicFunctionList));
				scanner = head;
				entering = 0;
			}
			else
			{
				scanner->next = (DynamicFunctionList *)
								malloc(sizeof(DynamicFunctionList));
				scanner = scanner->next;
			}
			/*
			 * Add one for "_", ie
			 * overpaid() will be _overpaid
			 */

			q = strings + (table_entry->n_un.n_strx - 4) + 1;

			strcpy(scanner->funcname, q);
			scanner->func = (func_ptr) (table_entry->n_value + entry_addr);
			scanner->next = NULL;
		}
	}

	free(symb_table);
	free(strings);
	close(fd);
	return(head);
}

func_ptr
dynamic_load(err)

char **err;

{
	*err = "Dynamic load: Should not be here!";
	return(NULL);
}

/* 
 *   ld -N -x -A SYMBOL_TABLE -T ADDR -o TEMPFILE FUNC -lc
 */

execld(address, tmp_file, filename)

char *address, *tmp_file, *filename;

{
	char command[256];
	int retval;

	sprintf(command,"ld -N -x -A %s -T %lx -o %s  %s -lc -lm -ll",
	    	pg_pathname,
	    	address,
	    	tmp_file,  filename);
	retval = OurSystem(command);
	return(retval);
}
@


1.18
log
@add c.h to include file list
@
text
@d6 1
a6 1
	 $Header: /n/hermes/usr5/postgres/mao/postgres/src/port/seq/RCS/dynloader.c,v 1.17 1991/12/15 02:01:34 glass Exp mao $
d21 1
a21 1
#include "utils/fmgr.h"
@


1.17
log
@fmgr cleanups
@
text
@d6 1
a6 1
	 $Header: ./port/seq/RCS/dynloader.c,v 1.16 91/03/08 19:58:06 kemnitz Exp Locker: glass $
d20 1
@


1.16
log
@Fixes the funky filedescriptor problem.
@
text
@d6 1
a6 1
	 $Header: RCS/dynloader.c,v 1.15 90/11/02 13:37:20 kemnitz Exp Locker: kemnitz $
d20 1
a20 1
#include "utils/dynamic_loader.h"
@


1.15
log
@Fixed problem in generating temp file name.
@
text
@d6 1
a6 1
	 $Header: RCS/dynloader.c,v 1.11 90/11/01 18:25:44 kemnitz Exp Locker: kemnitz $
d49 2
d53 1
d223 1
a223 1
	retval = system(command);
@


1.14
log
@Closes all files that it opens.
@
text
@d6 1
a6 1
	 $Header: RCS/dynloader.c,v 1.13 90/10/22 04:36:17 kemnitz Exp $
d29 1
a29 1
static char *path = "/usr/tmp/postgres%6d";
d47 1
d71 4
a74 2
		temp_file_name = (char *)malloc(strlen(path) + 4);
		sprintf(temp_file_name, path, getpid());
@


1.13
log
@Fixed file descriptor devouring problem.
@
text
@a2 6
Return-Path: jsmith@@king.mcs.drexel.edu

cc -Bstatic loader.c

when this is executed by typing a.out it loads tst.o and calls it.

d6 1
d29 1
a29 1
static char *path = "/usr/tmp/postgresXXXXXX";
a37 2
	extern end;
	extern char *mktemp();
a47 2
/* commented out -lc */

d70 2
a71 3
		temp_file_name = (char *)malloc(strlen(path) + 1);
		strcpy(temp_file_name,path);
		mktemp(temp_file_name);
d187 1
@


1.12
log
@Now returns error when it can't open a file
@
text
@d10 1
a10 1
	 fails otherwise 
d69 2
d116 1
a116 1
	retval = load_symbols(fd, &ld_header, load_address);
a119 1
	close(fd);
d133 1
a133 1
load_symbols(fd, hdr, entry_addr)
d135 1
a135 1
int fd;
d140 1
d149 2
@


1.11
log
@Fixed a size bug.
@
text
@d59 6
@


1.10
log
@Now makes sure that we close all open files.
@
text
@d94 2
a95 2
		load_address = valloc(image_size);
		
@


1.9
log
@Added two new parameters
@
text
@a0 1

a2 1
(Message inbox:4)
a3 10
Received: from king.mcs.drexel.edu by postgres.Berkeley.EDU (5.61/1.29)
	id AA08681; Wed, 29 Aug 90 13:54:19 -0700
Received: by king.mcs.drexel.edu (4.0/SMI-4.0)
	id AA13668; Wed, 29 Aug 90 16:54:44 EDT
Date: Wed, 29 Aug 90 16:54:44 EDT
From: jsmith@@king.mcs.drexel.edu (Justin Smith)
Message-Id: <9008292054.AA13668@@king.mcs.drexel.edu>
To: post_questions@@postgres.berkeley.edu
Subject: Dynamic loader for Sparc systems
Status: O
a4 10


I recently sent a message to postgres_bugs suggesting a way to do
dynamic loading on a Sparc system -- one that should be fairly
system-independant.  Here is a sample program that uses this:
there is a main program 'loader.c' that calls 'dynamic_load' and
loads a subprogram called 'tst.o'.  The program 'loader.c' must be
compiled with the 'static' option, i.e. the command to compile it
must be 

d9 2
a11 2
Here is 'loader.c':

a20 4
#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#endif

d27 2
a28 6
/* 
 *
 *   ld -N -x -A SYMBOL_TABLE -o TEMPFILE FUNC -lc
 *
 *   ld -N -x -A SYMBOL_TABLE -T ADDR -o TEMPFILE FUNC -lc
 *
d31 2
d49 1
a49 1
	unsigned long image_size, zz;
a51 1
	char command[256];
a54 1

d61 1
a61 1
	image_size = ld_header.a_text + ld_header.a_data + ld_header.a_bss;
d63 1
a63 1
	if (!(load_address = valloc(zz=image_size)))
d72 2
d76 1
a76 9
	strcpy(temp_file_name,path);
	mktemp(temp_file_name);

	sprintf(command,"ld -N  -A %s -T %lx -o %s  %s -lc -lm -ll",
	    pg_pathname,
	    load_address,
	    temp_file_name,  filename);

	if(system(command))
d88 3
a90 2
	image_size = header.a_text + header.a_data + header.a_bss;
	if (zz<image_size)
d92 11
a102 2
		*err = "loader out of phase!";
		goto finish_up;
d106 1
a106 4
	nread = fread(load_address, zz=(header.a_text + header.a_data),1,temp_file);
	/* zero the BSS segment */
	while (zz<image_size)
		load_address[zz++] = 0;
d112 1
d198 20
@


1.8
log
@Added two new parameters.
@
text
@@


1.7
log
@First revision of new dynamic loader using "ld -A"
@
text
@d65 1
a65 1
dynamic_file_load(err, filename)
d67 2
a68 1
char **err, *filename;
d141 2
@


1.6
log
@Updating from revision 1.5 to revision 1.6
@
text
@a2 15
 *   DYNAMIC_LOADER.C
 *
 *   Dynamically load specified object module
 *
 *   TODO!
 *	-remember loaded object's symbols so objects are not loaded more
 *	 than once (which means they use a different set of static and
 *	 glboal variables
 *
 *	-BSS space variables do not work (i.e., static or global
 *	 declarations which are not assigned
 *
 *	 int a;		// doesn't work
 *	 int b = 1; 	// works
 */
d4 33
d38 4
a41 2
#include <fcntl.h>
#include <a.out.h>
d43 2
a44 2
#ifndef CIncluded
#include "tmp/c.h"
d47 4
a50 1
#include "utils/log.h"
d53 7
a59 5
#ifdef sun
#define N_DATAOFF(hdr)	(N_TXTOFF(hdr) + (hdr).a_text)
#define N_TROFF(hdr)	(N_DATAOFF(hdr) + (hdr).a_data)
#define N_DROFF(hdr)	(N_TROFF(hdr) + (hdr).a_trsize)
#endif
d61 2
a62 1
RcsId("$Header: RCS/dynloader.c,v 1.6 90/08/14 14:41:55 cimarron Exp $");
d64 2
a65 2
typedef struct relocation_info	Reloc;
typedef struct nlist		NList;
d67 1
a67 2
char *sbrk();
char *Align();
a68 7
static struct exec hdr;

func_ptr
dynamic_load(err, filename, funcname)
char **err;
char *filename;
char *funcname;
d70 3
a72 13
    int fd;
    int n;
    int a_strsize;
    char *p_start;
    char *p_text;
    char *p_data;
    char *p_bss;
    char *p_syms;
    char *p_treloc;
    char *p_dreloc;
    char *p_strs;
    char *p_end;
    func_ptr entryadr = NULL;	/* entry address of function */
d74 8
a81 1
    elog(DEBUG, "dynamic_load %s %s\n", filename, funcname);
a82 24
    AllocateFile();	/* ensure a file descriptor is free for use */
    fd = open(filename, O_RDONLY, 0);
    if (fd < 0) {
	*err = "unable to open file";
	return(NULL);
    }
    n = read(fd, &hdr, sizeof(hdr));
    if (n != sizeof(hdr) /*|| N_BADMAG(hdr)*/) {
	*err = "bad object header";
	close(fd);
	return(NULL);
    }
    /*
     *  BRK enough for:
     *		a_text
     *		a_data
     *		a_bss
     *		a_syms
     *		a_trsize
     *		a_drsize
     *
     *  When through relocating, BRK to remove a_syms, a_trsize, a_drsize
     *  NOTE THAT NO CALLS THAT USE MALLOC() MAY BE MADE AFTER THE SBRK!
     */
d84 1
a84 1
    a_strsize = lseek(fd, 0, 2) - N_STROFF(hdr);
d86 1
a86 9
    p_start = sbrk(0);
    p_text = Align(p_start);
    p_data = p_text + hdr.a_text;
    p_bss  = p_data + hdr.a_data;
    p_syms = Align(p_bss  + hdr.a_bss);
    p_treloc = Align(p_syms + hdr.a_syms);
    p_dreloc = Align(p_treloc + hdr.a_trsize);
    p_strs   = Align(p_dreloc + hdr.a_drsize);
    p_end    = Align(p_strs + a_strsize);
d88 1
a88 25
    if (p_end < p_strs) {
	*err = "format error";
	close(fd);
	return(NULL);
    }
    if (brk(p_end) == -1) {
	*err = "brk() failed";
	close(fd);
	return(NULL);
    }
    n = seekread("text", fd, N_TXTOFF(hdr), p_text, hdr.a_text);
    n += seekread("data", fd, N_DATAOFF(hdr), p_data, hdr.a_data);
    n += seekread("syms", fd, N_SYMOFF(hdr), p_syms, hdr.a_syms);
    n += seekread("trel", fd, N_TROFF(hdr), p_treloc, hdr.a_trsize);
    n += seekread("drel", fd, N_DROFF(hdr), p_dreloc, hdr.a_drsize);
    n += seekread("strs", fd, N_STROFF(hdr), p_strs, a_strsize);
    close(fd);
    if (n) {
	*err = "format-read error";
        if (sbrk(0) != p_end) 
	    elog(WARN, "dynamic_load: unexpected malloc");
	else
	    brk(p_start);	/* restore allocated memory */
	return(NULL);
    }
d90 1
a90 3
    /*
     *  Find entry symbol
     */
d92 5
a96 3
    {
	NList *s;
	NList *syme = (NList *)(p_syms + hdr.a_syms);
d98 3
a100 12
	for (s = (NList *)p_syms; s < syme; ++s) {
	    char *str = p_strs + s->n_un.n_strx;
	    if ((s->n_type & N_EXT) == 0 || (s->n_type & N_TYPE) != N_TEXT)
		continue;
	    if (strcmp(str, funcname) == 0) {
		entryadr = (func_ptr)(p_text + s->n_value);
		break;
	    }
	    if (*str == '_' && strcmp(str + 1, funcname) == 0) {
		entryadr = (func_ptr)(p_text + s->n_value);
		break;
	    }
a101 1
    }
d103 2
a104 5
    /*
     *  relocate
     *
     *  n holds cumulative error
     */
d106 4
a109 4
    {
	NList *syms = (NList *)p_syms;
	Reloc *reloc;
	Reloc *relend;
d111 4
a114 6
	n = 0;
	reloc = (Reloc *)p_treloc;
	relend= (Reloc *)(p_treloc + hdr.a_trsize);
	while (reloc < relend) {
	    n += relocate(p_text,reloc, p_syms, p_strs, p_text, p_data, p_bss);
	    ++reloc;
d116 5
a120 6
	
	reloc = (Reloc *)p_dreloc;
	relend= (Reloc *)(p_dreloc + hdr.a_drsize);
	while (reloc < relend) {
	    n += relocate(p_data,reloc, p_syms, p_strs, p_text, p_data, p_bss);
	    ++reloc;
d122 7
a128 5
    }
    if (n)
	*err = "relocate error";
    if (entryadr == NULL)
	*err = "entry pt. not found";
d130 18
a147 6
    if (sbrk(0) != p_end) {
	elog(WARN, "unexpected malloc %08lx %08lx", sbrk(0), p_end);
    } else {
        brk(p_syms);	/* destroy non essential data */
    }
    return(entryadr);
d150 7
a156 6
relocate(base, reloc, sym, strs, tbase, dbase, bbase)
char *base;
Reloc *reloc;
NList *sym;
char  *strs;
char  *tbase, *dbase, *bbase;
d158 5
a162 3
    NList *symbase = sym;
    unsigned long value;
    short n_type;
d164 2
a165 1
    sym += reloc->r_symbolnum;		/* only valid if r_extern */
d167 8
a174 17
    switch(reloc->r_length) {
    case 0:
	value = *(unsigned char *)(base + reloc->r_address);
	break;
    case 1:
	value = *(unsigned short *)(base + reloc->r_address);
	break;
    case 2:
	value = *(unsigned long *)(base + reloc->r_address);
	break;
    default:
	return(-1);
    }
#ifdef sequent
    if (reloc->r_bsr)
	value = -value;
#endif
d176 25
a200 19
    /*
    printf("reloc %08lx sym %d %d%d%d%d%d vadr %08lx (symbol %02x %08lx %s)\n",
	reloc->r_address,
	reloc->r_symbolnum,
	reloc->r_pcrel,
	1 << reloc->r_length,
	reloc->r_extern,
#ifdef sequent
	reloc->r_bsr,
	reloc->r_disp,
#else
	0,0,
#endif
	value,
	sym->n_type,
	sym->n_value,
	(reloc->r_extern) ? strs + sym->n_un.n_strx : "null"
    );
    */
d202 1
a202 4
    if (reloc->r_extern)
	n_type = sym->n_type & N_TYPE;
    else
	n_type = reloc->r_symbolnum & N_TYPE;
d204 4
a207 19
    switch(n_type) {
    case N_UNDF:
	{
	    FList *fl = ExtSyms;
	    while (fl->name) {
		if (strcmp(fl->name, strs + sym->n_un.n_strx) == 0)
		    break;
		++fl;
	    }
	    if (fl->name == NULL) {
		elog(WARN, "dynamic_loader: Illegal ext. symbol %s",
		    strs + sym->n_un.n_strx
		);
		return(-1);
	    }
	    value += (long)fl->func;
	    /*
	    printf("func %08lx value %08lx\n", fl->func, value);
	    */
a208 20
	break;
    case N_ABS:
	value += sym->n_value;
	break;
    case N_TEXT:
	value += (long)tbase;
	break;
    case N_DATA:
	value += (long)tbase;
	break;
    case N_BSS:
	value += (long)bbase;
	break;
    default:
	return(-1);
	/*
	printf("Unknown type %02x\n", sym->n_type);
	*/
	break;
    }
d210 3
a212 19
#ifdef sequent
    if (reloc->r_bsr)
	value = value - (long)tbase;
#endif
    if (reloc->r_pcrel)
	value = value - (long)base;

    switch(reloc->r_length) {
    case 0:
	*(unsigned char *)(base + reloc->r_address) = value;
	break;
    case 1:
	*(unsigned short *)(base + reloc->r_address) = value;
	break;
    case 2:
	*(unsigned long *)(base + reloc->r_address) = value;
	break;
    }
    return(0);
d215 2
a216 7
seekread(seg, fd, offset, ptr, bytes)
char *seg;
int fd;
int offset, bytes;
unsigned char *ptr;
{
    int n;
d218 1
a218 8
    n = lseek(fd, offset, 0);
    if (n != offset)
	return(-1);
    n = read(fd, ptr, bytes);
    if (n != bytes)
	return(-1);
    return(0);
}
a219 3
char *
Align(padr)
char *padr;
d221 2
a222 2
    long adr = ((long)padr + 3) & ~3;
    return((char *)adr);
a223 1

@


1.5
log
@Fixed compile problem.
@
text
@d21 2
d24 1
a24 1
#include "c.h"
a25 2
#include "log.h"
#include "dynamic_loader.h"
d27 2
a28 1
#include <a.out.h>
d36 1
a36 1
RcsId("$Header: RCS/dynloader.c,v 1.4 90/04/19 17:07:24 kemnitz Exp Locker: kemnitz $");
@


1.4
log
@Got rid of sun-specific stuff.
@
text
@d35 1
a35 1
RcsId("$Header: RCS/dynloader.c,v 1.4 90/03/02 16:37:37 postgres Exp $");
d263 1
a263 1
	    value += (fl->name != NULL) ? (long)fl->func : (long)ss->func;
@


1.3
log
@changed name from dynamic_loader to dynloade in
include statement.
@
text
@d7 4
a10 1
 *   SOURCE IN ../SUNOS
d12 2
a13 2
 *   Unfortunately there are ports other than these two which is why this
 *   stuff is in the port directory.
d15 2
a16 2
 * $Header: RCS/dynloader.c,v 1.2 89/11/24 14:20:57 hirohama Exp Locker: kemnitz $
 *
d19 3
d23 3
d27 307
a333 1
#include "../sun/dynloader.c"
@


1.2
log
@directory renamed
@
text
@d12 1
a12 1
 * $Header: RCS/dynamic_loader.c,v 1.1 89/09/17 23:23:56 dillon Exp Locker: hirohama $
d18 1
a18 1
#include "../sun/dynamic_loader.c"
@


1.1
log
@Initial revision
@
text
@d12 1
a12 1
 * $Header: RCS/dynamic_loader.c,v 1.6 89/09/07 14:26:17 dillon Exp Locker: dillon $
d18 1
a18 1
#include "../sunos/dynamic_loader.c"
@
