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.