head	1.3;
access;
symbols;
locks
	postgres:1.3; strict;
comment	@ * @;


1.3
date	93.06.10.17.33.26;	author postgres;	state Exp;
branches;
next	1.2;

1.2
date	93.06.10.15.40.28;	author postgres;	state Exp;
branches;
next	1.1;

1.1
date	93.04.06.16.54.33;	author postgres;	state Exp;
branches;
next	;


desc
@dynloader.c for AIX.
@


1.3
log
@First version that permit to run the whole demo.
@
text
@
/*
 *  $Header: /usr/postgres/src/port/aix/RCS/dynloader.c,v 1.2 1993/06/10 15:40:28 postgres Exp postgres $
 */


/*
 * New dynamic loader.
 *
 * How does this work?  Glad you asked :-)
 *
 * The algorithm is as follows:
 *
 * 1.  Find out how much text/data space will be required.  This is done
 *     by reading the header of the ".o" to be loaded.
 *
 */ 

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

#include <a.out.h>
#include <ldfcn.h>
#include <sys/ldr.h>

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

#define TEXT_NAME	".text"
#define DATA_NAME	".data"
#define BSS_NAME	".bss"

FILHDR ld_file_struct;
AOUTHDR obj_aout_hdr, ld_aout_hdr;

extern char pg_pathname[];

static char *load_address = NULL;
static char *temp_file_name = NULL;
static char *path = "/usr/tmp/postgresXXXXXX";
char command[256];

DynamicFunctionList *
load_symbols(ldp, first_entry)
    LDFILE *ldp;
    char **first_entry;
{
    int text_id = 1;		/* Text section is number 1 in object files. */
    DynamicFunctionList *head, *scanner;
    int entering = 1, func_addr;
    char *funcname;
    SYMENT simb;
    long i;

    for (i = 0; i < HEADER(ldp).f_nsyms; i++)
	if (ldtbread(ldp,i,&simb) != SUCCESS)
	    return NULL;
        else {
	    i += simb.n_numaux;
	    if (simb.n_scnum == text_id
		&& simb.n_sclass == C_EXT) {
		if (entering) {
		    head = (DynamicFunctionList *)
			malloc(sizeof(DynamicFunctionList));
		    scanner = head;
		    *first_entry = scanner->funcname;
		    entering = 0;
		}
		else {
		    scanner->next = (DynamicFunctionList *)
			malloc(sizeof(DynamicFunctionList));
		    scanner = scanner->next;
		}
		strncpy(scanner->funcname, ldgetname(ldp,&simb)+1, 16);
		scanner->func = (func_ptr) simb.n_value;
		scanner->next = NULL;
	    }
	}
    return(head);
}


adjust_addresses (list, entry_point)
    DynamicFunctionList *list;
    func_ptr	entry_point;
{
    int	step = 0xC;
    int	inc = 0;

    while (list != NULL) {
	list->func =  (char *) entry_point + inc;
	inc += step;
	list = list->next;
    }
}


DynamicFunctionList *
dynamic_file_load(err, filename, start_addr, size)
    char **err, *filename, **start_addr;
    long *size;
{
    extern _text, etext, edata, end;
    extern char *mktemp();

    FILE *temp_file = NULL;
    DynamicFunctionList *retval = NULL, *temp;
    SCNHDR scn_struct;
    int size_text, size_data = 0, size_bss = 0, bss_offset;
    int i, fd;

    LDFILE	*ldp = NULL;
    int		text_id, *entry_point;
    char	*first_entry;
    
    if ((ldp = ldopen(filename,ldp)) == NULL) {
	*err = "unable to open xcoff file";
	goto finish_up;
    }

    /* Getting the list of functions. After it, the object file es no */
    /* longer examined. */
    retval = load_symbols(ldp, &first_entry);
    ldclose(ldp);

    /* Linking, with first_entry as the entry point. */
    if (temp_file_name == NULL)
       temp_file_name = (char *)malloc(strlen(path) + 1);
    strcpy(temp_file_name,path);
    mktemp(temp_file_name);

    sprintf(command,
	    "ld -e %s -H512 -T512 -bI:/usr/postgres/postgres.exp -bE:%s.exp -o %s  %s -lc -lm -ll",
	    first_entry,
	    filename, temp_file_name,  filename);
    if (system(command)) {
	*err = command;
	goto finish_up;
    }

    /* Loading.  The load(3) function returns a pointer to the
       entry point of the loaded program. */

    if ((entry_point = load(temp_file_name,1,"")) == NULL) {
	perror("dynloader(load)");
	*err = "load failed!";
	goto finish_up;
    }
/*    if (loadbind(0,_text,entry_point) != 0) {
	perror("dynloader(loadbind)");
	*err = "load failed!";
	goto finish_up;
    }
*/
    /* The loadbind(3) function resolves imported symbols in the */
    /* loaded module. */
    
    adjust_addresses(retval,entry_point);
  finish_up:
    /* unlink(temp_file_name); */
    *start_addr = load_address;
    *size = 0;
    for (temp = retval; temp != NULL; temp = temp->next) {
	printf("Nombre: %s\tDir: %lX\n",
	       temp->funcname,(unsigned long) (temp->func));
	printf("Valor: %lX,%lX\n",*((unsigned long *) (temp->func)),
	       *((unsigned long *) (temp->func) + 1));
    }
    return retval;
}

@


1.2
log
@It works, but without imported symbols.
@
text
@d3 1
a3 1
 *  $Header: /home/maestria/alu7/mno3/mr370673/Postgres/RCS/dynloader.c,v 1.2 1993/06/01 14:46:03 mr370673 Exp mr370673 $
d28 1
d107 1
a107 1
    extern etext, edata, end;
d149 1
a149 1
	perror("command");
d153 8
@


1.1
log
@Initial revision
@
text
@d3 1
a3 1
 *  $Header: /u/maestria/mr370673/Tmp/port/aix/RCS/dynloader.c,v 1.2 1992/12/10 19:16:38 mr370673 Exp mr370673 $
a11 14
 * In the DEC dynamic loader, we have to have done the following in order
 * for it to work:
 *
 * 1. Make sure that we stay near & etext (the highest base text address)
 *    so that we do not try to jump into the data area.  The data area starts
 *    by default at 0x1000000.
 *
 * 2. Make sure everything is linked with the -N option, so that "ld -A" will
 *    do the right thing.
 *
 * 3. Make sure loaded objects are compiled with "-G 0"
 *
 * 4. Make sure loaded objects are loaded ONCE AND ONLY ONCE.
 *
a16 17
 * 2.  Execute the "ld -A" with a an address equal to some memory we malloc'ed.
 *     "ld -A" will do all the relocation, etc. for us.
 *
 * 3.  Using the output of "ld -A", read the text and data area into a valid
 *     text area.  (The DEC 3100 allows data to be read in the text area, but
 *     not vice versa.)
 * 
 * 4.  Determine which functions are defined by the object file we are loading,
 *     and using the address we loaded the output of "ld -A" into, find the
 *     addresses of those functions.  In object files, the symbol table (and 
 *     the output of nm) will give the offsets for functions.  Adding the
 *     function offset to the base text address gives the function's true
 *     address.  (This could also be done by reading the symbol table of the
 *     output of "ld -A", but it is so massive that this is VERY wasteful.)
 * 
 *     (In this case, we cheat rather hugely and use the output of nm because
 *     the symbol table format for MIPSEL/DS3100 is not well-documented).
d27 1
d32 7
d44 1
a45 2
#define PAGE_ROUND(X) ((X) % 512 == 0 ? (X) : (X) - (X) % 512 + 512)

d47 3
a49 5
dynamic_file_load(err, filename, start_addr, size)

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

d51 25
a75 81
	extern etext, edata, end;
	extern char *mktemp();

	int nread;
	char command[256];
	unsigned long image_size, true_image_size;
	FILE *temp_file = NULL;
	DynamicFunctionList *retval = NULL, *load_symbols();
	struct filehdr obj_file_struct, ld_file_struct;
	AOUTHDR obj_aout_hdr, ld_aout_hdr;
	struct scnhdr scn_struct;
	int size_text, size_data = 0, size_bss = 0, bss_offset;
	int i, fd;

	fd = open(filename, O_RDONLY);

	read(fd, & obj_file_struct, sizeof(struct filehdr));
	read(fd, & obj_aout_hdr, sizeof(AOUTHDR));

	read(fd, & scn_struct, sizeof(struct scnhdr)); /* text hdr */
	size_text = scn_struct.s_size;
	if (obj_file_struct.f_nscns > 1)
	{
		read(fd, & scn_struct, sizeof(struct scnhdr)); /* data hdr */
		size_data = scn_struct.s_size;
	}

	close(fd);

/*
 * add 10000 for fudge factor to account for data areas that appear in
 * the linking process (yes, there are such beasts!).
 */

	image_size = size_text + size_data + 10000;

	if (temp_file_name == NULL)
	{
		temp_file_name = (char *)malloc(strlen(path) + 1);
	}

	strcpy(temp_file_name,path);
	mktemp(temp_file_name);

	load_address = (char *) valloc(image_size);

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

	if (system(command))
	{
		*err = "link failed!";
		goto finish_up;
	}

	if(!(temp_file = fopen(temp_file_name,"r")))
	{
		*err = "unable to open tmp file";
		goto finish_up;
	}
	fread(&ld_file_struct, sizeof(struct filehdr), 1, temp_file);
	fread(&ld_aout_hdr, sizeof(AOUTHDR), 1, temp_file);

	fread(&scn_struct, sizeof(struct scnhdr), 1, temp_file); /* text hdr */

/*
 * Figure out how big the data areas (including the bss area) are,
 * and determine where the bss area is if there is one.
 */

	true_image_size = scn_struct.s_size;
	for (i = 1; i < ld_file_struct.f_nscns; i++)
	{
		fread(&scn_struct, sizeof(struct scnhdr), 1, temp_file);
		true_image_size += scn_struct.s_size;
		if (!strcmp(scn_struct.s_name, "bss"))
		{
			size_bss = scn_struct.s_size;
			bss_offset = scn_struct.s_vaddr - (int) load_address;
d77 4
d82 2
a84 5
/*
 * Here we see if our "fudge guess" above was too small.  We do it this way
 * because loading is so ungodly expensive, and we want to avoid having to
 * create 3 megabyte files unnecessarily.
 */
d86 6
a91 21
	if (true_image_size > image_size)
	{
		free(load_address);
		fclose(temp_file);
		unlink(temp_file_name);
		load_address = (char *) valloc(true_image_size);
		sprintf(command,"ld -x -N -A %s -T %lx -o %s  %s -lc -lm -ll",
	    		pg_pathname,
	    		load_address,
	    		temp_file_name,  filename);
		system(command);
		temp_file = fopen(temp_file_name,"r");
		fread(&ld_file_struct, sizeof(struct filehdr), 1, temp_file);
		fread(&ld_aout_hdr, sizeof(AOUTHDR), 1, temp_file);
	}

	fseek(temp_file, sizeof(ld_file_struct)+sizeof(ld_aout_hdr), 0);

	fread(load_address, true_image_size,1,temp_file);

	/* zero the BSS segment */
d93 5
a97 20
	if (size_bss != 0)
	{
		bzero(bss_offset + load_address, size_bss);
	}

/*	if (cachectl(load_address, PAGE_ROUND(true_image_size), UNCACHEABLE))
	{
		*err = "dynamic_file_load: Cachectl failed!";
	}
	else
	{
*/		retval = load_symbols(filename, load_address);
/*	}
*/
finish_up:
	fclose(temp_file);
	unlink(temp_file_name);
	*start_addr = load_address;
	*size = true_image_size;
	return retval;
a99 4
/*
 * Cheat massively because I can't figure out how to read the symbol table
 * properly, so use system("nm ...") to do it instead.
 */
d102 3
a104 5
load_symbols(filename, entry_addr)

char *filename;
int entry_addr;

d106 2
a107 14
	char command[256];
	char line[128];
	char *tmp_file = "/tmp/PG_DYNSTUFF";
	FILE *fp;
	DynamicFunctionList *head, *scanner;
	int entering = 1, func_addr;
	char funcname[16];

	sprintf(command, "/usr/bin/nm %s | grep \' T \' > %s", filename, tmp_file);

	if (system(command))
	{
		fprintf(stderr, "system() died\n");
	}
d109 57
a165 1
	fp = fopen(tmp_file, "r");
a166 26
	while (fgets(line, 127, fp) != NULL)
	{
		sscanf(line, "%lx T %s", &func_addr, funcname);
		if (entering)
		{
			head = (DynamicFunctionList *)
				   malloc(sizeof(DynamicFunctionList));
			scanner = head;
			entering = 0;
		}
		else
		{
			scanner->next = (DynamicFunctionList *)
							malloc(sizeof(DynamicFunctionList));
			scanner = scanner->next;
		}

		strncpy(scanner->funcname, funcname, 16);
		scanner->func = (func_ptr) (func_addr + entry_addr);
		scanner->next = NULL;
	}

	fclose(fp);
	unlink(tmp_file);
	return(head);
}
@
