A name in a module is private to it until the module declares it PUBLIC; then the object file carries it for the linker. A module that uses a name defined elsewhere declares it EXTRN with its type, so the assembler knows how to encode each use: NEAR and FAR for procedures (a near or far CALL), BYTE, WORD and DWORD for variables, ABS for a constant. The assembler leaves the address blank and the linker fills it in.

MAIN.ASM
; MAIN.ASM: the program; PRINT comes from another module
.MODEL SMALL
.STACK 256
.DATA
MSG DB 'Two modules, one program', 13, 10, '$'
.CODE
EXTRN PRINT:NEAR
START: MOV AX, @DATA
MOV DS, AX
MOV DX, OFFSET MSG
CALL PRINT
MOV AX, 4C00h
INT 21h
END START
PRINT.ASM
; PRINT.ASM: a module of routines for others to call
.MODEL SMALL
.CODE
PUBLIC PRINT
; PRINT: write the $-terminated string at DS:DX
PRINT PROC NEAR
MOV AH, 09h
INT 21h
RET
PRINT ENDP
END

Both modules use the small model, so their .CODE sections are the same segment (_TEXT) and their .DATA sections the same _DATA: the linker puts the pieces of a segment next to each other, and a near CALL from MAIN reaches PRINT. Only one module ends with END start-label; that label is the program's entry point. Only one needs .STACK.

Assemble each, link once

Each prints "Two modules, one program".
ML /c MAIN.ASM PRINT.ASM ; MASM: two .OBJ files
LINK MAIN+PRINT,PROG,PROG.MAP ; ; objects, program, map
ML /FePROG.EXE MAIN.ASM PRINT.ASM ; MASM: the same in one command
JWASMR MAIN.ASM PRINT.ASM ; JWasm: two .OBJ files
JWLINK format dos file MAIN.OBJ,PRINT.OBJ name PROG.EXE option map

When one module changes, only it is assembled again before the link. That is the point of modules in a big program, and what NMAKE (MASM) and MAKE (Borland) automate.

Libraries

A library (.LIB) is a file of object modules with an index of their public names. The linker searches it only for names still missing after the object files, and takes just the modules that define them, so a library of a hundred routines adds only the ones the program calls.

LIB UTIL.LIB +PRINT.OBJ ; ; MASM: create UTIL.LIB, add PRINT
LINK MAIN,PROG,,UTIL.LIB ; ; libraries are the fourth field
JWLIB -n UTIL.LIB +PRINT.OBJ ; JWlib: -n makes a new library
JWLINK format dos file MAIN.OBJ library UTIL.LIB name PROG.EXE
TLIB UTIL +PRINT ; Borland
TLINK MAIN, PROG,, UTIL

Pitfalls

A name declared EXTRN that no module makes PUBLIC stops the link: LINK reports error L2029 "unresolved external", TLINK "Undefined symbol", JWlink "undefined reference". The type in EXTRN must match the definition: a near CALL to a FAR procedure, which ends in a far return, does not come back where it should. A .EXE without a stack segment gets LINK's warning L4021 "no stack segment" and runs on whatever stack DOS left it.