/* * convert.c - convert AmigaDOS "hunk"-format load file to * memory image similar to a.out format * Based on CVT Amiga->ST program * which is Copyright (C) 1985 Landon M. Dyer. * * Changes to CVT and everything new is Copyright 1986 * by Eric D. Black. Permission is given to redistribute * this program and its source code subject to the * restrictions given in the file "unhunk.c" * */ #include #include "convert.h" #include "hunk.h" #include "bin.out.h" #ifdef DBUG #include #else #include "dbugstubs.h" #endif Hinfo *ahinfo(); /* hunk information */ Hinfo **hunk; /* -> vector of ptrs to Hinfo structs */ Hinfo *firsthunk; /* -> first hunk */ int nhunks; /* #hunks in input file */ int curhunk; /* current hunk# */ int hvalid; /* state variable (to bump curhunk) */ long filpos; /* position in input file */ long siz[3]; /* segment sizes */ long maxhunk; /* size of biggest hunk found */ char *hunkbuf; /* ptr to buffer for doing hunk relocation */ int curtype; /* current hunk type: 0=Code, 1=Data, 2=BSS */ char *secname[] = { "CODE", "DATA", "BSS " }; /* * Macro to bump address up to next longword boundary */ #define ROUNDLONG(a) ((a + 3) & 0xfffffffc); /* * Convert AMIG* binary loadfile to memory image file similar to a.out */ convert(ifd, ofd) int ifd, ofd; { DBUG_ENTER("convert"); /* init globals */ hunk = (Hinfo **)NULL; firsthunk = (Hinfo *)NULL; hvalid = nhunks = 0; curhunk = -1; filpos = 0L; maxhunk = 0L; pass1(ifd); /* gather info on hunks, see what we have to do */ if (curhunk < nhunks) panic("Bugcheck: not enough hunks in input body."); bind(); /* decide where each hunk will go */ output(ifd, ofd); /* spit out hunks in desired order */ release(); /* free memory */ DBUG_RETURN(0); } /* * Parse hunks in AMIG* binary loadfile, * gather information about it. * * Add error checks, handle symbol records 19Apr86 edb * Handle extra HUNK_ENDs which alink sometimes produces 20Apr86 edb */ pass1(ifd) int ifd; { long lw; Hinfo *h; DBUG_ENTER("pass1"); for(;;) { if (readlong(ifd, &lw) == EOF) { DBUG_3("hunk", "Got EOF", 0); break; } switch ((int)lw) { case HUNK_UNIT: case HUNK_NAME: DBUG_3("hunk","%s",(lw==HUNK_UNIT)?"HUNK_UNIT":"HUNK_NAME"); getlong(ifd, &lw); skip(ifd, lw); break; case HUNK_CODE: DBUG_2("hunk", "HUNK_CODE"); chkhunk(); curtype = TEXT; h = hunk[curhunk]; getlong(ifd, &lw); /* get size (in longs) */ if (lw != h->hsize) { fprintf(stderr, "Code hunk %d size %ld doesn't match header (%ld)\n", h->hunkno, lw, h->hsize); errflg++; } lw *= 4; if (maxhunk < lw) { maxhunk = lw; DBUG_3("hunk", "maxhunk=%ld", maxhunk); } h->hsize = lw; h->hpos = filpos; h->htype = TEXT; skip(ifd, lw); if (printing) printf("Hunk %d, type %s, size %ld\n", h->hunkno, secname[h->htype], h->hsize); DBUG_EXECUTE("dump", dumphinfo(h); ); break; case HUNK_DATA: DBUG_2("hunk", "HUNK_DATA"); chkhunk(); curtype = DATA; h = hunk[curhunk]; getlong(ifd, &lw); /* get size (in longs) */ if (lw != h->hsize) { fprintf(stderr, "Data hunk %d size %ld doesn't match header (%ld)\n", h->hunkno, lw, h->hsize); errflg++; } lw *= 4; if (maxhunk < lw) { maxhunk = lw; DBUG_3("hunk", "maxhunk=%ld", maxhunk); } h->hsize = lw; h->hpos = filpos; h->htype = DATA; skip(ifd, lw); if (printing) printf("Hunk %d, type %s, size %ld\n", h->hunkno, secname[h->htype], h->hsize); DBUG_EXECUTE("dump", dumphinfo(h); ); break; case HUNK_BSS: DBUG_2("hunk", "HUNK_BSS"); chkhunk(); curtype = BSS; h = hunk[curhunk]; getlong(ifd, &lw); /* get size (in longs) */ if (lw != h->hsize) { fprintf(stderr, "BSS hunk %d size %ld doesn't match header (%ld)\n", h->hunkno, lw, h->hsize); errflg++; } h->hsize = lw * 4; h->htype = BSS; if (printing) printf("Hunk %d, type %s, size %ld\n", h->hunkno, secname[h->htype], h->hsize); DBUG_EXECUTE("dump", dumphinfo(h); ); break; case HUNK_RELOC32: DBUG_2("hunk", "HUNK_RELOC32"); h = hunk[curhunk]; if (!h->hrel) { h->hrel = filpos; DBUG_4("hunk", "hunk %d relinfo at %ld",curhunk,filpos); } for (;;) { /* skip past reloc records */ getlong(ifd, &lw); /* # of offsets */ DBUG_3("hunk", "%ld offsets", lw); if (!lw) break; /* done */ skip(ifd, (lw+1) * 4); } break; case HUNK_RELOC16: DBUG_2("hunk", "HUNK_RELOC16"); panic("16-bit relocation not supported."); break; case HUNK_RELOC8: DBUG_2("hunk", "HUNK_RELOC8"); panic("8-bit relocation not supported."); break; case HUNK_EXT: DBUG_2("hunk", "HUNK_EXT"); panic("External symbols not supported."); break; case HUNK_SYMBOL: /* ignore symbol records */ DBUG_2("hunk", "HUNK_SYMBOL"); do { getlong(ifd, &lw); DBUG_3("hunk", "typ/namlen=0x%lx", lw); if (lw) skip(ifd, ((lw & 0xffffffL) + 1) * 4); } while (lw); break; case HUNK_DEBUG: /* ignore debug records */ DBUG_2("hunk", "HUNK_DEBUG"); getlong(ifd, &lw); /* get size (in longs) */ lw *= 4; skip(ifd, lw); break; case HUNK_END: DBUG_2("hunk", "HUNK_END"); if (hvalid) { hvalid = 0; DBUG_3("dump", "end of hunk %d\n", curhunk); } else printf("Extra HUNK_END for %s hunk %d, ignored\n", (curtype>=0 && curtype<=2) ? secname[curtype]:"???", curhunk); break; case HUNK_HEADER: DBUG_2("hunk", "HUNK_HEADER"); header(ifd); break; case HUNK_OVERLAY: DBUG_2("hunk", "HUNK_OVERLAY"); panic("Overlays not supported."); break; case HUNK_BREAK: DBUG_2("hunk", "HUNK_BREAK"); panic("Breaks (overlays) not supported."); break; default: DBUG_3("hunk", "Unknown hunk type: 0x%lx", lw); panic("Out of phase, lost in space..."); } } curhunk++; /* boundary adjustment */ DBUG_4("hunk","%d hunks expected, %d found", nhunks, curhunk); DBUG_RETURN(0); } /* * Sanity check about hunk adjacency (which may not be a * problem) and hunk number range. * * Remove panic for (presumably) missing HUNK_END 23Apr86 edb */ chkhunk() { DBUG_ENTER("chkhunk"); #if 0 if (hvalid) panic("Bugcheck: two adjacent hunks w/o HUNK_END!"); #endif curhunk++; /* bump hunk# here in case of extra HUNK_ENDs */ if (curhunk >= nhunks) panic("Bugcheck: too many hunks!"); hvalid = 1; DBUG_RETURN(0); } /* * Read hunk header, * get info for global vars. * */ header(fd) int fd; { long lw; long htabsize, firsthunk, lasthunk; unsigned int j; DBUG_ENTER("header"); /* * Skip library names. */ for (;;) { getlong(fd, &lw); DBUG_3("hunk", "namlen=%d", lw); if (!lw) break; skip(fd, lw*4); } /* more random header info */ getlong(fd, &htabsize); getlong(fd, &firsthunk); getlong(fd, &lasthunk); DBUG_5("hunk", "htabsize = %ld\nfirsthunk = %ld\nlasthunk = %ld\n", htabsize, firsthunk, lasthunk); /* alloc space for hunk database */ nhunks = (unsigned)(lasthunk - firsthunk + 1); j = nhunks * sizeof(*hunk); DBUG_4("mem", "grabbing %ld bytes for %d hunks", j, nhunks); hunk = (Hinfo **)malloc(j); if (hunk == NULL) allerr(); for (j = 0; j < nhunks; ++j) { hunk[j] = ahinfo(j); hunk[j]->hunkno = j; getlong(fd, &hunk[j]->hsize); DBUG_5("dump", "%d hsize = %ld ($%lx)\n", j, hunk[j]->hsize, hunk[j]->hsize); } DBUG_RETURN(0); } /* * Compute hunk order and starting addresses. * * Changed for unhunk 19Apr86 edb * We have three bases to work with: text, data, bss; * each may be specified individually, otherwise text is assumed to * start at zero, data immediately follows text (padded to longword), * and bss immediately follows data (padded to longword). */ bind() { int typ, hnk; long addr; Hinfo *hptr; DBUG_ENTER("bind"); hptr = firsthunk; if (printing) printf("Assigning hunk load addresses:\n"); for (typ = TEXT; typ <= BSS; ++typ) { /* text, then data, then bss */ addr = origin[typ]; siz[typ] = 0L; for (hnk = 0; hnk < nhunks; ++hnk) if (hunk[hnk]->htype == typ) { if (firsthunk == (Hinfo *)NULL) hptr = firsthunk = hunk[hnk]; else { /* list of each type in order found */ hptr->hnext = hunk[hnk]; hptr = hunk[hnk]; } siz[typ] += hptr->hsize; hptr->haddr = addr; addr += hptr->hsize; if(printing) printf("Hunk %d (%s) load address 0x%lx\n", hnk, secname[hptr->htype], hptr->haddr); DBUG_5("dump", "%s hunk[%d]->haddr = $%lx\n",secname[typ],hnk,hptr->haddr); } /* * if not otherwise specified, round data and bss segments * each up to longword boundary */ if (!orgspec[DATA]) { /* * charge pad bytes to text segment */ siz[TEXT] = ROUNDLONG(siz[TEXT]); origin[DATA] = origin[TEXT] + siz[TEXT]; } if (!orgspec[BSS]) { siz[DATA] = ROUNDLONG(siz[DATA]); origin[BSS] = origin[DATA] + siz[DATA]; } } printf("Section Origin Size(bytes)\n"); for(typ=TEXT; typ<=BSS; typ++) printf(" %s 0x%-6lx %ld (0x%lx)\n", secname[typ], origin[typ], siz[typ], siz[typ]); DBUG_RETURN(0); } /* * Allocate (and initialize) a Hinfo node. * * use hrel as filepos to re-read reloc info 20Apr86 edb */ Hinfo *ahinfo(hnum) int hnum; { Hinfo *h; DBUG_ENTER("ahinfo"); if (hnum >= nhunks) panic("curhunk >= nhunks, too many hunks!"); DBUG_4("mem","malloc'ing %d bytes for hunk %d",sizeof(Hinfo),hnum); if ((h = (Hinfo *)malloc(sizeof(Hinfo))) == NULL) allerr(); h->hsize = 0L; h->hpos = 0L; h->haddr = 0L; h->hrsize = 0L; h->htype = -1; h->hrel = 0L; h->hnext = (Hinfo *)NULL; DBUG_RETURN(h); } /* * Release memory used by hunk database. */ release() { int i; DBUG_ENTER("release"); for (i = 0; i < nhunks; ++i) { DBUG_3("mem", "freeing node at 0x%x", hunk[i]); free(hunk[i]); } DBUG_2("mem", "freeing hunk"); free(hunk); DBUG_RETURN(0); } /* * Skip some of the input file */ skip(fd, count) int fd; long count; { DBUG_ENTER("skip"); DBUG_3("hunk", "skipping %ld bytes", count); filpos += count; lseek(fd, count, 1); DBUG_RETURN(0); } /* * Out of memory (malloc() didn't work); * complain and die. */ allerr() { DBUG_ENTER("allerr"); panic("Allocation failure, heap exhausted, I give up!\n"); /*NOTREACHED*/ DBUG_RETURN(0); } /* * Print information about an Hinfo node. */ dumphinfo(h) Hinfo *h; { DBUG_ENTER("dumphinfo"); printf("hsize = %ld ($%lx), hpos = %ld, haddr = %ld ($%lx)\n", h->hsize, h->hsize, h->hpos, h->haddr, h->haddr); printf("htype = %s ", secname[h->htype]); printf("hrel = %ld, hnext = $%lx\n", h->hrel, (long)h->hnext); DBUG_RETURN(0); } /* cvt2long() moved to longio.c to help localize machine dependencies edb*/