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.DOC
< prev
next >
Wrap
Text File
|
2000-06-30
|
15KB
|
529 lines
L2 (C Linker) v2.1 1 7 Dec 81
The Mark of the Unicorn Linker
For BDS C
v2.1 7 Dec 81
Linker and Docs by
Scott W. Layson, Mark of the Unicorn
L2 is an alternative to CLINK for linking BDS C programs. A
program linked with CLINK will have a jump table at the beginning
of each function; calls to other functions are made indirectly
through the table. L2 eliminates these jump tables, and adjusts
indirect calls through them to go directly to the target function.
Besides making the code imperceptibly faster, this has two real
advantages: one, it makes the code smaller by 4% to 10% (the latter
has been observed in a program containing many small functions
which do little besides call a few other functions), and it allows
SID to display the name of the target function of a call,
simplifying debugging.
L2 seems to be complete enough to replace CLINK entirely. Its
biggest advantage is that it's written in C, so that if you need
some feature it doesn't have, you can just hack it in. However,
its user interface and certain aspects of its behavior are rather
different.
The most important difference is the distinction it makes between
"program" and "library" CRL files. Program files are loaded in
their entirety; each function in a program file is linked in,
whether or not it has been referenced by the time it is encountered
(unless another function with the same name has already been
loaded). Library files are scanned for needed functions; only
those that have been referenced by another function are included in
the object code. CLINK treats all CRL files as libraries in this
sense (except see the -f option for v1.4).
A typical command line is
l2 foo bar -l bletch grotz -wa
Given this command, L2 will load all the functions in FOO.CRL and
BAR.CRL (the program files). Then it will scan the libraries
BLETCH.CRL, GROTZ.CRL, DEFF.CRL, and DEFF2.CRL (in that order) for
functions that have been referenced but not linked. If there
remain unsatisfied references, L2 will display a list of the needed
functions and prompt for the name of a CRL file to scan; it will
L2 (C Linker) v2.1 2 7 Dec 81
repeat this process until all references are satisfied (just like
CLINK). Then it will write the resulting code to FOO.COM, display
the link statistics, and write a symbol table (with the link stats
appended) to FOO.SYM.
In more detail, then: here is a list of the available command-line
options. Options consist of a dash followed by a (possibly
one-letter) word, preceded and followed by a space. Unlike
CLINK's, L2's options may not be combined; "-l -w", for example,
may not be abbreviated "-lw"; and "-m fubar" may not be written
"-mfubar".
-f <funcs> Reserves enough table size for <funcs> functions.
(<funcs> is in decimal.) The default is 200. If
you often link programs with more than 200
functions, you may wish to change the default --
it's in setup() in L2.C.
-l CRL file names before the first "-l" on the
command line will be treated as program files; CRL
files after the first "-l" are treated as
libraries. Subsequent "-l"s have no effect.
-m <name> <name> becomes the top-level function. This is
the function initially called when the .COM file
is run; by default, of course, it is "main". Note
that, unlike with CLINK, the top-level function
need not be the first function in the first CRL
file; it can be anywhere. -m also works with -ovl
(see below).
-ovl <name> <addr>
An overlay segment will be built instead of a root
segment; the overlay will be linked to run at base
address <addr> (entered in hex). <name> is the
name of the root segment for which the overlay is
being built; <name>.SYM, a symbol table produced
with either L2 or CLINK, will be read in *before*
the CRL files, to allow overlay functions to call
root functions. The name of the top-level
function in the overlay -- i.e., the one that gets
invoked by a call to the overlay base address --
is by default not "main", but rather <firstcrl>,
the name of the first CRL file in the L2 command
line. The overlay segment is written to
<firstcrl>.OVL. (See example below.)
-org <addr> This option is used to produce a root segment with
base address <addr>, e.g., for use in generating
code for ROMming. <addr> is entered in hex, and is
the starting address of the code, not of RAM; the
default is, of course, 0x100. (To link a program
L2 (C Linker) v2.1 3 7 Dec 81
for a nonstandard CP/M, you need a C.CCC,
DEFF.CRL, and DEFF2.CRL which have been assembled
for that address. If you are running L2 on a
nonstandard CP/M, you should change the default
origin in setup() to 0x4300.) If you are using
this option to generate code for ROM, be sure to
use the "-t" option also (see below).
-t <addr> Works just like the CLINK "-t" option: sets the
stack pointer to the given address at the start of
the run-time package. This option MUST ALWAYS BE
USED when "-org" is used to generate code for ROM.
IF "-t" is NOT used, then the first two
instructions of the resulting COM file will be:
lhld origin-100h+6
sphl
(where "origin" is normally 0x100 or 0x4300) while
using "-t" causes the first two instructions to
be:
lxi sp,<addr>
nop
-w A SID-compatible symbol table is written to
<firstcrl>.SYM, where <firstcrl> is the name of
the first CRL file listed in the command line.
This table is normally produced in address order,
not alphabetical order like CLINK's; see below for
how to change this.
-wa A variation on -w. The link statistics, which are
always displayed on the console at the end of
linking, are also appended to the .SYM file. If
the resulting .SYM file is read into SID, SID will
complain by issuing its typical verbose error
message "?", but then will work correctly. The
big advantage of putting the stats at the end of
the .SYM file is that one can subsequently look at
that file to see exactly how long the code was and
where the externals started.
-ws Another variation on -w. This one writes the
symbol table to <firstcrl>.SYM and the link
statistics to <firstcrl>.LNK.
Because L2 is so large, it cannot always link large programs in a
single pass. If it runs out of memory during linking, it will
switch automatically to (very slow) two-pass mode. (If it says
"Module won't fit in memory at all", you probably have a very large
program file. Split it up or make it a library. If this doesn't
L2 (C Linker) v2.1 4 7 Dec 81
work, you don't have enough memory to use L2.)
L2 is built from the source files L2.C, SCOTT.C, and CHARIO.C. A
typical compilation is
cc l2.c -e4500
cc scott.c
cc chario.c
followed by either
clink l2 chario scott
or
l2 l2 chario -l scott
depending on whether an L2.COM is handy.
If you want a slightly shorter version, comment out the "#define
OVERLAYS" statement near the beginning of L2.C. You can then
compile with -e4100; the resulting L2 will not accept the "-ovl"
option.
If you have a pre-release of MARC and want a MARC cross-linker,
uncomment the "#define MARC". Then, when you use the "-marc"
option, L2 will look for CM.CCC, DEFFM.CRL, and DEFF2M.CRL, which
should be the MARC versions of these files. L2 will produce a .COM
file which must be MFTPed to MARC, then converted to load format.
L2 itself does not yet run under MARC; if anyone has the energy to
convert it, let me know!
L2 (C Linker) v2.1 5 7 Dec 81
Relocatable Overlay Manager
MAKOVL is a variation on L2. It builds relocatable overlays and
stores them in fixed-size slots in a single overlay file. Here is
the (rather terse) documentation from the beginning of MAKOVL.C:
Command format:
makovl <root name> <overlay name> {<CRL file>
[-l {<CRL file>}] [-nd]}
Overlay descriptor file, <root name>.DES, contains:
<overlay slot size> <relocation info size>
<CRL file> ... (default search list)
... (more default search list)
<blank line>
<overlay name> <slot number>
<function name> <comments or whatnot>
<function name> <comments or whatnot>
... (an entry for each top-level function in
the overlay)
<blank line>
<overlay name> <slot number>
<function name> <comments or whatnot>
<function name> <comments or whatnot>
...
... (an entry for each overlay in the file)
Overlay segments are of length <overlay slot size> bytes,
of which the last <relocation info size> bytes holds a
list of relocation offsets. This is a null-terminated
string of byte values giving the difference between
successive addresses to be relocated; a value of 255
means to add 255 to the next byte value to get the
offset. The first offset is relative to -1 (so that we
can relocate the first word of the overlay). At the
beginning of the overlay is a table of addresses of
top-level functions, one address for each function listed
for that overlay in the descriptor file.
The -l option works as for L2: CRL files listed before
L2 (C Linker) v2.1 6 7 Dec 81
the -l are loaded in entirety; those after are just
scanned for needed functions. Any functions specified in
the default search list in the overlay descriptor file
are also scanned, unless the -nd (no default) option is
given.
The overlay, once created, is written into <root
name>.OVL, at address <slot number> * <overlay slot
size>.
Here is an example of a .DES file, with comments in brackets:
1024 128 [1K overlay slots; 128 relocation
bytes]
lib1 lib2 lib3 [default CRL libraries]
OvlOne 0 [overlay name, slot number]
Func11 [callable functions in the overlay]
Func12
Func13
OvlTwo 1 [another overlay name & slot]
Func21
Func22
Func23
Here is some code to load and execute the generated overlays:
/* Overlay manager */
int curovl, ovlfd;
#define OVLSIZE 1024 /* overlay space size in bytes
*/
#define RELOCSIZE 128 /* size of relocation info */
char overlay[OVLSIZE];
OvlInit() /* start overlay manager */
{
curovl = -1;
if ((ovlfd = open ("FUBAR.OVL", INPUT)) < 0) {
puts ("Can't find the overlay file, FUBAR.OVL\n");
exit (1);
}
}
OvlFini() /* clean up overlay manager */
{
close (ovlfd);
}
L2 (C Linker) v2.1 7 7 Dec 81
OvlCall (ovlno, fun, arg1, arg2) /* call function <fun> in
overlay <ovlno> */
int ovlno, fun, arg1, arg2; /* with args (<arg1>,
<arg2>) */
{
int *ovltab, (*ovlfunct)(); /* note C bug: "int
(**ovltab)()" doesn't work */
OvlLoad (ovlno);
ovltab = overlay;
ovlfunct = ovltab[fun];
return (*ovlfunct) (arg1, arg2);
}
OvlLoad (ovlno) /* load overlay <ovlno> */
int ovlno;
{
char reloc[RELOCSIZE];
if (ovlno == curovl) return;
if (seek (ovlfd, ovlno * ((OVLSIZE + RELOCSIZE) / 128),
ABSOLUTE) < 0
|| read (ovlfd, overlay, (OVLSIZE / 128)) < 0
|| read (ovlfd, reloc, (RELOCSIZE / 128)) < 0) {
puts ("Read error in the overlay file,
FUBAR.OVL\n");
exit (1);
}
OvlReloc (overlay, reloc);
curovl = ovlno;
}
OvlReloc (code, rels) /* relocate an overlay */
char *code, *rels;
{
int *itemp;
char *btemp;
btemp = code - 1;
while (*rels) {
btemp += *rels;
if (*rels++ == 255) btemp += *rels++;
itemp = btemp;
*itemp += code;
}
}
To call these functions:
L2 (C Linker) v2.1 8 7 Dec 81
#define FUNC11 0, 0
#define FUNC12 0, 1
#define FUNC13 0, 2
...
OvlCall (FUNC11, arg1, arg2);
...
To make a MAKOVL.COM:
cc makovl.c -e4100
cc chario.c (if necessary)
cc scott.c (if necessary)
l2 makovl chario -l scott
Good luck
Scott W. Layson
Mark of the Unicorn
P.O. Box 423
Arlington, MA 02174