home *** CD-ROM | disk | FTP | other *** search
/ CBM Funet Archive / cbm-funet-archive-2003.iso / cbm / programming / msdos / xa214f.lzh / xa214f / misc / ld65.c < prev    next >
C/C++ Source or Header  |  1997-04-16  |  15KB  |  640 lines

  1.  
  2. /*
  3.     XA65 - 6502 CROSS ASSEMBLER AND UTILITY SUITE
  4.     LD65 - O65 RELOCATABLE OBJECT FILE LINKER
  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 *NAME;
  33. INTLEN;
  34. {$7d} UNDEFS;
  35.  
  36. TYPEDEF STRUCT {$7b}
  37. CHAR *FNAME;
  38. SIZE_T FSIZE;
  39. UNSIGNED CHAR*BUF;
  40. INTTBASE, TLEN, DBASE, DLEN, BBASE, BLEN, ZBASE, ZLEN;
  41. INTTDIFF, DDIFF, BDIFF, ZDIFF;
  42. INTTPOS, DPOS, UPOS, TRPOS, DRPOS, GPOS;
  43. INTLASTTRELOC, LASTDRELOC;
  44. INTNUNDEF;
  45. UNDEFS *UD;
  46. {$7d} FILE65;
  47.  
  48. TYPEDEF STRUCT {$7b}
  49. CHAR *NAME;
  50. INTLEN;/* LENGTH OF LABELNAME */
  51. INTFL;/* 0=OK, 1=MULTIPLY DEFINED */
  52. INTVAL;/* ADDRESS VALUE */
  53. INTSEG;/* SEGMENT */
  54. FILE65*FILE;/* IN WHICH FILE IS IT? */
  55. {$7d} GLOB;
  56.  
  57. FILE65 *LOAD_FILE(CHAR *FNAME);
  58.  
  59. INT READ_OPTIONS(UNSIGNED CHAR *F);
  60. INT READ_UNDEF(UNSIGNED CHAR *F, FILE65 *FP);
  61. INT LEN_RELOC_SEG(UNSIGNED CHAR *BUF, INT RI);
  62. INT RELOC_SEG(UNSIGNED CHAR *BUF, INT ADR, INT RI, INT *LRELOC, FILE65 *FP);
  63. UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *, FILE65 *FP);
  64. INT READ_GLOBALS(FILE65 *FILE);
  65. INT WRITE_OPTIONS(file *FP, FILE65 *FILE);
  66. INT WRITE_RELOC(FILE65 *FP[], INT NFP, file *F);
  67. INT WRITE_GLOBALS(file *FP);
  68.  
  69. FILE65 FILE;
  70. UNSIGNED CHAR CMP[] = {$7b} 1, 0, 'O', '6', '5' {$7d};
  71. UNSIGNED CHAR HDR[26] = {$7b} 1, 0, 'O', '6', '5', 0 {$7d};
  72.  
  73. VOID USAGE(VOID) {$7b}
  74. PRINTF("LD65: LINK 'O65' FILES\N"
  75. "  LD65 [OPTIONS] [FILENAMES...]\N"
  76. "OPTIONS:\N"
  77. "  -V        = PRINT VERSION NUMBER\N"
  78. "  -H, -?    = PRINT THIS HELP\N"
  79. "  -B? ADR   = RELOCATES SEGMENT '?' (I.E. 'T' FOR TEXT SEGMENT,\N"
  80. "              'D' FOR DATA, 'B' FOR BSS AND 'Z' FOR ZEROPAGE) TO THE NEW\N"
  81. "              ADDRESS 'ADR'.\N"
  82. "  -O FILE   = USES 'FILE' AS OUTPUT FILE. OTHERWISE WRITE TO 'A.O65'.\N"
  83. "  -g        = SUPPRESS WRITING OF GLOBALS\N"
  84. );
  85. EXIT(0);
  86. {$7d}
  87.  
  88. INT MAIN(INT ARGC, CHAR *ARGV[]) {$7b}
  89. INT NOGLOB=0;
  90. INT I = 1;
  91. INT TBASE = 0X0400, DBASE = 0X1000, BBASE = 0X4000, ZBASE = 0X0002;
  92. INT TTLEN, TDLEN, TBLEN, TZLEN;
  93. CHAR *OUTFILE = "A.O65";
  94. INT J, JM;
  95. FILE65 *FILE, **FP = null;
  96. file *FD;
  97.  
  98.  IF(ARGC<=1) USAGE();
  99.  
  100. /* READ OPTIONS */
  101. WHILE(I<ARGC && ARGV[I][0]=='-') {$7b}
  102.     /* PROCESS OPTIONS */
  103.     SWITCH(ARGV[I][1]) {$7b}
  104.     CASE 'V':
  105. PRINTF("RELOC65 VERSION 0.1 (C) 1997 A.FACHAT\N");
  106. BREAK;
  107.     CASE 'g':
  108. NOGLOB=1;
  109. BREAK;
  110.     CASE 'O':
  111. IF(ARGV[I][2]) OUTFILE=ARGV[I]+2;
  112. ELSE OUTFILE=ARGV[++I];
  113. BREAK;
  114.     CASE 'B':
  115. SWITCH(ARGV[I][2]) {$7b}
  116. CASE 'T':
  117. IF(ARGV[I][3]) TBASE = ATOI(ARGV[I]+3);
  118. ELSE TBASE = ATOI(ARGV[++I]);
  119. BREAK;
  120. CASE 'D':
  121. IF(ARGV[I][3]) DBASE = ATOI(ARGV[I]+3);
  122. ELSE DBASE = ATOI(ARGV[++I]);
  123. BREAK;
  124. CASE 'B':
  125. IF(ARGV[I][3]) BBASE = ATOI(ARGV[I]+3);
  126. ELSE BBASE = ATOI(ARGV[++I]);
  127. BREAK;
  128. CASE 'Z':
  129. IF(ARGV[I][3]) ZBASE = ATOI(ARGV[I]+3);
  130. ELSE ZBASE = ATOI(ARGV[++I]);
  131. BREAK;
  132. DEFAULT:
  133. PRINTF("uNKNOWN SEGMENT TYPE '%C' - IGNORED!\N", ARGV[I][2]);
  134. BREAK;
  135. {$7d}
  136. BREAK;
  137.     CASE 'H':
  138.     CASE '?':
  139. USAGE();
  140.     DEFAULT:
  141. FPRINTF(STDERR,"FILE65: %S UNKNOWN OPTION, USE '-?' FOR HELP\N",ARGV[I]);
  142. BREAK;
  143.     {$7d}
  144.     I++;
  145. {$7d}
  146. /* EACH FILE IS LOADED FIRST */
  147. J=0; JM=0; FP=null;
  148. WHILE(I<ARGC) {$7b}
  149.   FILE65 *F;
  150.   F = LOAD_FILE(ARGV[I]);
  151.   IF(F) {$7b}
  152.     IF(J>=JM) FP=REALLOC(FP, (JM=(JM?JM*2:10))*SIZEOF(FILE65*));
  153.     IF(!FP) {$7b} FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N"); EXIT(1); {$7d}
  154.     FP[J++] = F;
  155.   {$7d}
  156.   I++;
  157. {$7d}
  158.  
  159. /* NOW [TDBZ]BASE HOLDS NEW SEGMENT BASE ADDRESS */
  160. /* SET TOTAL LENGTH TO ZERO */
  161. TTLEN = TDLEN = TBLEN = TZLEN = 0;
  162.  
  163. /* FIND NEW ADDRESSES FOR THE FILES AND READ GLOBALS */
  164. FOR(I=0;I<J;I++) {$7b}
  165.   FILE = FP[I];
  166.  
  167.   FILE->TDIFF =  ((TBASE + TTLEN) - FILE->TBASE);
  168.   FILE->DDIFF =  ((DBASE + TDLEN) - FILE->DBASE);
  169.   FILE->BDIFF =  ((BBASE + TBLEN) - FILE->BBASE);
  170.   FILE->ZDIFF =  ((ZBASE + TZLEN) - FILE->ZBASE);
  171. /*PRINTF("TBASE=%04X, FILE->TBASE=%04X, TTLEN=%04X -> TDIFF=%04X\N",
  172. TBASE, FILE->TBASE, TTLEN, FILE->TDIFF);*/
  173.   TTLEN += FILE->TLEN;
  174.   TDLEN += FILE->DLEN;
  175.   TBLEN += FILE->BLEN;
  176.   TZLEN += FILE->ZLEN;
  177.  
  178.   READ_GLOBALS(FILE);
  179. {$7d}
  180.  
  181. FOR(I=0;I<J;I++) {$7b}
  182.   FILE = FP[I];
  183.  
  184.   RELOC_SEG(FILE->BUF, 
  185. FILE->TPOS, 
  186. FILE->TRPOS,
  187. &(FILE->LASTTRELOC),
  188. FILE);
  189.   RELOC_SEG(FILE->BUF,
  190. FILE->DPOS,
  191. FILE->DRPOS,
  192. &(FILE->LASTDRELOC),
  193. FILE);
  194.   RELOC_GLOBALS(FILE->BUF+FILE->GPOS, FILE);
  195.  
  196.   FILE->TBASE += FILE->TDIFF;
  197.   FILE->DBASE += FILE->DDIFF;
  198.   FILE->BBASE += FILE->BDIFF;
  199.   FILE->ZBASE += FILE->ZDIFF;
  200.  
  201.   FILE->LASTTRELOC += FILE->TBASE - FILE->TPOS;
  202.   FILE->LASTDRELOC += FILE->DBASE - FILE->DPOS;
  203.  
  204. {$7d}
  205.  
  206. HDR[ 6] = 0;           HDR[ 7] = 0;
  207. HDR[ 8] = TBASE & 255; HDR[ 9] = (TBASE>>8) & 255;
  208. HDR[10] = TTLEN & 255; HDR[11] = (TTLEN >>8)& 255;
  209. HDR[12] = DBASE & 255; HDR[13] = (DBASE>>8) & 255;
  210. HDR[14] = TDLEN & 255; HDR[15] = (TDLEN >>8)& 255;
  211. HDR[16] = BBASE & 255; HDR[17] = (BBASE>>8) & 255;
  212. HDR[18] = TBLEN & 255; HDR[19] = (TBLEN >>8)& 255;
  213. HDR[20] = ZBASE & 255; HDR[21] = (ZBASE>>8) & 255;
  214. HDR[22] = TZLEN & 255; HDR[23] = (TZLEN >>8)& 255;
  215. HDR[24] = 0;           HDR[25] = 0;
  216.  
  217. FD = FOPEN(OUTFILE, "WB");
  218. IF(!FD) {$7b}
  219.   FPRINTF(STDERR,"cOULDN'T OPEN OUTPUT FILE %S (%S)\N",
  220. OUTFILE, STRERROR(ERRNO));
  221.   EXIT(2);
  222. {$7d}
  223. FWRITE(HDR, 1, 26, FD);
  224. /* THIS WRITES _ALL_ OPTIONS FROM _ALL_FILES! */
  225. FOR(I=0;I<J;I++) {$7b}
  226.   WRITE_OPTIONS(FD, FP[I]);
  227. {$7d}
  228. FPUTC(0,FD);
  229. /* WRITE TEXT SEGMENT */
  230. FOR(I=0;I<J;I++) {$7b}
  231.   FWRITE(FP[I]->BUF + FP[I]->TPOS, 1, FP[I]->TLEN, FD);
  232. {$7d}
  233. /* WRITE DATA SEGMENT */
  234. FOR(I=0;I<J;I++) {$7b}
  235.   FWRITE(FP[I]->BUF + FP[I]->DPOS, 1, FP[I]->DLEN, FD);
  236. {$7d}
  237. WRITE_RELOC(FP, J, FD);
  238. IF(!NOGLOB) {$7b} 
  239.   WRITE_GLOBALS(FD);
  240. {$7d} ELSE {$7b}
  241.   FPUTC(0,FD);
  242.   FPUTC(0,FD);
  243. {$7d}
  244.  
  245. FCLOSE(FD);
  246. RETURN 0;
  247. {$7d}
  248.  
  249. /***************************************************************************/
  250.  
  251. INT WRITE_OPTIONS(file *FP, FILE65 *FILE) {$7b}
  252. RETURN FWRITE(FILE->BUF+buf, 1, FILE->TPOS-buf-1, FP);
  253. {$7d}
  254.  
  255. INT READ_OPTIONS(UNSIGNED CHAR *BUF) {$7b}
  256. INT C, L=0;
  257.  
  258. C=BUF[0];
  259. WHILE(C && C!=eof) {$7b}
  260.   C&=255;
  261.   L+=C;
  262.   C=BUF[L];
  263. {$7d}
  264. RETURN ++L;
  265. {$7d}
  266.  
  267. INT READ_UNDEF(UNSIGNED CHAR *BUF, FILE65 *FILE) {$7b}
  268. INT I, N, L = 2, LL;
  269.  
  270. N = BUF[0] + 256*BUF[1];
  271.  
  272. FILE->NUNDEF = N;
  273. FILE->UD = MALLOC(N*SIZEOF(UNDEFS));
  274. IF(!FILE->UD) {$7b}
  275.   FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N");
  276.   EXIT(1);
  277. {$7d}
  278. I=0;
  279. WHILE(I<N){$7b}
  280.   FILE->UD[I].NAME = (CHAR*) BUF+L;
  281.   LL=L;
  282.   WHILE(BUF[L++]);
  283.   FILE->UD[I].LEN = L-LL-1;
  284. /*PRINTF("READ UNDEF '%S'(%P), LEN=%D, LL=%D, L=%D\N",
  285. FILE->UD[I].NAME, FILE->UD[I].NAME, FILE->UD[I].LEN,LL,L);*/
  286.   I++;
  287. {$7d}
  288. /*PRINTF("RETURN L=%D\N",L);*/
  289. RETURN L;
  290. {$7d}
  291.  
  292. INT LEN_RELOC_SEG(UNSIGNED CHAR *BUF, INT RI) {$7b}
  293. INT TYPE, SEG;
  294.  
  295. /*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
  296. FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
  297. WHILE(BUF[RI]) {$7b}
  298.   IF((BUF[RI] & 255) == 255) {$7b}
  299.     RI++;
  300.   {$7d} ELSE {$7b}
  301.     RI++;
  302.     TYPE = BUF[RI] & 0XE0;
  303.     SEG = BUF[RI] & 0X07;
  304. /*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",BUF+RI-1, *(BUF+RI-1), ADR, TYPE, SEG);*/
  305.     RI++;
  306.     SWITCH(TYPE) {$7b}
  307.     CASE 0X80:
  308. BREAK;
  309.     CASE 0X40:
  310. RI++;
  311. BREAK;
  312.     CASE 0X20:
  313. BREAK;
  314.     {$7d}
  315.     IF(SEG==0) RI+=2;
  316.   {$7d}
  317. {$7d}
  318. RETURN ++RI;
  319. {$7d}
  320.  
  321. #DEFINERELDIFF(S) (((S)==2)?FP->TDIFF:(((S)==3)?FP->DDIFF:(((S)==4)?FP->BDIFF:(((S)==5)?FP->ZDIFF:0))))
  322.  
  323. UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *BUF, FILE65 *FP) {$7b}
  324. INT N, OLD, NEW, SEG;
  325.  
  326. N = BUF[0] + 256*BUF[1];
  327. BUF +=2;
  328.  
  329. WHILE(N) {$7b}
  330. /*PRINTF("RELOCATING %S, ", BUF);*/
  331.   WHILE(*(BUF++));
  332.   SEG = *BUF;
  333.   OLD = BUF[1] + 256*BUF[2];
  334.   NEW = OLD + RELDIFF(SEG);
  335. /*PRINTF("OLD=%04X, SEG=%D, REL=%04X, NEW=%04X\N", OLD, SEG, RELDIFF(SEG), NEW);*/
  336.   BUF[1] = NEW & 255;
  337.   BUF[2] = (NEW>>8) & 255;
  338.   BUF +=3;
  339.   N--;
  340. {$7d}
  341. RETURN BUF;
  342. {$7d}
  343.  
  344. /***************************************************************************/
  345.  
  346. FILE65 *LOAD_FILE(CHAR *FNAME) {$7b}
  347. FILE65 *FILE;
  348. STRUCT STAT FS;
  349. file *FP;
  350. INT MODE, HLEN;
  351. SIZE_T N;
  352.  
  353. FILE=MALLOC(SIZEOF(FILE65));
  354. IF(!FILE) {$7b}
  355.   FPRINTF(STDERR,"oOPS, NOT ENOUGH MEMORY!\N");
  356.   EXIT(1);
  357. {$7d}
  358.  
  359. /*PRINTF("LOAD_FILE(%S)\N",FNAME);*/
  360.  
  361. FILE->FNAME=FNAME;
  362. STAT(FNAME, &FS);
  363. FILE->FSIZE=FS.ST_SIZE;
  364. FILE->BUF=MALLOC(FILE->FSIZE);
  365. IF(!FILE->BUF) {$7b}
  366.   FPRINTF(STDERR,"oOPS, NO MORE MEMORY!\N");
  367.   EXIT(1);
  368. {$7d}
  369.  
  370. FP = FOPEN(FNAME,"RB");
  371.     IF(FP) {$7b}
  372.   N = FREAD(FILE->BUF, 1, FILE->FSIZE, FP);
  373.   FCLOSE(FP);
  374.   IF((N>=FILE->FSIZE) && (!MEMCMP(FILE->BUF, CMP, 5))) {$7b}
  375.     MODE=FILE->BUF[7]*256+FILE->BUF[6];
  376.     IF(MODE & 0X2000) {$7b}
  377.       FPRINTF(STDERR,"FILE65: %S: 32 BIT SIZE NOT SUPPORTED\N", FNAME);
  378.       FREE(FILE->BUF); FREE(FILE); FILE=null;
  379.     {$7d} ELSE
  380.     IF(MODE & 0X4000) {$7b}
  381.       FPRINTF(STDERR,"FILE65: %S: PAGEWISE RELOCATION NOT SUPPORTED\N", 
  382. FNAME);
  383.       FREE(FILE->BUF); FREE(FILE); FILE=null;
  384.     {$7d} ELSE {$7b}
  385.       HLEN = buf+READ_OPTIONS(FILE->BUF+buf);
  386.   
  387.       FILE->TBASE = FILE->BUF[ 9]*256+FILE->BUF[ 8];
  388.       FILE->TLEN  = FILE->BUF[11]*256+FILE->BUF[10];
  389.       FILE->DBASE = FILE->BUF[13]*256+FILE->BUF[12];
  390.       FILE->DLEN  = FILE->BUF[15]*256+FILE->BUF[14];
  391.       FILE->BBASE = FILE->BUF[17]*256+FILE->BUF[16];
  392.       FILE->BLEN  = FILE->BUF[19]*256+FILE->BUF[18];
  393.       FILE->ZBASE = FILE->BUF[21]*256+FILE->BUF[20];
  394.       FILE->ZLEN  = FILE->BUF[23]*256+FILE->BUF[21];
  395.  
  396.       FILE->TPOS = HLEN;
  397.       FILE->DPOS = HLEN + FILE->TLEN;
  398.       FILE->UPOS = FILE->DPOS + FILE->DLEN;
  399.       FILE->TRPOS= FILE->UPOS + READ_UNDEF(FILE->BUF+FILE->UPOS, FILE);
  400.       FILE->DRPOS= LEN_RELOC_SEG(FILE->BUF, FILE->TRPOS);
  401.       FILE->GPOS = LEN_RELOC_SEG(FILE->BUF, FILE->DRPOS);
  402.     {$7d}
  403.   {$7d} ELSE
  404.     FPRINTF(STDERR,"FILE65: %S: %S\N", FNAME, STRERROR(ERRNO));
  405. {$7d} ELSE
  406.   FPRINTF(STDERR,"FILE65: %S: %S\N", FNAME, STRERROR(ERRNO));
  407.  
  408. RETURN FILE;
  409. {$7d}
  410.  
  411. /***************************************************************************/
  412.  
  413. GLOB *GP = null;
  414. INT GM=0;
  415. INT G=0;
  416.  
  417. INT WRITE_RELOC(FILE65 *FP[], INT NFP, file *F) {$7b}
  418. INT TPC, PC, I;
  419. UNSIGNED CHAR *P;
  420. INT LOW, SEG, TYP, LAB;
  421.  
  422. /* NO UNDEFINED LABLES ? todo */
  423. FPUTC(0,F);
  424. FPUTC(0,F);
  425.  
  426. TPC = FP[0]->TBASE-1;
  427.  
  428. FOR(I=0;I<NFP;I++) {$7b}
  429.   PC = FP[I]->TBASE-1;
  430.   P = FP[I]->BUF + FP[I]->TRPOS;
  431.  
  432.   WHILE(*P) {$7b}
  433.     WHILE((*P)==255) {$7b} PC+=254; P++; {$7d}
  434.     PC+=*(P++);
  435.     SEG=(*P)&7;
  436.     TYP=(*P)&0XE0;
  437.     IF(TYP==0X40) LOW=*(++P);
  438.     P++;
  439.     IF(SEG==0) {$7b}
  440.       LAB=P[0]+256*P[1];
  441.       SEG=GP[LAB].SEG;
  442.       P+=2;
  443.     {$7d}
  444.     IF(SEG>1) {$7b}
  445.       WHILE(PC-TPC>254) {$7b}
  446. FPUTC(255,F);
  447. TPC+=254;
  448.       {$7d}
  449.       FPUTC(PC-TPC, F);
  450.       TPC=PC;
  451.       FPUTC(TYP {$7c} SEG, F);
  452.       IF(TYP==0X40) {$7b}
  453. FPUTC(LOW,F);
  454.       {$7d}
  455.     {$7d}
  456.   {$7d}
  457. {$7d}
  458. FPUTC(0,F);
  459.  
  460. TPC = FP[0]->DBASE-1;
  461.  
  462. FOR(I=0;I<NFP;I++) {$7b}
  463.   PC = FP[I]->DBASE-1;
  464.   P = FP[I]->BUF + FP[I]->DRPOS;
  465.  
  466.   WHILE(*P) {$7b}
  467.     WHILE((*P)==255) {$7b} PC+=254; P++; {$7d}
  468.     PC+=*(P++);
  469.     SEG=(*P)&7;
  470.     TYP=(*P)&0XE0;
  471.     IF(TYP==0X40) LOW=*(++P);
  472.     P++;
  473.     IF(SEG==0) {$7b}
  474.       LAB=P[0]+256*P[1];
  475.       SEG=GP[LAB].SEG;
  476.       P+=2;
  477.     {$7d}
  478.     IF(SEG>1) {$7b}
  479.       WHILE(PC-TPC>254) {$7b}
  480. FPUTC(255,F);
  481. TPC+=254;
  482.       {$7d}
  483.       FPUTC(PC-TPC, F);
  484.       TPC=PC;
  485.       FPUTC(TYP {$7c} SEG, F);
  486.       IF(TYP==0X40) {$7b}
  487. FPUTC(LOW,F);
  488.       {$7d}
  489.     {$7d}
  490.   {$7d}
  491. {$7d}
  492. FPUTC(0,F);
  493.  
  494. RETURN 0;
  495. {$7d}
  496.  
  497. INT WRITE_GLOBALS(file *FP) {$7b}
  498. INT I;
  499.  
  500. FPUTC(G&255, FP);
  501. FPUTC((G>>8)&255, FP);
  502.  
  503. FOR(I=0;I<G;I++) {$7b}
  504.   FPRINTF(FP,"%S%C%C%C%C",GP[I].NAME,0,GP[I].SEG, 
  505. GP[I].VAL & 255, (GP[I].VAL>>8)&255);
  506. {$7d}
  507. RETURN 0;
  508. {$7d}
  509.  
  510. INT READ_GLOBALS(FILE65 *FP) {$7b}
  511. INT I, L, N, OLD, NEW, SEG, LL;
  512. CHAR *NAME;
  513. UNSIGNED CHAR *BUF = FP->BUF + FP->GPOS;
  514.  
  515. N = BUF[0] + 256*BUF[1];
  516. BUF +=2;
  517.  
  518. WHILE(N) {$7b}
  519. /*PRINTF("READING %S, ", BUF);*/
  520.   NAME = (CHAR*) BUF;
  521.   L=0;
  522.   WHILE(BUF[L++]);
  523.   BUF+=L;
  524.   LL=L-1;
  525.   SEG = *BUF;
  526.   OLD = BUF[1] + 256*BUF[2];
  527.   NEW = OLD + RELDIFF(SEG);
  528. /*PRINTF("OLD=%04X, SEG=%D, REL=%04X, NEW=%04X\N", OLD, SEG, RELDIFF(SEG), NEW);*/
  529.  
  530.   /* MULTIPLY DEFINED? */
  531.   FOR(I=0;I<G;I++) {$7b}
  532.     IF(LL==GP[I].LEN && !STRCMP(NAME, GP[I].NAME)) {$7b}
  533.       FPRINTF(STDERR,"wARNING: LABEL '%S' MULTIPLY DEFINED (%S AND %S)\N",
  534. NAME, FP->FNAME, GP[I].FILE->FNAME);
  535.       GP[I].FL = 1;
  536.       BREAK;
  537.     {$7d}
  538.   {$7d}
  539.   /* NOT ALREADY DEFINED */
  540.   IF(I>=G) {$7b}
  541.     IF(G>=GM) {$7b}
  542.       GP = REALLOC(GP, (GM=(GM?2*GM:40))*SIZEOF(GLOB));
  543.       IF(!GP) {$7b}
  544.         FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N");
  545.         EXIT(1);
  546.       {$7d}
  547.     {$7d}
  548.     IF(G>=0X10000) {$7b}
  549.       FPRINTF(STDERR,"oUTCH, MAXIMUM NUMBER OF LABELS (65536) EXCEEDED!\N");
  550.       EXIT(3);
  551.     {$7d}
  552.     GP[G].NAME = NAME;
  553.     GP[G].LEN = LL;
  554.     GP[G].SEG = SEG;
  555.     GP[G].VAL = NEW;
  556.     GP[G].FL = 0;
  557.     GP[G].FILE = FP;
  558. /*PRINTF("SET LABEL '%S' (L=%D, SEG=%D, VAL=%04X)\N", GP[G].NAME,
  559. GP[G].LEN, GP[G].SEG, GP[G].VAL);*/
  560.     G++;
  561.   {$7d}
  562.  
  563.   BUF +=3;
  564.   N--;
  565. {$7d}
  566. RETURN 0;
  567. {$7d}
  568.  
  569. INT FIND_GLOBAL(UNSIGNED CHAR *BP, FILE65 *FP, INT *SEG) {$7b}
  570. INT I,L;
  571. CHAR *N;
  572. INT NL = BP[0]+256*BP[1];
  573.  
  574. L=FP->UD[NL].LEN;
  575. N=FP->UD[NL].NAME;
  576. /*PRINTF("FIND_GLOBAL(%S (LEN=%D))\N",N,L);*/
  577.  
  578. FOR(I=0;I<G;I++) {$7b}
  579.   IF(GP[I].LEN == L && !STRCMP(GP[I].NAME, N)) {$7b}
  580.     *SEG = GP[I].SEG;
  581.     BP[0] = I & 255; BP[1] = (I>>8) & 255;
  582. /*PRINTF("RETURN GP[%D]=%S (LEN=%D), VAL=%04X\N",I,GP[I].NAME,GP[I].LEN,GP[I].VAL);*/
  583.     RETURN GP[I].VAL;
  584.   {$7d}
  585. {$7d}
  586. FPRINTF(STDERR,"wARNING: UNDEFINED LABEL '%S' IN FILE %S\N",
  587.  N, FP->FNAME);
  588. RETURN 0;
  589. {$7d}
  590.  
  591. INT RELOC_SEG(UNSIGNED CHAR *BUF, INT ADR, INT RI, INT *LRELOC, FILE65 *FP) {$7b}
  592. INT TYPE, SEG, OLD, NEW;
  593.  
  594. ADR--;
  595. /*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
  596. FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
  597. WHILE(BUF[RI]) {$7b}
  598.   IF((BUF[RI] & 255) == 255) {$7b}
  599.     ADR += 254;
  600.     RI++;
  601.   {$7d} ELSE {$7b}
  602.     ADR += BUF[RI] & 255;
  603.     RI++;
  604.     TYPE = BUF[RI] & 0XE0;
  605.     SEG = BUF[RI] & 0X07;
  606. /*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",BUF+RI-1, *(BUF+RI-1), ADR, TYPE, SEG);*/
  607.     RI++;
  608.     SWITCH(TYPE) {$7b}
  609.     CASE 0X80:
  610. OLD = BUF[ADR] + 256*BUF[ADR+1];
  611. IF(SEG) NEW = OLD + RELDIFF(SEG);
  612. ELSE NEW = OLD + FIND_GLOBAL(BUF+RI, FP, &SEG);
  613. /*PRINTF("OLD=%04X, NEW=%04X\N",OLD,NEW);*/
  614. BUF[ADR] = NEW & 255;
  615. BUF[ADR+1] = (NEW>>8)&255;
  616. BREAK;
  617.     CASE 0X40:
  618. OLD = BUF[ADR]*256 + BUF[RI];
  619. IF(SEG) NEW = OLD + RELDIFF(SEG);
  620. ELSE NEW = OLD + FIND_GLOBAL(BUF+RI+1, FP, &SEG);
  621. BUF[ADR] = (NEW>>8)&255;
  622. BUF[RI] = NEW & 255;
  623. RI++;
  624. BREAK;
  625.     CASE 0X20:
  626. OLD = BUF[ADR];
  627. IF(SEG) NEW = OLD + RELDIFF(SEG);
  628. ELSE NEW = OLD + FIND_GLOBAL(BUF+RI, FP, &SEG);
  629. BUF[ADR] = NEW & 255;
  630. BREAK;
  631.     {$7d}
  632.     IF(SEG==0) RI+=2;
  633.   {$7d}
  634. {$7d}
  635. *LRELOC = ADR;
  636. RETURN ++RI;
  637. {$7d}
  638.  
  639.  
  640.