ftp.nice.ch/pub/next/developer/languages/lisp/AKCL.1.599.s.tar.gz#/akcl-1-599/c/sfaslNeXT.c

This is sfaslNeXT.c in view mode; [Download] [Up]

/*
 *	sfaslNeXT.c:	remade sfasl.c for NeXT computers
 *
 *		by Noritake Yonezawa, May 3 1991
 */

#include <varargs.h>
#include <mach.h>
#include <sys/loader.h>
#include <stdio.h>

#include "include.h"
#undef S_DATA
#include "ext_sym.h"
struct node        *find_sym();
int                 node_compare();
char               *malloc();
char               *the_start;
char               *bsearch();

#define R_SCATTERED 0x80000000

struct scattered_relocation_info {
    unsigned int        r_scattered:1, r_pcrel:1, r_length:2, r_reserved:4, r_address:24;
    long                r_value;
};

static int
                    text_size, text_offset, text_reloff, text_nreloc, text_ordinal, data_size, data_offset, data_reloff, data_nreloc, data_ordinal, bss_size, bss_offset, bss_reloff, bss_nreloc, bss_ordinal, symoff, nsyms, stroff, strsize;

struct reloc        relocation_info;

/* next 5 static after debug */

int                 debug;

#define MAXPATHLEN 200
#define PTABLE_EXTRA 20

static struct syment *symbol_table;
static char          *start_address;
static char          *my_string_table;
static int            extra_bss;

static char           command[200];
static char           tmpfile1[50];

#define TEMPSPACE 50000
char                tempspace[TEMPSPACE];
char               *bil;
char
                   *
temp_malloc(n)
    unsigned int        n;
{
    char               *val;

    val = (char *)(4 * ((((int)bil) + 4) / 4));
    bil = val + n;
    if (bil < tempspace + TEMPSPACE)
	return val;
    else {
	bil = val;
	return malloc(n);
    }
}

/* begin reloc_file */

relocate()
{
    struct scattered_relocation_info scattered_info;
    char               *where;

    {
	unsigned int        new_value;

	where = the_start + relocation_info.r_address;

	if (relocation_info.r_address & R_SCATTERED) {
	    bcopy(&relocation_info, &scattered_info, sizeof(struct relocation_info));
	    where = the_start + scattered_info.r_address;

/*
	    if (scattered_info.r_pcrel)
	      new_value=   - (int)start_address + scattered_info.r_value;
	    else
	      new_value= scattered_info.r_value;

*/
	    new_value = (int)start_address;
	    switch (scattered_info.r_length) {
	    case 0:
	      *(char *)where = new_value + *(char *)where;
	      break;
	    case 1:
	      *(short *)where = new_value + *(short *)where;
	      break;
	    case 2:
	      *(long *)where = new_value + *(long *)where;
	      break;
	    }
	    return;
	}
	if (relocation_info.r_extern) {
	    if (relocation_info.r_pcrel)
		new_value = -(int)start_address
		  + symbol_table[relocation_info.r_symbolnum].n_value;
	    else {
		new_value =
		  symbol_table[relocation_info.r_symbolnum].n_value;
	    }
	} else {
	    if (relocation_info.r_symbolnum == text_ordinal ||
		relocation_info.r_symbolnum == data_ordinal ||
		relocation_info.r_symbolnum == bss_ordinal) {
		new_value = (int)start_address;
	    } else {
		printf("\nrelocation_info {r_symbolnum= %d, r_address = %d, r_extern=0 Ignored:", relocation_info.r_address,
		       relocation_info.r_symbolnum);
		fflush(stdout);
		return;
	    }
	}
	switch (relocation_info.r_length) {
	case 0:
	    *(char *)where = new_value + *(char *)where;
	    break;
	case 1:
	    *(short *)where = new_value + *(short *)where;
	    break;
	case 2:
	    *(long *)where = new_value + *(long *)where;
	    break;
	}
    }
}

/* end reloc_file */

/* free up space which is not allocated in tempspace */

#define TEMP_FREE(x) \
if (((char *)x)> tempspace+TEMPSPACE || ((char *)x)< tempspace) \
     free(x)

int
fasload(faslfile)
    object              faslfile;
{
    long                fasl_vector_start;
    int                 string_size = 0;
    object              memory, data;
    FILE               *fp;
    char                filename[MAXPATHLEN];
    int                 i;
    int                 init_address = 0;

    object             *old_vs_base = vs_base;
    object             *old_vs_top = vs_top;

    bil = tempspace;		/* reset tmp malloc */
    extra_bss = 0;
    coerce_to_filename(faslfile, filename);
    faslfile = open_stream(faslfile, smm_input, Cnil, Kerror);
    vs_push(faslfile);
    fp = faslfile->sm.sm_fp;

    if (!read_header_info(fp))
	FEerror("Could not get the header", 0, 0);

    symbol_table =
      (struct syment *) temp_malloc(sizeof(struct syment) *
				    (unsigned int)nsyms);
    fseek(fp, symoff, 0);
    {
	for (i = 0; i < nsyms; i++) {
	    fread((char *)&symbol_table[i], SYMESZ, 1, fp);
	}
    }
    translate_mach_o_symbols(symbol_table, nsyms);

    fseek(fp, stroff, 0);

    {
	int                 ii = 0;

	if (!(ii = strsize)) {
	    FEerror("The string table of this file did not have any length", 0,
		    0);
	}
    /* at present the string table is located just after the symbols */
	my_string_table = temp_malloc((unsigned int)ii);

	if (ii != fread(my_string_table, 1, ii, fp))
	    FEerror("Could not read whole string table", 0, 0);
    }

    SEEK_TO_END_OFILE(fp);

    fasl_vector_start = ftell(fp);

    if (!((c_table.ptable) && *(c_table.ptable)))
	build_symbol_table();

/* figure out if there is more bss space needed */
    extra_bss = get_extra_bss(symbol_table, nsyms, data_size + text_size + bss_size,
			      &init_address, bss_size);

/* allocate some memory */
    memory = alloc_object(t_cfdata);
    memory->cfd.cfd_self = 0;
    memory->cfd.cfd_start = 0;
    memory->cfd.cfd_size = data_size + text_size + bss_size + extra_bss;
    vs_push(memory);
    the_start = start_address =
      memory->cfd.cfd_start =
      alloc_contblock(memory->cfd.cfd_size);
/*
    if (fseek(fp, text_offset, 0) < 0)
	FEerror("file seek error", 0, 0);
    fread(the_start, text_size + data_size + bss_size, 1, fp);
*/
    if (fseek(fp, text_offset, 0) < 0)
	FEerror("file seek error", 0, 0);
    fread(the_start, text_size, 1, fp);
    if (fseek(fp, data_offset, 0) < 0)
	FEerror("file seek error", 0, 0);
    if (data_size != 0)
	fread(the_start + text_size, data_size, 1, fp);
    if (fseek(fp, bss_offset, 0) < 0)
	FEerror("file seek error", 0, 0);
    if (bss_size != 0)
	fread(the_start + text_size + data_size, bss_size, 1, fp);

/* relocate the actual loaded text  */


 /*
  * this looks up symbols in c.ptable and also adds new externals to that
  * c.table 
  */
/*	relocate_symbols(NSYMS(fileheader));  	*/
    relocate_symbols(nsyms);

    fseek(fp, text_reloff, 0);
    {
	int                 nrel = text_nreloc;

	for (i = 0; i < nrel; i++) {
	    fread((char *)&relocation_info, sizeof(struct reloc),
		  1, fp);
	    relocate();
	}
    }
    fseek(fp, data_reloff, 0);
    {
	int                 nrel = data_nreloc;

	the_start += text_size;
	for (i = 0; i < nrel; i++) {
	    fread((char *)&relocation_info, sizeof(struct reloc),
		  1, fp);
	    relocate();
	}
    }
    fseek(fp, bss_reloff, 0);
    {
	int                 nrel = bss_nreloc;

	the_start += data_size;
	for (i = 0; i < nrel; i++) {
	    fread((char *)&relocation_info, sizeof(struct reloc),
		  1, fp);
	    relocate();
	}
	the_start -= data_size;
    }


/* end of relocation */

/* read in the fasl vector */
    fseek(fp, fasl_vector_start, 0);
    if (feof(fp)) {
	data = 0;
    } else {
	data = read_fasl_vector(faslfile);
	vs_push(data);
    }
    close_stream(faslfile, 1);


    TEMP_FREE(my_string_table);
    TEMP_FREE(symbol_table);


    asm("trap #2");

    call_init(init_address, memory, data);

    vs_base = old_vs_base;
    vs_top = old_vs_top;
    if (symbol_value(Vload_verbose) != Cnil)
	printf("start address -T %x ", memory->cfd.cfd_start);
    return (memory->cfd.cfd_size);
}


struct node        *
find_sym(sym, name)
    struct syment      *sym;
    char               *name;
{
    char                tem[SYMNMLEN + 1];

    tem[SYMNMLEN] = 0;
    if (name == 0)
	name = SYM_NAME(sym);
    {
	struct node         joe, *answ;

	joe.string = name;
	answ = (struct node *) bsearch((char *)(&joe), (char *)(c_table.ptable),
				       c_table.length,
				       sizeof(struct node), node_compare);

	return answ;
    }
}


get_extra_bss(symbol_table, length, start, ptr, bsssize)
    int                 length, bsssize;
    struct syment      *symbol_table;
    int                *ptr;	/* store init address offset here */
{
    int                 result = start;
    int                 next_bss = start - bsssize;
    struct syment      *end, *sym;
    char                tem[SYMNMLEN + 1];

    end = symbol_table + length;
    for (sym = symbol_table; sym < end; sym++) {
	tem;			/* ignored */
	if (SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym))
	/* external bss so not included in size of bss for file */
	{
	    int                 val = sym->n_value;

	    if (val && c_table.ptable
		&& (0 == find_sym(sym, 0))) {
		sym->n_value = result;
		result += val;
	    }
	}
	sym += NUM_AUX(sym);

    }
    return (result - start);
}



/* go through the symbol table changing the addresses of the symbols
to reflect the current cfd_start */



relocate_symbols(nsyms)
    int                 nsyms;
{
    struct syment      *sym;
    unsigned int        typ;
    int                 i;
    char               *str;
    char                tem[SYMNMLEN + 1];

    tem[SYMNMLEN] = 0;
    for (i = 0; i < nsyms; i++) {
	sym = &symbol_table[i];
	typ = NTYPE(sym);
#ifdef N_STAB
	if (N_STAB & sym->n_type)
	    continue;		/* skip: It  is for dbx only */
#endif
	typ = N_SECTION(sym);
/* if(sym->n_type  &  N_EXT) should add the symbol name,
   so it would be accessible by future loads  */
	switch (typ) {
	case N_ABS:
	case N_TEXT:
	case N_DATA:
	case N_BSS:
	    str = SYM_NAME(sym);

	    sym->n_value = (int)start_address;
	    break;
	case N_UNDEF:
	    str = SYM_NAME(sym);
	    set_symbol_address(sym, str);
	    break;
	default:
	    break;
	}
	sym += NUM_AUX(sym);
    }
}

/* 
STEPS:
1) read in the symbol table from the file,
2) go through the symbol table, relocating external entries.
3) for i <=2 go thru the relocation information for this section
 relocating the text.
4) done.
*/

set_symbol_address(sym, string)
    struct syment      *sym;
    char               *string;
{
    struct node        *answ;

    if (c_table.ptable) {
	answ = find_sym(sym, string);
	if (answ) {
	/*
	 * the old value of sym->n_value is the length of the common area
	 * starting at this address 
	 */
	    sym->n_value = answ->address;
	} else {
	    {
		char               *name;

		name = malloc(1 + strlen(string));
		strcpy(name, string);
		sym->n_value = sym->n_value + (unsigned int)the_start;
		add_symbol(string, sym->n_value, NULL);
	    }

	    fprintf(stdout, "undefined %s symbol", string);
	    fflush(stdout);

	}
    } else {
	FEerror("symbol table not loaded", 0, 0);
    }
}

/*
#define ADD_SYMBOL(name) add_symbol("name",(int) &(name),0)
Use the add_symbol to add a c symbol, which you want to refer
to in subsequent loads.  The address used in subsequent loads,
will be the load address of the current symbol.
Such a symbol may only be added once, since subsequent references
will try to link to the old address.
*/

build_symbol_table()
{
    printf("Building symbol table for %s ..\n", kcl_self);
    fflush(stdout);
    sprintf(tmpfile1, "/tmp/rsym%d", getpid());
    coerce_to_filename(symbol_value(siVsystem_directory),
		       system_directory);
    sprintf(command, "%srsym %s %s", system_directory, kcl_self, tmpfile1);
    if (system(command) != 0)
	FEerror("The rsym command ~a failed .", 1, make_simple_string(command)
	  );

    read_special_symbols(tmpfile1);
    unlink(tmpfile1);
    qsort((char *)(c_table.ptable), (int)(c_table.length), sizeof(struct node), node_compare);
}



/*to do:Addition of one symbol to the ptable is very slow, because we 
sort each time! */

add_symbol(va_alist)
va_dcl
{
    char               *string;
    int                 address;
    int                 nstr, i;
    va_list             ap;

 /* terminate arg list with NULL pointer */

    if (!(c_table.ptable))
	return;			/* this is in a function before ptable is
				 * init */
    nstr = 0;
 /* count the number of strings */

    va_start(ap);
    while (va_arg(ap, char *)!=0) {
	nstr++;
	va_arg(ap, int);
	if (nstr > 1000)
	    FEerror("Did you really give 1000 strings or just forget 0 ending", 0, 0);
    };
    va_end(ap);

    va_start(ap);
    if ((int)((c_table.alloc_length) - (c_table.length)) - nstr > 0) {
BEGIN:
	for (i = 0; i < 2 * nstr; i = i + 2) {
	    string = va_arg(ap, char *);
	    if (find_sym(0, string)) {
		FEerror("The string ~a is already in the ptable", 1,
			make_simple_string(string));
	    };
	    {
		struct node        *u;

		u = ((*(c_table.ptable)) + ((c_table.length) + (i / 2)));
		u->string = string;
		u->address = va_arg(ap, int);
	    }
	}
	(c_table.length) = (c_table.length) + nstr;
	qsort((char *)(c_table.ptable), (int)(c_table.length), sizeof(struct node), node_compare);
    } else
    /* grow the ptable */
    {
	TABL               *new, *old_pt;

	new =
	  (TABL *) malloc(sizeof(struct node)
			  * ((c_table.alloc_length) = ((c_table.length) + nstr + PTABLE_EXTRA)));
	old_pt = (c_table.ptable);
    /* copy it */
	{
	    register int        i;

	    for (i = 0; i < c_table.length; i++) {
		(*new)[i].string = (*old_pt)[i].string;
		(*new)[i].address = (*old_pt)[i].address;
	    }
	}

	(c_table.ptable) = new;
	free((char *)old_pt);
	goto BEGIN;
    }
    va_end(ap);

}


int
read_header_info(fp)
    FILE               *fp;
{
    struct mach_header  mach_header;
    char               *hdrbuf;
    struct load_command *load_command;
    struct segment_command *segment_command;
    struct section     *section;
    struct symtab_command *symtab_command;
    struct symseg_command *symseg_command;
    int                 ordinal;
    int                 len, cmd, seg;

    ordinal = 1;

    fseek(fp, 0L, 0);
    len = fread((char *)&mach_header, sizeof(struct mach_header), 1, fp);
    if (len == 1 && mach_header.magic == MH_MAGIC) {
	hdrbuf = malloc(mach_header.sizeofcmds);
	len = fread(hdrbuf, mach_header.sizeofcmds, 1, fp);
	if (len != 1) {
	    fprintf(stderr, "failure reading Mach-O load commands\n");
	    return 0;
	}
	load_command = (struct load_command *) hdrbuf;
	for (cmd = 0; cmd < mach_header.ncmds; ++cmd) {
	    switch (load_command->cmd) {
	    case LC_SEGMENT:
		segment_command = (struct segment_command *) load_command;
		section = (struct section *) ((char *)(segment_command + 1));
		for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal) {
		    if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname)) {
			text_size = section->size;
			text_offset = section->offset;
			text_reloff = section->reloff;
			text_nreloc = section->nreloc;
			text_ordinal = ordinal;
		    } else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname)) {
			data_size = section->size;
			data_offset = section->offset;
			data_reloff = section->reloff;
			data_nreloc = section->nreloc;
			data_ordinal = ordinal;
		    } else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname)) {
			bss_size = section->size;
			bss_offset = section->offset;
			bss_reloff = section->reloff;
			bss_nreloc = section->nreloc;
			bss_ordinal = ordinal;
		    }
		}
		break;
	    case LC_SYMTAB:
		symtab_command = (struct symtab_command *) load_command;
		symoff = symtab_command->symoff;
		nsyms = symtab_command->nsyms;
		stroff = symtab_command->stroff;
		strsize = symtab_command->strsize;
		break;
	    }
	    load_command = (struct load_command *)
	      ((char *)load_command + load_command->cmdsize);
	}
	free(hdrbuf);
	return 1;
    }
    return 0;
}

#ifndef N_SLINE
#define N_SLINE 0x44
#endif
#ifndef N_DSLINE
#define N_DSLINE 0x46
#endif
#ifndef N_BSLINE
#define N_BSLINE 0x48
#endif

translate_mach_o_symbols(symbol_table, nsyms)
    struct syment      *symbol_table;
    int                 nsyms;
{
    int                 i;
    struct syment      *sym;

    for (i = 0; i < nsyms; ++i) {
	if (((sym = &symbol_table[i])->n_type & ~N_EXT) == N_SECT) {
	    if (sym->n_sect == text_ordinal)
		sym->n_type = (sym->n_type & N_EXT) | N_TEXT;
	    else if (sym->n_sect == data_ordinal)
		sym->n_type = (sym->n_type & N_EXT) | N_DATA;
	    else if (sym->n_sect == bss_ordinal)
		sym->n_type = (sym->n_type & N_EXT) | N_BSS;
	    else
		fprintf(stderr, "unknown section referenced in symbols\n");
	    sym->n_sect = 0;
	} else if (sym->n_type == N_SLINE) {
	    if (sym->n_sect == text_ordinal)
		sym->n_type = N_SLINE;
	    else if (sym->n_sect == data_ordinal)
		sym->n_type = N_DSLINE;
	    else if (sym->n_sect == bss_ordinal)
		sym->n_type = N_BSLINE;
	    else
		fprintf(stderr, "unknown section referenced in debugging symbols");
	}
    }
}

#define RELOC_EXTERN_P(r)		((r)->r_extern)
#define RELOC_TYPE(r)		((r)->r_symbolnum)

translate_mach_o_relocation(reloc)
    struct relocation_info *reloc;
{
    int                 i;

    if (!RELOC_EXTERN_P(reloc)) {
	if (RELOC_TYPE(reloc) == R_ABS)
	    RELOC_TYPE(reloc) = N_ABS;
	else if (RELOC_TYPE(reloc) == text_ordinal)
	    RELOC_TYPE(reloc) = N_TEXT;
	else if (RELOC_TYPE(reloc) == data_ordinal)
	    RELOC_TYPE(reloc) = N_DATA;
	else if (RELOC_TYPE(reloc) == bss_ordinal)
	    RELOC_TYPE(reloc) = N_BSS;
	else
	    fprintf(stderr, "unknown section ordinal in relocation info\n");
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.