-3

Can anyone give me an example to understand how array indexing is working in assembly.

For example, in C:

char s[1000]; 

for (int = 0; i < 5; i++)
{
  s[i]  = i;
}

And, in x86 assembly:

add eax,edx
movzx eax, byte ptr [eax]
2
  • 3
    For God sake! Learn about the wiki syntax and try to better proof read your question before hitting the "Send" button...
    – perror
    Jul 11 '18 at 15:54
  • First you want to know the C version of an array in assembly and now the same in the opposite direction. Tempting to close-vote this as a mirror-duplicate of your earlier question. You accepted an answer ... but did you not understand it? Then you need to work on your assembly knowledge.
    – Jongware
    Jul 11 '18 at 17:46
6

First of all, here is a small example written in C:

#include <stdio.h>
#include <stdlib.h>

#define MAX_ROW 5
#define MAX_COLUMN 10

int main (void)
{
  int array[MAX_ROW][MAX_COLUMN];

  for (int row = 0; row < MAX_ROW; ++row)
    for (int column = 0; column < MAX_COLUMN; ++column)
      array[row][column] = ((row - 1) * (column + 1)) & ~row ;

  for (int i = 0; i < MAX_ROW; ++i)
    fprintf (stdout, "array[%1$d][%1$d] = %2$d\n", i, array[i][i]);

  return EXIT_SUCCESS;
}

I compiled it with:

$> gcc -Wall -Wextra -std=c11 -Os -o sample sample.c

The resulting (amd64) assembly is as follow:

0000000000001050 <main>:
    1050:       41 54                   push   %r12
    1052:       55                      push   %rbp
    1053:       83 c8 ff                or     $0xffffffff,%eax
    1056:       53                      push   %rbx
    1057:       41 b8 fe ff ff ff       mov    $0xfffffffe,%r8d
    105d:       48 81 ec d0 00 00 00    sub    $0xd0,%rsp
    1064:       48 8d 4c 24 08          lea    0x8(%rsp),%rcx
    1069:       49 89 cc                mov    %rcx,%r12
    106c:       44 89 c7                mov    %r8d,%edi
    106f:       31 d2                   xor    %edx,%edx
    1071:       29 c7                   sub    %eax,%edi
    1073:       89 fe                   mov    %edi,%esi
    1075:       41 89 f1                mov    %esi,%r9d
    1078:       01 fe                   add    %edi,%esi
    107a:       41 21 c1                and    %eax,%r9d
    107d:       44 89 0c 91             mov    %r9d,(%rcx,%rdx,4)
    1081:       48 ff c2                inc    %rdx
    1084:       48 83 fa 0a             cmp    $0xa,%rdx
    1088:       75 eb                   jne    1075 <main+0x25>
    108a:       ff c8                   dec    %eax
    108c:       48 83 c1 28             add    $0x28,%rcx
    1090:       83 f8 fa                cmp    $0xfffffffa,%eax
    1093:       75 d7                   jne    106c <main+0x1c>
    1095:       48 8d 2d 68 0f 00 00    lea    0xf68(%rip),%rbp
    109c:       31 db                   xor    %ebx,%ebx
    109e:       48 6b c3 2c             imul   $0x2c,%rbx,%rax
    10a2:       48 8b 3d 87 2f 00 00    mov    0x2f87(%rip),%rdi
    10a9:       89 da                   mov    %ebx,%edx
    10ab:       48 89 ee                mov    %rbp,%rsi
    10ae:       48 ff c3                inc    %rbx
    10b1:       41 8b 0c 04             mov    (%r12,%rax,1),%ecx
    10b5:       31 c0                   xor    %eax,%eax
    10b7:       e8 74 ff ff ff          callq  1030 <fprintf@plt>
    10bc:       48 83 fb 05             cmp    $0x5,%rbx
    10c0:       75 dc                   jne    109e <main+0x4e>
    10c2:       48 81 c4 d0 00 00 00    add    $0xd0,%rsp
    10c9:       31 c0                   xor    %eax,%eax
    10cb:       5b                      pop    %rbx
    10cc:       5d                      pop    %rbp
    10cd:       41 5c                   pop    %r12
    10cf:       c3                      retq   

If we take the time to look precisely at the whole assembly code, we can see that the interesting part is the following:

1064:       48 8d 4c 24 08          lea    0x8(%rsp),%rcx
1069:       49 89 cc                mov    %rcx,%r12
106c:       44 89 c7                mov    %r8d,%edi <-----------------\
106f:       31 d2                   xor    %edx,%edx                   |
1071:       29 c7                   sub    %eax,%edi                   |
1073:       89 fe                   mov    %edi,%esi                   |
1075:       41 89 f1                mov    %esi,%r9d <-----------\     |
1078:       01 fe                   add    %edi,%esi             |     |
107a:       41 21 c1                and    %eax,%r9d             |     |
107d:       44 89 0c 91             mov    %r9d,(%rcx,%rdx,4)    |     |
1081:       48 ff c2                inc    %rdx                  |     |
1084:       48 83 fa 0a             cmp    $0xa,%rdx             |     |
1088:       75 eb                   jne    1075 <main+0x25>------/     |
108a:       ff c8                   dec    %eax                        |
108c:       48 83 c1 28             add    $0x28,%rcx                  |
1090:       83 f8 fa                cmp    $0xfffffffa,%eax            |
1093:       75 d7                   jne    106c <main+0x1c> -----------/

It depict the double loop that initialize the example matrix where rdx is the column variable (it is compared to 0xa which is 10 in decimal) and eax is the row variable (it is compared to 0xfffffffa which is -6). For some reasons that we will see later, one index is increased and the other one is decreased, but both start from zero.

Now, the access to the array is located here:

107d:       44 89 0c 91             mov    %r9d,(%rcx,%rdx,4)

Which would be translated into mov [rcx + 4*rdx], r9d in Intel format. Basically:

  • rcx is the base address of the current row.
  • rdx is the column index within the same row vector.

Note that when we move to the next row, rcx is updated like that:

108c:       48 83 c1 28             add    $0x28,%rcx

Basically, it moves from the current row to the next one knowing that the row contains 10 items and each item is an int (4 bytes). So, 40 bytes in total which is 0x28 in hexadecimal.

And, the very first initialization of rcx is given by:

1064:       48 8d 4c 24 08          lea    0x8(%rsp),%rcx

It clearly load the address of the array which is somewhere on the stack.

Getting all together now!

So, we have the array on the stack at rsp+0x8 which is a contiguous memory area of size:

5 * 10 * 4 bytes (`rows * columns * sizeof(int)`) = 200 bytes = 0xc8 bytes

And, it is mapped as a sequence of rows of 40 bytes each. Each row gather 10 columns with cells of 4 bytes which can be depicted as follow:

---------------------------------------------------------------------------------
 ... | array[0][0] | array[0][1] | array[0][2] | array[0][3] | array[0][4] | ...
---------------------------------------------------------------------------------

Of course, you can find more complex mapping when dealing with multi-dimensional arrays in C, this one is quite simple. Just for completude remember that in total generality the mapping of a multi-dimensional array in C looks usually like that:

Matrix memory mapping in C

And, the structure of the assembly code will follow these constraints (slightly more complex but not so much once you understood the previous simple example).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.