home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CBM Funet Archive
/
cbm-funet-archive-2003.iso
/
cbm
/
programming
/
msdos
/
xa214f.lzh
/
xa214f
/
misc
/
reloc65.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-04-16
|
9KB
|
340 lines
/*
XA65 - 6502 CROSS ASSEMBLER AND UTILITY SUITE
RELOC65 - RELOCATES 'O65' FILES
cOPYRIGHT (c) 1997 aNDR{$e9} 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.
*/
#INCLUDE <STDIO.H>
#INCLUDE <STDLIB.H>
#INCLUDE <SYS/STAT.H>
#INCLUDE <UNISTD.H>
#INCLUDE <ERRNO.H>
#INCLUDE <STRING.H>
#DEFINEbuf(9*2+8)/* 16 BIT HEADER */
TYPEDEF STRUCT {$7b}
CHAR *FNAME;
SIZE_T FSIZE;
UNSIGNED CHAR*BUF;
INTTBASE, TLEN, DBASE, DLEN, BBASE, BLEN, ZBASE, ZLEN;
INTTDIFF, DDIFF, BDIFF, ZDIFF;
UNSIGNED CHAR*SEGT;
UNSIGNED CHAR*SEGD;
UNSIGNED CHAR *UTAB;
UNSIGNED CHAR *RTTAB;
UNSIGNED CHAR *RDTAB;
UNSIGNED CHAR *EXTAB;
{$7d} FILE65;
INT READ_OPTIONS(UNSIGNED CHAR *F);
INT READ_UNDEF(UNSIGNED CHAR *F);
UNSIGNED CHAR *RELOC_SEG(UNSIGNED CHAR *F, INT LEN, UNSIGNED CHAR *RTAB, FILE65 *FP);
UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *, FILE65 *FP);
FILE65 FILE;
UNSIGNED CHAR CMP[] = {$7b} 1, 0, 'O', '6', '5' {$7d};
VOID USAGE(VOID) {$7b}
PRINTF("RELOC65: RELOCATES 'O65' FILES\N"
" RELOC65 [OPTIONS] [FILENAMES...]\N"
"OPTIONS:\N"
" -V = PRINT VERSION NUMBER\N"
" -H, -? = PRINT THIS HELP\N"
" -B? ADR = RELOCATES SEGMENT '?' (I.E. 'T' FOR TEXT SEGMENT,\N"
" 'D' FOR DATA, 'B' FOR BSS AND 'Z' FOR ZEROPAGE) TO THE NEW\N"
" ADDRESS 'ADR'.\N"
" -O FILE = USES 'FILE' AS OUTPUT FILE. OTHERWISE WRITE TO 'A.O65'.\N"
" -X? = EXTRACTS TEXT '?'='T' OR DATA '?'='D' SEGMENT FROM FILE\N"
" INSTEAD OF WRITING BACK THE WHOLE FILE\N"
);
EXIT(0);
{$7d}
INT MAIN(INT ARGC, CHAR *ARGV[]) {$7b}
INT I = 1, MODE, HLEN;
SIZE_T N;
file *FP;
INT TFLAG=0, DFLAG=0, BFLAG=0, ZFLAG=0;
INT TBASE, DBASE, BBASE, ZBASE;
CHAR *OUTFILE = "A.O65";
INT EXTRACT = 0;
IF(ARGC<=1) USAGE();
WHILE(I<ARGC) {$7b}
IF(ARGV[I][0]=='-') {$7b}
/* PROCESS OPTIONS */
SWITCH(ARGV[I][1]) {$7b}
CASE 'V':
PRINTF("RELOC65 VERSION 0.2 (C) 1997 A.FACHAT\N");
BREAK;
CASE 'O':
IF(ARGV[I][2]) OUTFILE=ARGV[I]+2;
ELSE OUTFILE=ARGV[++I];
BREAK;
CASE 'B':
SWITCH(ARGV[I][2]) {$7b}
CASE 'T':
TFLAG= 1;
IF(ARGV[I][3]) TBASE = ATOI(ARGV[I]+3);
ELSE TBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'D':
DFLAG= 1;
IF(ARGV[I][3]) DBASE = ATOI(ARGV[I]+3);
ELSE DBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'B':
BFLAG= 1;
IF(ARGV[I][3]) BBASE = ATOI(ARGV[I]+3);
ELSE BBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'Z':
ZFLAG= 1;
IF(ARGV[I][3]) ZBASE = ATOI(ARGV[I]+3);
ELSE ZBASE = ATOI(ARGV[++I]);
BREAK;
DEFAULT:
PRINTF("uNKNOWN SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
BREAK;
{$7d}
BREAK;
CASE 'X':/* EXTRACT SEGMENT */
SWITCH(ARGV[I][2]) {$7b}
CASE 'T':
EXTRACT = 1;
BREAK;
CASE 'D':
EXTRACT = 2;
BREAK;
CASE 'Z':
CASE 'B':
PRINTF("cANNOT EXTRACT SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
BREAK;
DEFAULT:
PRINTF("uNKNOWN SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
BREAK;
{$7d}
BREAK;
CASE 'H':
CASE '?':
USAGE();
DEFAULT:
FPRINTF(STDERR,"RELOC65: %S UNKNOWN OPTION, USE '-?' FOR HELP\N",ARGV[I]);
BREAK;
{$7d}
{$7d} ELSE {$7b}
STRUCT STAT FS;
FILE.FNAME=ARGV[I];
STAT(ARGV[I], &FS);
FILE.FSIZE=FS.ST_SIZE;
FILE.BUF=MALLOC(FILE.FSIZE);
IF(!FILE.BUF) {$7b}
FPRINTF(STDERR,"oOPS, NO MORE MEMORY!\N");
EXIT(1);
{$7d}
PRINTF("RELOC65: READ FILE %S -> %S\N",ARGV[I],OUTFILE);
FP = FOPEN(ARGV[I],"RB");
IF(FP) {$7b}
N = FREAD(FILE.BUF, 1, FILE.FSIZE, FP);
FCLOSE(FP);
IF((N>=FILE.FSIZE) && (!MEMCMP(FILE.BUF, CMP, 5))) {$7b}
MODE=FILE.BUF[7]*256+FILE.BUF[6];
IF(MODE & 0X2000) {$7b}
FPRINTF(STDERR,"RELOC65: %S: 32 BIT SIZE NOT SUPPORTED\N", ARGV[I]);
{$7d} ELSE
IF(MODE & 0X4000) {$7b}
FPRINTF(STDERR,"RELOC65: %S: PAGEWISE RELOCATION NOT SUPPORTED\N", ARGV[I]);
{$7d} ELSE {$7b}
HLEN = buf+READ_OPTIONS(FILE.BUF+buf);
FILE.TBASE = FILE.BUF[ 9]*256+FILE.BUF[ 8];
FILE.TLEN = FILE.BUF[11]*256+FILE.BUF[10];
FILE.TDIFF = TFLAG? TBASE - FILE.TBASE : 0;
FILE.DBASE = FILE.BUF[13]*256+FILE.BUF[12];
FILE.DLEN = FILE.BUF[15]*256+FILE.BUF[14];
FILE.DDIFF = DFLAG? DBASE - FILE.DBASE : 0;
FILE.BBASE = FILE.BUF[17]*256+FILE.BUF[16];
FILE.BLEN = FILE.BUF[19]*256+FILE.BUF[18];
FILE.BDIFF = BFLAG? BBASE - FILE.BBASE : 0;
FILE.ZBASE = FILE.BUF[21]*256+FILE.BUF[20];
FILE.ZLEN = FILE.BUF[23]*256+FILE.BUF[21];
FILE.ZDIFF = ZFLAG? ZBASE - FILE.ZBASE : 0;
FILE.SEGT = FILE.BUF + HLEN;
FILE.SEGD = FILE.SEGT + FILE.TLEN;
FILE.UTAB = FILE.SEGD + FILE.DLEN;
FILE.RTTAB = FILE.UTAB + READ_UNDEF(FILE.UTAB);
FILE.RDTAB = RELOC_SEG(FILE.SEGT, FILE.TLEN, FILE.RTTAB, &FILE);
FILE.EXTAB = RELOC_SEG(FILE.SEGD, FILE.DLEN, FILE.RDTAB, &FILE);
RELOC_GLOBALS(FILE.EXTAB, &FILE);
IF(TFLAG) {$7b}
FILE.BUF[ 9]= (TBASE>>8)&255;
FILE.BUF[ 8]= TBASE & 255;
{$7d}
IF(DFLAG) {$7b}
FILE.BUF[13]= (DBASE>>8)&255;
FILE.BUF[12]= DBASE & 255;
{$7d}
IF(BFLAG) {$7b}
FILE.BUF[17]= (BBASE>>8)&255;
FILE.BUF[16]= BBASE & 255;
{$7d}
IF(ZFLAG) {$7b}
FILE.BUF[21]= (ZBASE>>8)&255;
FILE.BUF[20]= ZBASE & 255;
{$7d}
FP = FOPEN(OUTFILE, "WB");
IF(FP) {$7b}
SWITCH(EXTRACT) {$7b}
CASE 0:/* WHOLE FILE */
FWRITE(FILE.BUF, 1, FILE.FSIZE, FP);
BREAK;
CASE 1:/* TEXT SEGMENT */
FWRITE(FILE.SEGT, 1, FILE.TLEN, FP);
BREAK;
CASE 2:
FWRITE(FILE.SEGD, 1, FILE.DLEN, FP);
BREAK;
{$7d}
FCLOSE(FP);
{$7d} ELSE {$7b}
FPRINTF(STDERR,"RELOC65: WRITE '%S': %S\N",
OUTFILE, STRERROR(ERRNO));
{$7d}
{$7d}
{$7d} ELSE {$7b}
FPRINTF(STDERR,"RELOC65: %S: NOT AN O65 FILE!\N", ARGV[I]);
IF(FILE.BUF[0]==1 && FILE.BUF[1]==8 && FILE.BUF[3]==8) {$7b}
PRINTF("%S: c64 basic EXECUTABLE (START ADDRESS $0801)?\N", ARGV[I]);
{$7d} ELSE
IF(FILE.BUF[0]==1 && FILE.BUF[1]==4 && FILE.BUF[3]==4) {$7b}
PRINTF("%S: cbm pet basic EXECUTABLE (START ADDRESS $0401)?\N", ARGV[I]);
{$7d}
{$7d}
{$7d} ELSE {$7b}
FPRINTF(STDERR,"RELOC65: READ '%S': %S\N",
ARGV[I], STRERROR(ERRNO));
{$7d}
{$7d}
I++;
{$7d}
EXIT(0);
{$7d}
INT READ_OPTIONS(UNSIGNED CHAR *BUF) {$7b}
INT C, L=0;
C=BUF[0];
WHILE(C && C!=eof) {$7b}
C&=255;
L+=C;
C=BUF[L];
{$7d}
RETURN ++L;
{$7d}
INT READ_UNDEF(UNSIGNED CHAR *BUF) {$7b}
INT N, L = 2;
N = BUF[0] + 256*BUF[1];
WHILE(N){$7b}
N--;
WHILE(!BUF[L++]);
{$7d}
RETURN L;
{$7d}
#DEFINERELDIFF(S)(((S)==2)?FP->TDIFF:(((S)==3)?FP->DDIFF:(((S)==4)?FP->BDIFF:(((S)==5)?FP->ZDIFF:0))))
UNSIGNED CHAR *RELOC_SEG(UNSIGNED CHAR *BUF, INT LEN, UNSIGNED CHAR *RTAB, FILE65 *FP) {$7b}
INT ADR = -1;
INT TYPE, SEG, OLD, NEW;
/*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
WHILE(*RTAB) {$7b}
IF((*RTAB & 255) == 255) {$7b}
ADR += 254;
RTAB++;
{$7d} ELSE {$7b}
ADR += *RTAB & 255;
RTAB++;
TYPE = *RTAB & 0XE0;
SEG = *RTAB & 0X07;
/*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",RTAB-1, *(RTAB-1), ADR, TYPE, SEG);*/
RTAB++;
SWITCH(TYPE) {$7b}
CASE 0X80:
OLD = BUF[ADR] + 256*BUF[ADR+1];
NEW = OLD + RELDIFF(SEG);
BUF[ADR] = NEW & 255;
BUF[ADR+1] = (NEW>>8)&255;
BREAK;
CASE 0X40:
OLD = BUF[ADR]*256 + *RTAB;
NEW = OLD + RELDIFF(SEG);
BUF[ADR] = (NEW>>8)&255;
*RTAB = NEW & 255;
RTAB++;
BREAK;
CASE 0X20:
OLD = BUF[ADR];
NEW = OLD + RELDIFF(SEG);
BUF[ADR] = NEW & 255;
BREAK;
{$7d}
IF(SEG==0) RTAB+=2;
{$7d}
{$7d}
IF(ADR > LEN) {$7b}
FPRINTF(STDERR,"RELOC65: %S: wARNING: RELOCATION TABLE ENTRIES PAST SEGMENT END!\N",
FP->FNAME);
{$7d}
RETURN ++RTAB;
{$7d}
UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *BUF, FILE65 *FP) {$7b}
INT N, OLD, NEW, SEG;
N = BUF[0] + 256*BUF[1];
BUF +=2;
WHILE(N) {$7b}
/*PRINTF("RELOCATING %S, ", BUF);*/
WHILE(*(BUF++));
SEG = *BUF;
OLD = BUF[1] + 256*BUF[2];
NEW = OLD + RELDIFF(SEG);
/*PRINTF("OLD=%04X, SEG=%D, REL=%04X, NEW=%04X\N", OLD, SEG, RELDIFF(SEG), NEW);*/
BUF[1] = NEW & 255;
BUF[2] = (NEW>>8) & 255;
BUF +=3;
N--;
{$7d}
RETURN BUF;
{$7d}