392 lines
18 KiB
Plaintext
392 lines
18 KiB
Plaintext
![]() |
CHAPTER 13 ASSOCIATED TOOLS
|
|||
|
|
|||
|
|
|||
|
XREF Cross-reference and Symbol Listing Facility
|
|||
|
|
|||
|
|
|||
|
XREF is a tool that creates a cross-referenced symbol table
|
|||
|
listing of your program.
|
|||
|
|
|||
|
To invoke XREF, you must provide a program invocation line,
|
|||
|
either typed to the console when the DOS command prompt appears,
|
|||
|
or included in a batch file. The program invocation line
|
|||
|
consists of the program name XREF, followed by the name of a .SYM
|
|||
|
symbol table file produced by A86 when you assembled your
|
|||
|
program. You do not need to give the .SYM extension. Note that
|
|||
|
if you follow normal methodology, the name of the symbol table
|
|||
|
file is the same as the name of the program.
|
|||
|
|
|||
|
XREF will obtain the list of source files from the symbols file,
|
|||
|
read those source files, and create a listing file with the same
|
|||
|
name as the .SYM file, but with a .XRF extension.
|
|||
|
|
|||
|
Prior to V3.12, XREF required the list of source files to be
|
|||
|
explicitly given, and allowed you to specify the name of the
|
|||
|
output file. To retain compatibility with batch files invoking
|
|||
|
the old XREF, the current version ignores anything on the command
|
|||
|
tail after the symbols file name. This means you can no longer
|
|||
|
specify a different output file name. Sorry about that-- I
|
|||
|
couldn't think of any other way to be compatible without
|
|||
|
overwriting somebody's source files with XREF output. You can
|
|||
|
always rename the file after XREF is completed.
|
|||
|
|
|||
|
For example, you can type XREF myprog to obtain the cross-
|
|||
|
reference for the assembly that produced myprog.SYM. The output
|
|||
|
will be in the file myprog.XRF.
|
|||
|
|
|||
|
The output of XREF is an alphabetical listing of all the
|
|||
|
non-local symbols in your program. For each symbol, XREF gives
|
|||
|
its type, the file in which it was defined, its value, and a list
|
|||
|
of all procedures in which the file was used. If you print this
|
|||
|
file, you typically use the TCOLS tool to obtain a multi-column
|
|||
|
listing from XREF's single-column output.
|
|||
|
|
|||
|
Note the use of procedure names to identify references -- this is
|
|||
|
unique to the A86 package, and makes the cross-reference listing
|
|||
|
truly readable. Other cross-reference listings give either line
|
|||
|
numbers, which are meaningless unless you go find the associated
|
|||
|
line; or a file name, which doesn't give you as much useful
|
|||
|
information.
|
|||
|
|
|||
|
Here is a more detailed description of the various pieces of
|
|||
|
information provided for each symbol:
|
|||
|
|
|||
|
1. TYPE. Labels are indicated by a colon immediately following
|
|||
|
the symbol name. Special symbols such as macro names are
|
|||
|
denoted by an appropriate word such as "macro" in place of the
|
|||
|
value on the following line. Other symbol types are described
|
|||
|
by one or two characters, following the symbol name.
|
|||
|
Possibilities for the first character are:
|
|||
|
13-2
|
|||
|
|
|||
|
m for a simple memory variable
|
|||
|
+ for an index memory quantity
|
|||
|
c for a constant
|
|||
|
i for an interrupt-equate
|
|||
|
s for a structure
|
|||
|
|
|||
|
If there is a second letter, it is a size attribute: b for
|
|||
|
byte, w for word, f for far (or doubleword).
|
|||
|
|
|||
|
2. FILE in which the symbol was defined. The name is stripped of
|
|||
|
its extension, which is presumably the same for all your
|
|||
|
source files. The name is preceded by = or period, which
|
|||
|
denotes a definition of, not a reference to the symbol.
|
|||
|
|
|||
|
3. VALUE, given as 4 hex digits, on the line following the
|
|||
|
symbol. For memory variables, this is the location of the
|
|||
|
variable. For indexed quantities, this is the
|
|||
|
constant-displacement part of the quantity. For structures,
|
|||
|
it is the size of the structure. For interrupt equates, it is
|
|||
|
the number of the interrupt.
|
|||
|
|
|||
|
4. REFERENCES, given on indented lines following the symbol name.
|
|||
|
All occurrences of the symbol in your program produce a
|
|||
|
reference. If the symbol is the first thing on a line, it is
|
|||
|
considered a "definition" of that symbol, the reference listed
|
|||
|
is the source file name. The name is preceded by a period if
|
|||
|
the definition was via a colon (i.e., a label); it is preceded
|
|||
|
by an equals sign otherwise. If the symbol is not the first
|
|||
|
thing on the line, then it is not a definition. The reference
|
|||
|
listing consists of the name of the last definition that XREF
|
|||
|
scanned (which, if your program is organized in a standard
|
|||
|
way, will be the name of the procedure in which the reference
|
|||
|
occurred.
|
|||
|
|
|||
|
Observe that you must use the local-label facility of A86 to
|
|||
|
make this work. If you don't use local labels as your
|
|||
|
"place-marker" symbols, the symbol XREF gives you will often
|
|||
|
be the name of the last "place-marker" symbol, not the name of
|
|||
|
the last procedure.
|
|||
|
|
|||
|
To save space, duplicate reference entries are denoted by a
|
|||
|
single entry, followed by "*n", where n is the decimal number
|
|||
|
of occurrences of that entry.
|
|||
|
|
|||
|
|
|||
|
EXMAC Macro Expansion Tool
|
|||
|
|
|||
|
There is a tool called EXMAC which will help you troubleshoot A86
|
|||
|
program lines that call macros. If you are not sure about what
|
|||
|
code is being generated by your macro calls, EXMAC will tell you.
|
|||
|
|
|||
|
To use this tool, you must first assemble your macro definitions,
|
|||
|
to produce a symbol table file. A86 will produce a .SYM file
|
|||
|
even if there were errors. If the errors weren't too
|
|||
|
catastrophic, the SYM file should be good enough to enable EXMAC
|
|||
|
to do its job.
|
|||
|
13-3
|
|||
|
|
|||
|
EXMAC can be used in two different ways. First, it can be used
|
|||
|
as an interactive program. You invoke the program in this way by
|
|||
|
typing just "EXMAC myprog", where myprog.SYM is the name of the
|
|||
|
symbols file. Then you can type in any number of macro-call
|
|||
|
lines. After each line, the program will display the expanded
|
|||
|
program text it produces. If the program does not think your
|
|||
|
line is a macro call, it will simply echo the line back to you.
|
|||
|
In this mode, you exit the program by typing control-Z at the
|
|||
|
beginning of a line, then terminating the line with the ENTER
|
|||
|
(RETURN on some computers) key. On most IBM-compatible
|
|||
|
computers, the control-Z code is also generated by the F6 key,
|
|||
|
for convenience.
|
|||
|
|
|||
|
The second way of using EXMAC is to feed a source file to it. It
|
|||
|
will output the equivalent source file with the macros expanded.
|
|||
|
You may then, if you wish, rename the new file as the original
|
|||
|
source file, and assemble the new file. This method is useful if
|
|||
|
you get an error on a macro expansion line, and you don't know
|
|||
|
where the error came from. To use EXMAC in this second way, you
|
|||
|
simply redirect standard input and output: "EXMAC myprog <infile
|
|||
|
>outfile". With the redirection, EXMAC will take its input from
|
|||
|
the file "infile" instead of the keyboard; and it will send its
|
|||
|
output to the file "outfile" instead of the screen. (If you are
|
|||
|
not familiar with redirection of standard input and output, you
|
|||
|
might want to read about it in Chapter 6, "Standard Input and
|
|||
|
Standard Output", of the MS-DOS reference manual.)
|
|||
|
|
|||
|
|
|||
|
A86LIB Source File Library Tool
|
|||
|
|
|||
|
There is a tool, A86LIB.COM, available only if you are
|
|||
|
registered, that lets you build libraries of source files. To
|
|||
|
use A86LIB, you must first code and debug the A86 source files
|
|||
|
that you wish to include in your library. Then you issue the
|
|||
|
command A86LIB followed by the names of the source files.
|
|||
|
Wildcards are accepted; so you will typically want to gather the
|
|||
|
source files into a single directory, and use the wildcard
|
|||
|
specification. For example, if you use the filename extension .8
|
|||
|
for your source files, you can issue the command A86LIB *.8 to
|
|||
|
create the library.
|
|||
|
|
|||
|
The library created consists of a catalog file, always named
|
|||
|
A86.LIB, together with the source files that you fed to A86LIB to
|
|||
|
create the catalog.
|
|||
|
|
|||
|
The following observations about A86LIB are in order:
|
|||
|
|
|||
|
1. Unlike object-code libraries, A86.LIB contains only symbol
|
|||
|
names and file names; it does not contain the code itself. You
|
|||
|
MUST retain the source files used to create A86.LIB, because
|
|||
|
A86 will read those files that it needs after consulting
|
|||
|
A86.LIB to read their names.
|
|||
|
13-4
|
|||
|
|
|||
|
2. A86LIB records all non-local symbols that start a line, and
|
|||
|
are followed by a colon or an EQU. (Recall that local symbols
|
|||
|
are those names consisting of a single letter followed by one
|
|||
|
or more decimal digits.) A86LIB also records all symbols
|
|||
|
appearing on lines starting with the word PUBLIC.
|
|||
|
|
|||
|
3. If a symbol appears in more than one library source file, it
|
|||
|
will be logged for the first file A86LIB sees, and not the
|
|||
|
subsequent ones. No error will be reported, unless and until
|
|||
|
A86 tries to assemble both files in one assembly, and sees a
|
|||
|
conflict.
|
|||
|
|
|||
|
4. A86LIB is simple-minded. A86LIB does NOT recognize or expand
|
|||
|
macros; nor does it recognize conditional-assembly directives.
|
|||
|
This is because the library files do not stand by themselves;
|
|||
|
the macros and conditional-assembly variables being used might
|
|||
|
well be defined in the main program of the programs accessing
|
|||
|
the library files.
|
|||
|
|
|||
|
You may update A86.LIB by running A86LIB again; either with new
|
|||
|
files or previously-recorded ones. If A86LIB is given a file it
|
|||
|
had already read in a previous run, then A86LIB marks all the
|
|||
|
symbols it had logged for the file as deleted, before rereading
|
|||
|
the file. Those symbols that are still in the file are then
|
|||
|
"unmarked". Thus, symbols that have been deleted from the file
|
|||
|
disappear functionally from A86.LIB, but still occupy space
|
|||
|
within A86.LIB. What I'm getting at is this: A86LIB will
|
|||
|
tolerate alterations in library files quite nicely; but for
|
|||
|
optimum storage efficiency you should delete A86.LIB and rebuild
|
|||
|
it from scratch any time you delete anything from the library.
|
|||
|
A86LIB is so fast that this is never very painful.
|
|||
|
|
|||
|
|
|||
|
Using A86.LIB in A86 Assemblies
|
|||
|
|
|||
|
Once you have created a library with A86LIB, you access it simply
|
|||
|
by calling the procedures in it from your A86 program. When A86
|
|||
|
finishes an assembly and sees that there are undefined symbols in
|
|||
|
your program, it will automatically look for copies of A86.LIB in
|
|||
|
the current directory (then in other directories, as described in
|
|||
|
the next section). If any of the undefined symbols are found in
|
|||
|
the A86.LIB catalog, the files containing them are assembled.
|
|||
|
You see this in the list of files output to the console by A86.
|
|||
|
|
|||
|
The subroutines in your library or libraries are effectively a
|
|||
|
permanent part of the A86 language. They can be called up
|
|||
|
effortlessly in your A86 programs. In time you can build up an
|
|||
|
impressive arsenal of library modules, making A86 as easy to
|
|||
|
program in as most high-level languages.
|
|||
|
13-5
|
|||
|
|
|||
|
Environment Variable A86LIB
|
|||
|
|
|||
|
You can set an environment variable A86LIB to specify which
|
|||
|
drives or subdirectories contain A86.LIB files. The variable
|
|||
|
consists of a sequence of path names separated by semicolons,
|
|||
|
just like the PATH variable used by the operating system. For
|
|||
|
example, if you include in your AUTOEXEC.BAT file the line
|
|||
|
|
|||
|
SET A86LIB=C:\bin\lib;\tools\a86lib
|
|||
|
|
|||
|
then A86 will look for A86.LIB in the current directory, then it
|
|||
|
will look for C:\bin\lib\A86.LIB, then \tools\a86lib\A86.LIB. A86
|
|||
|
will keep looking in all three catalog files, assembling the
|
|||
|
appropriate source files from any or all of them, until there are
|
|||
|
no more undefined symbols, or there are no more source files to
|
|||
|
assemble.
|
|||
|
|
|||
|
For every symbol in an A86.LIB catalog, there is recorded the
|
|||
|
name of the library file containing the symbol. The library file
|
|||
|
is assumed to be in the same directory as its A86.LIB file,
|
|||
|
unless a complete path name (starting with \ or a drive
|
|||
|
specifier) was fed to A86.LIB when A86.LIB was created.
|
|||
|
|
|||
|
|
|||
|
Forcing a Library Search
|
|||
|
|
|||
|
You may force A86 to assemble library files before moving on to
|
|||
|
more of your program's source files. You do this by placing a
|
|||
|
hash sign # (hex code 23) between file names in your invocation
|
|||
|
line. For example, suppose your program has two modules FIRST.8
|
|||
|
and LAST.8. FIRST.8 calls subroutines from your library; but you
|
|||
|
need the library files assembled before LAST.8 is assembled. (You
|
|||
|
might want this because LAST.8 allocates memory space beyond the
|
|||
|
end of your program, which would be the end of LAST.8 if it were
|
|||
|
truly the last module.) You accomplish this by the invocation
|
|||
|
line:
|
|||
|
|
|||
|
A86 FIRST.8 # LAST.8
|
|||
|
|
|||
|
Note that there is never any need to force a library search at
|
|||
|
the end of your program modules: A86 always makes a library
|
|||
|
search there, if you have any undefined symbols.
|
|||
|
|
|||
|
|
|||
|
Listings with A86
|
|||
|
|
|||
|
A86 does not produce a .LST file, or anything similar to it! (We
|
|||
|
now pause, to allow traditionalists to recover from their
|
|||
|
swooning shock.) OK, everybody back to consciousness? Good.
|
|||
|
Now let's all try to strip away our preconceptions, and look at
|
|||
|
things with a fresh viewpoint.
|
|||
|
|
|||
|
In particular, let's consider what we use a listing file for, and
|
|||
|
see how A86 meets those needs. I've been programming for 20
|
|||
|
years; I have generated literally tons of listings. Historically,
|
|||
|
here's what I have used listings for:
|
|||
|
13-6
|
|||
|
|
|||
|
1. To find out what my error messages are. In the early days of
|
|||
|
Intel, the text editor was so bad that it was actually faster
|
|||
|
to march across the building and physically print the list
|
|||
|
file, than it was to use an editor to find error messages! But
|
|||
|
even with a fast editor, what a pain it is to go into the list
|
|||
|
file, enduring its 120-column wide format on your 80-column
|
|||
|
screen, copy down the errors on paper, then go back to the
|
|||
|
source file to find where the errors were. Why doesn't the
|
|||
|
assembler just stick the messages directly into your source
|
|||
|
file, where you can view them and edit the source
|
|||
|
simultaneously? That's what A86, and only A86, does, if you
|
|||
|
want it to.
|
|||
|
|
|||
|
2. To see what code was generated; those hexadecimal bytes at the
|
|||
|
left of the listing. That was a real necessity, back in the
|
|||
|
days of hexadecimal debuggers. There we were, furiously
|
|||
|
patching those hex object bytes. We needed the listings to
|
|||
|
find our way around the program, while debugging. Today, we
|
|||
|
have symbolic, disassembling debuggers, such as D86. The
|
|||
|
power of today's debuggers means that you seldom need to look
|
|||
|
at hex object bytes. If you do, the debugger can show them to
|
|||
|
you.
|
|||
|
|
|||
|
3. To get a symbol-table listing. The necessity of this
|
|||
|
diminishes a great deal when you have a SYMBOLIC debugger; but
|
|||
|
I still like to have a listing from time to time. So I have
|
|||
|
devised a separate program, XREF, that goes through another
|
|||
|
pass of the source file(s), and creates the most useful
|
|||
|
cross-reference listing.
|
|||
|
|
|||
|
You may ask, "Why am I being forced to essentially re-assemble
|
|||
|
my code to get a symbol table, when other assemblers will give
|
|||
|
it to me in the original assembly?" Don't be fooled. Those
|
|||
|
other assemblers go through all your source files twice, or
|
|||
|
even three times. They just do it behind your back, every
|
|||
|
time you want an assembly. That's one reason why my assembler
|
|||
|
is so much faster than everyone else's.
|
|||
|
|
|||
|
4. To just look at the code. I have often in the past needed to
|
|||
|
see that program, spread out on paper, just to get a handle on
|
|||
|
what the program is doing. But I have needed this less and
|
|||
|
less lately. Why? For two reasons. First, text editors have
|
|||
|
improved. It's much, much easier than it was before to cruise
|
|||
|
through a file on the screen. Second, my programs have
|
|||
|
adapted to the screen-viewing methodology. Almost
|
|||
|
subconsciously, I have started making the conceptual "chunks"
|
|||
|
of my code fit into 1 or 2 24-line screens, rather than 1 or 2
|
|||
|
60-line pages. This, of course, makes better, more modular
|
|||
|
programs. (Spaghetti tends to untangle when you chop it up.)
|
|||
|
It's gotten to the point where I can develop (and have
|
|||
|
developed) a 5000-line application, fully debugged, without
|
|||
|
ever making a listing!
|
|||
|
13-7
|
|||
|
|
|||
|
5. For archival purposes. I still do this; you should never put
|
|||
|
100% trust in magnetic media. But I've stripped away the
|
|||
|
reasons for having anything but the source code and the symbol
|
|||
|
table. So I just copy the source files and the
|
|||
|
cross-reference listing to the printer. I haven't looked at
|
|||
|
the listings too much; so I haven't bothered with pagination
|
|||
|
control. If you want to, you can insert form feeds into your
|
|||
|
source; A86 will ignore them. Or, you can write a simple
|
|||
|
listing tool that recognizes the PAGE directive; A86 ignores
|
|||
|
that directive, also.
|
|||
|
|
|||
|
As a partial remedy to those who have not been convinced by the
|
|||
|
above arguments, I now have a D86 command that sends a
|
|||
|
disassembly to a file. The disassembly is formatted in the style
|
|||
|
of an assembler listing file, with locations and hex codes at the
|
|||
|
left. See the D86 manual for details.
|
|||
|
|
|||
|
|
|||
|
Mimicking Tool: FAKE.EXE
|
|||
|
|
|||
|
As of this writing, Turbo C is aware only of the existence of
|
|||
|
Microsoft's MASM for assembling source files it generates. I
|
|||
|
hope to persuade Borland to provide a switch to Turbo C that
|
|||
|
causes it to invoke A86 directly. Until that happens, I offer
|
|||
|
the tool FAKE.EXE, that convinces Turbo C that A86 is really
|
|||
|
MASM.
|
|||
|
|
|||
|
To use FAKE.EXE, it must be renamed MASM.EXE in your disk system.
|
|||
|
I would have named it MASM myself, except that
|
|||
|
|
|||
|
1. Bill Gates would probably get mad at me if I did, and
|
|||
|
|
|||
|
2. You need to decide what to do with your real MASM if you have
|
|||
|
it, before installing FAKE. You could either place FAKE
|
|||
|
(named MASM.EXE) into the individual directories containing
|
|||
|
Turbo C programs, or you can rename MASM to something like
|
|||
|
MSM.EXE or REALMASM.EXE.
|
|||
|
|
|||
|
Having renamed FAKE.EXE to MASM.EXE, you may now use the Turbo
|
|||
|
C's switch, -B, that allows you to place A86 statements into your
|
|||
|
C program. You don't need to worry about the gory details of
|
|||
|
what FAKE does.
|
|||
|
|
|||
|
If you like gory details, here they are: FAKE filters the command
|
|||
|
line handed to it, replacing switches:
|
|||
|
|
|||
|
/D becomes =
|
|||
|
/ml becomes +c
|
|||
|
/mx becomes +C
|
|||
|
/E becomes +f
|
|||
|
|
|||
|
FAKE also eliminates the semicolon, appends .ASM to the source
|
|||
|
file name, and turns on the O and S switches. It then feeds the
|
|||
|
resulting filtered command line to A86 for assembly.
|
|||
|
|
|||
|
|