Using Indirect References

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.

The wrong size will not be detected by the assembler

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.

Incrementing by the wrong amount

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

Using byte ptr and word ptr

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.

Using the wrong pointer

If the wrong ptr is used, then the assembler will not warn you.

Using byte instead of word

	.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.

Using word instead of byte

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