Because of 8086 being a 16-bit architecture, it has difficulties in accessing more than 64 KB memory.
The most efficient way to use pointers is to use the dedicated 16-bit registers (like bx
). However, when your program wants to access more than 64 KB, it has to use also segment registers (like es
). To allow both ways of addressing, memory models were invented.
So, the directive .model small
tells the assembler that you intend to use the small memory model - one code segment, one data segment and one stack segment - and the values of the segment registers are never changed.
It has the following effects:
You are allowed to write the instruction retn
(return from a near
subroutine) as ret
. Because the assembler knows that all your code is in the same segment, all your subroutines will be near
(i.e. have a 16-bit address), and all ret
instructions mean retn
.
Sounds silly and insignificant? Read on.
If your code is scattered across several source files, you will have call
instructions that call subroutines that the assembler doesn't know anything about. When you use a small memory model, it knows at least that each subroutine has a 16-bit address, and a near call opcode can be used.
You could write code without declaring your memory model, but then you'd have to call near
instead of just call
.
If all your source files declare .model small
, the linker will take all the code segments and try to fit them all into 64 KB (the same for data segments). This may fail, if the stuff is too big.
Small assembly programs usually don't care about memory model - 64 KB code is more than enough to write complex programs, unless you're using a big external library. In such case, .model small
can mean "I don't care about that memory model stuff, just use the default".