ack/mach/minixST/cv/cv.c
1988-05-06 17:03:06 +00:00

332 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"); }