Two programs stand between a source file and something DOS can run. The assembler reads one .ASM file and writes an object module (.OBJ): the machine code, the names the module defines for others and the names it needs from them, and notes on every place that holds an address not yet known. The linker reads object modules and libraries, matches each needed name with its definition, lays the segments out one after another, fills in the addresses, and writes the program.
The program is a .EXE or a .COM. A .EXE starts with a header: where the code starts (CS:IP), where the stack is (SS:SP), and a table of the words DOS must adjust because the program is loaded at a segment nobody knew in advance. It can be as large as memory allows. A .COM is a plain memory image, loaded at offset 100h of one segment and started there; it has no header and no relocations, so it fits in 64 KB and uses no segment addresses of its own. Both assemblers and linkers can also write a listing (.LST: each source line with its offset and bytes) and a map (.MAP: where every segment and public name ended up).
The cheat sheet
| To | MASM 6.11 | JWasm | TASM |
|---|---|---|---|
| make a one-file .COM | ML /AT HELLO.ASM | JWASMR -bin -Fo=HELLO.COM HELLO.ASM | TASM HELLO, then TLINK /t HELLO |
| make a one-file .EXE | ML HELLOX.ASM | JWASMR -mz HELLOX.ASM | TASM HELLOX, then TLINK HELLOX |
| only assemble | ML /c MAIN.ASM PRINT.ASM | JWASMR MAIN.ASM PRINT.ASM | TASM MAIN, then TASM PRINT |
| link modules | LINK MAIN+PRINT,PROG; | JWLINK format dos file MAIN.OBJ,PRINT.OBJ name PROG.EXE | TLINK MAIN PRINT, PROG |
| build a library | LIB UTIL.LIB +PRINT.OBJ; | JWLIB -n UTIL.LIB +PRINT.OBJ | TLIB UTIL +PRINT |
| link with a library | LINK MAIN,PROG,,UTIL.LIB; | JWLINK format dos file MAIN.OBJ library UTIL.LIB name PROG.EXE | TLINK MAIN, PROG,, UTIL |
| write a listing | ML /Fl ... | JWASMR -Fl ... | TASM /l ... |
| write a map | ML /Fm ..., or LINK's third field | JWLINK ... option map | TLINK writes one (/x: none) |
| debug with symbols | ML /Zi, then CV PROG | DEBUG (no symbols) | TASM /zi, TLINK /v, then TD PROG |
| step in the console | DEBUG PROG.EXE | DEBUG PROG.EXE | DEBUG PROG.EXE |
Every MASM and JWasm line above was run on a dosbench box, and so were TLINK and TLIB; TASM itself was not (see its article). The sources are the two below and the pair in the article on several modules.
The two kinds of program
.MODEL TINY.CODEORG 100hSTART: MOV DX, OFFSET MSGMOV AH, 09hINT 21hMOV AX, 4C00hINT 21hMSG DB 'Hello from a .COM', 13, 10, '$'END START
.MODEL SMALL.STACK 256.DATAMSG DB 'Hello from an .EXE', 13, 10, '$'.CODESTART: MOV AX, @DATAMOV DS, AXMOV DX, OFFSET MSGMOV AH, 09hINT 21hMOV AX, 4C00hINT 21hEND START
On a dosbench box
The workbench's Build button assembles the open file for you: with MASM 6.11 when the box has it in C:\MASM611, otherwise with JWasm from C:\JWASM, and keeps the listing so the debugger can show your source lines. Add JWasm, JWlink and DOS-debug to a box from the catalog; they are free. MASM and TASM are not, so bring your own copy in the box's files if you have one.