Everywhere it is explained as a thing which binds/associates registers with segments, but I want to understand what is bound exactly.
The ASSUME
directive tells the assembler what segment register you are going to use to access a segment.
This "binding" is useful to automate some common patterns:
It tell the assembler which segment register to use to access a variable.
If you don't explicit a segment register during a memory access the assembler uses the ASSUME
d values to automatically add a segment override prefix to the instruction.
If a segment has not been ASSUME
d to be pointed by any segment register, the assembler fails with an error if you try to load/store a variable inside that register.
It tell the assembler with respect to which segment to calculate the offsets.
If you specify a segment register in a memory access the assembler use the segment ASSUME
d for that segment register to calculate the offset of the memory access.
Note that although DS
is implicitly used by the CPU on every memory access, an explicit override with DS:
is needed make clear the intention to use its segment as a base for the offset.
The segment ASSUME
d by CS
is the segment the code labels belong to.
You can't jump/call a symbol unless it is in the segment ASSUME
d by CS
.
Consider the program below, not intended to be run but just disassembled.
.MODEL SMALL
.286
;Segment are laid out sequentially, starting from X and aligned on 16 bytes.
;
;_DATI X
;_DATI2 X + 10h
;_DATI3 X + 20h
;
;All the variables testX are the first variables in a segment so their
;addresses are the same of their segments
_DATI SEGMENT PARA PUBLIC 'DATA' USE16
test1 dw 0
_DATI ENDS
_DATI2 SEGMENT PARA PUBLIC 'DATA' USE16
test2 dw 0
_DATI2 ENDS
_DATI3 SEGMENT PARA PUBLIC 'DATA' USE16
test3 dw 0
_DATI3 ENDS
_CODE SEGMENT PARA PUBLIC 'CODE' USE16
;Use CS to access labels defined inside _CODE and use _CODE to compute those offsets
;Use DS to access names defined inside _DATI and use _DATI to compute offsets whenever DS is explicitly used as a segment register
;... and so on
ASSUME CS:_CODE, DS:_DATI, ES:_DATI2
;NOTE: _DATI3 NOT ASSUMED!
__START__:
;No explicit segment override, find the segment of test1 (_DATI) and use
;the assumed register (DS).
;Assembled into mov ax, WORD PTR [0000] (A1 00 00)
mov ax, WORD PTR [test1]
;No explicit segment override, find the segment of test2 (_DATI2) and use
;the assumed register (ES).
;Assembled into mov bx, WORD PTR es:[0000] (26 8B 1E 00 00)
mov bx, WORD PTR [test2]
;Explicit segment override, use the segment assumed for ES (_DATI2) to
;calculate the offset (0000h).
;Assembled as the previous mov cx, WORD PTR es:[0000] (26 8B 0E 00 00)
mov cx, WORD PTR es:[test2]
;Explicit segment override, use the segment assumed for DS (_DATI) to
;calculate the offset (0010h).
;Assembled as the previous mov dx, WORD PTR es:[0010] (8B 16 10 00)
mov dx, WORD PTR ds:[test2]
;OFFSET of X is always relative to the segment X is declared in.
;This is true for MASM mode only, IDEAL mode use the group
;Both use an offset of 0, as both test1 and test2 are the first variables
;of their segments
mov ax, OFFSET test1 ;mov ax, 0000 (B8 00 00)
mov bx, OFFSET test2 ;mov bx, 0000 (BB 00 00)
;No explicit segment override, find the segment of test3 (_DATI3) and
;use the assumed register (none)
;Can't assemly: error -> Can't address with currently ASSUMEd segment registers
mov ax, WORD PTR [test3]
;Explicit segment override, calculate offset of test3 with respect of the
;segment assumed for DS (_DATI)
;Offset is 20h
mov bx, WORD PTR ds:[test3] ;mov bx, WORD PTR [0020] (8B 1E 20 00)
;OFFSET operator don't use assumed register
mov cx, OFFSET test3
_CODE ENDS
END __START__
If you did't ASSUME
CS
the assembler would complain with
CS unreachable from current segment
because you were defining a label __START__
in a code segment not ASSUME
d anywhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With