home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
BDSC
/
BDSC-2
/
L2-225.ARK
/
LI.C
< prev
next >
Wrap
Text File
|
1988-05-21
|
37KB
|
1,414 lines
/* ********
* L2.C * New linker for BDS C
********
Written 1980 by Scott W. Layson
This code is in the public domain.
This is an improved linker for BDS C CRL format.
Modified to v2.2.3, 11/27/1982 by David Kirkland
This is version 2.2 as distributed by BDS C UG, with
the following modifications:
- The c debugger is supported. This adds the "-NS", "-S", and
"-D" command line options.
- DEFF3.CRL is scanned, if it is present on disk
- New mechanism for default drive selection--the DEF_DRIVE macro added.
- Minor changes to messages.
- Eliminates need for SCOTT.C by change to fscanf format string
in function "loadsyms" when reading .SYM file for overlay processing.
- Ability to rescan DEFF*.CRL if reply with a carriage return to prompt
message when functions are missing.
- "-I" option, which allows interactive entry of command line
arguments. If the command line ends in a "-i", then L2 treats
the command line as Incomplete, and prompts the user for more
arguments. This is especially useful if you have a replacement
CCP which does not allow 127 character long command lines
(e.g., ZCPR). This option orginally implemented, in a different
way, by Gil Shapiro.
Modified to v2.2.4, 03/24/1983 by David Kirkland
- "-N" option added to produce .COM files which do not perform a
warm boot after execution
As in clink, if both "-n" and "-t" are specified, "-t" is given
priority.
- "-NS" option removed/"-S" option changed. Now the default is NO
system library files (see CDB docs for explanation of system
library files); system library functions made it impossible to set
a breakpoint at the return of library functions in certain instances.
Mod. v2.2.5, July 1984 by Greg Lee to read MicroSoft REL files:
- Z option added like that of CLINK -- don't zero externals.
- E option added to provide default beginning external address.
- Program or library files can be entered with extension .REL,
in which case they are assumed to be REL files with
a CSEG and/or a DSEG (but no ASEG or COMMON). DSEG's are
intended to correspond with external data of C-compiled modules.
- Function names must be "public" and external functions "ext"
in the assembler source for M80. All public names are assumed
to be functions by C-compiled modules, but references
from one assembled module to data in another are ok. As
with L80, if external references are not forward, the
appropriate modules of a library may fail to be loaded on
the first pass.
- One can't do arithmetic with external symbols, such as
"abra equ cadabra+6" where cadabra is external.
- CRL symbols can have 8 characters, but REL file symbols
only 7, so 7 character long REL file symbols are considered to have
an 8th wild character ('?') that will match any 8th character in
a CRL symbol.
- DSEG data and addresses are assumed to be offset by the address
provided with the "-e" option when the main program module
was compiled or else with the new "-e" option of the linker.
If no such address was given, and a DSEG is encountered, this
causes the linker to abort.
- If any real data is found in a DSEG (after "db" or "dw"), then
(1) the Z option is automatically triggered, and
(2) the COM file written to disk is extended sufficiently
to include the part of the external area where the
the (initialization) data was deposited.
- Long files requiring disk mode may require DSEG data to be
loaded last, since the linker cannot write code to disk after
DSEG data has been written to disk.
- The M80 pseudo-op '.REQUEST' is implemented. The requested
REL files are searched after other library files.
Compilation instructions (assuming l2.com, v2.2.5 is available):
cc l2 -e5100
cc chario
m80 =rdrl
m80 =chario
m80 =spr
l2 l2 rdrl.rel spr.rel chario.rel
(SPR.MAC is just an assembly language version of the '_spr' library
function -- it need not be used, but it saves 1/2k of code. Also,
the C version of CHARIO could be used.)
Mod. v2.2.6, November, 1984 by Greg Lee to use the library
BDSCLIB.REL (instead of DEFF.CRL and DEFF2.CRL)
- * option added to load WILD.CCC instead of C.CCC (cf.
wildccc.doc)
Revised compilation instructions (using v2.2.6 of l2):
cc l2 -e4900
cc chario
m80 =rdrl
m80 =chario
l2 l2 rdrl.rel chario.rel
(The above "-e4900" assumes my revised C.CCC, which is 1/2k
smaller than the standard version.)
*********************************
The DEF_DRIVE macro is used to define the drive from which L2 will load C.CCC,
DEFF.CRL, DEFF2.CRL, and DEFF3.CRL (if it exists). The macro takes as an
argument the filename and extension, and "returns" the name with whatever drive
designator is needed. The macro also encloses the name in quotes; thus, the
argument when the macro is invoked must NOT be within quotes.
That is, to open C.CCC on the proper drive, we use the C code
if (ERROR==fopen(DEF_DRIVE(C.CCC), iobuf)) .....
*/
#define RTRACE 0 /*3 show stuff in rel file */
#define DEF_DRIVE(fn) "fn" /* Make this "0/A:fn" for, say, user 0 on A */
#define SUB_FILE "$$$.SUB" /* submit file to delete on error exit...
* if you use SDOS, use "a:$$$$.sub"; if you've
* hacked your CCP, you may need to change the
* drive designator letter */
#define RST_NUM 6 /* C debugger RST number. Should be identical
to the RSTNUM symbol in CCC.ASM */
#define OVERLAYS /* comment this out for shorter version */
/* These #defines from NOBOOT.C for version 1.50 */
#define SNOBSP 0x0138 /* Location of Set NoBoot SP routine in C.CCC */
#define NOBRET 0x013B /* Location of NoBoot RETurn routine in C.CCC */
#define CLREX 0x0141 /*3 location of clear externals vector in C.CCC */
/*
#define MARC /* for MARC cross-linker version
(enables the "-marc" option) */
*/
#include <bdscio.h>
#define NUL 0
#define FLAG char
#define repeat while (1)
#define STDOUT 1
/* Phase control */
#define INMEM 1 /* while everything still fits */
#define DISK1 2 /* overflow; finish building table */
#define DISK2 3 /* use table to do window link */
int phase;
/* function table */
struct funct {
char fname[9];
FLAG flinkedp; /* in memory already? */
FLAG fdebug; /* TRUE unless this routine required
only by a lib function after -s */
char *faddr; /* address of first ref link if not linked */
} *ftab;
int nfuncts; /* no. of functions in table */
int maxfuncts; /* table size */
#define LINKED 1 /* (flinkedp) function really here */
#define EXTERNAL 2 /* function defined in separate symbol table */
char fdir [512]; /* CRL file function directory */
/* command line parameters etc. */
int nprogs, nlibs;
char progfiles [30] [15]; /* program file names */
char libfiles [20] [15]; /* library file names */
int deflibindex; /* index of first default (DEFF*) library */
FLAG symsp, /* write symbols to .sym file? */
appstatsp, /* append stats to .sym file? */
sepstatsp; /* write stats to .lnk file? */
FLAG Zflag, /*3 disable zeroing of external area? */
Wflag; /*3 use wild expansion? */
#ifdef MARC
FLAG maxmemp, /* punt MARC shell? */
marcp; /* uses CM.CCC */
#endif
FLAG relflag; /*3 loading a REL file? */
FLAG anynotlinked; /*3 any unlinked symbols after scanlib? */
int minlk; /*3 during scanlib, index before first unlinked
symbol */
FLAG nomorecode; /*3 cannot accept code after data written */
char mainfunct[10];
FLAG ovlp; /* make overlay? */
char symsfile [15]; /* file to load symbols from (for overlays) */
/* C debugger variables */
FLAG Dflag;
FLAG SysStat; /* TRUE if "-s" option given & now active */
int SysNum; /* index into libfiles of "-s", or -1 if none */
FLAG Tflag; /* TRUE if "-t" option given */
FLAG Nflag; /* TRUE if "-n" option given */
unsigned Tval; /* arg to "-t", if present */
/* useful things to have defined */
struct inst {
char opcode;
char *address;
};
union ptr {
unsigned u; /* an int */
unsigned *w; /* a word ptr */
char *b; /* a byte ptr */
struct inst *i; /* an instruction ptr */
};
/* Link control variables */
union ptr codend; /* last used byte of code buffer + 1 */
union ptr loadpt; /*3 where to put code during REL load */
union ptr datapt; /*3 where to put data during REL load */
union ptr maxdata; /*3 max dseg address, to estimate end of
of externals when main() is .REL */
union ptr exts; /* start of externals */
union ptr acodend; /* actual code-end address */
unsigned extspc; /* size of externals */
unsigned origin; /* origin of code */
unsigned buforg; /* origin of code buffer */
unsigned jtsaved; /* bytes of jump table saved */
char *lspace; /* space to link in */
char *lspcend; /* end of link area */
char *lodstart; /* beginning of current file */
char *lastdata; /*3 remember how much of ext. area to save */
/*3 external function rdrl reads REL bitstream */
struct rrec {
char itemtype;
char segtype;
char linktype;
int dataword;
char lsymlen;
char lsymbol[8];
} *rdrl(), *cd;
/*3 REL file address type codes */
#define ASEG 0
#define CSEG 1
#define DSEG 2
#define COMMON 3
/*3 character used for 8th char.C of REL external symbols */
#define WILDC '?'
/* i/o buffer */
struct iobuf {
int fd;
int isect; /* currently buffered sector */
int nextc; /* index of next char in buffer */
char buff [128];
} ibuf, obuf;
/* BDS C i/o buffer */
char symbuf[BUFSIZ];
/* seek opcodes */
#define ABSOLUTE 0
#define RELATIVE 1
#define INPUT 0
#define TRUE (-1)
#define FALSE 0
#define NULL 0
/* 8080 instructions */
#define LHLD 0x2A
#define LXISP 0x31
#define LXIH 0x21
#define SPHL 0xF9
#define JMP 0xC3
#define CALL 0xCD
#define RET 0xC9
#define PARMSIZE 400
char parmtext[PARMSIZE]; /* "-i" command line args go here */
int parmindex; /* first unused character in parmtext */
/* strcmp7 locals, made global for speed */
char _c1, _c2, _end1, _end2;
/**************** End of Globals ****************/
main (argc, argv)
int argc;
char **argv;
{
char *argvv[40];
puts ("Mark of the Unicorn Linker ver. 2.2.6\n");
inc_proc(&argc, argv, &argvv);
setup (argc, argvv);
linkprog();
linklibs();
if (phase == DISK1) rescan();
else wrtcom();
if (symsp) wrtsyms();
}
inc_proc(count, argv, argvv) int *count; char **argv, **argvv; {
/* process the "-i" argument by building a new argv vector
* in argvv.
*/
int i;
for (i=0; i<*count; i++) argvv[i] = argv[i];
while (!strcmp(argvv[*count-1],"-I"))
buildvec(count, argvv);
}
buildvec (count, argvv) int *count; char **argvv; {
char line[MAXLINE], *p;
puts("Enter continuation\n*");
gets(line);
for (p=line, --*count; ;) {
while (isspace(*p)) p++;
if (!*p) break;
argvv[(*count)++] = &parmtext[parmindex];
while (*p && !isspace(parmtext[parmindex] = toupper(*p++)) )
parmindex++;
parmtext[parmindex++] = 0;
}
}
setup (argc, argv) /* initialize function table, etc. */
int argc;
char **argv;
{
symsp = appstatsp = sepstatsp = FALSE; /* default options */
#ifdef MARC
marcp = maxmemp = FALSE;
#endif
ovlp = FALSE;
nprogs = 0;
nlibs = 0;
strcpy (&mainfunct, "MAIN"); /* default top-level function */
origin = 0x100; /* default origin */
maxfuncts = 200; /* default function table size */
Zflag = Tflag = Nflag = FALSE; /* no "-z","-t" or "-n" yet */
SysNum = -1;
SysStat = FALSE;
Dflag = FALSE;
cmdline (argc, argv);
ftab = endext();
lspace = ftab + maxfuncts;
lspcend = topofmem() - (1024 + 2100);
if (lspace > lspcend)
Fatal ("Insufficient memory to do anything at all!\n");
loadccc();
nfuncts = 0;
#ifdef OVERLAYS
if (ovlp) loadsyms();
#endif
intern (&mainfunct);
phase = INMEM;
buforg = origin;
jtsaved = 0;
nomorecode = FALSE; /* no data yet written to disk */
maxdata.u =
lastdata = 0; /* no data encountered so far */
}
cmdline (argc, argv) /* process command line */
int argc;
char **argv;
{
int i, progp;
if (argc == 1) {
puts ("Usage is:\n");
puts (" l2 {program files} [-l {library files} ] ");
puts ("[-s {library files} ]\n");
puts ("\t[-m <main_name>] [-f <maxfuncts>] [-org <addr>]");
puts (" [-t <addr>] [-e <addr>]\n");
puts ("\t[-d] [-w | -wa | -ws] [-n][-z][-*]\n");
#ifdef OVERLAYS
puts ("\t[-ovl <rootname> <addr>]");
#endif
#ifdef MARC
puts ("\t[-marc]");
#endif
puts ("\t[-i]");
lexit (1);
}
progp = TRUE;
for (i=1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (!strcmp (argv[i], "-F")) {
if (++i>=argc) Fatal ("-f argument missing.\n");
sscanf (argv[i], "%d", &maxfuncts);
}
else if (!strcmp (argv[i], "-L")) progp = FALSE;
else if (!strcmp (argv[i], "-S")) {
progp = FALSE;
SysNum = nlibs;
}
else if (!strcmp (argv[i], "-M")) {
if (++i>=argc) Fatal ("-m argument missing.\n");
strcpy (&mainfunct, argv[i]);
}
#ifdef MARC
else if (!strcmp (argv[i], "-MARC")) {
maxmemp = TRUE;
marcp = TRUE;
}
#endif
else if (!strcmp (argv[i], "-ORG")) {
if (++i>=argc) Fatal ("-org argument missing.\n");
sscanf (argv[i], "%x", &origin);
}
else if (!strcmp (argv[i], "-N")) Nflag = TRUE;
else if (!strcmp (argv[i], "-Z")) Zflag = TRUE;
else if (!strcmp (argv[i], "-*")) Wflag = TRUE;
else if (!strcmp (argv[i], "-T")) {
if (++i >= argc)
Fatal ("-t argument missing.\n");
Tflag = TRUE;
sscanf (argv[i], "%x", &Tval);
}
else if (!strcmp (argv[i], "-E")) {
if (++i >= argc)
Fatal ("-e argument missing.\n");
sscanf (argv[i], "%x", &exts.u);
}
#ifdef OVERLAYS
else if (!strcmp (argv[i], "-OVL")) {
ovlp = TRUE;
if (i + 2 >= argc)
Fatal ("-ovl argument missing.\n");
strcpy (&symsfile, argv[++i]);
sscanf (argv[++i], "%x", &origin);
}
#endif
else if (!strcmp (argv[i], "-D")) Dflag = TRUE;
else if (!strcmp (argv[i], "-W")) symsp = TRUE;
else if (!strcmp (argv[i], "-WA"))
symsp = appstatsp = TRUE;
else if (!strcmp (argv[i], "-WS"))
symsp = sepstatsp = TRUE;
else if (!strcmp (argv[i], "-I"))
printf("-I ignored, must be last on line\n");
else printf ("Unknown option: '%s'\n", argv[i]);
}
else {
if (progp) strcpy (&progfiles[nprogs++], argv[i]);
else strcpy (&libfiles[nlibs++], argv[i]);
}
}
if (ovlp)
strcpy(&mainfunct, &progfiles[0][2*(progfiles[0][1]==':')] );
if (Dflag || SysNum!=-1)
Dflag = symsp = TRUE;
deflibindex = nlibs;
#ifdef MARC
#define NDEFF 3
strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFFM) : DEF_DRIVE(DEFF));
strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFF2M): DEF_DRIVE(DEFF2));
strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFF3M): DEF_DRIVE(DEFF3));
#else
#define NDEFF 4 /*3 deff's + bdsclib*/
strcpy(&libfiles[nlibs++], DEF_DRIVE(BDSCLIB.REL) );
strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF) );
strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF2) );
strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF3) );
#endif
}
loadccc() /* load C.CCC (runtime library) */
{
union ptr temp;
unsigned len;
codend.b = lspace;
if (!ovlp) {
#ifdef MARC
if (copen (&ibuf,
marcp ? DEF_DRIVE(CM.CCC) : DEF_DRIVE(C.CCC) ) < 0)
#else
if (copen (&ibuf,
Wflag ? DEF_DRIVE(WILD.CCC) : DEF_DRIVE(C.CCC) ) < 0)
#endif
Fatal ("Can't open %s\n", DEF_DRIVE(C.CCC) );
if (cread (&ibuf, lspace, 128) < 128) /* read a sector */
Fatal ("C.CCC: read error!\n");
temp.b = lspace + 0x17;
len = *temp.w; /* how long is it? */
cread (&ibuf, lspace + 128, len - 128); /* read rest */
codend.b += len;
cclose (&ibuf);
}
else codend.i++->opcode = JMP;
}
linkprog() /* link in all program files */
{
int i;
union ptr dirtmp;
struct funct *fnct;
for (i=0; i<nprogs; ++i) {
makecrl (&progfiles[i]);
if (copen (&ibuf, progfiles[i]) < 0) {
printf ("Can't open %s\n", progfiles[i]);
continue;
}
printf ("Loading %s\n", &progfiles[i]);
if (relflag)
{ readrel(1);
relflag = FALSE;
cclose(&ibuf);
continue;
}
readprog (i==0);
for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) {
fnct = intern (dirtmp.b); /* for each module */
skip7 (&dirtmp); /* in directory */
if (!fnct->flinkedp)
linkmod (fnct, lodstart + *dirtmp.w - 0x205,0);
else if (phase != DISK2) {
puts ("Duplicate program function '");
puts (&fnct->fname);
puts ("', not linked.\n");
}
dirtmp.w++;
} /* intern & link it */
cclose (&ibuf);
}
}
linklibs() /* link in library files */
{
int ifile;
anynotlinked = TRUE;
minlk = 0;
for (ifile=0; anynotlinked && ifile < nlibs; ++ifile) {
if (ifile==SysNum) SysStat = TRUE;
scanlib (ifile);
}
while (missingp()) {
anynotlinked = TRUE;
puts ("Enter the name of a file to be searched or CR: ");
gets (&libfiles[nlibs]);
if (libfiles[nlibs][0]) {
SysStat = FALSE;
scanlib (nlibs);
}
else {
if (SysNum!=-1)
SysStat = TRUE;
for (ifile=0; anynotlinked && ifile<NDEFF; ++ifile)
scanlib (deflibindex + ifile);
}
}
acodend.b = codend.b - lspace + buforg; /* save that number! */
if (!exts.b) exts.b = acodend.b;
}
missingp() /* are any functions missing? print them out */
{
int i, foundp;
foundp = FALSE;
for (i=0; i<nfuncts; ++i)
if (!ftab[i].flinkedp) {
if (!foundp) puts ("*** Missing functions:\n");
puts (&ftab[i].fname);
puts ("\n");
foundp = TRUE;
}
return (foundp);
}
rescan() /* perform second disk phase */
{
int i;
for (i=0; i < nfuncts; ++i)
if (ftab[i].flinkedp == LINKED) ftab[i].flinkedp = FALSE;
phase = DISK2;
buforg = origin;
puts ("\n\n**** Beginning second disk pass ****\n");
if (!ovlp) makeext (&progfiles[0], "COM");
else makeext (&progfiles[0], "OVL");
ccreat (&obuf, &progfiles[0]);
loadccc();
hackccc();
linkprog();
linklibs();
if (lastdata > codend.b) codend.b = lastdata;
if (cwrite (&obuf, lspace, codend.b - lspace) == -1
|| cflush (&obuf) < 0) Fatal ("Disk write error!\n");
cclose (&obuf);
stats (STDOUT);
}
readprog (mainp) /* read in a program file */
FLAG mainp;
{
char extp; /* was -e used? */
char *extstmp;
union ptr dir;
unsigned len;
if (cread (&ibuf, &fdir, 512) < 512) /* read directory */
Fatal ("-- read error!\n");
if (phase == INMEM && mainp) {
cread (&ibuf, &extp, 1);
cread (&ibuf, &extstmp, 2);
cread (&ibuf, &extspc, 2);
if (extp) exts.b = extstmp;
else exts.b = 0; /* will be set later */
}
else cseek (&ibuf, 5, RELATIVE);
for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir)); /* find end of dir */
++dir.b;
len = *dir.w - 0x205;
readobj (len, TRUE);
}
readobj (len, crllod) /* read in an object (program or lib funct) */
unsigned len;
FLAG crllod; /*3 read CRL? (or just check len for REL load) */
{
if (phase == DISK1 || codend.b + len >= lspcend) {
if (phase == INMEM) {
puts("\n** Out of memory--switching to disk mode **\n");
phase = DISK1;
}
if (phase == DISK2) {
if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
Fatal ("Disk write error!\n");
}
buforg += codend.b - lspace;
codend.b = lspace;
if (codend.b + len >= lspcend)
Fatal ("Module won't fit in memory at all!\n");
}
lodstart = codend.b;
if (crllod && cread (&ibuf, lodstart, len) < len)
Fatal ("-- read error!\n");
}
scanlib (ifile)
int ifile;
{
int i;
union ptr dirtmp;
FLAG morerel; /*3 keep track of whether have read eof link in REL */
if (minlk >= nfuncts)
{ anynotlinked = FALSE;
return;
}
makecrl (&libfiles[ifile]);
if (copen (&ibuf, libfiles[ifile]) < 0) {
if (ifile != deflibindex + (NDEFF-1))
printf ("Can't open %s\n", libfiles[ifile]);
return;
}
printf ("Scanning %s\n", &libfiles[ifile]);
if (!relflag && cread (&ibuf, &fdir, 512) < 512) /* read directory */
Fatal ("-- Read error!\n");
anynotlinked = FALSE;
if (relflag)
{ morerel = readrel(FALSE); /* position at first link 0 item */
i = minlk;
while (i < nfuncts && morerel)
{
if (ftab[i].flinkedp) /* a feeble attempt at opt'n */
{ if (i == minlk) minlk++; }
else
{ anynotlinked = TRUE;
if (!strcmp7(cd->lsymbol,&ftab[i].fname) )
/* load this module and go back to first unlinked f'n*/
{ morerel = readrel(2); i = minlk-1; }
}
i++;
/* when last unlinked function has been compared,
scan to next module (if there is one) and go back
to first unlinked function */
if (i == nfuncts)
{ if (morerel) morerel = readrel(FALSE);
i = minlk;
}
}
/* make sure to read to end of REL file */
while (morerel) morerel = readrel(FALSE);
}
else
for (i=minlk; i<nfuncts; ++i) /* scan needed functions */
if (ftab[i].flinkedp)
{ if (i == minlk) minlk++; }
else
{ anynotlinked = TRUE;
if (dirtmp.b = dirsearch (&ftab[i].fname))
{ readfunct (dirtmp.b);
linkmod (&ftab[i], lodstart,0);
}
}
relflag = FALSE;
cclose (&ibuf);
}
readfunct (direntry) /* read a function (from a library) */
union ptr direntry;
{
unsigned start, len;
skip7 (&direntry);
start = *direntry.w++;
skip7 (&direntry);
len = *direntry.w - start;
if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
readobj (len, TRUE);
}
/*3 load or scan a REL file */
/* loadit = FALSE -- don't load, and stop at link item 0
loadit = 1 -- load all 'til link item 15 (eof)
loadit = 2 -- load, but stop at link item 0
Returns TRUE when stopped at link 0, else FALSE */
readrel(loadit)
char loadit;
{
struct funct *fnct;
union ptr finalloc, raddr, temp;
char litem, currseg;
int i;
unsigned modoffset; /* when loading rel lib, keep track
of offset of beginning of module from
beginning of lib file */
lodstart =
loadpt.b = codend.b;
modoffset = 0;
currseg = CSEG;
finalloc.b = codend.b - lspace + buforg;
litem = 16; /* assign any value except 15 */
while(litem != 15)
{ cd = rdrl();
#if RTRACE
if (loadit) printf("Load "); else printf("Scan ");
printf("at %04x: ",loadpt.u);
#endif
switch(cd->itemtype)
{
case 0:
#if RTRACE
printf("code %02x\n", cd->dataword);
#endif
if (loadit)
{ if (currseg == DSEG)
{ dataroom(1);
if (phase != DISK1)
*datapt.b++ = cd->dataword;
}
else *loadpt.b++ = cd->dataword;
}
break;
case 1:
#if RTRACE
printf("addr %04x seg %d\n", cd->dataword,cd->segtype);
#endif
if (loadit)
{ temp.b = (cd->segtype==DSEG) ? (exts.b + cd->dataword)
: cd->dataword + modoffset + finalloc.b;
if (currseg == CSEG)
*loadpt.w++ = temp.b;
else if (currseg == DSEG)
{ dataroom(2);
if (phase != DISK1)
*datapt.w++ = temp.b;
}
}
break;
case 2: litem = cd->linktype;
#if RTRACE
printf("link %d : ", litem);
if (litem >= 5 && litem <= 14)
printf("addr %x seg %d ", cd->dataword,cd->segtype);
if (litem <= 7)
for (i = 0; i < cd->lsymlen; i++ )
putchar(0x7F & (cd->lsymbol[i]));
printf("\n");
#endif
if (!loadit)
{
if (litem == 0) return(TRUE);
}
else switch(litem)
{
case 0: /* PUBLIC SYMBOL */
modoffset = loadpt.b - lodstart;
if (loadit > 2)
{ codend.b = loadpt.b;
return(TRUE);
}
break;
case 7: /* ENTRY POINT */
fnct = intern(cd->lsymbol);
linkmod(fnct, lodstart, cd->dataword + modoffset);
/* during scanlib, signal stop at next link item 0 */
if (loadit > 1) loadit++;
break;
case 6: /* EXTERNAL REFERENCE */
/* a symbol declared "ext" but not referenced
will be link item 6, seg 0=ASEG - it should be ignored */
if (cd->segtype != ASEG)
{ fnct = intern(cd->lsymbol);
temp.b =
raddr.b = lodstart + cd->dataword + modoffset;
if (!fnct->flinkedp && phase == INMEM)
{
/* find end of chain in REL file */
while (*raddr.w)
{
#if RTRACE
printf("*chaining addr %x, contents %x\n", raddr.b, *raddr.w);
#endif
/* convert to real memory address */
*raddr.w = (*raddr.w - modoffset)
+ (lspace - buforg);
/* and descend one link */
raddr.b = *raddr.w;
}
/* point end of chain to head of old chain */
*raddr.w = fnct->faddr;
/* enter here in ftab as new chain head */
fnct->faddr = temp.b;
}
else /* put addr in each link of REL chain */
while (temp.b)
{ temp.b = *raddr.w;
*raddr.w = fnct->faddr;
#if RTRACE
printf("*Changed %x from %x to %x\n", raddr.b, temp.b, *raddr.w);
#endif
raddr.u = (temp.u - modoffset)
+ (lspace - buforg);
}
} /* end of if (cd->segtype == CSEG) */
break; /* for case litem == 6 */
case 11: /* ORG */
if ( (currseg = cd->segtype) == CSEG)
loadpt.b = lodstart + modoffset + cd->dataword;
else if (currseg == DSEG)
{ if (!exts.b) Fatal("Need -e<address> for DSEG");
if (maxdata.u < cd->dataword)
maxdata.u = cd->dataword;
datapt.b = (exts.u + cd->dataword) + (lspace - buforg);
if (datapt.u < lspace) Fatal("DSEG addr. too low");
}
break;
case 13: /* LENGTH OF CODE IN MODULE */
if (nomorecode)
Fatal("Cannot write code because of preceding DSEG data");
if
( loadit
&& (phase == DISK1 || loadpt.b + cd->dataword >= lspcend)
)
{ codend.b = loadpt.b;
readobj(cd->dataword, FALSE);
loadpt.b = codend.b;
modoffset = 0;
}
break;
case 3: /* REQUEST */
if (loadit && phase != DISK2)
{ temp.b = &libfiles[nlibs++];
strcpy7(temp.b, cd->lsymbol);
str7tont(temp.b);
*(temp.b+7) = '\0';
makeext(temp.b,"REL");
#if RTRACE
printf("Requested %s\n", temp.b);
#endif
}
break;
/* other cases for possible future use are
- 9 - offset for external reference
- 4 - arithmetic with external symbols (1st letter
of lsymbol gives the operation to perform)
- 2 - gives module name
- 10 - gives length of data
*/
default:
break;
} /* end switch(litem) */
break;
default: Fatal("Illegal code in REL file\n");
break;
} /* end switch(cd->itemtype) */
} /* end while(litem != 15) */
if (loadit) codend.b = loadpt.b;
return(FALSE);
}
/*3 check room for DSEG data */
dataroom(len)
char len;
{ if (phase != DISK1 && datapt.b + len >= lspcend)
if (phase == INMEM) phase = DISK1;
else
{ codend.b = datapt.b;
readobj(len, FALSE);
datapt.b = codend.b;
nomorecode = TRUE;
}
lastdata = datapt.b + len;
Zflag = TRUE;
}
/*3 global return value from cread1 */
char rrch ;
/*3 called by rdrl to read one byte from REL file */
cread1()
{
if (cread(&ibuf, &rrch, 1) != 1)
Fatal("Premature end of REL file\n");
return(rrch);
}
linkmod (fnct, modstart, foffset) /* link in a module */
struct funct *fnct;
union ptr modstart; /* loc. of module in memory */
unsigned foffset; /*3 for REL files with late entry pts*/
{
union ptr temp,
jump, /* jump table temp */
body, /* loc. of function in memory */
code, /* loc. of code proper in mem. */
finalloc; /* runtime loc. of function */
unsigned flen, nrelocs, jtsiz, offset;
fnct->flinkedp = LINKED;
if (phase != DISK2) {
finalloc.b =
(relflag && cd->segtype == DSEG)? exts.u + foffset
: codend.b - lspace + buforg + foffset;
if (phase == INMEM) chase (fnct->faddr, finalloc.b);
fnct->faddr = finalloc.b;
}
else finalloc.b = fnct->faddr;
/* REL file relocation already done */
if (relflag) return;
body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of fn body */
jump.i = body.i + (*modstart.b ? 1 : 0);
for (temp.b = modstart.b; *temp.b; skip7(&temp)) {
jump.i->address = intern (temp.b);
++jump.i;
}
++temp.b;
flen = *temp.w;
code.b = jump.b;
temp.b = body.b + flen; /* loc. of reloc parameters */
nrelocs = *temp.w++;
jtsiz = code.b - body.b;
if (Dflag && fnct->fdebug) {
if (phase!=DISK1) {
codend.i->opcode = (0307 + (8*RST_NUM));
codend.i->address = 0;
finalloc.b += 3;
}
codend.b += 3;
}
offset = code.b - codend.b;
if (phase != DISK1)
while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
finalloc.b, offset, flen);
flen -= jtsiz;
if (phase != DISK2) jtsaved += jtsiz;
if (phase != DISK1) movmem (code.b, codend.b, flen);
codend.b += flen;
}
relocate (param, body, jtsiz, base, offset, flen) /* do a relocation!! */
unsigned param, jtsiz, base, offset, flen;
union ptr body;
{
union ptr instr, /* instruction involved */
ref; /* jump table link */
struct funct *fnct;
/* if (param == 1) return; /* don't reloc jt skip */*/
instr.b = body.b + param - 1;
if (instr.i->address >= jtsiz)
instr.i->address += base - jtsiz; /* vanilla case */
else {
ref.b = instr.i->address + body.u;
if (instr.i->opcode == LHLD) {
instr.i->opcode = LXIH;
--ref.b;
}
fnct = ref.i->address;
instr.i->address = fnct->faddr; /* link in */
if (!fnct->flinkedp && phase == INMEM)
fnct->faddr = instr.b + 1 - offset; /* new list head */
}
}
intern (name) /* intern a function name in the table */
char *name;
{
struct funct *fptr;
if (*name == 0x9D) name = "MAIN"; /* Why, Leor, WHY??? */
for (fptr = &ftab[nfuncts-1]; fptr >= ftab; --fptr)
if (!strcmp7 (name, fptr->fname)) break;
if (fptr < ftab) {
if (nfuncts >= maxfuncts)
Fatal("Too many functions (limit is %d)!\n", maxfuncts);
fptr = &ftab[nfuncts];
strcpy7 (fptr->fname, name);
str7tont (fptr->fname);
fptr->flinkedp = FALSE;
fptr->faddr = NULL;
fptr->fdebug = !SysStat;
++nfuncts;
}
return (fptr);
}
dirsearch (name) /* search directory for a function */
char *name;
{
union ptr temp;
for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
if (!strcmp7 (name, temp.b)) return (temp.b);
return (NULL);
}
nextd (ptrp) /* move this pointer to the next dir entry */
union ptr *ptrp;
{
skip7 (ptrp);
++(*ptrp).w;
}
chase (head, loc) /* chase chain of refs to function */
union ptr head;
unsigned loc;
{
union ptr temp;
while (head.w) {
temp.w = *head.w;
*head.w = loc;
head.u = temp.u;
}
}
wrtcom() /* write out com file (from in-mem link) */
{
hackccc();
if (!ovlp) makeext (&progfiles[0], "COM");
else makeext (&progfiles[0], "OVL");
if (lastdata > codend.b) codend.b = lastdata;
if (!ccreat (&obuf, &progfiles[0]) < 0
|| cwrite (&obuf, lspace, codend.b - lspace) == -1
|| cflush (&obuf) < 0)
Fatal ("Disk write error!\n");
cclose (&obuf);
stats (STDOUT);
}
hackccc() /* store various goodies in C.CCC code */
{
union ptr temp;
struct funct *fptr;
temp.b = lspace;
fptr = intern (&mainfunct);
if (!ovlp) {
#ifdef MARC
if (!marcp) {
#endif
if (Tflag) {
temp.i->opcode = LXISP;
temp.i->address = Tval;
}
else if (Nflag) {
temp.i->opcode = JMP;
temp.i->address = SNOBSP;
temp.b = lspace + 0x09;
temp.i->opcode = JMP;
temp.i->address = NOBRET;
}
else {
temp.i->opcode = LHLD;
temp.i->address = origin - 0x100 + 6;
(++temp.i)->opcode = SPHL;
}
if (Zflag)
{ temp.b = lspace + 0x41;
temp.i->opcode = RET;
}
temp.b = lspace + 0xF; /* main function address */
temp.i->address = fptr->faddr;
#ifdef MARC
}
#endif
temp.b = lspace + 0x15;
*temp.w++ = exts.u;
++temp.w;
*temp.w++ = acodend.u;
if (extspc < maxdata.u)
extspc = maxdata.u;
*temp.w++ = exts.u + extspc;
}
else temp.i->address = fptr->faddr; /* that's a JMP */
#ifdef MARC
if (maxmemp) {
temp.b = lspace + 0x258;
temp.i->opcode = CALL;
temp.i->address = 0x50;
}
#endif
}
wrtsyms() /* write out symbol table */
{
int i, fd, compar();
qsort (ftab, nfuncts, sizeof(*ftab), &compar);
makeext (&progfiles[0], "SYM");
if (fcreat (&progfiles[0], &symbuf) < 0)
Fatal ("Can't create .SYM file\n");
for (i=0; i < nfuncts; ++i) {
puthex (ftab[i].faddr, &symbuf);
putc (' ', &symbuf);
fputs (&ftab[i].fname, &symbuf);
if (i % 4 == 3) fputs ("\n", &symbuf);
else {
if (strlen (&ftab[i].fname) < 3) putc ('\t', &symbuf);
putc ('\t', &symbuf);
}
}
if (i % 4) fputs ("\n", &symbuf);
if (appstatsp) stats (&symbuf);
putc (CPMEOF, &symbuf);
fflush (&symbuf);
fclose (&symbuf);
if (sepstatsp) {
makeext (&progfiles[0], "LNK");
if (fcreat (&progfiles[0], &symbuf) < 0)
Fatal ("Can't create .LNK file\n");
stats (&symbuf);
putc (CPMEOF, &symbuf);
fflush (&symbuf);
fclose (&symbuf);
}
}
compar (f1, f2) /* compare two symbol table entries by name */
struct funct *f1, *f2;
{
/* return (strcmp (&f1->fname, &f2->fname)); alphabetical order */
return (f1->faddr > f2->faddr); /* memory order */
}
#ifdef OVERLAYS
loadsyms() /* load base symbol table (for overlay) */
{ /* symbol table must be empty! */
int nread;
FLAG done;
char *c;
makeext (&symsfile, "SYM");
if (fopen (&symsfile, &symbuf) < 0)
Fatal ("Can't open %s.\n", &symsfile);
done = FALSE;
while (!done) {
nread =
fscanf (&symbuf, "%x %s\t%x %s\t%x %s\t%x %s\n",
&(ftab[nfuncts].faddr), &(ftab[nfuncts].fname),
&(ftab[nfuncts+1].faddr), &(ftab[nfuncts+1].fname),
&(ftab[nfuncts+2].faddr), &(ftab[nfuncts+2].fname),
&(ftab[nfuncts+3].faddr), &(ftab[nfuncts+3].fname));
nread /= 2;
if (nread < 4) done = TRUE;
while (nread-- > 0) ftab[nfuncts++].flinkedp = EXTERNAL;
}
fclose (&symbuf);
}
#endif
stats (chan) /* print statistics on chan */
int chan;
{
unsigned temp, *tptr;
tptr = 6;
fprintf (chan, "\n\nLink statistics:\n");
fprintf (chan, " Number of functions: %d\n", nfuncts);
fprintf (chan, " Code ends at: 0x%x\n", acodend.u);
fprintf (chan, " Externals begin at: 0x%x\n", exts.u);
fprintf (chan, " Externals end at: 0x%x\n", exts.u + extspc);
fprintf (chan, " End of current TPA: 0x%x\n", *tptr);
fprintf (chan, " Jump table bytes saved: 0x%x\n", jtsaved);
temp = lspcend;
if (phase == INMEM)
fprintf (chan,
" Link space remaining: %dK\n", (temp - codend.u) / 1024);
}
/*3 force extension to .CRL unless is .REL */
makecrl(fname) char *fname;
{
/*3 keep REL extension and raise flag */
if
( index(fname,".REL") > 0
|| index(fname,".rel") > 0
) relflag = TRUE;
else
{ makeext (fname, "CRL");
relflag = FALSE;
}
}
makeext (fname, ext) /* force a file extension to ext */
char *fname, *ext;
{
while (*fname && (*fname != '.')) {
*fname = toupper (*fname); /* upcase as well */
++fname;
}
*fname++ = '.';
strcpy (fname, ext);
}
strcmp7(s1, s2) char *s1, *s2; {
/* compare two strings, either bit-7-terminated or null-terminated */
for (; (_c1 = *s1) == *s2; s1++, s2++)
if ( (0x80 & _c1) || !_c1) return 0;
/*3 8th char of REL symbol is wild */
if ( (_c1 &= 0x7F) == WILDC || (_c2 = 0x7F & *s2) == WILDC ) return 0;
/* if ((_c1 &= 0x7F) < (_c2 = 0x7F & *s2)) return -1;*/
if (_c1 < _c2) return -1;
if (_c1 > _c2) return 1;
_end1 = (*s1 & 0x80) || !*(s1+1) || *(s1+1) == WILDC;
_end2 = (*s2 & 0x80) || !*(s2+1) || *(s2+1) == WILDC;
if (_end2 && !_end1) return 1;
if (_end1 && !_end2) return -1;
/* if (_end1 && _end2) */
return 0;
}
strcpy7 (s1, s2) /* copy s2 into s1 */
char *s1, *s2;
{
do {
*s1 = *s2;
if (!*(s2+1)) { /* works even if */
*s1 |= 0x80; /* s2 is null-term */
break;
}
++s1;
} while (!(*s2++ & 0x80));
}
skip7 (ptr7) /* move this pointer past a string */
char **ptr7;
{
while (!(*(*ptr7)++ & 0x80));
}
str7tont (s) /* add null at end */
char *s;
{
while (!(*s & 0x80)) {
if (!*s) return; /* already nul term! */
s++;
}
*s = *s & 0x7F;
*++s = NUL;
}
puthex (n, obuf) /* output a hex word, with leading 0s */
unsigned n;
char *obuf;
{
int i, nyb;
for (i = 3; i >= 0; --i) {
nyb = (n >> (i * 4)) & 0xF;
nyb += (nyb > 9) ? 'A' - 10 : '0';
putc (nyb, obuf);
}
}
Fatal (arg1, arg2, arg3, arg4) /* lose, lose */
char *arg1, *arg2, *arg3, *arg4;
{
printf (arg1, arg2, arg3, arg4);
lexit (1);
}
lexit (status) /* exit the program */
int status;
{
if (status == 1)
unlink (SUB_FILE);
exit(); /* bye! */
}
/* END OF L2.C */