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 >
C/C++ Source or Header  |  1997-04-16  |  9KB  |  340 lines

  1.  
  2. /*
  3.     XA65 - 6502 CROSS ASSEMBLER AND UTILITY SUITE
  4.     RELOC65 - RELOCATES 'O65' FILES 
  5.     cOPYRIGHT (c) 1997 aNDR{$e9} fACHAT (A.FACHAT@PHYSIK.TU-CHEMNITZ.DE)
  6.  
  7.     tHIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
  8.     IT UNDER THE TERMS OF THE gnu gENERAL pUBLIC lICENSE AS PUBLISHED BY
  9.     THE fREE sOFTWARE fOUNDATION; EITHER VERSION 2 OF THE lICENSE, OR
  10.     (AT YOUR OPTION) ANY LATER VERSION.
  11.  
  12.     tHIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
  13.     BUT without any warranty; WITHOUT EVEN THE IMPLIED WARRANTY OF
  14.     merchantability OR fitness for a particular purpose.  sEE THE
  15.     gnu gENERAL pUBLIC lICENSE FOR MORE DETAILS.
  16.  
  17.     yOU SHOULD HAVE RECEIVED A COPY OF THE gnu gENERAL pUBLIC lICENSE
  18.     ALONG WITH THIS PROGRAM; IF NOT, WRITE TO THE fREE sOFTWARE
  19.     fOUNDATION, iNC., 675 mASS aVE, cAMBRIDGE, ma 02139, usa.
  20. */
  21.  
  22. #INCLUDE <STDIO.H>
  23. #INCLUDE <STDLIB.H>
  24. #INCLUDE <SYS/STAT.H>
  25. #INCLUDE <UNISTD.H>
  26. #INCLUDE <ERRNO.H>
  27. #INCLUDE <STRING.H>
  28.  
  29. #DEFINEbuf(9*2+8)/* 16 BIT HEADER */
  30.  
  31. TYPEDEF STRUCT {$7b}
  32. CHAR *FNAME;
  33. SIZE_T FSIZE;
  34. UNSIGNED CHAR*BUF;
  35. INTTBASE, TLEN, DBASE, DLEN, BBASE, BLEN, ZBASE, ZLEN;
  36. INTTDIFF, DDIFF, BDIFF, ZDIFF;
  37. UNSIGNED CHAR*SEGT;
  38. UNSIGNED CHAR*SEGD;
  39. UNSIGNED CHAR *UTAB;
  40. UNSIGNED CHAR *RTTAB;
  41. UNSIGNED CHAR *RDTAB;
  42. UNSIGNED CHAR *EXTAB;
  43. {$7d} FILE65;
  44.  
  45.  
  46. INT READ_OPTIONS(UNSIGNED CHAR *F);
  47. INT READ_UNDEF(UNSIGNED CHAR *F);
  48. UNSIGNED CHAR *RELOC_SEG(UNSIGNED CHAR *F, INT LEN, UNSIGNED CHAR *RTAB, FILE65 *FP);
  49. UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *, FILE65 *FP);
  50.  
  51. FILE65 FILE;
  52. UNSIGNED CHAR CMP[] = {$7b} 1, 0, 'O', '6', '5' {$7d};
  53.  
  54. VOID USAGE(VOID) {$7b}
  55. PRINTF("RELOC65: RELOCATES 'O65' FILES\N"
  56. "  RELOC65 [OPTIONS] [FILENAMES...]\N"
  57. "OPTIONS:\N"
  58. "  -V        = PRINT VERSION NUMBER\N"
  59. "  -H, -?    = PRINT THIS HELP\N"
  60. "  -B? ADR   = RELOCATES SEGMENT '?' (I.E. 'T' FOR TEXT SEGMENT,\N"
  61. "              'D' FOR DATA, 'B' FOR BSS AND 'Z' FOR ZEROPAGE) TO THE NEW\N"
  62. "              ADDRESS 'ADR'.\N"
  63. "  -O FILE   = USES 'FILE' AS OUTPUT FILE. OTHERWISE WRITE TO 'A.O65'.\N"
  64. "  -X?       = EXTRACTS TEXT '?'='T' OR DATA '?'='D' SEGMENT FROM FILE\N"
  65. "              INSTEAD OF WRITING BACK THE WHOLE FILE\N"
  66. );
  67. EXIT(0);
  68. {$7d}
  69.  
  70. INT MAIN(INT ARGC, CHAR *ARGV[]) {$7b}
  71. INT I = 1, MODE, HLEN;
  72. SIZE_T N;
  73. file *FP;
  74. INT TFLAG=0, DFLAG=0, BFLAG=0, ZFLAG=0;
  75. INT TBASE, DBASE, BBASE, ZBASE;
  76. CHAR *OUTFILE = "A.O65";
  77. INT EXTRACT = 0;
  78.  
  79.  IF(ARGC<=1) USAGE();
  80.  
  81. WHILE(I<ARGC) {$7b}
  82.   IF(ARGV[I][0]=='-') {$7b}
  83.     /* PROCESS OPTIONS */
  84.     SWITCH(ARGV[I][1]) {$7b}
  85.     CASE 'V':
  86. PRINTF("RELOC65 VERSION 0.2 (C) 1997 A.FACHAT\N");
  87. BREAK;
  88.     CASE 'O':
  89. IF(ARGV[I][2]) OUTFILE=ARGV[I]+2;
  90. ELSE OUTFILE=ARGV[++I];
  91. BREAK;
  92.     CASE 'B':
  93. SWITCH(ARGV[I][2]) {$7b}
  94. CASE 'T':
  95. TFLAG= 1;
  96. IF(ARGV[I][3]) TBASE = ATOI(ARGV[I]+3);
  97. ELSE TBASE = ATOI(ARGV[++I]);
  98. BREAK;
  99. CASE 'D':
  100. DFLAG= 1;
  101. IF(ARGV[I][3]) DBASE = ATOI(ARGV[I]+3);
  102. ELSE DBASE = ATOI(ARGV[++I]);
  103. BREAK;
  104. CASE 'B':
  105. BFLAG= 1;
  106. IF(ARGV[I][3]) BBASE = ATOI(ARGV[I]+3);
  107. ELSE BBASE = ATOI(ARGV[++I]);
  108. BREAK;
  109. CASE 'Z':
  110. ZFLAG= 1;
  111. IF(ARGV[I][3]) ZBASE = ATOI(ARGV[I]+3);
  112. ELSE ZBASE = ATOI(ARGV[++I]);
  113. BREAK;
  114. DEFAULT:
  115. PRINTF("uNKNOWN SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
  116. BREAK;
  117. {$7d}
  118. BREAK;
  119.     CASE 'X':/* EXTRACT SEGMENT */
  120.         SWITCH(ARGV[I][2]) {$7b}
  121. CASE 'T':
  122. EXTRACT = 1;
  123. BREAK;
  124. CASE 'D':
  125. EXTRACT = 2;
  126. BREAK;
  127. CASE 'Z':
  128. CASE 'B':
  129. PRINTF("cANNOT EXTRACT SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
  130. BREAK;
  131. DEFAULT:
  132. PRINTF("uNKNOWN SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
  133. BREAK;
  134. {$7d}
  135. BREAK;
  136.     CASE 'H':
  137.     CASE '?':
  138. USAGE();
  139.     DEFAULT:
  140. FPRINTF(STDERR,"RELOC65: %S UNKNOWN OPTION, USE '-?' FOR HELP\N",ARGV[I]);
  141. BREAK;
  142.     {$7d}
  143.   {$7d} ELSE {$7b}
  144.     STRUCT STAT FS;
  145.     FILE.FNAME=ARGV[I];
  146.     STAT(ARGV[I], &FS);
  147.     FILE.FSIZE=FS.ST_SIZE;
  148.     FILE.BUF=MALLOC(FILE.FSIZE);
  149.     IF(!FILE.BUF) {$7b}
  150.       FPRINTF(STDERR,"oOPS, NO MORE MEMORY!\N");
  151.       EXIT(1);
  152.     {$7d}
  153.     PRINTF("RELOC65: READ FILE %S -> %S\N",ARGV[I],OUTFILE);
  154.     FP = FOPEN(ARGV[I],"RB");
  155.     IF(FP) {$7b}
  156.       N = FREAD(FILE.BUF, 1, FILE.FSIZE, FP);
  157.       FCLOSE(FP);
  158.       IF((N>=FILE.FSIZE) && (!MEMCMP(FILE.BUF, CMP, 5))) {$7b}
  159. MODE=FILE.BUF[7]*256+FILE.BUF[6];
  160. IF(MODE & 0X2000) {$7b}
  161.           FPRINTF(STDERR,"RELOC65: %S: 32 BIT SIZE NOT SUPPORTED\N", ARGV[I]);
  162. {$7d} ELSE
  163. IF(MODE & 0X4000) {$7b}
  164.           FPRINTF(STDERR,"RELOC65: %S: PAGEWISE RELOCATION NOT SUPPORTED\N", ARGV[I]);
  165. {$7d} ELSE {$7b}
  166.   HLEN = buf+READ_OPTIONS(FILE.BUF+buf);
  167.   
  168.   FILE.TBASE = FILE.BUF[ 9]*256+FILE.BUF[ 8];
  169.   FILE.TLEN  = FILE.BUF[11]*256+FILE.BUF[10];
  170.   FILE.TDIFF = TFLAG? TBASE - FILE.TBASE : 0;
  171.   FILE.DBASE = FILE.BUF[13]*256+FILE.BUF[12];
  172.   FILE.DLEN  = FILE.BUF[15]*256+FILE.BUF[14];
  173.   FILE.DDIFF = DFLAG? DBASE - FILE.DBASE : 0;
  174.   FILE.BBASE = FILE.BUF[17]*256+FILE.BUF[16];
  175.   FILE.BLEN  = FILE.BUF[19]*256+FILE.BUF[18];
  176.   FILE.BDIFF = BFLAG? BBASE - FILE.BBASE : 0;
  177.   FILE.ZBASE = FILE.BUF[21]*256+FILE.BUF[20];
  178.   FILE.ZLEN  = FILE.BUF[23]*256+FILE.BUF[21];
  179.   FILE.ZDIFF = ZFLAG? ZBASE - FILE.ZBASE : 0;
  180.  
  181.   FILE.SEGT  = FILE.BUF + HLEN;
  182.   FILE.SEGD  = FILE.SEGT + FILE.TLEN;
  183.   FILE.UTAB  = FILE.SEGD + FILE.DLEN;
  184.  
  185.   FILE.RTTAB = FILE.UTAB + READ_UNDEF(FILE.UTAB);
  186.  
  187.   FILE.RDTAB = RELOC_SEG(FILE.SEGT, FILE.TLEN, FILE.RTTAB, &FILE);
  188.   FILE.EXTAB = RELOC_SEG(FILE.SEGD, FILE.DLEN, FILE.RDTAB, &FILE);
  189.  
  190.   RELOC_GLOBALS(FILE.EXTAB, &FILE);
  191.  
  192.   IF(TFLAG) {$7b}
  193. FILE.BUF[ 9]= (TBASE>>8)&255;
  194. FILE.BUF[ 8]= TBASE & 255;
  195.   {$7d}
  196.     IF(DFLAG) {$7b}
  197. FILE.BUF[13]= (DBASE>>8)&255;
  198. FILE.BUF[12]= DBASE & 255;
  199.   {$7d}
  200.   IF(BFLAG) {$7b}
  201. FILE.BUF[17]= (BBASE>>8)&255;
  202. FILE.BUF[16]= BBASE & 255;
  203.   {$7d}
  204.   IF(ZFLAG) {$7b}
  205. FILE.BUF[21]= (ZBASE>>8)&255;
  206. FILE.BUF[20]= ZBASE & 255;
  207.   {$7d}
  208.  
  209.   FP = FOPEN(OUTFILE, "WB");
  210.   IF(FP) {$7b}
  211.     SWITCH(EXTRACT) {$7b}
  212.     CASE 0:/* WHOLE FILE */
  213.     FWRITE(FILE.BUF, 1, FILE.FSIZE, FP);
  214. BREAK;
  215.     CASE 1:/* TEXT SEGMENT */
  216. FWRITE(FILE.SEGT, 1, FILE.TLEN, FP);
  217. BREAK;
  218.     CASE 2:
  219. FWRITE(FILE.SEGD, 1, FILE.DLEN, FP);
  220. BREAK;
  221.     {$7d}
  222.     FCLOSE(FP);
  223.   {$7d} ELSE {$7b}
  224.             FPRINTF(STDERR,"RELOC65: WRITE '%S': %S\N", 
  225. OUTFILE, STRERROR(ERRNO));
  226.   {$7d}
  227. {$7d}
  228.       {$7d} ELSE {$7b}
  229.         FPRINTF(STDERR,"RELOC65: %S: NOT AN O65 FILE!\N", ARGV[I]);
  230. IF(FILE.BUF[0]==1 && FILE.BUF[1]==8 && FILE.BUF[3]==8) {$7b}
  231.   PRINTF("%S: c64 basic EXECUTABLE (START ADDRESS $0801)?\N", ARGV[I]);
  232. {$7d} ELSE
  233. IF(FILE.BUF[0]==1 && FILE.BUF[1]==4 && FILE.BUF[3]==4) {$7b}
  234.   PRINTF("%S: cbm pet basic EXECUTABLE (START ADDRESS $0401)?\N", ARGV[I]);
  235. {$7d}
  236.       {$7d}
  237.     {$7d} ELSE {$7b}
  238.       FPRINTF(STDERR,"RELOC65: READ '%S': %S\N", 
  239. ARGV[I], STRERROR(ERRNO));
  240.     {$7d}
  241.   {$7d}
  242.   I++;
  243. {$7d}
  244. EXIT(0);
  245. {$7d}
  246.  
  247.  
  248. INT READ_OPTIONS(UNSIGNED CHAR *BUF) {$7b}
  249. INT C, L=0;
  250.  
  251. C=BUF[0];
  252. WHILE(C && C!=eof) {$7b}
  253.   C&=255;
  254.   L+=C;
  255.   C=BUF[L];
  256. {$7d}
  257. RETURN ++L;
  258. {$7d}
  259.  
  260. INT READ_UNDEF(UNSIGNED CHAR *BUF) {$7b}
  261. INT N, L = 2;
  262.  
  263. N = BUF[0] + 256*BUF[1];
  264. WHILE(N){$7b}
  265.   N--;
  266.   WHILE(!BUF[L++]);
  267. {$7d}
  268. RETURN L;
  269. {$7d}
  270.  
  271. #DEFINERELDIFF(S)(((S)==2)?FP->TDIFF:(((S)==3)?FP->DDIFF:(((S)==4)?FP->BDIFF:(((S)==5)?FP->ZDIFF:0))))
  272.  
  273. UNSIGNED CHAR *RELOC_SEG(UNSIGNED CHAR *BUF, INT LEN, UNSIGNED CHAR *RTAB, FILE65 *FP) {$7b}
  274. INT ADR = -1;
  275. INT TYPE, SEG, OLD, NEW;
  276. /*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
  277. FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
  278. WHILE(*RTAB) {$7b}
  279.   IF((*RTAB & 255) == 255) {$7b}
  280.     ADR += 254;
  281.     RTAB++;
  282.   {$7d} ELSE {$7b}
  283.     ADR += *RTAB & 255;
  284.     RTAB++;
  285.     TYPE = *RTAB & 0XE0;
  286.     SEG = *RTAB & 0X07;
  287. /*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",RTAB-1, *(RTAB-1), ADR, TYPE, SEG);*/
  288.     RTAB++;
  289.     SWITCH(TYPE) {$7b}
  290.     CASE 0X80:
  291. OLD = BUF[ADR] + 256*BUF[ADR+1];
  292. NEW = OLD + RELDIFF(SEG);
  293. BUF[ADR] = NEW & 255;
  294. BUF[ADR+1] = (NEW>>8)&255;
  295. BREAK;
  296.     CASE 0X40:
  297. OLD = BUF[ADR]*256 + *RTAB;
  298. NEW = OLD + RELDIFF(SEG);
  299. BUF[ADR] = (NEW>>8)&255;
  300. *RTAB = NEW & 255;
  301. RTAB++;
  302. BREAK;
  303.     CASE 0X20:
  304. OLD = BUF[ADR];
  305. NEW = OLD + RELDIFF(SEG);
  306. BUF[ADR] = NEW & 255;
  307. BREAK;
  308.     {$7d}
  309.     IF(SEG==0) RTAB+=2;
  310.   {$7d}
  311. {$7d}
  312. IF(ADR > LEN) {$7b}
  313.   FPRINTF(STDERR,"RELOC65: %S: wARNING: RELOCATION TABLE ENTRIES PAST SEGMENT END!\N",
  314. FP->FNAME);
  315. {$7d}
  316. RETURN ++RTAB;
  317. {$7d}
  318.  
  319. UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *BUF, FILE65 *FP) {$7b}
  320. INT N, OLD, NEW, SEG;
  321.  
  322. N = BUF[0] + 256*BUF[1];
  323. BUF +=2;
  324.  
  325. WHILE(N) {$7b}
  326. /*PRINTF("RELOCATING %S, ", BUF);*/
  327.   WHILE(*(BUF++));
  328.   SEG = *BUF;
  329.   OLD = BUF[1] + 256*BUF[2];
  330.   NEW = OLD + RELDIFF(SEG);
  331. /*PRINTF("OLD=%04X, SEG=%D, REL=%04X, NEW=%04X\N", OLD, SEG, RELDIFF(SEG), NEW);*/
  332.   BUF[1] = NEW & 255;
  333.   BUF[2] = (NEW>>8) & 255;
  334.   BUF +=3;
  335.   N--;
  336. {$7d}
  337. RETURN BUF;
  338. {$7d}
  339.  
  340.