mirror of
https://github.com/fachat/xa65.git
synced 2025-01-07 19:29:40 +00:00
699 lines
16 KiB
C
699 lines
16 KiB
C
/* ldo65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
|
|
* o65 relocatable object file linker
|
|
*
|
|
* A part of the xa65 - 65xx/65816 cross-assembler and utility suite
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef _MSC_VER
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
|
|
#include "version.h"
|
|
|
|
#define BUF (9*2+8) /* 16 bit header */
|
|
|
|
#define programname "ldo65"
|
|
#define progversion "v0.1.1"
|
|
#define author "Written by André Fachat"
|
|
#define copyright "Copyright (C) 1997-2002 André Fachat. Formerly ld65."
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int len;
|
|
} undefs;
|
|
|
|
/* file information */
|
|
typedef struct {
|
|
char *fname; /* file name */
|
|
size_t fsize; /* length of file */
|
|
unsigned char *buf; /* file content */
|
|
|
|
int tbase; /* header: text base */
|
|
int tlen; /* text length */
|
|
int dbase; /* data base */
|
|
int dlen; /* data length */
|
|
int bbase; /* bss base */
|
|
int blen; /* bss length */
|
|
int zbase; /* zero base */
|
|
int zlen; /* zero length */
|
|
|
|
int tdiff; /* text segment relocation diff */
|
|
int ddiff; /* data segment relocation diff */
|
|
int bdiff; /* bss segment relocation diff */
|
|
int zdiff; /* zero segment relocation diff */
|
|
|
|
int tpos; /* position of text segment in file */
|
|
int dpos; /* position of data segment in file */
|
|
int upos; /* position of undef'd list in file */
|
|
int trpos; /* position of text reloc tab in file */
|
|
int drpos; /* position of data reloc tab in file */
|
|
int gpos; /* position of globals list in file */
|
|
|
|
int lasttreloc;
|
|
int lastdreloc;
|
|
|
|
int nundef; /* number of undefined labels */
|
|
undefs *ud; /* undefined labels list NULL if none */
|
|
} file65;
|
|
|
|
/* globally defined lables are stored in this struct */
|
|
typedef struct {
|
|
char *name;
|
|
int len; /* length of labelname */
|
|
int fl; /* 0=ok, 1=multiply defined */
|
|
int val; /* address value */
|
|
int seg; /* segment */
|
|
file65 *file; /* in which file is it? */
|
|
} 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[] = { 1, 0, 'o', '6', '5' };
|
|
unsigned char hdr[26] = { 1, 0, 'o', '6', '5', 0 };
|
|
|
|
void usage(FILE *fp)
|
|
{
|
|
fprintf(fp,
|
|
"Usage: %s [OPTION]... [FILE]...\n"
|
|
"Linker for o65 object files\n"
|
|
"\n"
|
|
" -b? addr relocates segment `?' (i.e. `t' for text segment,\n"
|
|
" `d' for data, `b' for bss, and `z' for zeropage) to the new\n"
|
|
" address `addr'\n"
|
|
" -o file uses `file' as output file. Default is `a.o65'\n"
|
|
" -G suppress writing of globals\n"
|
|
" --version output version information and exit\n"
|
|
" --help display this help and exit\n",
|
|
programname);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
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(stderr);
|
|
exit(1);
|
|
}
|
|
|
|
if (strstr(argv[1], "--help")) {
|
|
usage(stdout);
|
|
exit(0);
|
|
}
|
|
|
|
if (strstr(argv[1], "--version")) {
|
|
version(programname, progversion, author, copyright);
|
|
exit(0);
|
|
}
|
|
|
|
/* read options */
|
|
while(i<argc && argv[i][0]=='-') {
|
|
/* process options */
|
|
switch(argv[i][1]) {
|
|
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]) {
|
|
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;
|
|
}
|
|
break;
|
|
default:
|
|
fprintf(stderr,"file65: %s unknown option, use '-?' for help\n",argv[i]);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
/* each file is loaded first */
|
|
j=0; jm=0; fp=NULL;
|
|
while(i<argc) {
|
|
file65 *f;
|
|
f = load_file(argv[i]);
|
|
if(f) {
|
|
if(j>=jm) fp=realloc(fp, (jm=(jm?jm*2:10))*sizeof(file65*));
|
|
if(!fp) { fprintf(stderr,"Oops, no more memory\n"); exit(1); }
|
|
fp[j++] = f;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
/* 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++) {
|
|
file = fp[i];
|
|
|
|
/* compute relocation differences */
|
|
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);*/
|
|
|
|
/* update globals (for result file) */
|
|
ttlen += file->tlen;
|
|
tdlen += file->dlen;
|
|
tblen += file->blen;
|
|
tzlen += file->zlen;
|
|
|
|
read_globals(file);
|
|
}
|
|
|
|
for(i=0;i<j;i++) {
|
|
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;
|
|
|
|
}
|
|
|
|
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) {
|
|
fprintf(stderr,"Couldn't open output file %s (%s)\n",
|
|
outfile, strerror(errno));
|
|
exit(2);
|
|
}
|
|
fwrite(hdr, 1, 26, fd);
|
|
/* this writes _all_ options from _all_files! */
|
|
for(i=0;i<j;i++) {
|
|
write_options(fd, fp[i]);
|
|
}
|
|
fputc(0,fd);
|
|
/* write text segment */
|
|
for(i=0;i<j;i++) {
|
|
fwrite(fp[i]->buf + fp[i]->tpos, 1, fp[i]->tlen, fd);
|
|
}
|
|
/* write data segment */
|
|
for(i=0;i<j;i++) {
|
|
fwrite(fp[i]->buf + fp[i]->dpos, 1, fp[i]->dlen, fd);
|
|
}
|
|
write_reloc(fp, j, fd);
|
|
if(!noglob) {
|
|
write_globals(fd);
|
|
} else {
|
|
fputc(0,fd);
|
|
fputc(0,fd);
|
|
}
|
|
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
int write_options(FILE *fp, file65 *file) {
|
|
return fwrite(file->buf+BUF, 1, file->tpos-BUF-1, fp);
|
|
}
|
|
|
|
int read_options(unsigned char *buf) {
|
|
int c, l=0;
|
|
|
|
c=buf[0];
|
|
while(c && c!=EOF) {
|
|
c&=255;
|
|
l+=c;
|
|
c=buf[l];
|
|
}
|
|
return ++l;
|
|
}
|
|
|
|
int read_undef(unsigned char *buf, file65 *file) {
|
|
int i, n, l = 2, ll;
|
|
|
|
n = buf[0] + 256*buf[1];
|
|
|
|
file->nundef = n;
|
|
|
|
if (n == 0) {
|
|
file->ud = NULL;
|
|
} else {
|
|
file->ud = malloc(n*sizeof(undefs));
|
|
if(!file->ud) {
|
|
fprintf(stderr,"Oops, no more memory\n");
|
|
exit(1);
|
|
}
|
|
i=0;
|
|
while(i<n){
|
|
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, buf[l]=%d\n",
|
|
file->ud[i].name, file->ud[i].name, file->ud[i].len,ll,l,buf[l]);*/
|
|
i++;
|
|
}
|
|
}
|
|
return l;
|
|
}
|
|
|
|
/* compute and return the length of the relocation table */
|
|
int len_reloc_seg(unsigned char *buf, int ri) {
|
|
int type, seg;
|
|
|
|
while(buf[ri]) {
|
|
if((buf[ri] & 255) == 255) {
|
|
ri++;
|
|
} else {
|
|
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) {
|
|
case 0x80:
|
|
break;
|
|
case 0x40:
|
|
ri++;
|
|
break;
|
|
case 0x20:
|
|
break;
|
|
}
|
|
if(seg==0) ri+=2;
|
|
}
|
|
}
|
|
return ++ri;
|
|
}
|
|
|
|
#define reldiff(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) {
|
|
int n, old, new, seg;
|
|
|
|
n = buf[0] + 256*buf[1];
|
|
buf +=2;
|
|
|
|
while(n) {
|
|
/*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--;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
file65 *load_file(char *fname) {
|
|
file65 *file;
|
|
struct stat fs;
|
|
FILE *fp;
|
|
int mode, hlen;
|
|
size_t n;
|
|
|
|
file=malloc(sizeof(file65));
|
|
if(!file) {
|
|
fprintf(stderr,"Oops, not enough memory!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*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) {
|
|
fprintf(stderr,"Oops, no more memory!\n");
|
|
exit(1);
|
|
}
|
|
|
|
fp = fopen(fname,"rb");
|
|
if(fp) {
|
|
n = fread(file->buf, 1, file->fsize, fp);
|
|
fclose(fp);
|
|
if((n>=file->fsize) && (!memcmp(file->buf, cmp, 5))) {
|
|
mode=file->buf[7]*256+file->buf[6];
|
|
if(mode & 0x2000) {
|
|
fprintf(stderr,"file65: %s: 32 bit size not supported\n", fname);
|
|
free(file->buf); free(file); file=NULL;
|
|
} else
|
|
if(mode & 0x4000) {
|
|
fprintf(stderr,"file65: %s: pagewise relocation not supported\n",
|
|
fname);
|
|
free(file->buf); free(file); file=NULL;
|
|
} else {
|
|
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);
|
|
}
|
|
} else
|
|
fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno));
|
|
} else
|
|
fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno));
|
|
|
|
return file;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
glob *gp = NULL;
|
|
int gm=0;
|
|
int g=0;
|
|
|
|
int write_reloc(file65 *fp[], int nfp, FILE *f) {
|
|
int tpc, pc, i;
|
|
unsigned char *p;
|
|
int low = 0, seg, typ, lab;
|
|
|
|
/* no undefined labels ? TODO */
|
|
fputc(0,f);
|
|
fputc(0,f);
|
|
|
|
tpc = fp[0]->tbase-1;
|
|
|
|
for(i=0;i<nfp;i++) {
|
|
pc = fp[i]->tbase-1;
|
|
p = fp[i]->buf + fp[i]->trpos;
|
|
|
|
while(*p) {
|
|
while((*p)==255) { pc+=254; p++; }
|
|
pc+=*(p++);
|
|
seg=(*p)&7;
|
|
typ=(*p)&0xe0;
|
|
if(typ==0x40) low=*(++p);
|
|
p++;
|
|
if(seg==0) {
|
|
lab=p[0]+256*p[1];
|
|
seg=gp[lab].seg;
|
|
p+=2;
|
|
}
|
|
if(seg>1) {
|
|
while(pc-tpc>254) {
|
|
fputc(255,f);
|
|
tpc+=254;
|
|
}
|
|
fputc(pc-tpc, f);
|
|
tpc=pc;
|
|
fputc(typ | seg, f);
|
|
if(typ==0x40) {
|
|
fputc(low,f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fputc(0,f);
|
|
|
|
tpc = fp[0]->dbase-1;
|
|
|
|
for(i=0;i<nfp;i++) {
|
|
pc = fp[i]->dbase-1;
|
|
p = fp[i]->buf + fp[i]->drpos;
|
|
|
|
while(*p) {
|
|
while((*p)==255) { pc+=254; p++; }
|
|
pc+=*(p++);
|
|
seg=(*p)&7;
|
|
typ=(*p)&0xe0;
|
|
if(typ==0x40) low=*(++p);
|
|
p++;
|
|
if(seg==0) {
|
|
lab=p[0]+256*p[1];
|
|
seg=gp[lab].seg;
|
|
p+=2;
|
|
}
|
|
if(seg>1) {
|
|
while(pc-tpc>254) {
|
|
fputc(255,f);
|
|
tpc+=254;
|
|
}
|
|
fputc(pc-tpc, f);
|
|
tpc=pc;
|
|
fputc(typ | seg, f);
|
|
if(typ==0x40) {
|
|
fputc(low,f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fputc(0,f);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int write_globals(FILE *fp) {
|
|
int i;
|
|
|
|
fputc(g&255, fp);
|
|
fputc((g>>8)&255, fp);
|
|
|
|
for(i=0;i<g;i++) {
|
|
fprintf(fp,"%s%c%c%c%c",gp[i].name,0,gp[i].seg,
|
|
gp[i].val & 255, (gp[i].val>>8)&255);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int read_globals(file65 *fp) {
|
|
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) {
|
|
/*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++) {
|
|
if(ll==gp[i].len && !strcmp(name, gp[i].name)) {
|
|
fprintf(stderr,"Warning: label '%s' multiply defined (%s and %s)\n",
|
|
name, fp->fname, gp[i].file->fname);
|
|
gp[i].fl = 1;
|
|
break;
|
|
}
|
|
}
|
|
/* not already defined */
|
|
if(i>=g) {
|
|
if(g>=gm) {
|
|
gp = realloc(gp, (gm=(gm?2*gm:40))*sizeof(glob));
|
|
if(!gp) {
|
|
fprintf(stderr,"Oops, no more memory\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
if(g>=0x10000) {
|
|
fprintf(stderr,"Outch, maximum number of labels (65536) exceeded!\n");
|
|
exit(3);
|
|
}
|
|
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++;
|
|
}
|
|
|
|
buf +=3;
|
|
n--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int find_global(unsigned char *bp, file65 *fp, int *seg) {
|
|
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++) {
|
|
if(gp[i].len == l && !strcmp(gp[i].name, n)) {
|
|
*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;
|
|
}
|
|
}
|
|
fprintf(stderr,"Warning: undefined label '%s' in file %s\n",
|
|
n, fp->fname);
|
|
return 0;
|
|
}
|
|
|
|
int reloc_seg(unsigned char *buf, int pos, int ri, int *lreloc, file65 *fp) {
|
|
int type, seg, old, new;
|
|
|
|
/*
|
|
pos = position of segment in *buf
|
|
ri = position of relocation table in *buf
|
|
*/
|
|
pos--;
|
|
/*printf("reloc_seg: adr=%04x, tdiff=%04x, ddiff=%04x, bdiff=%04x, zdiff=%04x\n", pos, fp->tdiff, fp->ddiff, fp->bdiff, fp->zdiff); */
|
|
while(buf[ri]) {
|
|
if((buf[ri] & 255) == 255) {
|
|
pos += 254;
|
|
ri++;
|
|
} else {
|
|
pos += buf[ri] & 255;
|
|
ri++;
|
|
type = buf[ri] & 0xe0;
|
|
seg = buf[ri] & 0x07;
|
|
/*printf("reloc entry @ ri=%04x, pos=%04x, type=%02x, seg=%d\n",ri, pos, type, seg);*/
|
|
ri++;
|
|
switch(type) {
|
|
case 0x80:
|
|
old = buf[pos] + 256*buf[pos+1];
|
|
if(seg) {
|
|
new = old + reldiff(seg);
|
|
} else {
|
|
new = old + find_global(buf+ri, fp, &seg);
|
|
ri += 2; /* account for label number */
|
|
}
|
|
/*printf("old=%04x, new=%04x\n",old,new);*/
|
|
buf[pos] = new & 255;
|
|
buf[pos+1] = (new>>8)&255;
|
|
break;
|
|
case 0x40:
|
|
old = buf[pos]*256 + buf[ri];
|
|
if(seg) {
|
|
new = old + reldiff(seg);
|
|
} else {
|
|
new = old + find_global(buf+ri+1, fp, &seg);
|
|
ri += 2; /* account for label number */
|
|
}
|
|
buf[pos] = (new>>8)&255;
|
|
buf[ri] = new & 255;
|
|
ri++;
|
|
break;
|
|
case 0x20:
|
|
old = buf[pos];
|
|
if(seg) {
|
|
new = old + reldiff(seg);
|
|
} else {
|
|
new = old + find_global(buf+ri, fp, &seg);
|
|
ri += 2; /* account for label number */
|
|
}
|
|
buf[pos] = new & 255;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*lreloc = pos;
|
|
return ++ri;
|
|
}
|