pabru / x86-s

A ONE-PASS ASSEMBLER FOR DOS/MINIX. Automatically exported.

Home Page:http://code.google.com/p/x86-s

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

		A ONE-PASS ASSEMBLER FOR DOS/MINIX
		------------------------------

			1 ABSTRACT

The assembler that comes with the MINIX operating system is heavily
used. At present it is extremely slow and requires a large amount of
disk space for its temporary file. I wanted to develop a fast
assembler that could do without much extra space.

This project also tries to find good data structures and methods of
coding a fast one pass assembler(`asm') with the restrictions on a
MINIX system.


			2 INTRODUCTION

MINIX is a UNIX clone that was designed to work on the IBM PC range of
machines. It is a very popular operating system among students because
of its low requirements from the hardware (a normal PC with 540KB
memory and 2 360KB floppy drives does quite well), for its proximity
to the UNIX operating system (its almost like System V) and most
importantly, the sources for the operating system and most of the
tools are included in the distribution.

The sources of the C compiler (`cc') and the assembler and loader
(`asld') are not included in the distribution.


			3 THE MINIX ASSEMBLER

The assembler plays an important role in the MINIX operating
system. There are no object files in the system.  The C compiler
generates code in the assembly language and the assembly language is
directly converted into an executable by `asld'. The C compiler has no
other form of output. (`cc', with or without the -S or the -c option
generates a `.s' assembly file only). The assembler takes the `.s'
assembly files and generates an executable.

The specifications of the assembler [1;384-385] are also adhered to by
this assembler. There are slight differences, which are mentioned in a
later chapter.

The assembler also accepts something called as packed assembly
language. Packed assembly language is generated from normal assembly
language by the utility called as the `libpack' and the reverse is
performed by the `libupack' utility [1;393]. What `libpack' does is
recognize commonly occurring strings and replace them with codes 128
to 255.  e.g. `push ax' is 128 and so on. Packing strips an assembly
file of its comments.[1;412]

Whether the input is packed or not does not matter to the
assembler. If there is a byte on the input which is greater than 127
then the assembler unpacks it. `asm' does not do unpacking now.

The MINIX `asld' also searches libraries for the files to be linked to
the current file and links them. The code for multiple files is
already there in `asm', but the code for searching the libraries
isn't.

		4 DEVELOPMENT OF THE ASSEMBLER

The assembler on the MINIX is extremely slow, and even with no
libraries to link to, it takes ages to assemble a program. Therefore I
decided to do the work on DOS using the Microsoft assembler
`MASM'. The debugging facilities on DOS are great compared to MINIX. I
used only `debug' on the generated files. With the options available
in MASM, (such as selective listing) debugging of the `.COM' file,
which doesn't have any symbolic information, even on a PC was easy.

The assembler is written in such a way that it should be able to
assemble itself under DOS to create a `.COM' file or under MINIX to
create an executable file directly.

The testing of the assembler was done on DOS, and then the source was
put onto MINIX. Since the input syntax of the MINIX assembler are not
exactly compatible with the DOS syntax, I've made some slight
adjustments to the assembler so that it accepts a language, which can
be assembled on DOS and which with very little modifications can be
assembled under MINIX.

		5 OPERATING SYSTEM CONSTRAINTS

The current assembler on the MINIX system does not generate separate
Instruction and Data space programs. The operating system supports two
models. The `small' model (The equivalent of the `tiny' model on the
MASM) in which the Instruction and the Data space (including stack and
all) together should occupy less than 64K and a separate I & D space
model (the equivalent of the MASM `small' model) where 64K is allowed
for the instruction and 64K for Data and Stack. Other modules are not
supported, to encourage programmers to use small modular
programs. Separate I and D programs have to be generated by the PCIX
assembler.

As I intended to assemble the assembler using the host assembler
itself, it meant that I had only 64K for the data and instruction
space. This means that the code and the data space of the assembler
should be as little as possible, so that larger programs can be
assembled.

Another restriction is that disk space is precious on the MINIX
because of the platforms that it operates on. Smaller the assembler
executable size, better is it.

		6 OPERATING SYSTEM INCOMPATIBILITIES

The output executable file formats for DOS and MINIX are quite
different.

On DOS for the `.COM' file, there is no header. The memory image of
the program is stored on the disk. The first 100H or 256 bytes of the
program are not stored. The program starts at location 100H. No
relocation information can be stored in the file. The same is the case
with the debug information.

This is managed by the assembler, with the help of a few assemble time
variables. The variable `OutputFrom' decides what part at the
beginning should be skipped. On DOS, this is set to 256 so that the
first 256 bytes are skipped. Also the location counter automatically
starts at 256 (100H) without any directive.

On MINIX, the executable which is generated has a 32 byte header,
which is generated by the assembler. Execution starts at location 0.

			7 DESIGN ISSUES


One of the primary aims was to keep the assembler small and fast. The
bast way to do this is to write the assembler in assembly language.

Since the amount of memory space is restricted, (64K for the
instruction and the data), I had to decide between creating a
temporary file or to restrict the output file size to 64K less the
space taken up by the assembler's instruction and data. I chose the
second option i.e.  restricting the output file size.

This means that at present the maximum size of the output file is
around 43K.

			8 THE INPUT LANGUAGE

The language accepted by asm is similar to the language accepted by
the PC-IX assembler. The symbols are made up of letters, digits and
underscores. (though [1] does not mention it, the period is also
allowed in an identifier, also as the starting character). The modes
using multiple registers are coded as in this example.

mov ax,34[bx+si]

The `bx+si' is treated as a single identifier and cannot have spaces
between it.  Constant operands have to be preceded by the number sign
`#'. Local variables are not permitted.

The pseudo instructions or the assembler directives are a superset of
the MINIX directives and they are as follows.

	.align	n	Align to a multiple of n bytes
	.ascii	str	Assemble a string
	.asciz	str	Assemble a zero terminated string
	.bss		What follows goes to the bss segment
	.byte	n	Assemble one or more bytes
	.data		What follows goes to the data segment
	.define	sym	Export the symbol from the file
	.errnz	n	Force Error if n is nonzero
	.even		Align to an even address
	.extern	sym	Declare sym external
	.globl	sym	same as .extern
	.include file	include the file into the current file
	.long	n	assemble a long
	.org	addr	Set Address within the current segment
	.short	n	assemble n as a short
	.space	n	skip n bytes
	.text		what follows goes into the text segment
	.word		assemble n as a word
	.zerow	n	assemble n words of zeros



The segment directives don't make much sense here as everything goes
into the same segment anyway. They are just ignored by `asm'.

The new directive that has been added is the include directive. It
includes another file at the current position into the source
file. After the include file finishes, processing is continued with
the main file, from where it was left off. There is no restriction on
the number of times includes can be nested. The filename should not be
enclosed in quotes and the full filename with path (relative or
absolute) and extension should be given


	9 DIFFERENCES BETWEEN THE MINIX ASSEMBLER AND ASM

There are some minor differences between the language that `asld'
assembles and the language that `asm' assembles.  Some of the
differences are detailed below.

The addressing mode in an instruction is enclosed in sqaure brackets
and not in parantheses. e.g. [bx].

The addressing mode, when it consists of multiple registers, has the
`+' sign separating the register names instead of the `_'
sign. e.g. mov ax,[bx+si]. This was done because the DOS assemblers
also accept this syntax and this makes the porting to minix simpler.

`asm' does not allow local labels as the documentation about their
behaviour is not very clear.

The documentation is also not very clear about when the decimal point
`.' is allowed in labels and when it isn't.  Looking at the sources of
`klib88.s' [1;456-470], it seems that the `.' is allowed in symbols
wherever alphabets are allowed.

One major difference is not in the specifications but in the behaviour
of the assembler. If you give an instruction like `add al,bl' (when
actually the instruction should have been `addb al,bl'), the assembler
silently accepts it and generates the instruction `add ax,bx' which is
wrong. `asm' reports errors whenever the operand sizes do not match
the mnemonics.  


			   10 STRING TABLE

The string table, in spite of its name doesn't mean a table. It means
string space. Keeping any string fixed size meant that there would be
a wastage of space.

e.g. The maximum size of the path is say 64 bytes. If you want to keep
an array of filenames that have been encountered, then the amount of
space that would have been wasted is tremendous.

The maximum size of the symbols is 32 bytes and again if these names
were kept in the symbol table, then the size of the symbol table would
have been tremendous.

Therefore all strings are kept in the string table. It works more or
less like a heap. There are no deletions from the string table, only
additions. Therefore, there is no complex management done. The only
thing kept track of is the position upto which the string table is
full.

All the references to the strings in the string table is done through
absolute pointers (not indices relative to the start of the string
table or the like).

At present the things stored in the symbol table are the names of the
files being assembled, the names of the symbols (assembler generated
as well as user specified) and the compiled expressions.

			    11 EXPRESSIONS

In assembly you keep encoutering assemble time expressions.  These
range from constant equates to complex operands.  Expressions can
occur at the right hand side of an equate or in operands, either as an
immediate operand or as the displacement in an addressing mode.

Expressions are normal infix expressions with only a few
operators. The operators are `+', `-', `*', `/' and `%' with the same
meanings that they have in C. Expressions can be paranthesized to any
level. The operands are symbols or constants. All values are treated
as 16 bit integer values.  whether symbols or constants. The number of
operators can be very easily changed as mentioned in `Improvements'.

The expressions can be arbitrarily complex and may contain symbols
that are defined, symbols that are not defined and
constants. Expressions may not be evaluatable at the time that they
are encountered. Therefore the evaluation of the expressions may have
to be delayed. All the symbols will be defined after the first
pass. `asm' is a one pass assembler so it doesn't have a second pass
to evaluate the expressions.

The expressions that are evaluatable when they are encountered are
evaluated. The expressions that are not evaluatable are stored as
compiled expressions in the string space.

The compiled expression is actually a postfix form of the expression,
in which the operands preceed the operators.  The operators are stored
as the ascii value of the character. One word is used for the operands
and one word is used for the operators. Since there is only one word
for the operands, it is not possible to specify whether the operand is
an index into the symbol table or it is a constant that was input.

The solution is that all operands are considered as indexes into the
symbol table. For constants fake entries are created, which is
actually an underscore `_' followed by the value of the symbol in hex
e.g. the fake symbol with the value 10 has the symbol `_000A'. When
another constant of the same value is used, the same entry is used and
new entries are not created.

The procedure of converting an infix paranthesized expression to a
postfix expression is given in most books.  The rules are all operands
on the input are put onto the output directly. When an operator comes
on the input. All the operators that are on the stack with precedence
more than (or equal to also for normal left associative operators) are
popped into the output and the input operator is pushed onto the
stack. If the end of the expression is encountered, then the operators
on the stack are popped onto the output.

The structure of the compiled expression is as follows. The first word
has the lower byte 0 the higher byte (as in the operators described
later) specifies the number of the operands that follow this
word. This is because, just looking at the word, it is impossible for
the expression evaluator to know whether the word is an operator or an
operand. All operands, as mentioned before are indexes into the symbol
table. Again indexes are actually not indexes of the symbol table
array, but pointers to the base of the entry in the symbol table.

After the specified number of operands have been read, there will be
another operator word. The operator word has the low byte as the ascii
value of the operator and the high byte as the number of operands that
follow this operator. (this might be zero, if the operands come right
one after the other). The sequence continues till you reach an
operator word that is zero, which means that the expression ended. The
expression always ends with a zero word.

The evaluation of the expression is simple. All the operands, whenever
they are encountered are pushed onto the stack and whenever an
operator is encountered the operands are popped from the stack and the
result is pushed onto the stack.

For operands in this case, the operands are actually pointers into the
symbol table, so for each operand encountered during evaluation, the
evaluator looks up the value of the operand from the symbol table. If
the attributes of the symbols say that he symbol hasn't been
evaluated, then the evaluation is abandoned and a flag is returned to
signify that the expression could not be evaluated.


			12 SYMBOL TABLE

Considering all the space restrictions that were mentioned before, one
of the main issues while designing the symbol table was the space
required.

The name of the symbol is not kept in the symbol table, instead the
pointer to the start of the name in the string space is kept.

Since the assembler is written in the `tiny' model, the code and the
data space is 64K. That means that 16 bits are enough for the pointers
into the string space. These pointers are absolute pointers and not
relative to the start of the string table (or anything else).

The other values that are stored in the symbol table are the offset of
the filename and the line number of the definition of the symbol (see
`string table').  Upto the point when the definition of the symbol is
encountered these actually hold the line number and the filename of
the first reference to the symbol. This is done for reporting errors
about undefined symbols. When the symbols are listed, the line number
and the filename of the definition are picked up from here.

A symbol can be defined by one of only two ways. The first way is as
the left hand side of an equate and the second way is as a
label. `asm' keeps track of whether a symbol is an equate or a label
for listing purposes, but otherwise the usage for both of them is the
same.

There is a word reserved in the symbol table for the attributes of the
symbol. The various attributes are stored as bits. The attributes are
`calculated, equate, fake, label, defined'. The bits are on if that
attribute is yes.  For labels, they are always defined and
calculated. Equates and other expressions may or may not be
evaluated. The calculated bit in the attributes is for that.

Fake symbols are generated for constants in expressions and also for
nameless expressions. When there are exoressions for operands and the
expression can not be evaluated, then an entry is made in the symbol
table for this expression with a fake symbol. These (like the fakes
discussed before) have two underscores `__' followed by a number in
hexadecimal.

If an expression can not be evaluated, then the compiled expression is
put into the string space and the value field of the symbol table
entry for that symbol points to the compiled expression. If the
expression can be evaluated, then all the fakes that were added for
this expression are also deleted from the symbol table as their use is
over.

An exception is when the expression is just the name of another symbol
that hasn't been evaluated. This is called a simple expression. In
this case, the compiled expression is not kept, but another bit in the
attributes (Fake bit) is set and the symbol entry offset of the target
symbol is put in the value field. This saves string space.

All expressions that could not be evaluated are reevalutaed at the end
of the assembly. If they are not evaluatable at that time, it is
because an undefined symbol was encountered and so an error is
declared.

The contents of the symbol table are printed out at the end of the
assembly.

The symbol tables are searched linearly. i.e. for every symbol the
search starts at the beginning of the symbol table and goes on down
the symbol table till the symbol is found. For a failure the whole
symbol table is searched.


			13 PREDEFINED SYMBOLS

The predefined symbols are the symbols that are defined in the
assembler itself. The predefined symbols are in groups.  These groups
are - the assembler directives or the pseudo instructions, the
instructions, the addressing modes, the 16-bit registers, the 8-bit
registers and the segment registers.

The organizaton of the predefined symbol tables is simple.  There are
many symbol tables and a generic symbol table driver.Each of the
tables is organized as follows.

The first byte in the symbol table is the number of bytes of
attributes (and other information) that have to be skipped after every
symbol. Then follows the list of symbols (with attributes and
all). After the last symbol there is a zero length symbol indicating
that the symbol table is over.

Each symbol in the symbol table consists of one byte that indicates
the length of the symbol. Then comes the string, that is the symbol
itself and then come the attributes. The attributes could be anything
from register numbers (for the register symbol tables) to names of
procedures to be called (for the directives) to the opcodes for the
instructions.

The symbol tables may be lexically ordered, but no use is made of this
as the searches through these symbol tables is always done
linearly. The number of options at the beginning of the instruction
are large compared to the high level languages. The number of
instructions are 136 compared to the few dozen that are there in the
higher level languages.


		13 INSTRUCTIONS SYMBOL TABLE

This was the most time-consuming table to build. During the design I
had to decide about how many bytes of attributes should be put in the
symbol table and how they should be processed. After analysing the
instruction set (for which the appendices at the end of [2] were very
useful), I decided to have two bytes of information.

There are routines written for each set of instructions, whose
encodings are similar. e.g. for add, sub and the other mathematical
and logical instructions except `test' the type of instructions that
can be generated and their encoding is the same except for a few
bits. These few bits are there in the attributes for the
instruction. All of these are directed to the same subroutine.

For each subroutine, the sets of bits mean different things. The aim
was to reduce the number of subroutines that have to be coded to
reduce the code size. This has led to quite a lot of bit twiddling in
the support routines.

One of the vaguest things in the 8086 is the `test' and the `xchg'
instructions. The `test' instruction, though a logical instruction has
a totally different encoding scheme. Therefore there is an exception
made in the add subroutine to accomodate the test and the xchg
instructions.


			14 BACKPATCHING CODE

When expressions are not evaluatable, then there should be a record
that when the expression is evaluated the result of the expression
should be put in such and such a location.

Therefore there is an `offent' table, which keeps track of what
symbols' values are to be put in what location. The form of the table
is a.symbol table entry offset and b.patch location.

All symbols are evaluated as words and the symbols can be used as
bytes as well. This means that the size of the patch is not a property
of the symbol but a property of the location at which the patch is
done.

Therefore the size of the symbol is not stored in the symbol
table. Each patch will be atleast one byte long. The least significant
bit in the patch lovation specifies whether the patch is a byte patch
(0) or a word patch (1).

Some of the most common expressions will be relative expressions. The
value of a relative patch is got as the patch location - the target
value location. If for all forward jumps or calls, these expressions
are put on the string space (see the `expressions' chapter) then a lot
of string space would be wasted.

This property of being relative or absolute is also a property of the
patch and not the symbol. Therefore the second least significant bit
in the patch location is kept for indicating whether the patch is
relative or absolute.  Relative patches can also be bytes or words.

Patching is done only after all the symbols have been evaluated
successfully. For each entry in the `offent' table, the value of the
symbol pointed to is taken and is put at that location. If it is a
byte patch only one byte is put, else a word is put. If it is a
relative patch then the value of the symbol is subtracted from the end
of the relative patch location (for jumps the PC is actually pointing
to the instruction after the jump) before the patch is done.

For byte patches if the value to be patched exceeds one byte then an
error is declared.


			15 IMPLEMENTATION

The assembler is implemented as separate files, which do not form
separate compilation modules. There is one main file - `asm.asm' and
the rest of the files are included in this file.

Here is a list of the files that form the assembler and a short
description of the functionality of the code in each file.

  ASM.ASM : This is the main assembler file. It contains code wich
opens the input and the output files. It also contains code to analyze
the command line and form the input and the output filenames. It also
contains the main loop of the assembler that scans each line and
decides what to do with it.


  SYMBOLS.ASM : In this file, there is a small procedure in the
beginning that searches through the predefined symbol tables. Then
follow the tables themselves. Ths structure of the tables has been
described before. The table for the directives is simple. There is ony
one word which is the offset if the routine to be called. The tables
for the registers and the addressing modes are also simple with only
one byte of attributes (the number of the register or the addressing
mode). The tables for the instructions are a little complex and are
described in one of the previous chapters.


  SYMTAB.ASM : This file has the code to manipulate the symbol
table. There are two main procedures that manage the symbol table and
they are `AddSymbol' and `FindSymbol'.  There is also a procedure to
find the value of a symbol and for creating `offent' entries (see one
of the previous chapters). It also has code to keep making passes over
the symbol table till all the symbols are evaluated and also to patch
the code.

  MESSAGE.ASM : This file contains the procedures that form the
message displaying mechanism of the assembler. All the messages are
also stored in this file and so also some general purpose displaying
routines. Some of the globals are also declared in this file.

  SUPPORT.ASM : This file contains the procedures that are called for
the instructions in the symbol table. These are more or less self
explanatory and most of the routines do mundane, similar things.

  EQU.ASM : This file contains the routines for processing the
definition of a symbol. The symbols can be defined either as a label
or as an equate. The labels are simple to process, but the equates -
considering that the expressions on the right hand sides might not be
evaluatable, are difficult to handle. At the end of this file are
procedures that also get operands for instructions and expressions and
return appropriate values.

  INPUT.ASM : This file contains the procedures to read the input file
(with buffering) and process it. It allows for ungetting upto one
character. It also provides routines to get a token from the input - a
number an identifer or any other character. There are procedures to
classify characters as numeric or alphabetic or alphanumeric etc.

  EXPR.ASM : This file contains the procedures to compile an exprssion
and also to evaluate it. The procedure is described in a previous
chapter `expressions'.

  OUTPUT.ASM : This file contains the routines for outputting a byte
or a word to the output file and for also writing the output file.

  DIRECT.ASM : This file contains the routines that process the
assembler directives. These are more or less trivial.

			16 CONCLUSIONS

The assembler size on disk was 7365 bytes. The speed of assembly was
faster than `tasm' the turbo assembler on DOS, which in turn (being
one-pass) is a lot faster than `masm' the Microsoft Assembler. The
minix assembler was way below in comparison.

The assembler was tested by converting two of the modules in the
assembler to the MINIX input format and assembling them. The result
was checked using DOS's `DEBUG'.

The data structures seemed to be quite effective for the purpose. The
idea of compiled assemble time expressions and their partial
evaluation could be very useful for constant folding in higher level
languages.

			17 IMPROVEMENTS

Since the number of symbols that can be stored in the symbol table is
restricted, the number of labels in a big program can exceed this
limit - especially if the assembler program is generated (by a C
compiler say). Therefore there should be some way to discard useless
values.

I propose that two new directives should be added - `.mark' and
`.release'. All the symbols that are added to the symbol table after
the last mark are released when the release is encoutered. Note that
it is not the symbols that are `defined' after the mark, but the
symbols that are added to the symbol table after the mark. This means
that symbols that weren't defined at the mark (they have been added to
the symbol table because they were referenced) but are there in the
symbol table, and which get defined between the mark and the release
do not get removed at the release.

A common usage would be in a C file. After defining the globals we can
put a mark. Since the globals have been referenced (in the `.globl'
statament), they would have been added to the symbol table.  At the
end of the file you can put a release. All the symbols local to that
file will be removed from the symbol table.

The operators that are usable now should be increased. The addition of
new operators is simple. I suggest the operators
'>','<','!','~','^','&', and '|', with the same meanings as in C. The
operators are restricted to one character only. If left shift and
right shift are essential then the '}' and '{' could be used.

Error reporting is fine, but now the assembler stops at the first
error. Error recovery can be easily implemented as the
resynchronization with the input text is easy in an assembler. The
new-line is considered as the resynchronization point in the
assembler. And as such the recovery actions that can be done are - the
symbols added during this statement can be deleted, the string space
used up can be recovered. Anyway, the output should not be written
onto the output file.

At least for the predefined symbols, there could be a better way of
organising the symbol tables so that a binary search would be possible
or a hashing of sime sort. If this is done for the user defined
symbols as well then there would be a big improvement in performance.

In the routines that exist for the instructions, there are many
redundancies in the code and lots of code duplication.  With some
effort the size of this code could be reduced by a fourth.

Generation of cross-reference and other listings. With a few changes
to the symbol table and the patching routines, it will be easy to
write the information required for the cross reference listings onto a
file. This need not be in a readable format. We could have a post
processor that can go through this file and generate a redable output.

The format of the intermediate file (with the extension `.xrf') would
be tuples which have the following information in binary a.File name
offset, b.line number, c.Symbol name offset and
d.Definition/reference.

There would also be another file generated, which would be a listing
of all the symbols that were found. This would contain tuples of the
form a.Offset and b.Name. The Name would be null terminated. Symbol
names and file names would be recorded. The offset in this case refers
to the offset in the string table.

In addition to the name of the assembly file and the line number
information that we put in the symbol table for the definition. We
could also put the C file name and the line number in the C
source. This can be done by adding another assembler directive -
(`.line' and `.file' seem to be fine or possibly only `.line'). The
cross reference procedure can also be enhanced so that these file and
line numbers also occur in the xref file.

More testing is required to find out whether all the data in the
symbol table is accurate or not. During the little testing that I had
done. I found one mistake in the symbol table (sub always got
translated to subb). THe possibility of more errors in the symbols
cannot be ruled out.


			       18 USAGE

The source is distributed as one .COM file and a bunch of .s
(assembly) and .i (include) files.  It takes one filename as an
argument (with an optional .s suffix).  There are no other arguments.

To rebuild the assembler:

  C:> asm asm

This produces 2 files. asm.com (which is overwritten) and asm.lst 
which contains the symbol references.   

The .lst is a binary file.  See symtab.s for a description of it's
contents.  You need to build the lister utility to read it.

  C:> asm lister

This creates a file called lister.com.    The usage for lister is

   lister [-xz] <filename.lst>

Only one of -x or -z must be specified.  The -x option prints a
complete xref dump (definitions + references) The -z option prints a
list of labels that were not referenced anywhere.




e.g.
   
To print labels not referenced

C:> lister -z asm.lst
....
DisplaySignedAX               display.s    11    Label  115D 4445  
PadWithSpaces                 display.s    90    Label  11D2 4562  
DisplayRegister               display.s    113   Label  11F4 4596  
....

Format is:
Symbol-Name File-Name Line-No. Symbol-Type Value-Hex Value-Decimal


To print all defined symbols:
C:> lister asm.lst
....
PathSize                      asm.s        2     Equate 0040 64    
BufferSize                    asm.s        3     Equate 0014 20    
WordSize                      asm.s        4     Equate 0020 32    
....

Format is:
Symbol-Name File-Name Line-No. Number-of-Refs Symbol-Type Value-Hex Value-Dec


To print crossreferences:
C:> lister -x asm.lst
....
PathSize                      asm.s        2     Equate 0040 64    
  asm.s        148   
  asm.s        153   
  2      references found
...
 

Format is:
Def: Symbol-Name File-Name Line-No. Number-of-Refs Symbol-Type Value-Hex Value-Dec
Ref:    File-Name   Line-No.

			      REFERENCES

1. Tannenbaum A S, "Operating Systems : Design and
   Implementation", Prentice Hall of India, New Delhi,
   1989. 

2. Rector R and Alexy G, "The 8086 Book", Osborne /
   McGraw-Hill, California, 1980.

About

A ONE-PASS ASSEMBLER FOR DOS/MINIX. Automatically exported.

http://code.google.com/p/x86-s

License:BSD 2-Clause "Simplified" License


Languages

Language:Assembly 100.0%