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 >
Wrap
C/C++ Source or Header
|
1997-04-16
|
15KB
|
640 lines
/*
XA65 - 6502 CROSS ASSEMBLER AND UTILITY SUITE
LD65 - O65 RELOCATABLE OBJECT FILE LINKER
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 *NAME;
INTLEN;
{$7d} UNDEFS;
TYPEDEF STRUCT {$7b}
CHAR *FNAME;
SIZE_T FSIZE;
UNSIGNED CHAR*BUF;
INTTBASE, TLEN, DBASE, DLEN, BBASE, BLEN, ZBASE, ZLEN;
INTTDIFF, DDIFF, BDIFF, ZDIFF;
INTTPOS, DPOS, UPOS, TRPOS, DRPOS, GPOS;
INTLASTTRELOC, LASTDRELOC;
INTNUNDEF;
UNDEFS *UD;
{$7d} FILE65;
TYPEDEF STRUCT {$7b}
CHAR *NAME;
INTLEN;/* LENGTH OF LABELNAME */
INTFL;/* 0=OK, 1=MULTIPLY DEFINED */
INTVAL;/* ADDRESS VALUE */
INTSEG;/* SEGMENT */
FILE65*FILE;/* IN WHICH FILE IS IT? */
{$7d} GLOB;
FILE65 *LOAD_FILE(CHAR *FNAME);
INT READ_OPTIONS(UNSIGNED CHAR *F);
INT READ_UNDEF(UNSIGNED CHAR *F, FILE65 *FP);
INT LEN_RELOC_SEG(UNSIGNED CHAR *BUF, INT RI);
INT RELOC_SEG(UNSIGNED CHAR *BUF, INT ADR, INT RI, INT *LRELOC, FILE65 *FP);
UNSIGNED CHAR *RELOC_GLOBALS(UNSIGNED CHAR *, FILE65 *FP);
INT READ_GLOBALS(FILE65 *FILE);
INT WRITE_OPTIONS(file *FP, FILE65 *FILE);
INT WRITE_RELOC(FILE65 *FP[], INT NFP, file *F);
INT WRITE_GLOBALS(file *FP);
FILE65 FILE;
UNSIGNED CHAR CMP[] = {$7b} 1, 0, 'O', '6', '5' {$7d};
UNSIGNED CHAR HDR[26] = {$7b} 1, 0, 'O', '6', '5', 0 {$7d};
VOID USAGE(VOID) {$7b}
PRINTF("LD65: LINK 'O65' FILES\N"
" LD65 [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"
" -g = SUPPRESS WRITING OF GLOBALS\N"
);
EXIT(0);
{$7d}
INT MAIN(INT ARGC, CHAR *ARGV[]) {$7b}
INT NOGLOB=0;
INT I = 1;
INT TBASE = 0X0400, DBASE = 0X1000, BBASE = 0X4000, ZBASE = 0X0002;
INT TTLEN, TDLEN, TBLEN, TZLEN;
CHAR *OUTFILE = "A.O65";
INT J, JM;
FILE65 *FILE, **FP = null;
file *FD;
IF(ARGC<=1) USAGE();
/* READ OPTIONS */
WHILE(I<ARGC && ARGV[I][0]=='-') {$7b}
/* PROCESS OPTIONS */
SWITCH(ARGV[I][1]) {$7b}
CASE 'V':
PRINTF("RELOC65 VERSION 0.1 (C) 1997 A.FACHAT\N");
BREAK;
CASE 'g':
NOGLOB=1;
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':
IF(ARGV[I][3]) TBASE = ATOI(ARGV[I]+3);
ELSE TBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'D':
IF(ARGV[I][3]) DBASE = ATOI(ARGV[I]+3);
ELSE DBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'B':
IF(ARGV[I][3]) BBASE = ATOI(ARGV[I]+3);
ELSE BBASE = ATOI(ARGV[++I]);
BREAK;
CASE 'Z':
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 'H':
CASE '?':
USAGE();
DEFAULT:
FPRINTF(STDERR,"FILE65: %S UNKNOWN OPTION, USE '-?' FOR HELP\N",ARGV[I]);
BREAK;
{$7d}
I++;
{$7d}
/* EACH FILE IS LOADED FIRST */
J=0; JM=0; FP=null;
WHILE(I<ARGC) {$7b}
FILE65 *F;
F = LOAD_FILE(ARGV[I]);
IF(F) {$7b}
IF(J>=JM) FP=REALLOC(FP, (JM=(JM?JM*2:10))*SIZEOF(FILE65*));
IF(!FP) {$7b} FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N"); EXIT(1); {$7d}
FP[J++] = F;
{$7d}
I++;
{$7d}
/* NOW [TDBZ]BASE HOLDS NEW SEGMENT BASE ADDRESS */
/* SET TOTAL LENGTH TO ZERO */
TTLEN = TDLEN = TBLEN = TZLEN = 0;
/* FIND NEW ADDRESSES FOR THE FILES AND READ GLOBALS */
FOR(I=0;I<J;I++) {$7b}
FILE = FP[I];
FILE->TDIFF = ((TBASE + TTLEN) - FILE->TBASE);
FILE->DDIFF = ((DBASE + TDLEN) - FILE->DBASE);
FILE->BDIFF = ((BBASE + TBLEN) - FILE->BBASE);
FILE->ZDIFF = ((ZBASE + TZLEN) - FILE->ZBASE);
/*PRINTF("TBASE=%04X, FILE->TBASE=%04X, TTLEN=%04X -> TDIFF=%04X\N",
TBASE, FILE->TBASE, TTLEN, FILE->TDIFF);*/
TTLEN += FILE->TLEN;
TDLEN += FILE->DLEN;
TBLEN += FILE->BLEN;
TZLEN += FILE->ZLEN;
READ_GLOBALS(FILE);
{$7d}
FOR(I=0;I<J;I++) {$7b}
FILE = FP[I];
RELOC_SEG(FILE->BUF,
FILE->TPOS,
FILE->TRPOS,
&(FILE->LASTTRELOC),
FILE);
RELOC_SEG(FILE->BUF,
FILE->DPOS,
FILE->DRPOS,
&(FILE->LASTDRELOC),
FILE);
RELOC_GLOBALS(FILE->BUF+FILE->GPOS, FILE);
FILE->TBASE += FILE->TDIFF;
FILE->DBASE += FILE->DDIFF;
FILE->BBASE += FILE->BDIFF;
FILE->ZBASE += FILE->ZDIFF;
FILE->LASTTRELOC += FILE->TBASE - FILE->TPOS;
FILE->LASTDRELOC += FILE->DBASE - FILE->DPOS;
{$7d}
HDR[ 6] = 0; HDR[ 7] = 0;
HDR[ 8] = TBASE & 255; HDR[ 9] = (TBASE>>8) & 255;
HDR[10] = TTLEN & 255; HDR[11] = (TTLEN >>8)& 255;
HDR[12] = DBASE & 255; HDR[13] = (DBASE>>8) & 255;
HDR[14] = TDLEN & 255; HDR[15] = (TDLEN >>8)& 255;
HDR[16] = BBASE & 255; HDR[17] = (BBASE>>8) & 255;
HDR[18] = TBLEN & 255; HDR[19] = (TBLEN >>8)& 255;
HDR[20] = ZBASE & 255; HDR[21] = (ZBASE>>8) & 255;
HDR[22] = TZLEN & 255; HDR[23] = (TZLEN >>8)& 255;
HDR[24] = 0; HDR[25] = 0;
FD = FOPEN(OUTFILE, "WB");
IF(!FD) {$7b}
FPRINTF(STDERR,"cOULDN'T OPEN OUTPUT FILE %S (%S)\N",
OUTFILE, STRERROR(ERRNO));
EXIT(2);
{$7d}
FWRITE(HDR, 1, 26, FD);
/* THIS WRITES _ALL_ OPTIONS FROM _ALL_FILES! */
FOR(I=0;I<J;I++) {$7b}
WRITE_OPTIONS(FD, FP[I]);
{$7d}
FPUTC(0,FD);
/* WRITE TEXT SEGMENT */
FOR(I=0;I<J;I++) {$7b}
FWRITE(FP[I]->BUF + FP[I]->TPOS, 1, FP[I]->TLEN, FD);
{$7d}
/* WRITE DATA SEGMENT */
FOR(I=0;I<J;I++) {$7b}
FWRITE(FP[I]->BUF + FP[I]->DPOS, 1, FP[I]->DLEN, FD);
{$7d}
WRITE_RELOC(FP, J, FD);
IF(!NOGLOB) {$7b}
WRITE_GLOBALS(FD);
{$7d} ELSE {$7b}
FPUTC(0,FD);
FPUTC(0,FD);
{$7d}
FCLOSE(FD);
RETURN 0;
{$7d}
/***************************************************************************/
INT WRITE_OPTIONS(file *FP, FILE65 *FILE) {$7b}
RETURN FWRITE(FILE->BUF+buf, 1, FILE->TPOS-buf-1, FP);
{$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, FILE65 *FILE) {$7b}
INT I, N, L = 2, LL;
N = BUF[0] + 256*BUF[1];
FILE->NUNDEF = N;
FILE->UD = MALLOC(N*SIZEOF(UNDEFS));
IF(!FILE->UD) {$7b}
FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N");
EXIT(1);
{$7d}
I=0;
WHILE(I<N){$7b}
FILE->UD[I].NAME = (CHAR*) BUF+L;
LL=L;
WHILE(BUF[L++]);
FILE->UD[I].LEN = L-LL-1;
/*PRINTF("READ UNDEF '%S'(%P), LEN=%D, LL=%D, L=%D\N",
FILE->UD[I].NAME, FILE->UD[I].NAME, FILE->UD[I].LEN,LL,L);*/
I++;
{$7d}
/*PRINTF("RETURN L=%D\N",L);*/
RETURN L;
{$7d}
INT LEN_RELOC_SEG(UNSIGNED CHAR *BUF, INT RI) {$7b}
INT TYPE, SEG;
/*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
WHILE(BUF[RI]) {$7b}
IF((BUF[RI] & 255) == 255) {$7b}
RI++;
{$7d} ELSE {$7b}
RI++;
TYPE = BUF[RI] & 0XE0;
SEG = BUF[RI] & 0X07;
/*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",BUF+RI-1, *(BUF+RI-1), ADR, TYPE, SEG);*/
RI++;
SWITCH(TYPE) {$7b}
CASE 0X80:
BREAK;
CASE 0X40:
RI++;
BREAK;
CASE 0X20:
BREAK;
{$7d}
IF(SEG==0) RI+=2;
{$7d}
{$7d}
RETURN ++RI;
{$7d}
#DEFINERELDIFF(S) (((S)==2)?FP->TDIFF:(((S)==3)?FP->DDIFF:(((S)==4)?FP->BDIFF:(((S)==5)?FP->ZDIFF:0))))
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}
/***************************************************************************/
FILE65 *LOAD_FILE(CHAR *FNAME) {$7b}
FILE65 *FILE;
STRUCT STAT FS;
file *FP;
INT MODE, HLEN;
SIZE_T N;
FILE=MALLOC(SIZEOF(FILE65));
IF(!FILE) {$7b}
FPRINTF(STDERR,"oOPS, NOT ENOUGH MEMORY!\N");
EXIT(1);
{$7d}
/*PRINTF("LOAD_FILE(%S)\N",FNAME);*/
FILE->FNAME=FNAME;
STAT(FNAME, &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}
FP = FOPEN(FNAME,"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,"FILE65: %S: 32 BIT SIZE NOT SUPPORTED\N", FNAME);
FREE(FILE->BUF); FREE(FILE); FILE=null;
{$7d} ELSE
IF(MODE & 0X4000) {$7b}
FPRINTF(STDERR,"FILE65: %S: PAGEWISE RELOCATION NOT SUPPORTED\N",
FNAME);
FREE(FILE->BUF); FREE(FILE); FILE=null;
{$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->DBASE = FILE->BUF[13]*256+FILE->BUF[12];
FILE->DLEN = FILE->BUF[15]*256+FILE->BUF[14];
FILE->BBASE = FILE->BUF[17]*256+FILE->BUF[16];
FILE->BLEN = FILE->BUF[19]*256+FILE->BUF[18];
FILE->ZBASE = FILE->BUF[21]*256+FILE->BUF[20];
FILE->ZLEN = FILE->BUF[23]*256+FILE->BUF[21];
FILE->TPOS = HLEN;
FILE->DPOS = HLEN + FILE->TLEN;
FILE->UPOS = FILE->DPOS + FILE->DLEN;
FILE->TRPOS= FILE->UPOS + READ_UNDEF(FILE->BUF+FILE->UPOS, FILE);
FILE->DRPOS= LEN_RELOC_SEG(FILE->BUF, FILE->TRPOS);
FILE->GPOS = LEN_RELOC_SEG(FILE->BUF, FILE->DRPOS);
{$7d}
{$7d} ELSE
FPRINTF(STDERR,"FILE65: %S: %S\N", FNAME, STRERROR(ERRNO));
{$7d} ELSE
FPRINTF(STDERR,"FILE65: %S: %S\N", FNAME, STRERROR(ERRNO));
RETURN FILE;
{$7d}
/***************************************************************************/
GLOB *GP = null;
INT GM=0;
INT G=0;
INT WRITE_RELOC(FILE65 *FP[], INT NFP, file *F) {$7b}
INT TPC, PC, I;
UNSIGNED CHAR *P;
INT LOW, SEG, TYP, LAB;
/* NO UNDEFINED LABLES ? todo */
FPUTC(0,F);
FPUTC(0,F);
TPC = FP[0]->TBASE-1;
FOR(I=0;I<NFP;I++) {$7b}
PC = FP[I]->TBASE-1;
P = FP[I]->BUF + FP[I]->TRPOS;
WHILE(*P) {$7b}
WHILE((*P)==255) {$7b} PC+=254; P++; {$7d}
PC+=*(P++);
SEG=(*P)&7;
TYP=(*P)&0XE0;
IF(TYP==0X40) LOW=*(++P);
P++;
IF(SEG==0) {$7b}
LAB=P[0]+256*P[1];
SEG=GP[LAB].SEG;
P+=2;
{$7d}
IF(SEG>1) {$7b}
WHILE(PC-TPC>254) {$7b}
FPUTC(255,F);
TPC+=254;
{$7d}
FPUTC(PC-TPC, F);
TPC=PC;
FPUTC(TYP {$7c} SEG, F);
IF(TYP==0X40) {$7b}
FPUTC(LOW,F);
{$7d}
{$7d}
{$7d}
{$7d}
FPUTC(0,F);
TPC = FP[0]->DBASE-1;
FOR(I=0;I<NFP;I++) {$7b}
PC = FP[I]->DBASE-1;
P = FP[I]->BUF + FP[I]->DRPOS;
WHILE(*P) {$7b}
WHILE((*P)==255) {$7b} PC+=254; P++; {$7d}
PC+=*(P++);
SEG=(*P)&7;
TYP=(*P)&0XE0;
IF(TYP==0X40) LOW=*(++P);
P++;
IF(SEG==0) {$7b}
LAB=P[0]+256*P[1];
SEG=GP[LAB].SEG;
P+=2;
{$7d}
IF(SEG>1) {$7b}
WHILE(PC-TPC>254) {$7b}
FPUTC(255,F);
TPC+=254;
{$7d}
FPUTC(PC-TPC, F);
TPC=PC;
FPUTC(TYP {$7c} SEG, F);
IF(TYP==0X40) {$7b}
FPUTC(LOW,F);
{$7d}
{$7d}
{$7d}
{$7d}
FPUTC(0,F);
RETURN 0;
{$7d}
INT WRITE_GLOBALS(file *FP) {$7b}
INT I;
FPUTC(G&255, FP);
FPUTC((G>>8)&255, FP);
FOR(I=0;I<G;I++) {$7b}
FPRINTF(FP,"%S%C%C%C%C",GP[I].NAME,0,GP[I].SEG,
GP[I].VAL & 255, (GP[I].VAL>>8)&255);
{$7d}
RETURN 0;
{$7d}
INT READ_GLOBALS(FILE65 *FP) {$7b}
INT I, L, N, OLD, NEW, SEG, LL;
CHAR *NAME;
UNSIGNED CHAR *BUF = FP->BUF + FP->GPOS;
N = BUF[0] + 256*BUF[1];
BUF +=2;
WHILE(N) {$7b}
/*PRINTF("READING %S, ", BUF);*/
NAME = (CHAR*) BUF;
L=0;
WHILE(BUF[L++]);
BUF+=L;
LL=L-1;
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);*/
/* MULTIPLY DEFINED? */
FOR(I=0;I<G;I++) {$7b}
IF(LL==GP[I].LEN && !STRCMP(NAME, GP[I].NAME)) {$7b}
FPRINTF(STDERR,"wARNING: LABEL '%S' MULTIPLY DEFINED (%S AND %S)\N",
NAME, FP->FNAME, GP[I].FILE->FNAME);
GP[I].FL = 1;
BREAK;
{$7d}
{$7d}
/* NOT ALREADY DEFINED */
IF(I>=G) {$7b}
IF(G>=GM) {$7b}
GP = REALLOC(GP, (GM=(GM?2*GM:40))*SIZEOF(GLOB));
IF(!GP) {$7b}
FPRINTF(STDERR,"oOPS, NO MORE MEMORY\N");
EXIT(1);
{$7d}
{$7d}
IF(G>=0X10000) {$7b}
FPRINTF(STDERR,"oUTCH, MAXIMUM NUMBER OF LABELS (65536) EXCEEDED!\N");
EXIT(3);
{$7d}
GP[G].NAME = NAME;
GP[G].LEN = LL;
GP[G].SEG = SEG;
GP[G].VAL = NEW;
GP[G].FL = 0;
GP[G].FILE = FP;
/*PRINTF("SET LABEL '%S' (L=%D, SEG=%D, VAL=%04X)\N", GP[G].NAME,
GP[G].LEN, GP[G].SEG, GP[G].VAL);*/
G++;
{$7d}
BUF +=3;
N--;
{$7d}
RETURN 0;
{$7d}
INT FIND_GLOBAL(UNSIGNED CHAR *BP, FILE65 *FP, INT *SEG) {$7b}
INT I,L;
CHAR *N;
INT NL = BP[0]+256*BP[1];
L=FP->UD[NL].LEN;
N=FP->UD[NL].NAME;
/*PRINTF("FIND_GLOBAL(%S (LEN=%D))\N",N,L);*/
FOR(I=0;I<G;I++) {$7b}
IF(GP[I].LEN == L && !STRCMP(GP[I].NAME, N)) {$7b}
*SEG = GP[I].SEG;
BP[0] = I & 255; BP[1] = (I>>8) & 255;
/*PRINTF("RETURN GP[%D]=%S (LEN=%D), VAL=%04X\N",I,GP[I].NAME,GP[I].LEN,GP[I].VAL);*/
RETURN GP[I].VAL;
{$7d}
{$7d}
FPRINTF(STDERR,"wARNING: UNDEFINED LABEL '%S' IN FILE %S\N",
N, FP->FNAME);
RETURN 0;
{$7d}
INT RELOC_SEG(UNSIGNED CHAR *BUF, INT ADR, INT RI, INT *LRELOC, FILE65 *FP) {$7b}
INT TYPE, SEG, OLD, NEW;
ADR--;
/*PRINTF("TDIFF=%04X, DDIFF=%04X, BDIFF=%04X, ZDIFF=%04X\N",
FP->TDIFF, FP->DDIFF, FP->BDIFF, FP->ZDIFF);*/
WHILE(BUF[RI]) {$7b}
IF((BUF[RI] & 255) == 255) {$7b}
ADR += 254;
RI++;
{$7d} ELSE {$7b}
ADR += BUF[RI] & 255;
RI++;
TYPE = BUF[RI] & 0XE0;
SEG = BUF[RI] & 0X07;
/*PRINTF("RELOC ENTRY @ RTAB=%P (OFFSET=%D), ADR=%04X, TYPE=%02X, SEG=%D\N",BUF+RI-1, *(BUF+RI-1), ADR, TYPE, SEG);*/
RI++;
SWITCH(TYPE) {$7b}
CASE 0X80:
OLD = BUF[ADR] + 256*BUF[ADR+1];
IF(SEG) NEW = OLD + RELDIFF(SEG);
ELSE NEW = OLD + FIND_GLOBAL(BUF+RI, FP, &SEG);
/*PRINTF("OLD=%04X, NEW=%04X\N",OLD,NEW);*/
BUF[ADR] = NEW & 255;
BUF[ADR+1] = (NEW>>8)&255;
BREAK;
CASE 0X40:
OLD = BUF[ADR]*256 + BUF[RI];
IF(SEG) NEW = OLD + RELDIFF(SEG);
ELSE NEW = OLD + FIND_GLOBAL(BUF+RI+1, FP, &SEG);
BUF[ADR] = (NEW>>8)&255;
BUF[RI] = NEW & 255;
RI++;
BREAK;
CASE 0X20:
OLD = BUF[ADR];
IF(SEG) NEW = OLD + RELDIFF(SEG);
ELSE NEW = OLD + FIND_GLOBAL(BUF+RI, FP, &SEG);
BUF[ADR] = NEW & 255;
BREAK;
{$7d}
IF(SEG==0) RI+=2;
{$7d}
{$7d}
*LRELOC = ADR;
RETURN ++RI;
{$7d}