djasm is a special-purpose assembler used to compile the 16-bit stub that allows DOS to run the coff files generated by DJGPP.

This is Edition 0.1 of the djasm documentation, 23 December 1999, and incorporates the information in Bill Currie's djasm documentation (dated 19 November 1999).

What is djasm?
**************

Disclaimer
==========

This is an UNREVIEWED and UNGUARANTEED document describing some of the aspects of djasm. It might describe djasm, but then again, it might not.

Some features described herein may be specific to Bill Currie's latest version of djasm, available at www.taniwha.org, and may not (yet) have found their way into the official DJGPP release.

Description
===========

djasm is a restricted assembler that was developed for a single purpose: to compile the 16-bit stub that all DJGPP programs use to start DPMI, switch into protected mode, and load and execute a DJGPP-generated coff image. With djasm the DJGPP distribution is completely self-contained; you don't need commercial (or otherwise non-DJGPP) 16-bit tools to build any part of the DJGPP distribution.

Be aware, however, that although djasm can be used in other applications, it is not a full-featured assembler; if you need a sophisticated, general-purpose assembler then use GAS (the GNU Assembler) or NASM (the Netwide Assembler). Give some thought to what you want to do, and use the right tool for the job. GAS (as.exe) is part of the DJGPP bnuXXXb.zip archive and should be available in $DJGPP/bin if you use GCC. NASM lives at www.cryogen.com/Nasm.

A Brief History of djasm
========================

The need for djasm arose when when Cygnus, a major user of DJGPP for their DOS-based products, requested a version of DJGPP that was fully independent and self-bootstrapping. The existing DJGPP 1.x system didn't entirely meet their need, however, because a Borland (or other 16-bit) compiler was required to build the go32 program used by DJGPP 1.x.

The first task, therefore, in making a version 2.x of DJGPP that would be entirely self-contained was to write an assembler that could compile the 16-bit stub required by all DJGPP executables. The stub could have been written to use NASM, but (1) NASM wasn't around at the time, and (2) a dedicated 16-bit compiler would make DJGPP independent of any other product. Thus djasm was designed and written for a specific purpose---to compile the 16-bit code for DJGPP's startup stub and enable everything needed to build DJGPP to be distributed freely.

The djasm compiler was to have no other purpose in life, and was never intended to be a generic utility, until some of the developers got carried away and introduced support for many additional opcodes that had not yet been used. As a result, djasm has become sufficiently powerful to be useful for more 16-bit applications than just the DJGPP stub.

An Overview of djasm
********************

What djasm can do
=================

Despite many limitations and some glaring omissions, djasm does have some nice features:

  o The syntax was designed to be easy to parse, so djasm is relatively easy to learn and use, and code written for djasm tends to be straightforward.

  o djasm is released under the terms of the GPL and comes with DJGPP (djdevXXX.zip).

  o GCC/GAS-generated coff files can be linked with the code (the linking is done by djasm).

  o djasm produces 16-bit code (currently this is the only available mode).

  o There is support for several output formats, including raw hex output for subsequent use with assembler and C code.

  o Support for C-style structures and unions.

  o Most instructions and addressing modes are supported (a few are still missing).

  o Full 32-bit addressing.

Differences between djasm and other assemblers
==============================================

There are some important differences between djasm and other assemblers, such as GAS (the GNU Assembler) and NASM (Netwide Assembler).

  o Like most assemblers, djasm has its own syntax; in general it is similar to the Intel syntax, but there are some differences. GAS uses the AT&T syntax. Porting code to djasm shouldn't be difficult but will generally require a bit of editing.

  o djasm generates 16-bit code, GAS generates 32-bit code, and NASM can generate both 16- and 32-bit code.

  o djasm is incompletely documented and has incomplete opcode support; GAS and NASM are fully supported.

  o djasm does not support macros.

  o djasm is restricted in its output formats.

  o djasm does not support multi-file programs, so all source must be in a single file.

  o djasm builds .exe and other executables directly; there is no linker.

  o Code generated by djasm cannot be linked with DJGPP programs; GAS and NASM can produce standard coff objects. However, djasm can build a raw binary image for inclusion in other code.

What's missing from djasm?
==========================

Although djasm can do quite a bit as it stands, there are a number of things that experienced assembly-language programmers will miss. Future versions of djasm may add support for some or all of these items, but again, if you need a general-purpose assembler, you should consider GAS or NASM.

  o Complete instruction set support.

  o Object files---what format(s)?

  o A companion 16-bit linker.

  o Segments (Is this really necessary? Is it worth it? Should one just use NASM instead?)

  o Macros.

  o Complete documentation.

When would I want to use djasm?
===============================

Ordinarily, assembly language programmers should use GAS, or a 16/32-bit assembler like NASM, for most programming purposes. However, there are a few reasons why you might want to use djasm:

  o If you are looking for a free (GPL) 16-bit assembler.

  o To keep a project compatible with the spirit of DJGPP, without requiring the use of NASM or some other assembler to compile 16-bit code.

  o For small 16-bit projects, such as device drivers, TSRs, boot loaders, or micro-kernels.

The djasm Language
******************

Invoking djasm
==============

Invoke djasm as follows:

     djasm INFILE [OUTFILE] [MAPFILE]

where OUTFILE defaults to infile.exe after dropping the extension from INFILE, and MAPFILE defaults to infile.map after dropping the extension from INFILE.

The extension of outfile determines the format of the generated code. The following output formats are supported:

.exe
     Generate a normal DOS .exe (MZ signature) executable. Does not support more than one segment. This is the only output format that supports the .copyright directive.

.com
     Generate a normal DOS .com file. Program offset is at 0x100.

.bin
.sys
     Generate binary files starting at offset 0. The .sys format is supported so that device drivers can be built directly (i.e., without needing to rename a .bin output file to a .sys file).

.h
     Produce a C-compilable array of bytes (without type declaration or surrounding {}s).

.inc
     Produce a .db array for other djasm .asm files.

.ah
     Produce a .byte array for GAS .s or .S files.

For the .h, .inc, and .ah output types, the .type directive is used to determine which binary type to emit (see .type).

Assembler Syntax
================

As a general rule, djasm uses the TASM/MASM ordering of operands, and usually the same instruction names.

For ambiguous operand sizes, djasm uses operand suffixes instead of the word ptr, etc., operand modifiers used by other 16-bit assemblers. For example, djasm uses cmpb instead of cmp byte.

Until documentation for djasm is completed, however, you should examine the BISON source for djasm (in the file djasm.y) to learn exactly what the instruction mnemonics and their arguments are.

Assembler Directives
====================

General Directives
------------------

.align
     Usage:  .align BOUNDARY [, FILL]

     Emit bytes (if necessary) so that the program counter CS:IP (denoted by .) is a multiple of BOUNDARY (i.e., such that CS:IP % BOUNDARY == 0). The argument FILL specifies what bytes to emit; the default is 0x90 (NOP).

          .align 4       ; align on a 4-byte boundary, pad using 0x90
          .align 16,0    ; align on a 16-byte boundary, pad using 0x00

.bss
     Usage:  .bss

     Signifies the end of generated bytes. No more bytes will be emitted into the image, but space will be reserved so labels can be declared after this point to create uninitialize variables.

.copyright
     Usage:  .copyright STRING

     Inserts the copyright message STRING into the header of the executable, starting approximately at offset 0x61 (there is also some text with the generation details of the file starting at offset 0x28). STRING is a standard C string. Multiple .copyright directives concatenate. This directive is currently supported only for the .EXE output format.

.id
     Usage:  .id

     Emit an RCS-style identification string into the instruction stream. The id has the form:

          $Id: djasm.lyx,v 1.2 1999/06/22 07:08:56 bill Exp $
          @(#) foo.asm built 10/04/97 14:03:30 by djasm

.include
     Usage:  .include "FOO.INC"

     Include a text file for assembly. No path searching is performed to find FOO.INC.

.linkcoff
     Usage:  .linkcoff "FOO.O"

     Link in a GAS-generated 32-bit coff file (e.g., the output from gcc -c foo.c). Currently supports only i386 coff files with .text, .data, and .bss sections; these must be the first three sections in the coff file and must appear in that order. Any other sections will be ignored. These three sections will be placed into the output image in the same order as in the coff file. The .bss section of the coff file will be placed into the output image by emitting the appropriate number of zeros---this means that the .bss section from the coff file will occupy space in the output image rather than being implicit.

     As with .include, no path searching is done for .linkcoff.

.org
     Usage:  .org OFFSET

     Sets the instruction pointer IP to OFFSET. The IP can only be increased using .org, never decreased.

.stack
     Usage:  .stack

     For .exe files only, sets the initial value of the stack pointer SP to the current value of the instruction pointer IP.

.start
     Usage:  .start

     For .exe files only, sets the initial value of the instruction pointer IP to the current value of the program counter CS:IP.

.type
     Usage:  .type IMAGE

     where IMAGE is one of com, bin, sys, h, inc, or ah. The following table summarizes the effect of various combinations of output file extension and .type declaration.

     +---------+-----------------------------------------------------+
     | Output  | Value of .type                                    |
     |  file   +-----------------------------------------------------+
     |extension| exe     com     bin     sys(b)  h       inc     ah  |
     +---------+-----------------------------------------------------+
     |  exe    | exe     exe(a)  exe     exe     exe     exe     exe |
     |  com    | ---     com     ---     ---     ---     ---     --- |
     |  bin    | bin     bin(a)  bin     bin     bin     bin     bin |
     |  sys(b) | bin     bin(a)  bin     bin     bin     bin     bin |
     |  h      | exe     com     bin     bin     exe     bin     bin |
     |  inc    | exe     com     bin     bin     exe     bin     bin |
     |  ah     | exe     com     bin     bin     exe     bin     bin |
     +---------+-----------------------------------------------------+

 a. The first 0x100 bytes of the program are 0x90 (NOP), followed by the generated code.

 b. The .sys type is a synonym for .bin.

Data Directives
---------------

The data directives are used to reserve space for byte (8-bit), word (16-bit), and double word (32-bit) data. The allocated space may be initialized or left indeterminate. The general syntax of the data allocation directives is:

     .db [dblist [','dblist...]]
     .dw [dwlist [','dwlist...]]
     .dd [ddlist [','ddlist...]]

.db
     Define a byte of data.

.dd
     Define a word of data.

.dw
     Define a double word of data.

.dblist
.dwlist
.ddlist
     List of byte, word, or double word data.

The data lists dblist, dwlist, and ddlist are constructed from the following :

constant
     A decimal (e.g., 144), hexadecimal (e.g., 0x90), or character (e.g., 'A') constant.

string
     A C-style string constant, e.g. "THIS IS A STRING.".

UID offset
     This item is available only for the dwlist and ddlist directives.

const .dup const
     Repeat a block of data.

Structures and Unions
---------------------

The following directives provide support for C-style struct and union constructs.

.struct
     Start a structure.

.union
     Start a union.

.ends
     End a structure or union.

For example, the construct

     .struct FARPTR
             offs    .dw
             seg     .dw
     .ends

defines the following symbols:

     FARPTR      = 4         ; size of FARPTR structure
     FARPTR.offs = 0         ; offset of `offs' in the `FARPTR' structure
     FARPTR.seg  = 2         ; offset of `seg' in the `FARPTR' structure

Had the .union directive been used in the above example instead of .struct, the following structure would have been defined:

     FARPTR      = 2         ; size of FARPTR union
     FARPTR.offs = 0         ; offset of `offs' in the `FARPTR' union
     FARPTR.seg  = 0         ; offset of `seg' in the `FARPTR' union

In summary, .struct is the same as struct in C, while .union is the same as union in C.

Nested structures are supported. Here is an example using the FARPTR structure from the previous .struct example:

     .struct XMS_MOVE
             length          .dd
             lrc_handle      .dw
             src_offset      .struct FARPTR ; .union would also be valid here
             dst_handle      .dw
             dst_offset      .struct FARPTR
     .ends

This construct defines the following symbols:

     XMS_MOVE                    = 16        ; size of XMS_MOVE structure
     XMS_MOVE.length             = 0
     XMS_MOVE.src_handle         = 4
     XMS_MOVE.src_offset         = 6
     XMS_MOVE.src_offset.offs    = 6
     XMS_MOVE.src_offset.seg     = 8
     XMS_MOVE.dst_handle         = 10
     XMS_MOVE.dst_offset         = 12
     XMS_MOVE.dst_offset.offs    = 12
     XMS_MOVE.dst_offset.seg     = 14

Note that XMS_MOVE.src_offset and XMS_MOVE.src_offset.offs share the same offset, as do XMS_MOVE.dst_offset and XMS_MOVE.dst_offset.offs. This is so that the offset of the nested structure or union can be used directly.

When declaring structure or union members of a structure (or union), .struct and .union can be used interchangably without changing the layout of the structure. In other words, .struct can be used when inserting unions and .union can be used when inserting structures, but this practice can be confusing and is not recommended. The approriate directive should be used, but this is not enforced (mostly because there's no way of detecting it).

Variables can be declared using the structures in the following ways (note that the above message about .struct and .union applies here as well). For example, the statement

     xms_move_packet .struct XMS_MOVE

has the same effect as

     xms_move_packet:
             xms_move_packet.length:
             .dd 0
             xms_move_packet.src_handle:
             .dw 0
     xms_move_packet.src_offset:
             xms_move_packet.src_offset.offs:
             .dw 0
             xms_move_packet.src_offset.seg:
             .dw 0
             xms_move_packet.dst_handle:
             .dw 0
     xms_move_packet.dst_offset:
             xms_move_packet.dst_offset.offs:
             .dw 0
             xms_move_packet.dst_offset.seg:
             .dw 0

However, it is sometimes desirable to place the structure at a specified location (any valid expression using defined symbols is allowed, not just .token or .token-sym). For example:

     xms_move_packet .struct XMS_MOVE (.) ; doesn't emit any bytes!
     xms_move_packet .struct XMS_MOVE (.-sh_handle_cache)

These have the same effect as (X=. or X=.-sh_handle_cache, respectively, where . denotes the current program counter):

     xms_move_packet                 = X
     xms_move_packet.length          = X
     xms_move_packet.src_handle      = X + 4
     xms_move_packet.src_offset      = X + 6
     xms_move_packet.src_offset.offs = X + 6
     xms_move_packet.src_offset.seg  = X + 8
     xms_move_packet.dst_handle      = X + 10
     xms_move_packet.dst_offset      = X + 12
     xms_move_packet.dst_offset.offs = X + 12
     xms_move_packet.dst_offset.seg  = X + 14

The (.) form is useful for initializing structures---just follow the declaration line by anonymous .db/.dw/.dd lines. Unfortunately, this is prone to error, but is currently the only way of doing this. The form with some other expression (any expression that djasm can handle as a relocation is permitted in the parentheses) is useful for declaring structures at some specific address (e.g., the PSP structure or some of the DOS system tables).

Segment Override Prefixes
-------------------------

Usage:

     prefix
     instruction

where prefix can be one of the following:

.addrsize
     toggles selection of 16- or 32-bit addressing

.opsize
     toggles selection of 16- or 32-bit operands

.segcs
     code segment override

.segds
     data segment override

.seges
     extra segment override

.segss
     stack segment override

.segfs
     user segment `f' override

.seggs
     user segment `g' override

Each prefix causes the appropriate instruction prefix byte to be emitted into the instruction stream. The .segXX prefixes seem to be most appropriate when used with the string instructions such as movs, stos, etc.).

Programming Examples
********************

Some examples of programming with djasm.

``Hello, world'' demo program
=============================

     .org 0x100                      ; origin for .COM program
             mov dx, msg             ; point DX to message
             mov ah, 0x9             ; DOS print string function
             int 0x21
             mov ax, 0x4c00          ; DOS exit with errorlevel
             int 0x21
     msg:
             .db "hello, world\r\n$"

Enter the above code into a file hello.asm, then make a DOS .com executable using the command

     djasm hello.asm hello.com hello.map

Contributors to djasm
*********************

The following individuals (in alphabetical order) have contributed to djasm, or to its documentation, or both. If you have contributed to djasm in some way and are not listed here, please make yourself known!

  o John M. Aldrich fighteer@cs.com

  o Bill Currie billc@taniwha.org

  o DJ Delorie dj@delorie.com

  o Nate Eldredge nate@cartsys.com

  o Charles Sandmann sandmann@clio.rice.edu

  o Margo Schulter mschulter@value.net

  o Aaron Ucko ucko@vax1.rockhurst.edu

  o Vic tudor@cam.org

  o Morten Welinder terra@diku.dk

  o Jeff T. Williams jeffw@darwin.sfbr.org

  o Eli Zaretskii eliz@is.elta.co.il

Index
*****

Here be the index (eventually).