|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 6283 (0x188b)
Types: TextFile
Notes: UNIX file
Names: »pass2.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/ld/pass2.c«
/*
* Pass 2
*/
/*
* Names of segments
*/
char *sname[] = {
"SHRI", "PRVI", "BSSI", "SHRD", "PRVD", "BSSD", "DEBUG", "SYM", "REL"
};
/*
* Read, relocate and output segments of module
*/
void
loadmod(mp)
mod_t *mp;
{
seg_t *isgp, *irsp, *osgp, *orsp;
sym_t *sp;
int opcode, relseg;
int segn;
uaddr_t addr, bias;
unsigned int symno;
FILE *ifp, *irfp, *ofp, *orfp;
static FILE *inputf[NLSEG];
static char *fname = NULL;
if (mp->fname == NULL) {
lfixup2(mp);
return;
}
if (watch)
mpmsg(mp, "loading");
for (segn=0; segn<NLSEG; segn++) {
if (segn!=L_REL&&outputf[segn]==NULL)
continue;
if (fname!=mp->fname) {
if (fname!=NULL)
fclose(inputf[segn]);
if ((inputf[segn]=fopen(mp->fname, "r"))==NULL) {
filemsg(mp->fname, "can't open (pass 2)");
exit(1);
}
}
fseek(inputf[segn], mp->seg[segn].daddr, 0);
if (watch && mp->seg[segn].size!=0)
message("relocating seg#%d[%06lo]@%06lo to %06lo",
segn, (long)mp->seg[segn].size,
(long)mp->seg[segn].vbase,
(long)oseg[segn].vbase);
}
fname = mp->fname;
irfp = inputf[L_REL];
irsp = &mp->seg[L_REL];
orfp = outputf[L_REL];
orsp = &oseg[L_REL];
while ((opcode=getbyte(irfp, irsp))!=EOF) {
addr = getaddr(irfp, irsp);
/* find segment in which it address lies */
for (segn=0, isgp=&mp->seg[0]; segn<L_SYM; segn++, isgp++) {
if (addr>=isgp->vbase && addr<isgp->vbase+isgp->size)
break;
}
if (segn==L_BSSI
|| segn==L_BSSD
|| segn==L_SYM) {
mpmsg(mp, "bad relocation address %06lo", (long)addr);
continue;
}
ifp = inputf[segn];
ofp = outputf[segn];
osgp = &oseg[segn];
/* put unrelocated stuff */
while (isgp->vbase < addr)
putbyte(getbyte(ifp, isgp), ofp, osgp);
bias = 0;
switch (relseg = opcode&LR_SEG) {
case L_SYM:
symno = getsymno(irfp, irsp);
if (symno>=mp->nsym) {
mpmsg(mp, "bad reloc. sym. no. %d", symno);
} else if ((sp=mp->sym[symno])==NULL) {
mpmsg(mp, "symbol %d not kept", symno);
} else if (sp->s.ls_type==(L_GLOBAL|L_REF)) {
if (orfp!=NULL) {
putbyte(opcode, orfp, orsp);
putaddr(osgp->vbase, orfp, orsp);
putsymno(sp->symno, orfp, orsp);
}
} else {
bias = sp->s.ls_addr;
if (orfp!=NULL) {
putbyte(sp->s.ls_type&LR_SEG
|opcode&~LR_SEG,
orfp, orsp);
putaddr(osgp->vbase, orfp, orsp);
/* keep segment size correct */
orsp->size -= sizeof(short);
}
}
break;
case L_SHRI:
case L_PRVI:
case L_BSSI:
case L_SHRD:
case L_PRVD:
case L_BSSD:
bias = oseg[relseg].vbase
- mp->seg[relseg].vbase;
case L_ABS:
if (orfp!=NULL) {
putbyte(opcode, orfp, orsp);
putaddr(osgp->vbase, orfp, orsp);
}
break;
default:
goto BadCode;
}
if (opcode&LR_PCR)
bias += isgp->vbase - osgp->vbase;
switch (opcode&LR_OP) {
default:
BadCode:
mpmsg(mp, "bad relocation opcode %03o", opcode);
break;
case LR_BYTE:
bias += getbyte(ifp, isgp);
putbyte((int)bias, ofp, osgp);
break;
case LR_WORD:
bias += getword(ifp, isgp);
putword((short)bias, ofp, osgp);
break;
case LR_LONG:
bias += vtop(getlong(ifp, isgp));
#if 0
if (segoff && (bias&0x00FF0000L)==0x00FF0000L) {
bias &= ~0x00FF0000L;
bias += 0x01000000L;
}
#endif
putlong((long)ptov(bias), ofp, osgp);
break;
}
}
/* copy remainder of segments */
for (segn=0; segn<L_SYM; segn++) {
register int b;
if ((ofp=outputf[segn])==NULL)
continue;
ifp = inputf[segn];
isgp = &mp->seg[segn];
osgp = &oseg[segn];
while ((b=getbyte(ifp, isgp))!=EOF)
putbyte(b, ofp, osgp);
}
#ifdef LADDR
#endif
/* adjust bss bases (others done by putbyte) */
oseg[L_BSSD].vbase += mp->seg[L_BSSD].size;
oseg[L_BSSI].vbase += mp->seg[L_BSSI].size;
}
#ifdef LADDR
/*
* Pad out with the fake module.
* Deal with BSS and `real' segments as well.
*/
void
lfixup2(mp)
register mod_t *mp;
{
extern char *sname[];
register int i;
register FILE *ofp;
register seg_t *osgp;
long p;
for (i=0; i<NXSEG; i++)
if ((p = mp->seg[i].size) != 0)
break;
if (watch)
message("paddding %s for %D bytes", sname[i], p);
if ((ofp = outputf[i]) == NULL)
return;
osgp = &oseg[i];
while (p-- > 0)
putbyte(0, ofp, osgp);
}
#endif
/*
* I/O routines
*/
void
putstruc(p, s, fp, sgp)
register char *p;
register unsigned int s;
register FILE *fp;
register seg_t *sgp;
{
while (s--)
putbyte(*p++, fp, sgp);
}
unsigned short
getword(fp, sgp)
FILE *fp;
seg_t *sgp;
{
return (worder==LOHI ? getlohi(fp, sgp) : gethilo(fp, sgp));
}
unsigned long
getlong(fp, sgp)
FILE *fp;
seg_t *sgp;
{
register unsigned short w1, w2;
register unsigned long l;
w1 = getword(fp, sgp);
w2 = getword(fp, sgp);
if (lorder == LOHI)
l = ((long)w2<<16) + w1; else
l = ((long)w1<<16) + w2;
return (l);
}
unsigned short
getlohi(fp, sgp)
FILE *fp;
seg_t *sgp;
{
register unsigned char b;
b = getbyte(fp, sgp);
return((getbyte(fp, sgp)<<8)|b);
}
unsigned short
gethilo(fp, sgp)
FILE *fp;
seg_t *sgp;
{
register unsigned char b;
b = getbyte(fp, sgp);
return((b<<8)|getbyte(fp, sgp));
}
int
getbyte(fp, sgp)
FILE *fp;
seg_t *sgp;
{
if (sgp->size==0)
return (EOF);
else {
sgp->size--;
sgp->vbase++;
return (getc(fp));
}
}
void
putword(w, fp, sgp)
unsigned short w;
FILE *fp;
seg_t *sgp;
{
if (worder==LOHI)
putlohi(w, fp, sgp);
else
puthilo(w, fp, sgp);
}
/*
* Put out a long integer.
*/
void
putlong(l, fp, sgp)
register unsigned long l;
FILE *fp;
seg_t *sgp;
{
register unsigned short w1, w2;
w1 = l>>16;
w2 = l&0xFFFF;
if (lorder == LOHI) {
putword(w2, fp, sgp);
putword(w1, fp, sgp);
} else {
putword(w1, fp, sgp);
putword(w2, fp, sgp);
}
}
void
putlohi(w, fp, sgp)
unsigned short w;
FILE *fp;
seg_t *sgp;
{
putbyte(w&0377, fp, sgp);
putbyte(w>>8, fp, sgp);
}
void
puthilo(w, fp, sgp)
unsigned short w;
FILE *fp;
seg_t *sgp;
{
putbyte(w>>8, fp, sgp);
putbyte(w&0377, fp, sgp);
}
void
putbyte(b, fp, sgp)
unsigned char b;
FILE *fp;
seg_t *sgp;
{
sgp->vbase++;
putc(b, fp);
}
/*
* Get a relocation address. There has to
* be a more efficient thing than a shift to
* do this!!
*/
unsigned long
getaddr(fp, sgp)
FILE *fp;
seg_t *sgp;
{
register unsigned w1, w2;
w1 = getlohi(fp, sgp);
w2 = getlohi(fp, sgp);
return (((long)w1<<16) + w2);
}