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.