eric@chronon.UUCP (05/03/86)
A while ago in order to get something else done (which hopefully will be commercially available soon...) I needed a tool that processed the Amiga "hunk" loadfile format, performing the necessary relocation and otherwise de-hunking the file. I did a very quick and very dirty program that got my job done. I grabbed the CVT Amiga->ST conversion program by Landon Dyer which recently floated by, and used parts of it to make mine clearer. The result, "unhunk", follows. Features: 1) Collects code, data, and bss hunks together 2) Allows individual specification of code, data, and bss origins (which default to text at 0, data immediately following, bss after that, with data & bss rounded to next longword) 3) Generates binary file with format reminiscent of a.out 4) Output easily processed by separate program to produce "S-records" suitable for downloading to PROM programmer or development system In response to requests at the the last BADGE (Bay area Amiga Developers' Group [E], talk about reaching for an acronym!) I have added the capability to independently set the origins of the text, data, and bss segments. This makes it possible to use the Amiga C compiler, assembler, and linker to generate 68000 code which may be burned into ROM/PROM, turning the Amiga into a 68000 cross-development system (of course, the target 68000 system can't make use of any Amiga-specific goodies, but generic C code short of Amiga-specific goodies (or even stdio) could be OK). I whipped up a program which takes the output of 'unhunk' and generates Motorola-style S-records, such as are accepted by many PROM programmers. This program (dl.c) can be used as a model for downloading other formats, such as Intel-style ':'-records. All the usual caveats apply to generating ROMable code, including avoidance of initialized data... Basically, to do this correctly means NEVER using initialized data in your code, ALWAYS specifically initializing variables to constants in the code, and origining the DATA segment with your CODE in ROM; you want the DATA segment to have compiler-generated constants, and NONE of your variables, which should all be in the BSS segment which you point at RAM. I have tested this package only with the Lattice 3.03 C compiler; as far as I know I have avoided dependencies on that compiler (size of ints and such), but I am using some runtime library routines which may not be supported by Aztec C (string to decimal/hex conversion, for example). As it happens, I would be delighted to discover that the Manx compiler runtime routine correctly converts an ASCII string to binary using hexadecimal/decimal/octal conversion, as the Lattice strtol() is supposed to... Following are 10 files: unhunk.c dohunk.c convert.c binfio.c longio.c convert.h hunk.h bin.out.h dl.c dbugstubs.h The files convert.c, binfio.c, longio.c, and convert.h are adapted from Landon Dyer's CVT posting a couple weeks ago. The binary file format is defined in bin.out.h, and the separate program in dl.c can be used to translate that binary file into ASCII S-records for downloading. Have fun! ----------Cut here--------------------------snip,snip---------->%-- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # bin.out.h # binfio.c # convert.c # convert.h # dbugstubs.h # dl.c # dohunk.c # hunk.h # longio.c # unhunk.c # This archive created: Thu May 1 20:34:35 1986 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'bin.out.h'" '(1008 characters)' if test -f 'bin.out.h' then echo shar: "will not over-write existing file 'bin.out.h'" else cat << \Stunky!Fluff > 'bin.out.h' /* * bin.out.h 12 Mar 86 edb * definition of simple memory-image file format similar * in spirit to a.out on UNIX systems * Copyright 1986 Eric D. Black */ /* * This header is at the very beginning of the file */ struct bin { long b_magic; /* magic number, defined below */ long b_text; /* size of text segment in bytes */ long b_data; /* size of data segment in bytes */ long b_bss; /* size of bss segment in bytes */ long b_txorg; /* base address of text segment in memory */ long b_dtorg; /* base address of data segment in memory */ long b_bsorg; /* base address of bss segment in memory */ long b_entry; /* entry point offset in text segment */ long b_rsrv[8]; /* reserved for expansion */ }; /* * b_text bytes of text segment follow, then b_data bytes * of initialized data * If the data segment has to be rounded up to a longword boundary, * the 1-3 bytes of pad must have been added into the b_text byte count! */ #define BMAGIC 0407 /* why not? */ Stunky!Fluff if test 1008 -ne "`wc -c < 'bin.out.h'`" then echo shar: "error transmitting 'bin.out.h'" '(should have been 1008 characters)' fi fi echo shar: "extracting 'binfio.c'" '(1260 characters)' if test -f 'binfio.c' then echo shar: "will not over-write existing file 'binfio.c'" else cat << \Stunky!Fluff > 'binfio.c' /* * binfio.h Copyright 1985 Landon M. Dyer * * Minor mods for Amiga, DBUG macros 19Apr86 edb */ #include <stdio.h> #include "convert.h" #ifdef DBUG #include <local/dbug.h> #else #include "dbugstubs.h" #endif #define READ 0 #define WRITE 1 ebinopen(name, mode) char *name; int mode; { int fn; DBUG_ENTER("ebinopen"); if((fn = binopen(name, mode)) != -1) DBUG_RETURN(fn); fprintf(stderr, "Cannot %s: %s\n", mode == 1 ? "create" : "open", name); exit(1); /*NOTREACHED*/ DBUG_RETURN(-1); } binopen(name, mode) char *name; int mode; { int retval; DBUG_ENTER("binopen"); #if MACHINE == VAXVMS if(mode == WRITE) retval = creat(name, 0666); else retval = open(name, mode); #endif #if MACHINE == MSDOS #define UNCOOKED 0x8000 /* pure binary i/o */ if(mode == WRITE) retval = creat(name, 0666 | UNCOOKED); else retval = open(name, mode | UNCOOKED); #endif #if MACHINE == Amiga if(mode == WRITE) retval = creat(name, 0666); else retval = open(name, mode); #endif #if MACHINE == UNIX42 ))))) force-compiler-error #endif #if MACHINE == SYSV ))))) force-compiler-error #endif DBUG_RETURN(retval); } Stunky!Fluff if test 1260 -ne "`wc -c < 'binfio.c'`" then echo shar: "error transmitting 'binfio.c'" '(should have been 1260 characters)' fi fi echo shar: "extracting 'convert.c'" '(12492 characters)' if test -f 'convert.c' then echo shar: "will not over-write existing file 'convert.c'" else cat << \Stunky!Fluff > 'convert.c' /* * 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 <stdio.h> #include "convert.h" #include "hunk.h" #include "bin.out.h" #ifdef DBUG #include <local/dbug.h> #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*/ Stunky!Fluff if test 12492 -ne "`wc -c < 'convert.c'`" then echo shar: "error transmitting 'convert.c'" '(should have been 12492 characters)' fi fi echo shar: "extracting 'convert.h'" '(1644 characters)' if test -f 'convert.h' then echo shar: "will not over-write existing file 'convert.h'" else cat << \Stunky!Fluff > 'convert.h' /* convert.h 19 Apr 86 edb */ /* * Copyright (C) 1986 by Eric D. Black and 1985 Landon M. Dyer. * Based on the CVT Amiga->ST conversion program by Landon Dyer. * Permission is granted to redistribute this program and its * source code subject to the restrictions given in the file "unhunk.c" */ #define BUFFERSIZE 0x4000 #define OK 0 #define ERROR (-1) #define MSDOS 1 #define VAXVMS 2 #define UNIX42 3 #define SYSV 4 #define Amiga 5 /* type of machine doing the conversion; target is always assumed * to be 68000 processor, source is assumed to be AmigaDOS hunk-format * 68000 code... */ #define MACHINE Amiga /* * Hunk types. */ #define TEXT 0 #define DATA 1 #define BSS 2 extern long origin[]; /* origin for each type */ extern int orgspec[]; /* origin for each type specified on cmd line */ extern long entrypnt; /* entry point specified on cmd line */ extern int printing; /* !=0 if printing extra messages */extern int errflg; /* count of errors/inconsistencies found */ /* * Information about hunks: * * hrel is now filepos of start of reloc info for hunk 20Apr86 edb */ #define Hinfo struct hinfo Hinfo { long hsize; /* hunk size (bytes) */ long hpos; /* position of hunk info in file (or -1L) */ long haddr; /* starting address of hunk */ long hrsize; /* size of relocation information (bytes) */ int htype; /* hunk type (TEXT, DATA, BSS, or -1) */ int hunkno; /* hunk number */ long hrel; /* filepos of start of reloc info for hunk */ Hinfo *hnext; /* -> next hunk in order of saddr (or NULL) */ }; Stunky!Fluff if test 1644 -ne "`wc -c < 'convert.h'`" then echo shar: "error transmitting 'convert.h'" '(should have been 1644 characters)' fi fi echo shar: "extracting 'dbugstubs.h'" '(1396 characters)' if test -f 'dbugstubs.h' then echo shar: "will not over-write existing file 'dbugstubs.h'" else cat << \Stunky!Fluff > 'dbugstubs.h' /* * dbugstubs.h - derived from dbug.h by Fred Fish * * everything real has been deleted, only the stubs remain... edb */ /************************************************************************ * * * Copyright (c) 1984, Fred Fish * * All Rights Reserved * * * * This software and/or documentation is released into the * * public domain for personal, non-commercial use only. * * Limited rights to use, modify, and redistribute are hereby * * granted for non-commercial purposes, provided that all * * copyright notices remain intact and all changes are clearly * * documented. The author makes no warranty of any kind with * * respect to this product and explicitly disclaims any implied * * warranties of merchantability or fitness for any particular * * purpose. * * * ************************************************************************ */ # define DBUG_ENTER(a1) # define DBUG_RETURN(a1) return(a1) # define DBUG_VOID_RETURN return # define DBUG_EXECUTE(keyword,a1) # define DBUG_2(keyword,format) # define DBUG_3(keyword,format,a1) # define DBUG_4(keyword,format,a1,a2) # define DBUG_5(keyword,format,a1,a2,a3) # define DBUG_PUSH(a1) # define DBUG_POP() # define DBUG_PROCESS(a1) # define DBUG_FILE (stderr) # define DBUG_SETJMP setjmp # define DBUG_LONGJMP longjmp Stunky!Fluff if test 1396 -ne "`wc -c < 'dbugstubs.h'`" then echo shar: "error transmitting 'dbugstubs.h'" '(should have been 1396 characters)' fi fi echo shar: "extracting 'dl.c'" '(5812 characters)' if test -f 'dl.c' then echo shar: "will not over-write existing file 'dl.c'" else cat << \Stunky!Fluff > 'dl.c' /* * dl.c * * Convert bin.out file to Motorola S-record text file * Copyright (c) 1986 Eric D. Black * * Usage: * dl [-o oooooo] [-e eeeeee] binfile [srecfile] * where * oooooo is an offset added to to the address of every S-record * (no relocation of addresses in code is done) * eeeeee is the entry point (overrides any found in binfile) * binfile is the binary file in bin.out format * srecfile is the text file to receive S-records, stdout by default * addresses oooooo and eeeeee may be in hexadecimal (leading "0x"), * octal (leading "0"), otherwise decimal */ /* * Permission is given to distribute these files and the code they * generate, and to modify and/or extend them, providing that: * 1) All copyright notices remain intact (you may copyright your * specific changes) * 2) All source code accompanies any distribution, including any * changes and/or enhancements you may have made * 3) Any changes you make are clearly indicated * 4) No direct profit results from that distribution (i.e. you * may not sell this program or anything derived from it, but * you may include it at no charge on a system you sell for profit), * and you may give it away * */ #include <stdio.h> #include "bin.out.h" extern char getopt(); extern char *optarg; extern int optind; extern int Enable_Abort; FILE *infile; FILE *outfile; int eflag = 0; int oflag = 0; int entrypt = 0; int offset = 0; main(argc,argv) int argc; char *argv[]; { char c; /* * Process command line using getopt(3) */ if(argc<2) { fprintf(stderr,"Usage: dl [-e xxxx] infile [outfile]\n"); exit(1); } while ((c = getopt(argc, argv, "e:o:")) != EOF) { switch(c) { case 'e': entrypt = getnum(optarg); eflag++; break; case 'o': offset = getnum(optarg); oflag++; break; default: exit(1); /* error msg is printed by getopt */ } } argv += optind; argc -= optind; /* * Get input, output file names */ if((infile=fopen(argv[0],"r"))==NULL) { /* open infile */ fprintf(stderr,"dl: Can't open %s\n",argv[0]); exit(1); } if (argc>1) { if ((outfile = fopen(argv[1],"w")) == NULL) { fprintf(stderr,"dl: Can't open %s\n",argv[1]); exit(1); } } else outfile = stdout; Enable_Abort = 1; dofile(); fclose(infile); fclose(outfile); } /* * Translate input bin.out file to ASCII S-records in output file */ #define RECSIZE 32 /* Size of Motorola S-type records */ dofile() { struct bin binhdr; int Saddr; /* * get header info */ if(fread(&binhdr, sizeof(struct bin),1,infile) != 1) { fprintf(stderr,"dl: error reading input file\n"); exit(1); } if(binhdr.b_magic != BMAGIC) { /* check magic number */ fprintf(stderr,"dl: input not proper b.out file\n"); exit(1); } /* * Entry point is: * 1) as specified on command line, or * 2) as found in input bin.out header (plus offset), or * 3) start of text segment (plus offset) */ if (!eflag) { entrypt = binhdr.b_entry ? binhdr.b_entry : binhdr.b_text; entrypt += offset; } Saddr = offset; /* * Output records for TEXT portion */ outbin(infile,Saddr,binhdr.b_text); Saddr += binhdr.b_text; /* adjust output address */ /* * Output records for DATA segment */ outbin(infile,Saddr,binhdr.b_data); Saddr += binhdr.b_data; /* adjust output address */ /* * Output entry point: as in file header, * else default to start address */ print_s_rec(7,0,0,entrypt); } int checksum; /* * print out one S record of given type */ print_s_rec(type,buffer,Dcount,addr) char *buffer; int Dcount, addr; { fprintf(outfile,"S%d",type); checksum = 0; checkout((char) Dcount+5); checkout((char) (addr>>24)); checkout((char) (addr>>16)); checkout((char) (addr>>8)); checkout((char) addr); while (Dcount--) checkout(*buffer++); puthex(~(checksum & 0XFF)); fprintf(outfile,"\n"); } /* * output byte as two hex chars, keeping running checksum */ checkout(c) char c; { checksum += c; puthex(c); } #define hex(c) c>9 ? c+0X37 : c+0X30 /* macro for hex convert */ /* * print byte as two hex chars */ puthex(b) char b; { char c1,c2; c1=(b>>4) & 0XF; c2=b & 0XF; c1=hex(c1); c2=hex(c2); fprintf(outfile,"%c%c",c1,c2); } /* * put out records from a buffer, using addr as starting S-record * address, for size bytes */ outbuf(buffer,addr,size) char *buffer; int addr, size; { int count, /* counts total number of bytes processed*/ Dcount; /* number of bytes in current record */ for(count=0; count<size; count += RECSIZE) { Dcount= (size-count<RECSIZE) ? size-count : RECSIZE; print_s_rec(3,buffer,Dcount,addr); buffer += Dcount; addr += Dcount; } } /* * put out records from a file, reading from current filepos for size bytes, * using addr as starting S-record address, for size bytes */ outbin(file,addr,size) FILE *file; int addr, size; { int count, /* counts total number of bytes processed*/ Dcount; /* number of bytes in current record */ char buffer[RECSIZE]; /* buffer for data */ for(count=0; count<size; count += RECSIZE) { Dcount= (size-count<RECSIZE) ? size-count : RECSIZE; if(fread(buffer,Dcount,1,file) != 1) { fprintf(stderr,"Input read error\n"); exit(1); } print_s_rec(3,buffer,Dcount,addr); addr += Dcount; } } Stunky!Fluff if test 5812 -ne "`wc -c < 'dl.c'`" then echo shar: "error transmitting 'dl.c'" '(should have been 5812 characters)' fi fi echo shar: "extracting 'dohunk.c'" '(4430 characters)' if test -f 'dohunk.c' then echo shar: "will not over-write existing file 'dohunk.c'" else cat << \Stunky!Fluff > 'dohunk.c' /* * dohunk.c - Do hunk output & relocation for unhunk program. * 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 <stdio.h> #include "convert.h" #include "hunk.h" #include "bin.out.h" #ifdef DBUG #include <local/dbug.h> #else #include "dbugstubs.h" #endif /* hunk information */ extern Hinfo **hunk; /* -> vector of ptrs to Hinfo structs */ extern Hinfo *firsthunk; /* -> first hunk */ extern int nhunks; /* #hunks in input file */ extern int curhunk; /* current hunk# */ extern int hvalid; /* state variable (to bump curhunk) */ extern long filpos; /* position in input file */ extern long siz[3]; /* segment sizes */ extern long maxhunk; /* size of biggest hunk found */ extern long *hunkbuf; /* -> buffer for doing hunk relocation */ extern char *secname; /* "Text", "Data", "BSS" section name strs */ /* * Generate memory image file from hunk format load file and * information collected into Hinfo structs by 1st pass in convert() */ output(ifd, ofd) int ifd, ofd; { struct bin bin_hd; int i; Hinfo *hu; DBUG_ENTER("output"); /* * Write header, then hunks to output file in sorted order; * for each hunk, read it into buffer, read relocation * info & do relocation; then write buffer to output file */ bin_hd.b_magic = BMAGIC; bin_hd.b_text = siz[TEXT]; bin_hd.b_data = siz[DATA]; bin_hd.b_bss = siz[BSS]; bin_hd.b_txorg = origin[TEXT]; bin_hd.b_dtorg = origin[DATA]; bin_hd.b_bsorg = origin[BSS]; bin_hd.b_entry = entrypnt; for (i=0; i<8; i++) bin_hd.b_rsrv[i] = 0; if (write(ofd, &bin_hd, sizeof(bin_hd)) != sizeof(bin_hd)) { panic("Can't write output file\n"); } DBUG_3("mem","malloc'ing %d bytes for hunkbuf", maxhunk); if ((hunkbuf = (long *)malloc((int)maxhunk)) == NULL) allerr(); for (hu = firsthunk; hu != NULL; hu = hu->hnext) if (hu->htype == TEXT || hu->htype == DATA) { lseek(ifd, hu->hpos, 0); /* get hunk */ if (read(ifd, hunkbuf, (int)hu->hsize) != (int)hu->hsize) panic("Error reading input file."); DBUG_4("rel","hunk %d, %ld bytes", hu->hunkno, (int)hu->hsize); /* * relocate hunk in buffer */ if(hu->hsize) { /* for nonzero-size hunks */ reloc(hunkbuf, ifd, hu); /* relocate hunk */ if (write(ofd, hunkbuf, (int)hu->hsize) != (int)hu->hsize) panic("Error writing output file."); } else { DBUG_3("rel","hunk %d zero length", hu->hunkno); } } DBUG_2("mem", "freeing hunkbuf"); free(hunkbuf); DBUG_RETURN(0); } /* * Read relocation records from input hunk file, perform relocation * on hunk in buffer */ reloc(buffer, fd, hp) char *buffer; int fd; Hinfo *hp; { long pos; long hunksize; long numoffset; long hunknum; long reloffset; Hinfo *h; DBUG_ENTER("reloc"); pos = hp->hrel; if(pos==0L) { DBUG_2("rel", "no relocation info for this hunk"); DBUG_RETURN(0); } hunksize = hp->hsize; DBUG_4("rel","reloc start filepos %ld, buffer at 0x%lx", pos, buffer); lseek(fd, pos, 0); /* go to 1st relocation record this hunk */ do { getlong(fd, &numoffset); /* get # of offsets to relocate */ DBUG_3("rel","%ld offsets", numoffset); if (numoffset) { getlong(fd, &hunknum); /* add address of this hunk ... */ if((int)hunknum > nhunks) { printf("Bad hunk # in relocation info: %d, nhunks=%d\n", hunknum, nhunks); panic("phase error"); } h = hunk[hunknum]; DBUG_4("rel"," hunk %ld (base=0x%lx)",hunknum,h->haddr); while(numoffset--) { getlong(fd, &reloffset); /* ... to word at this offset */ DBUG_5("rel"," offset 0x%lx (addr 0x%lx) = 0x%lx",reloffset,buffer+reloffset,*(long *)(buffer+reloffset)); if(reloffset>hunksize-3) { fprintf(stderr, "Unreasonable relocation offset 0x%lx in %s hunk %d", reloffset, secname[h->htype], h->hunkno); panic("Input file possibly garbled"); } /* * Add base address of specified hunk to the contents of * longword at specified byte offset * (isn't the combination of bytes & longwords clear??) */ *(long *)(buffer+reloffset) += h->haddr; DBUG_3("rel"," new contents = 0x%lx", *(long *)(buffer+reloffset)); } } } while (numoffset); DBUG_RETURN(0); } Stunky!Fluff if test 4430 -ne "`wc -c < 'dohunk.c'`" then echo shar: "error transmitting 'dohunk.c'" '(should have been 4430 characters)' fi fi echo shar: "extracting 'hunk.h'" '(2605 characters)' if test -f 'hunk.h' then echo shar: "will not over-write existing file 'hunk.h'" else cat << \Stunky!Fluff > 'hunk.h' /* hunk.h 12 Mar 86 edb */ /* * defines for understanding object & load module formats * Copyright 1986 Eric D. Black */ /* * Hunks are blocks of code or data or bss reservations, possibly with * blocks of relocation information and symbols, with optional names. * Object modules are output of compilers (e.g. *.o files), load modules * are similar with all external references resolved. The program loader * uses hunk relocation information to relocate pieces of code and/or * data when loaded into memory for execution. * * Each hunk consists of some number of hunk records, each of which * consists of a longword hunk type code, a longword count of data words, * and that number of data words. */ /* * Hunk type codes (decimal, hex equivalent in comments) */ #define HUNK_UNIT 999 /* 3e7 Start of program unit */ #define HUNK_NAME 1000 /* 3e8 Name of a hunk */ #define HUNK_CODE 1001 /* 3e9 Code segment */ #define HUNK_DATA 1002 /* 3ea Initialized Data segment */ #define HUNK_BSS 1003 /* 3eb Unitialized Data segment */ #define HUNK_RELOC32 1004 /* 3ec 32-bit relocation list */ #define HUNK_RELOC16 1005 /* 3ed 16-bit PC-relative relocation info */ #define HUNK_RELOC8 1006 /* 3ee 8-bit PC-relative relocation info */ #define HUNK_EXT 1007 /* 3ef External symbol info */ #define HUNK_SYMBOL 1008 /* 3f0 Symbol table info */ #define HUNK_DEBUG 1009 /* 3f1 Debug data */ #define HUNK_END 1010 /* 3f2 End of this hunk */ #define HUNK_HEADER 1011 /* 3f3 hunk summary info for loader */ #define HUNK_OVERLAY 1013 /* 3f5 overlay table info */ #define HUNK_BREAK 1014 /* 3f6 end of overlay node */ /* * External symbol info * Each HUNK_EXT record is a null-terminated list of symbol data units; * each symbol data unit consists of a type byte, 3-byte symbol length * in longwords, symbol name (null-padded if necessary), and data word(s). * EXTSYMB has null-terminated list of symbol data units, * EXTDEF, EXTABS, EXTRES have 1 longword of data, * EXTREF32, EXTREF16, EXTREF8 have longword count and n longwords of data, * EXTCOMMON also has longword size of common block before the data count. */ #define HUNK_EXTSYMB 0 /* symbol table */ #define HUNK_EXTDEF 1 /* relocatable definition */ #define HUNK_EXTABS 2 /* absolute definition */ #define HUNK_EXTRES 3 /* resident library definition */ #define HUNK_EXTREF32 129 /* 32-bit reference to symbol */ #define HUNK_EXTCOMMON 130 /* 32-bit reference to COMMON */ #define HUNK_EXTREF16 131 /* 16-bit reference to symbol */ #define HUNK_EXTREF8 132 /* 8-bit reference to symbol */ Stunky!Fluff if test 2605 -ne "`wc -c < 'hunk.h'`" then echo shar: "error transmitting 'hunk.h'" '(should have been 2605 characters)' fi fi echo shar: "extracting 'longio.c'" '(2488 characters)' if test -f 'longio.c' then echo shar: "will not over-write existing file 'longio.c'" else cat << \Stunky!Fluff > 'longio.c' /* * longio.h Copyright 1985 Landon M. Dyer * * Minor mods for Amiga, DBUG macros 19Apr86 edb */ #include <stdio.h> #include "convert.h" #ifdef DBUG #include <local/dbug.h> #else #include "dbugstubs.h" #endif extern long filpos; extern int printing; extern char buf[]; /* * Get a longword or complain about premature EOF * */ getlong(fd, p_lw) int fd; long *p_lw; { DBUG_ENTER("getlong"); if (readlong(fd, p_lw) == EOF) panic("Premature EOF getting longword"); DBUG_RETURN(OK); } /* * Read 68000 longword from file, * stuff it into '*p_lw' in the * host machine's longword format. * */ readlong(fd, p_lw) int fd; long *p_lw; { char buf[4], *out; DBUG_ENTER("readlong"); DBUG_3("io", "input filepos=%ld", lseek(fd, 0L, 1)); out = (char *)p_lw; if (read(fd, buf, 4) != 4) /* probably end of file */ DBUG_RETURN(EOF); filpos += 4; #if MACHINE == MSDOS || MACHINE == VAXVMS /* * 8086/8088 conversion * hh hl lh ll ==> ll lh hl hh */ out[0] = buf[3]; out[1] = buf[2]; out[2] = buf[1]; out[3] = buf[0]; #endif #if MACHINE == Amiga out[0] = buf[0]; out[1] = buf[1]; out[2] = buf[2]; out[3] = buf[3]; #endif DBUG_4("io","got 0x%lx, ret=0x%lx", *(long *)buf, *(long *)out); DBUG_RETURN(0); } /* * Write word to file, * in 68000 format. */ writeword(fd, w) int fd; unsigned int w; { char buf[2], *out; DBUG_ENTER("writeword"); out = (char *)&w; #if MACHINE == MSDOS || MACHINE == VAXVMS buf[0] = out[1]; buf[1] = out[0]; #endif #if MACHINE == Amiga buf[0] = out[0]; buf[1] = out[1]; #endif DBUG_3("io", "out filepos=0x%lx", lseek(fd, 0L, 1)); DBUG_4("io", "got 0x%x, writing 0x%x", w, *(unsigned short *) out); if (write(fd, buf, 2) != 2) panic("Write error (word)"); DBUG_RETURN(0); } /* * Write longword to file, in * 68000 format. */ writelong(fd, lw) int fd; long lw; { char buf[4], *out; DBUG_ENTER("writelong"); out = (char *)&lw; #if MACHINE == MSDOS || MACHINE == VAXVMS buf[0] = out[3]; buf[1] = out[2]; buf[2] = out[1]; buf[3] = out[0]; #endif #if MACHINE == Amiga buf[0] = out[0]; buf[1] = out[1]; buf[2] = out[2]; buf[3] = out[3]; #endif DBUG_3("io", "out filepos=0x%lx", lseek(fd, 0L, 1)); DBUG_4("io", "got 0x%lx, writing 0x%lx", lw, *(long *) out); if (write(fd, buf, 4) != 4) panic("Write error (longword)"); DBUG_RETURN(0); } Stunky!Fluff if test 2488 -ne "`wc -c < 'longio.c'`" then echo shar: "error transmitting 'longio.c'" '(should have been 2488 characters)' fi fi echo shar: "extracting 'unhunk.c'" '(6366 characters)' if test -f 'unhunk.c' then echo shar: "will not over-write existing file 'unhunk.c'" else cat << \Stunky!Fluff > 'unhunk.c' /* unhunk.c Copyright (C) 1986 Eric D. Black */ /* * UNHUNK -- convert AmigaDOS "hunk"-format load files to * memory image similar to a.out; performs relocation, * allows specification of text, data, and bss origins. * Output suitable for simple processing & downloading * to PROM programmers... * * Portions of UNHUNK are based on the CVT Amiga->ST conversion * program by Landon Dyer; these appear in the files convert.c, binfio.c, * longio.c, and convert.h, which are all Copyright 1985 by Landon M. Dyer. * * Changes to those files, and all other code is Copyright 1986 by * Eric D. Black. Permission is given to distribute these files and * the code they generate, and to modify and/or extend them, providing * that: * 1) All copyright notices remain intact (you may copyright your * specific changes) * 2) All source code accompanies any distribution, including any * changes and/or enhancements you may have made * 3) Any changes you make are clearly indicated * 4) No direct profit results from that distribution (i.e. you * may not sell this program or anything derived from it, but * you may include it at no charge on a system you sell for profit), * and you may give it away * * Debug macros and routines are from the 'dbug' package by Fred Fish, * and are available on his freely redistributable Amiga library disks; * these are not included here. If you have them, and want to * compile with the debug code, compile with '-DDBUG'; otherwise the extra * debug statements will generate no code * */ #include <stdio.h> #include "convert.h" #ifdef DBUG #include <local/dbug.h> #else #include "dbugstubs.h" #endif char *version = "1.0"; char *date = "21-Apr-1986"; #define STRINGSIZ 256 #define READ 0 #define WRITE 1 int orgspec[3] = {0,0,0}; /* text, data, bss origin specified on cmdlin */ int printing = 0; /* print hunk information */ /* * origin of text, data, bss segments, seg types 0-2 defined in convert.h */ long origin[3] = { 0,0,0 }; long entrypnt = 0; /* entry offset in text section */ int errflg = 0; /* count of errors encountered */ extern int Enable_Abort; /* set non-zero to enable ^C and ^D abort */ main(argc, argv) int argc; char **argv; { int ifd, ofd; char c; extern char *optarg; extern int optind; DBUG_ENTER("main"); DBUG_PROCESS("unhunk"); /* since we get argv[0]="c" (!) */ /* * No instructions: * print info about use and * exit with bad return code. * (it's not worth making this work from the Workbench...) */ if (argc <= 1) { usage(); printf("\nUNHUNK Version %s (%s)\n", version, date); printf("This program is copyright (c) 1986 Eric D. Black\n"); printf(" and (c) 1985 Landon M. Dyer\n"); printf("It may be freely redistributed to others\n"); printf("ONLY if the following conditions are met:\n"); printf("\t1. You do not make a profit on it.\n"); printf("\t2. If you have the source code, you give that away, too.\n"); printf("\t3. You include this notice in the source and object code.\n"); exit(1); } /* * Parse command line, using getopt(), public domain goodie from * Henry Spencer, available from almost any USENET site */ while((c = getopt(argc, argv, "#:t:d:b:D:p")) != EOF) { switch(c) { case '#': /* debug package arguments */ DBUG_PUSH(optarg); break; case 't': /* text origin */ DBUG_3("args", "text origin '%s'", optarg); origin[TEXT] = getnum(optarg); orgspec[TEXT]++; DBUG_3("args", "text origin=0x%x", origin[TEXT]); break; case 'd': /* data origin */ DBUG_3("args", "data origin '%s'", optarg); origin[DATA] = getnum(optarg); orgspec[DATA]++; DBUG_3("args", "data origin=0x%x", origin[DATA]); break; case 'b': /* bss origin */ DBUG_3("args", "bss origin '%s'", optarg); origin[BSS] = getnum(optarg); orgspec[BSS]++; DBUG_3("args", "bss origin=0x%x", origin[BSS]); break; case 'p': /* print hunk info */ printing++; break; default: DBUG_3("args", "bad arg, exit status=5", 0); exit(5); /* error message is printed by getopt */ } } argv += optind; /* skip past flags */ argc -= optind; /* * Since we only use level 1 I/O (except for printf's...), and * only use malloc() to allocate memory, we can go ahead and * enable the Lattice C runtime check for ^C and ^D */ Enable_Abort++; if ((ifd = ebinopen(argv[0], READ)) < 0) { printf("Can't open input file: %s\n", argv[0]); exit(5); } if ((ofd = ebinopen(argv[1], WRITE)) < 0) { printf("Can't open output file: %s\n", argv[1]); exit(5); } /* * This is where we do the actual work */ convert(ifd, ofd); close(ifd); close(ofd); printf("Done\n%d errors encountered\n", errflg); exit(0); } /* end of main */ /* * Print info about usage */ usage() { DBUG_ENTER("usage"); printf("\nUsage:\n"); printf("\tunhunk [-t xxxx] [-d xxxx] [-b xxxx] infile outfile\n"); printf("\t(both input and output files are REQUIRED)\n"); DBUG_RETURN(0); } /* * Panic and give up. */ panic(s) char *s; { DBUG_ENTER("panic"); printf("unhunk disaster: %s\nGiving up...\n", s); exit(10); /* NOTREACHED */ DBUG_RETURN(0); } /* * Convert char string to long * prefixes understood: 0x (hex), 0 (octal), otherwise decimal * leading '-' means 2's complement */ long getnum(str) char *str; { long num; char *foo; int negflag; extern long strtol(); DBUG_ENTER("getnum"); if (*str == '-') { DBUG_3("args", "minus sign: '%s'", str); negflag = 1; str++; } else negflag = 0; DBUG_3("args", "string is: '%s'", str); #if 0 /**** this sucks! strtol() causes an address error guru med! ****/ DBUG_4("args", "about to call strtol: str='%s', &foo=0x%x", str, &foo); num = strtol(str, &foo, 0); DBUG_4("args", "got back from strtol, got num=%ld (0x%lx)", num, num); #else 0 if (*str == '0') { str++; if(*str == 'x' || *str == 'X') stch_i(++str, &num); else panic("Can't handle octal args"); } else stcd_i(str, &num); #endif 0 if (negflag) num = (long) (0 - (int) num); DBUG_4("args", "conversion returns %ld (0x%lx)", num, num); DBUG_RETURN(num); } Stunky!Fluff if test 6366 -ne "`wc -c < 'unhunk.c'`" then echo shar: "error transmitting 'unhunk.c'" '(should have been 6366 characters)' fi fi exit 0 # End of shell archive -- Eric Black "Garbage In, Gospel Out" UUCP: {sun,pyramid,hplabs,amdcad}!chronon!eric