7.1 Relative addressing
------------------------
In previous versions of C--, indexed access to elements in arrays of
any type of compiler was done byte-wise regardless of the declared data
type. Indexes were limited by the format of the 'RM' field of an 8086 so
only the following index formats were available (where the index is the
value of a 16-bit constant or constant expression):
variable[index]
variable[index+BX+SI]
variable[index+BX+DI]
variable[index+BP+SI]
variable[index+BP+DI]
variable[index+SI]
variable[index+DI]
variable[index+BP]
variable[index+BX]
Starting with version 0.210, the index can be a variable of type
'char', 'byte', 'int', 'word', 'long', or 'dword'. Access to elements of
the array now depends on the declared type of array.
Also starting with version 0.210, any 32-bit registers can be used as
index and base registers with relative addressing.
If registers and numeric constants from which the fields 'RM', 'BASE'
and 'SIB' can be obtained for the 80386 are used for addressing array
elements, the compiler uses these registers to generate instructions with
these fields. This results in relative bytewise addressing to array
elements.
If, however, 'RM', 'BASE', and 'SIB' cannot be obtained from these
registers, or if a variable is used for addressing, the compiler will first
calculate this expression to register (E)SI or some other similar register,
and then the contents of this register is multiplied by the bit-size of the
array. In this case there will be termwise addressing in the array. For
example:
AX = var [ 5 ];
AX = var [ BX + 5 ];
AX = var [ BX + CX ];
AX = var [ i ];
The compiler generates the following code:
test.c-- 7: AX=var[5];
0100 A12501 mov ax,[125h]
test.c-- 8: AX=var[BX+5];
0103 8B872501 mov ax,[bx+125h]
test.c-- 9: AX=var[BX+CX];
0107 89DE mov si,bx
0109 01CE add si,cx
010B 01F6 add si,si
010D 8B842001 mov ax,[si+120h]
test.c-- 10: AX=var[i];
0111 8B362201 mov si,[122h]
0115 01F6 add si,si
0117 8B842001 mov ax,[si+120h]
The first two expressions were converted to one assembler instruction
and bytewise addressing was obtained. In the two following expressions a
single assembler instruction could not be obtained, and the compiler used
termwise addressing for two of these expressions.
This dual approach was used to preserve compatibility between old and
new methods.
Although this seems chaotic to inexperienced users, the mechanism is
easily understood and remembered by the following simple rule: if only a
digital value or register BX, SI, DI or BP or any 32-bit register is used
as an index, the compiler will generate code with bytewise addressing. If,
however, you are quite familiar with assembly language, you will not find
it difficult to understand which cases give bytewise and which termwise
addressing.
Sometimes bytewise access to array elements using a variable as an
index is necessary. For example:
AX=var[i];
Termwise addressing is generated for this expression but bytewise
addressing is required. One can write:
SI=i;
AX=var[SI];
Or it can be written in shorter form as:
AX=DSWORD[#var+i];
In both cases the result is bytewise addressing to elements of the
array 'var.' In the first case you can control which register is used as
the index, and in the second case the compiler itself chooses the register
to use as an index.
Make sure to remember this dual approach of the compiler to calculating
an address in an array. To repeat: if a numerical constant or register BX,
DI, SI, or BP is used for addressing in an array, the compiler uses these
values without any change. In all other cases the value is corrected
depending on the array type.