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("%ld 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"); }
 |