Indirect references use a register to access memory. There are only four registers that can be used: BX, BP, SI, DI. It is important to use the right size (BYTE or WORD) when referencing memory. Using the wrong size will not be detected by the assembler, and will usually produce the wrong results.
Consider this section of code:
.data list dw 0102h,0304h,0506h,0708h .code ... mov bx,offset list mov cx,4 mov ah,0 top: add ah,[bx] add bx,2 loop top
Notice the statement add ah,[bx]. It would be nice if the assembler
would indicate that we are trying to add a word to a byte, but it won't.
We tend to give credit to the assembler for more abilities than it has. The
assembler is a simple program that does one thing over and over again: it
changes strings into numbers. The assembler does this by looking up a strings
in the symbol table and substituting the associated number into the instruction.
The symbol table also indicates how the string was declared: as a BYTE or
as a WORD. If no string is included in the instruction, then the assembler
does not reference the symbol table. In particular, [BX] is not a string
that appears in the symbol table, so the assembler has no idea as to what
it points to: a WORD or a BYTE. The assembler must look at the rest of the
instruction to find clues as to the size of the memory reference. In this
instruction, the AH register is used, so the assembler assumes that the memory
reference is to a byte.
In this example, the program will add the following bytes into the AH register: 02h, 04h, 06h,08h. This will result in a sum of 14h, which is the wrong result. The sum should have 1014h.
If the AX register had been used, then the total would have been correct. The point to realize is that the assembler will not warn you that the sizes don't match because it can not refer to the symbol table to see if [BX] points to a BYTE or to a WORD.
Another common mistake when referencing memory is to increment by the wrong amount. Here is the above example which now uses the AX register, but increments by 1 instead of 2.
.data list dw 0102h,0304h,0506h,0708h .code ... mov bx,offset list mov cx,4 mov ax,0 top: add ax,[bx] add bx,1 loop top
The assembler will not warn you that you are using the wrong increment. The increment should be 2 since words are being referenced, but it is easy to make the mistake and add 1 instead. By using the wrong increment, the assembler will add the following words: 0102h, 0203h,0304h,0405h. Two of the four words are correct, but how did the other two appear?
Since the increment was only one, the assembler referenced words beginning at successive bytes as follows:
| 01 | 01 | 01 | 01 |
| 02 | 02 | 02 | 02 |
| 03 | 03 | 03 | 03 |
| 04 | 04 | 04 | 04 |
| 05 | 05 | 05 | 05 |
| 06 | 06 | 06 | 06 |
| 07 | 07 | 07 | 07 |
| 08 | 08 | 08 | 08 |
In this example, I am trying to add a negative 1 to each element in the array. Here is the same example as above, but with different data.
.data list dw 0102h,0304h,0506h,0708h .code ... mov bx,offset list mov cx,4 top: add [bx],-1 add bx,2 loop top
This will not compile since the assembler cannot refer to the symbol table to determine the size of [BX] nor the size of -1. Neither of these has an entry in the symbol table. It is necessary to give the assembler some more information about the size of the operands. byte ptr indicates that the reference is to a byte, and word ptr indicates that the reference is to a word.
This will compile and calculate the correct results.
.data list dw 0100h,0300h,0500h,0700h .code ... mov bx,offset list mov cx,4 top: add word ptr [bx],-1 add bx,2 loop top
After the loop, the memory will be: 00FFh,02FFh,04FFh,06FFh.
If the wrong ptr is used, then the assembler will not warn you.
.data list dw 0100h,0300h,0500h,0700h .code ... mov bx,offset list mov cx,4 top: add byte ptr [bx],-1 add bx,2 loop top
This will change the words to the following: 01FFh,03FFh,05FFh,07FFh.
The problem is that BYTE arithemtic is being performed. -1 in a byte is FFh, -1 in a word is FFFFh. By adding bytes, the program is adding FFH to 00H resulting in FFH with the carry bit set. However, the next byte in memory is not affected by the operation.
Here is a similar problem, but with an array of bytes. I have added another byte to the program, just to see how it can be affected by an incorrect reference.
.data list db 00h,01h,02h,03h value db 04h .code ... mov bx,offset list mov cx,4 top: add word ptr [bx],-1 add bx,1 loop top
This program will add the word FFFFh to memory starting at each offset within list. list would be: FFh,FFh,00h,02h; value would be: 04h. The problem is that -1 was added to each word of memory starting at successive bytes.
This is how the arithmetic was performed:
| 0100 | 0200 | 0301 | 0403 |
| FFFF | FFFF | FFFF | FFFF |
| 00FF | 01FF | 0300 | 0402 |
This is how it looks in memory after each addition:
| 00 | FF | FF | FF | FF | FF | |||
| 01 | FF | 00 | FF | FF | FF | FF | ||
| 02 | 02 | FF | 01 | FF | 00 | 00 | ||
| 03 | 03 | 03 | FF | 03 | FF | 02 | ||
| 04 | 04 | 04 | 04 | FF | 04 |