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

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

/*
	ild: incremental linker/loader on System V

				(C) Masami Hagiya, 1986
              UTS version       (C) Akiumi Hasegawa, 1987

	Usage:
		% ild loading_object start_address \
		      loaded_object output_file
	
	The start address is in decimal.

	How to Create:

	To compile this file (ild.c) and make ild, do the following.

		% cc -o ild ild.c -lld

	
	Problem:
	This program only supports the simplest linear search for symbols.
 
        This program is modified for UTS system.

*/

#include <stdio.h>
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <reloc.h>
#include <syms.h>
#include <storclass.h>
#include <ldfcn.h>

struct filehdr my_header;
struct syment *my_symbol_table;
char *my_string_table;

struct filehdr header;
struct aouthdr opt_header;
struct scnhdr section[9];
char *text;
struct syment *symbol_table;
char *string_table;

char *start_address;

struct reloc relocation_info;

main(argc, argv)
int argc;
char *argv[];
{
	if (argc < 5) {
		fprintf(stderr, "Arg count.\n");
		exit(1);
	}

#ifdef DEBUG
        printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]);
	fflush(stdout);
#endif

        get_myself(argv[1]);
	start_address = (char *)atoi(argv[2]);

#ifdef DEBUG
        printf("start address= %x\n",(int)start_address);fflush(stdout);
#endif

	fasload(argv[3], argv[4]);
	exit(0);
}

get_myself(filename)
char *filename;
{
	int i;
	LDFILE *ldptr;
	extern char *malloc();
	ldptr = ldopen(filename, NULL);
	if (ldptr == NULL) {
		fprintf(stderr, "Can't open %s\n", filename);
		exit(1);
	}

	ldfhread(ldptr, &my_header);

	ldtbseek(ldptr);
	my_symbol_table
	= (struct syment *)malloc(sizeof(struct syment) * my_header.f_nsyms);

	/*
	sizeof(struct syment) and SYMESZ are not always the same.
	*/

        if(my_symbol_table == NULL){
                fprintf(stderr,"Can't allocate memory for my_symbol_table\n");
                exit(1);
        }
	for (i = 0;  i < my_header.f_nsyms;  i++)
		FREAD(&my_symbol_table[i], SYMESZ, 1, ldptr);

	/*
	If the string table is not empty,
	its length is stored after the symbol table,
	This is described in the manual.
        (see UTS Support Tools Guide V10L20)
	*/

	if (FREAD(&i, 4, 1, ldptr) > 0)	{
		my_string_table = malloc(i);
		FSEEK(ldptr, -4, 1);
		FREAD(my_string_table, 1, i, ldptr);
	}

	ldclose(ldptr);
}

fasload(filename, outputfilename)
char *filename, *outputfilename;
{
	register struct syment *sym, *end;
	int i, n;
	LDFILE *ldptr;
	FILE *fp;

	extern char *malloc();

	ldptr = ldopen(filename, "r");
	if (ldptr == NULL) {
		fprintf(stderr, "Can't open %s\n", filename);
		exit(1);
	}

	ldfhread(ldptr, &header);

        FREAD(&opt_header,sizeof(struct aouthdr),1,ldptr);

	if (header.f_nscns < 3 || header.f_nscns > 8) {
		fprintf(stderr, "Illegal number of sections.\n");
		exit(1);
	}

	for (i = 1;  i <= header.f_nscns;  i++)
		ldshread(ldptr, i, &section[i]);

	if (strcmp(section[1].s_name, ".text") != 0) {
		fprintf(stderr, ".text not found.\n");
		exit(1);
	}
	if (strcmp(section[2].s_name, ".data") != 0) {
		fprintf(stderr, ".data not found.\n");
		exit(1);
	}
	/*
	The bss segment need not exist.
	*/
	/*
	if (strcmp(section[3].s_name, ".bss") != 0) {
		fprintf(stderr, ".bss not found.\n");
		exit(1);
	}
	*/

	if (section[1].s_size > 0 &&
	    section[1].s_scnptr !=
	    sizeof(struct filehdr) + sizeof(struct aouthdr) +
	    header.f_nscns*sizeof(struct scnhdr)) {
		fprintf(stderr, "Contradictory text start.\n");
		exit(1);
	}
	if (section[1].s_size > 0 && section[2].s_size > 0 &&
	    section[1].s_scnptr + section[1].s_size !=
	    section[2].s_scnptr) {
		fprintf(stderr, "Contradictory data start.\n");
		exit(1);
	}

	text = malloc(section[1].s_size + section[2].s_size);

	FSEEK(ldptr, section[1].s_scnptr, 0);
	FREAD(text, 1, section[1].s_size + section[2].s_size, ldptr);

	ldtbseek(ldptr);
	symbol_table
	= (struct syment *)malloc(sizeof(struct syment) * header.f_nsyms);
	/*
	sizeof(struct syment) and SYMESZ are not always the same.
	*/
	for (i = 0;  i < header.f_nsyms;  i++)
		FREAD(&symbol_table[i], SYMESZ, 1, ldptr);
	/*
	If the string table is not empty,
	its length is stored after the symbol table,
	This is described in the manual.
        (see UTS Support Tools Guide V10L20)
	*/

	if (FREAD(&i, 4, 1, ldptr) > 0)	{
		string_table = malloc(i);
		FSEEK(ldptr, -4, 1);
		FREAD(string_table, 1, i, ldptr);
	}

	end = symbol_table + header.f_nsyms;
	for (sym = symbol_table; sym < end; sym++) {
		switch (sym->n_scnum)	{
                /* in UTS, relocatable address is the offset in the
                   section, in which it defined.
                   Thus "sym->n_value" for each section should be 
                   the the top address of the section. 
                   in case of ".data" section, s_vaddr is equal to 
                   s_size. However, ".bss" section, s_vaddr <> 
                   textsize+datasize. I cannot understand why. But 
                   this code works well.
                */
		case 1:
                       /* .text */
                       sym->n_value = (int)start_address; break;
                case 2:
                       /* .data */
                       sym->n_value = (int)start_address + section[1].s_size;
                       break;
                case 3:
                       /* .bss */
                       sym->n_value = (int)start_address + section[1].s_size 
                                      + section[2].s_size;
                       break;

		case N_UNDEF:
			search_symbol(sym);
			break;
		default:
			/*
			Does nothing. Is it OK?
			*/
			break;
		}
		sym += sym->n_numaux;
	}

	if(ldrseek(ldptr, 1) ==FAILURE){
           fprintf(stderr,"Can't locate relocation table\n");
           exit(1);
         }
        for (i=0; i< section[1].s_nreloc; i++){ 
                FREAD(&relocation_info,10,1,ldptr);
		relocate();
	}

	ldrseek(ldptr, 2);
	for (i = 0; i < section[2].s_nreloc; i++) {
		FREAD(&relocation_info, 10, 1, ldptr);
		relocate();
	}

	fp = fopen(outputfilename, "w");
	if (fp == NULL)	{
		fprintf(stderr, "Can't creat %s.\n", outputfilename);
		exit(1);
	}
        fwrite(&header, sizeof(struct filehdr), 1, fp);
        fwrite(&opt_header,sizeof(struct aouthdr),1,fp);
	for (i = 1; i<= header.f_nscns; i++) 
		fwrite(&section[i], sizeof(struct scnhdr), 1, fp); 
	fwrite(text, 1, section[1].s_size + section[2].s_size, fp);

	fclose(fp);
	ldclose(ldptr);
}

search_symbol(sym)
register struct syment *sym;
{
	register struct syment *p, *end;
	end = my_symbol_table + my_header.f_nsyms;
	for (p = my_symbol_table; p < end; p++)	{
		/*
		Is the following check enough?
		*/
		if (1 <= p->n_scnum && p->n_scnum <= 3 &&
		    p->n_sclass == C_EXT &&
		    (sym->n_zeroes == 0
		    ? (p->n_zeroes == 0 &&
		       strcmp(&my_string_table[p->n_offset],
			      &string_table[sym->n_offset]) == 0)
		    : (p->n_zeroes != 0 &&
		       strncmp(p->n_name, sym->n_name, SYMNMLEN) == 0)))
				goto FOUND;
		p += p->n_numaux;
	}

	sym->n_name[SYMNMLEN] = '\0';
	fprintf(stderr, "%s: undefined symbol.\n",
		(sym->n_zeroes ? sym->n_name : &string_table[sym->n_offset]));
	exit(1);

FOUND:
	sym->n_value = p->n_value;
}

relocate()
{
	char *where, *p;
	int value;

	where = text + relocation_info.r_vaddr;
	if (relocation_info.r_type == R_ABS)
		return;
	/*
	The following code depends on CPU.
        in case of UTS, R_RELLONG is assumed.
	*/
	if (relocation_info.r_type != R_RELLONG) {
		fprintf(stderr, "%d: unsupported relocation type.",
			relocation_info.r_type);
		exit(1);
	}
	/*
	Assuming R_RELLONG.
	*/
	p = (char *)(&value);
	p[0] = where[0];
	p[1] = where[1];
	p[2] = where[2];
	p[3] = where[3];

#ifdef DEBUG
        printf("%s\n",
               (symbol_table[relocation_info.r_symndx].n_zeroes ?
                symbol_table[relocation_info.r_symndx].n_name :
                &string_table
                  [symbol_table[relocation_info.r_symndx].n_offset])); 
        printf("value = %x\n",value);fflush(stdout);
#endif

        value += symbol_table[relocation_info.r_symndx].n_value;

#ifdef DEBUG
        printf("value = %x\n",value);fflush(stdout);
#endif

	where[0] = p[0];
	where[1] = p[1];
	where[2] = p[2];
	where[3] = p[3];
}

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