331 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			331 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Convert ACK a.out file to ST-Minix object format.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <out.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
struct outhead	outhead;
 | 
						|
struct outsect	outsect[S_MAX];
 | 
						|
 | 
						|
#define TEXTSG	0
 | 
						|
#define ROMSG	1
 | 
						|
#define DATASG	2
 | 
						|
#define BSSSG	3
 | 
						|
#define LSECT	BSSSG+1
 | 
						|
#define NSECT	LSECT+1
 | 
						|
 | 
						|
char	*output_file;
 | 
						|
int	outputfile_created;
 | 
						|
 | 
						|
char *program ;
 | 
						|
 | 
						|
/* Output file definitions and such */
 | 
						|
 | 
						|
int		output;
 | 
						|
 | 
						|
int unresolved;
 | 
						|
long	textsize ; 
 | 
						|
long	datasize ;
 | 
						|
long	bsssize;
 | 
						|
 | 
						|
char *chmemstr;
 | 
						|
 | 
						|
minixhead()
 | 
						|
{
 | 
						|
	long		mh[8];
 | 
						|
	long		stack;
 | 
						|
	long		chmem();
 | 
						|
	int		i;
 | 
						|
 | 
						|
	mh[0] = 0x04100301L;
 | 
						|
	mh[1] = 0x00000020L;
 | 
						|
	mh[2] = textsize;
 | 
						|
	mh[3] = datasize;
 | 
						|
	mh[4] = bsssize;
 | 
						|
	mh[5] = 0;
 | 
						|
	stack = 0x00010000L - (mh[3] + mh[4]);
 | 
						|
	if ((mh[0] & 0x00200000L) == 0)		/* not SEPARATE */
 | 
						|
		stack -= mh[2];
 | 
						|
	while (stack < 0)
 | 
						|
		stack += 0x00010000L;
 | 
						|
	if (chmemstr)
 | 
						|
		stack = chmem(chmemstr, stack);
 | 
						|
	printf("%D bytes assigned to stack+malloc area\n", stack);
 | 
						|
	mh[6] = stack + (mh[3] + mh[4]);
 | 
						|
	if ((mh[0] & 0x00200000L) == 0)		/* not SEPARATE */
 | 
						|
		mh[6] += mh[2];
 | 
						|
	mh[7] = 0;
 | 
						|
	for (i = 0; i < 8; i++) {
 | 
						|
		cvlong(&mh[i]);
 | 
						|
	}
 | 
						|
 | 
						|
	if (write(output, (char *) mh, sizeof(mh)) != sizeof(mh))
 | 
						|
		fatal("write error\n");
 | 
						|
}
 | 
						|
 | 
						|
long align(a,b)
 | 
						|
	long a,b;
 | 
						|
{
 | 
						|
	if (b == 0) return a;
 | 
						|
	a += b - 1;
 | 
						|
	return a - a % b;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
follows(pa, pb)
 | 
						|
	register struct outsect *pa, *pb;
 | 
						|
{
 | 
						|
	/* return 1 if pa follows pb */
 | 
						|
 | 
						|
	return pa->os_base == align(pb->os_base+pb->os_size, pa->os_lign);
 | 
						|
}
 | 
						|
 | 
						|
main(argc, argv)
 | 
						|
	int	argc;
 | 
						|
	char	*argv[];
 | 
						|
{
 | 
						|
 | 
						|
	program= argv[0] ;
 | 
						|
	if (argc > 1) {
 | 
						|
		switch (argv[1][0]) { 
 | 
						|
		case '-':
 | 
						|
		case '+':
 | 
						|
		case '=':
 | 
						|
			chmemstr = argv[1];
 | 
						|
			argc--;
 | 
						|
			argv++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	switch (argc) {
 | 
						|
	case 3:	if ((output = creat(argv[2], 0644)) < 0)
 | 
						|
			fatal("Can't write %s.\n", argv[2]);
 | 
						|
		output_file = argv[2];
 | 
						|
		outputfile_created = 1;
 | 
						|
		if (! rd_open(argv[1]))
 | 
						|
			fatal("Can't read %s.\n", argv[1]);
 | 
						|
		break;
 | 
						|
	default:fatal("Usage: %s [+-= amount] <ACK object> <ST-MINIX object>.\n", argv[0]);
 | 
						|
	}
 | 
						|
	rd_ohead(&outhead);
 | 
						|
	if (BADMAGIC(outhead))
 | 
						|
		fatal("Not an ack object file.\n");
 | 
						|
	if (outhead.oh_flags & HF_LINK) {
 | 
						|
		unresolved++;
 | 
						|
		fatal("Contains unresolved references.\n");
 | 
						|
	}
 | 
						|
	if ( outhead.oh_nsect!=LSECT && outhead.oh_nsect!=NSECT )
 | 
						|
		fatal("Input file must have %d sections, not %ld\n",
 | 
						|
			NSECT,outhead.oh_nsect) ;
 | 
						|
	rd_sect(outsect, outhead.oh_nsect);
 | 
						|
	/* A few checks */
 | 
						|
	if ( outsect[BSSSG].os_flen != 0 )
 | 
						|
		fatal("bss space contains initialized data\n") ;
 | 
						|
	if (! follows(&outsect[BSSSG], &outsect[DATASG]))
 | 
						|
		fatal("bss segment must follow data segment\n") ;
 | 
						|
	textsize= (outsect[DATASG].os_base - outsect[TEXTSG].os_base);
 | 
						|
	if (! follows(&outsect[ROMSG],&outsect[TEXTSG]))
 | 
						|
		fatal("rom segment must follow text\n") ;
 | 
						|
	if (! follows(&outsect[DATASG],&outsect[ROMSG]))
 | 
						|
		fatal("data segment must follow rom\n") ;
 | 
						|
	outsect[TEXTSG].os_size = outsect[ROMSG].os_base - outsect[TEXTSG].os_base;
 | 
						|
	outsect[ROMSG].os_size = outsect[DATASG].os_base - outsect[ROMSG].os_base;
 | 
						|
	outsect[DATASG].os_size = outsect[BSSSG].os_base - outsect[DATASG].os_base;
 | 
						|
	datasize= outsect[DATASG].os_size ;
 | 
						|
	bsssize = outsect[BSSSG].os_size;
 | 
						|
	if ( outhead.oh_nsect==NSECT ) {
 | 
						|
		if (! follows(&outsect[LSECT],&outsect[BSSSG]))
 | 
						|
			fatal("end segment must follow bss\n") ;
 | 
						|
		if ( outsect[LSECT].os_size != 0 )
 | 
						|
			fatal("end segment must be empty\n") ;
 | 
						|
	}
 | 
						|
 | 
						|
	minixhead();
 | 
						|
	emits(&outsect[TEXTSG]) ;
 | 
						|
	emits(&outsect[ROMSG]) ;
 | 
						|
	emits(&outsect[DATASG]) ;
 | 
						|
	emit_relo();
 | 
						|
	if ( outputfile_created) chmod(argv[2],0755);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Transfer the emitted byted from one file to another.
 | 
						|
 */
 | 
						|
emits(section) struct outsect *section ; {
 | 
						|
	char		*p;
 | 
						|
	char		*calloc(), *malloc();
 | 
						|
	long sz = section->os_flen;
 | 
						|
 | 
						|
	rd_outsect(section - outsect);
 | 
						|
	while (sz) {
 | 
						|
		unsigned int i = (sz >= 0x4000 ? 0x4000 : sz);
 | 
						|
		if (!(p = malloc(0x4000))) {
 | 
						|
			fatal("No memory.\n");
 | 
						|
		}
 | 
						|
		rd_emit(p, (long) i);
 | 
						|
		if (write(output, p, (int)i) < i) {
 | 
						|
			fatal("write error.\n");
 | 
						|
		}
 | 
						|
		free(p);
 | 
						|
		sz -= i;
 | 
						|
	}
 | 
						|
 | 
						|
	sz = section->os_size - section->os_flen;
 | 
						|
	if (sz) {
 | 
						|
		if (!(p = calloc(0x4000, 1))) {
 | 
						|
			fatal("No memory.\n");
 | 
						|
		}
 | 
						|
		while (sz) {
 | 
						|
			unsigned int i = (sz >= 0x4000 ? 0x4000 : sz);
 | 
						|
			if (write(output, p, (int)i) < i) {
 | 
						|
				fatal("write error.\n");
 | 
						|
			}
 | 
						|
			sz -= i;
 | 
						|
		}
 | 
						|
		free(p);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
compare(a,b)
 | 
						|
	register struct outrelo *a, *b;
 | 
						|
{
 | 
						|
	if (a->or_sect < b->or_sect) return -1;
 | 
						|
	if (a->or_sect > b->or_sect) return 1;
 | 
						|
	if (a->or_addr < b->or_addr) return -1;
 | 
						|
	if (a->or_addr > b->or_addr) return 1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
emit_relo()
 | 
						|
{
 | 
						|
	struct outrelo *ACKrelo;
 | 
						|
	register struct outrelo *ap;
 | 
						|
	unsigned int cnt = outhead.oh_nrelo;
 | 
						|
	long last, curr, base;
 | 
						|
	int sect;
 | 
						|
	char *bp;
 | 
						|
	register char *b;
 | 
						|
 | 
						|
	ACKrelo = ap = (struct outrelo *) calloc(cnt, sizeof(struct outrelo));
 | 
						|
	bp = b = malloc(4 + cnt);
 | 
						|
	if (!ap || !bp) {
 | 
						|
		fatal("No memory.\n");
 | 
						|
	}
 | 
						|
	rd_relo(ap, cnt);
 | 
						|
	qsort((char *) ap, (int) cnt, sizeof(struct outrelo), compare);
 | 
						|
	/*
 | 
						|
         * read relocation, modify to GEMDOS format, and write.
 | 
						|
         * Only longs can be relocated.
 | 
						|
         *
 | 
						|
         * The GEMDOS format starts with a long L: the offset to the
 | 
						|
         * beginning of text for the first long to be relocated.
 | 
						|
         * If L==0 then no relocations have to be made.
 | 
						|
         *
 | 
						|
         * The long is followed by zero or more bytes. Each byte B is
 | 
						|
         * processed separately, in one of the following ways:
 | 
						|
         *
 | 
						|
         * B==0:
 | 
						|
         *      end of relocation
 | 
						|
         * B==1:
 | 
						|
         *      no relocation, but add 254 to the current offset
 | 
						|
         * B==0bWWWWWWW0:
 | 
						|
         *      B is added to the current offset and the long addressed
 | 
						|
         *      is relocated. Note that 00000010 means 1 word distance.
 | 
						|
         * B==0bXXXXXXX1:
 | 
						|
         *      illegal
 | 
						|
         */
 | 
						|
 | 
						|
	last = 0;
 | 
						|
	curr = 0;
 | 
						|
	for (sect = S_MIN; sect <= S_MIN+2; sect++) {
 | 
						|
		base = outsect[sect-S_MIN].os_base;
 | 
						|
		for (;cnt > 0 && ap->or_sect == sect; ap++, cnt--) {
 | 
						|
			if (ap->or_type & RELPC ||
 | 
						|
			    ap->or_nami == outhead.oh_nname) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			assert(ap->or_type & RELO4);
 | 
						|
			curr = base + ap->or_addr;
 | 
						|
			if (last == 0) {
 | 
						|
				last = curr;
 | 
						|
				cvlong(&curr);
 | 
						|
				*((long *) b) = curr;
 | 
						|
				b += 4;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				while (curr - last > 255) {
 | 
						|
					*b++ = 1;
 | 
						|
					last += 254;
 | 
						|
				}
 | 
						|
				*b++ = curr - last;
 | 
						|
				last = curr;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		assert(cnt == 0 || ap->or_sect > sect);
 | 
						|
	}
 | 
						|
	assert(cnt == 0);
 | 
						|
	if (cnt = (b - bp)) {
 | 
						|
		*b++ = '\0';
 | 
						|
		write(output, bp, (int) cnt+1);
 | 
						|
	}
 | 
						|
	else write(output, "\0\0\0", 4);
 | 
						|
	free((char *) ACKrelo);
 | 
						|
	free(bp);
 | 
						|
}
 | 
						|
 | 
						|
long
 | 
						|
chmem(str, old)
 | 
						|
char *str;
 | 
						|
long old;
 | 
						|
{
 | 
						|
        register long num, new;
 | 
						|
        long atol();
 | 
						|
 | 
						|
        num = atol(str+1);
 | 
						|
        if (num == 0)
 | 
						|
                fatal("bad chmem amount %s\n", str+1);
 | 
						|
        switch (str[0]) {
 | 
						|
        case '-':
 | 
						|
                new = old - num; break;
 | 
						|
        case '+':
 | 
						|
                new = old + num; break;
 | 
						|
        case '=':
 | 
						|
                new = num; break;
 | 
						|
        }
 | 
						|
        return(new);
 | 
						|
}
 | 
						|
 | 
						|
cvlong(l)
 | 
						|
	long *l;
 | 
						|
{
 | 
						|
	long x = *l;
 | 
						|
	char *p = (char *) l;
 | 
						|
 | 
						|
	*p++ = x >> 24;
 | 
						|
	*p++ = x >> 16;
 | 
						|
	*p++ = x >> 8;
 | 
						|
	*p = x;
 | 
						|
}
 | 
						|
 | 
						|
/* VARARGS1 */
 | 
						|
fatal(s, a1, a2)
 | 
						|
	char	*s;
 | 
						|
{
 | 
						|
	fprintf(stderr,"%s: ",program) ;
 | 
						|
	fprintf(stderr, s, a1, a2);
 | 
						|
	if (outputfile_created)
 | 
						|
		unlink(output_file);
 | 
						|
	exit(-1);
 | 
						|
}
 | 
						|
 | 
						|
rd_fatal() { fatal("read error.\n"); }
 |