/* file65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite * Print information about o65 files * * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _MSC_VER #include #endif #include #include #include #include #include #include #include "version.h" #define BUF (9*4+8) #define programname "file65" #define progversion "v0.2.1" #define author "Written by Andre Fachat" #define copyright "Copyright (C) 1997-2002 Andre Fachat." /* o65 file format mode bits */ #define FM_OBJ 0x1000 #define FM_SIZE 0x2000 #define FM_RELOC 0x4000 #define FM_CPU 0x8000 #define FM_CPU2 0x00f0 #define FM_CPU2_6502 0x0000 #define FM_CPU2_65C02 0x0010 #define FM_CPU2_65SC02 0x0020 #define FM_CPU2_65CE02 0x0030 #define FM_CPU2_NMOS 0x0040 #define FM_CPU2_65816E 0x0050 const char *cpunames[16] = { "6502", "65C02", "65SC02", "65CE02", "NMOS6502", "65816", NULL, NULL, "6809", NULL, // 1000 - "Z80", NULL, NULL, // 1010 - "8086", // 1101 - "80286", // 1110 - NULL }; int read_options(FILE *fp); int print_labels(FILE *fp, int offset); unsigned char hdr[BUF]; unsigned char cmp[] = { 1, 0, 'o', '6', '5' }; int xapar = 0; int rompar = 0; int romoff = 0; int labels = 0; int verbose = 0; void usage(FILE *fp) { fprintf(fp, "Usage: %s [options] [file]\n" "Print file information about o65 files\n" "\n", programname); fprintf(fp, " -P print the segment end addresses according to `xa' command line\n" " parameters `-b?'\n" " -a offset print `xa' ``romable'' parameter for another file behind this one\n" " in the same ROM. Add offset to start address.\n" " -A offset same as `-a', but only print the start address of the next\n" " file in the ROM\n" " -v print undefined and global labels\n" " -vv print undefined and global labels, and relocation tables\n" " --version output version information and exit\n" " --help display this help and exit\n"); } int main(int argc, char *argv[]) { int i, j, n, mode, hlen; FILE *fp; char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"}; if(argc<=1) { usage(stderr); exit(1); } i = 1; if (strstr(argv[i], "--help") || strstr(argv[i], "-?") || strstr(argv[i], "-h")) { usage(stdout); exit(0); } if (strstr(argv[i], "--version")) { version(programname, progversion, author, copyright); exit(0); } while(i=8) && (!memcmp(hdr, cmp, 5))) { mode=hdr[7]*256+hdr[6]; if(!xapar && !rompar) { printf("%s: o65 version %d %s file\n", argv[i], hdr[5], hdr[7]&0x10 ? "object" : "executable"); printf(" mode: %04x =",mode ); printf("[%s][%sbit][%s relocation][CPU %s][CPU2 %s]%s\n", (mode & 0x1000)?"object":"executable", (mode & 0x2000)?"32":"16", (mode & 0x4000)?"page":"byte", (mode & 0x8000)?"65816":"6502", cpunames[(mode & FM_CPU2) >> 4], aligntxt[mode & 3]); } if(mode & 0x2000) { fprintf(stderr,"file65: %s: 32 bit size not supported\n", argv[i]); } else { n=fread(hdr+8, 1, 18, fp); if(n<18) { fprintf(stderr,"file65: %s: truncated file\n", argv[i]); } else { if(!xapar && !rompar) { printf(" text segment @ $%04x - $%04x [$%04x bytes]\n", hdr[9]*256+hdr[8], hdr[9]*256+hdr[8]+hdr[11]*256+hdr[10], hdr[11]*256+hdr[10]); printf(" data segment @ $%04x - $%04x [$%04x bytes]\n", hdr[13]*256+hdr[12], hdr[13]*256+hdr[12]+hdr[15]*256+hdr[14], hdr[15]*256+hdr[14]); printf(" bss segment @ $%04x - $%04x [$%04x bytes]\n", hdr[17]*256+hdr[16], hdr[17]*256+hdr[16]+hdr[19]*256+hdr[18], hdr[19]*256+hdr[18]); printf(" zero segment @ $%04x - $%04x [$%04x bytes]\n", hdr[21]*256+hdr[20], hdr[21]*256+hdr[20]+hdr[23]*256+hdr[22], hdr[23]*256+hdr[22]); printf(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24], (hdr[25]*256+hdr[24])==0?"(i.e. unknown)":""); if(verbose) { read_options(fp); print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]); } } else { struct stat fbuf; hlen = 8+18+read_options(fp); stat(argv[i],&fbuf); if(xapar) { if(!rompar) printf("-bt %d ", (hdr[9]*256+hdr[8]) + (hdr[11]*256+hdr[10]) ); printf("-bd %d -bb %d -bz %d ", (hdr[13]*256+hdr[12]) + (hdr[15]*256+hdr[14]), (hdr[17]*256+hdr[16]) + (hdr[19]*256+hdr[18]), (hdr[21]*256+hdr[20]) + (hdr[23]*256+hdr[22]) ); } if(rompar==1) { printf("-A %lu ", (unsigned long)((hdr[9]*256+hdr[8]) -hlen +romoff +(fbuf.st_size))); } else if(rompar==2) { printf("%lu ", (unsigned long)((hdr[9]*256+hdr[8]) -hlen +romoff +(fbuf.st_size))); } printf("\n"); } } } } else { fprintf(stderr,"file65: %s: not an o65 file!\n", argv[i]); if(hdr[0]==1 && hdr[1]==8 && hdr[3]==8) { printf("%s: C64 BASIC executable (start address $0801)?\n", argv[i]); } else if(hdr[0]==1 && hdr[1]==4 && hdr[3]==4) { printf("%s: CBM PET BASIC executable (start address $0401)?\n", argv[i]); } } } else { fprintf(stderr,"file65: %s: %s\n", argv[i], strerror(errno)); } } i++; } return 0; } static struct { int opt; int strfl; char *string; } otab[] = { { 0, 1, "Filename" }, { 1, 0, "O/S Type" }, { 2, 1, "Assembler" }, { 3, 1, "Author" }, { 4, 1, "Creation Date" }, { -1, -1, NULL } }; static char* stab[] = { "undefined" , "absolute" , "text" , "data" , "bss" , "zero" , "-" , "-" }; void print_option(unsigned char *buf, int len) { int i, strfl=0; for(i=0;otab[i].opt>=0; i++) if(*buf==otab[i].opt) break; if(otab[i].opt>=0) { printf("fopt: %-17s: ", otab[i].string); strfl = otab[i].strfl; } else { printf("fopt: Unknown Type $%02x : ", (*buf & 0xff)); } if(strfl) { buf[len]=0; printf("%s\n", buf+1); } else { for (i=1; i 1) { printf("Relocation table for %s:\n", i ? "text":"data"); } c=fgetc(fp); while(c && c!=EOF) { c&= 0xff; while(c == 255 && c!= EOF) { offset += 254; c=fgetc(fp); if(c==EOF) break; c&= 0xff; } if(c==EOF) break; offset += c; c=fgetc(fp); if( (c & 0xe0) == 0x40 ) { lowbyte = fgetc(fp); } if( (c & 0x07) == 0 ) { index = fgetc(fp) & 0xff; index += (fgetc(fp) & 0xff) << 8; } if (verbose > 1) { printf("\t%d:%s(%s (%d)", offset, reltype[ (c>>5) & 0xf], segments[c & 0x07], (c&0x07)); if ( (c & 0xe0) == 0x40) { printf(", %02x", lowbyte); } if ( (c & 0x07) == 0) { printf(", %04x", index); } printf(")"); } c=fgetc(fp); } if (verbose > 1) { printf("\n"); } } // --------------------------------------------------------- // print global labels nud = (fgetc(fp) & 0xff); nud += ((fgetc(fp) << 8) & 0xff00); printf("Global Labels: %d\n", nud); if(nud) { do { c=fgetc(fp); while(c && c!=EOF) { fputc(c, stdout); c=fgetc(fp); } if(c==EOF) break; seg = fgetc(fp) & 0xff; off= (fgetc(fp) & 0xff); off+= ((fgetc(fp) << 8) & 0xff00); printf(" (segID=%d (%s), offset=%04x)\n", seg, stab[seg&7], off); } while(--nud); } return 0; }