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

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

/*
	ild: incremental linker/loader on System V

				(C) Masami Hagiya, 1986

	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.

*/

#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 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);
	}
	/*
	printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]);
	fflush(stdout);
	*/
	get_myself(argv[1]);
	/*
	printf("Myself got.\n");
	fflush(stdout);
	*/
	start_address = (char *)atoi(argv[2]);
	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.
	*/
	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 not described in the manual, and may change in the future.
	*/
	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);
	if (header.f_opthdr != 0) {
		fprintf(stderr, "Unexpected optional header.\n");
		exit(1);
	}

	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) +
	    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 not described in the manual, and may change in the future.
	*/
	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)	{
		case 1: case 2: case 3:
			/*
			If the section number of the symbol is 1, 2, or 3,
			the start address of the text is stored.
			This is not described in the manual,
			and may depend on CPU or may change in the future.
			*/
			sym->n_value = (int)start_address;
			break;
		case N_UNDEF:
			search_symbol(sym);
			break;
		default:
			/*
			Does nothing. Is it OK?
			*/
			break;
		}
		sym += sym->n_numaux;
	}

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

	ldrseek(ldptr, 2);
	for (i = 0; i < section[2].s_nreloc; i++) {
		/*
		FREAD(&relocation_info, sizeof(struct reloc), 1, ldptr);
		*/
		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);
	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:
	/*
	Subtract the original value.
	This is not described in the manual,
	and I don't understand why.
	*/
	sym->n_value = p->n_value - sym->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.
	*/
switch(relocation_info.r_type){ int *q;

#ifdef MP386
 case    	R_DIR32:

        *(int *)where= *((int *)where) + 
        	 symbol_table[relocation_info.r_symndx].n_value;
	break;
 case		R_PCRLONG:
       *(int *)where= *((int *)where)  - (int)start_address
                      + symbol_table[relocation_info.r_symndx].n_value;
	break;
#else
case	R_DIR32S:
		p = (char *)(&value);
	p[3] = where[0];
	p[2] = where[1];
	p[1] = where[2];
	p[0] = where[3];
	value += symbol_table[relocation_info.r_symndx].n_value;
	where[0] = p[3];
	where[1] = p[2];
	where[2] = p[1];
	where[3] = p[0];
	break;
#endif
      default:
		fprintf(stderr, "%d: unsupported relocation type.",
			relocation_info.r_type);
		exit(1);
      }
}

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