0

I have the following C function:

int sum_arr(int b[], int size){
      int counter = size-1;
      int res = 0;
      while(counter >= 0){
          res = res + b[counter];
         counter = counter - 1;
       }
      return res;
}

From which I generated the following assembly code using:

gcc -Og -S file.c

Out came the following assembly code (I have included the parts of interest only):

sum_arr:
.LFB41:
    .cfi_startproc
    subl    $1, %esi
    movl    $0, %eax
    jmp     .L2
.L3:
    movslq  %esi, %rdx
    addl    (%rdi,%rdx,4), %eax
    subl    $1, %esi
.L2:
    testl   %esi, %esi
    jns     .L3
    rep     ret
    .cfi_endproc

I am having some trouble with .L3. The way I understand it is that it starts off by moving the int counter from a 32 bit register %esi into a 64 bit register %rdx. Then I don't understand the following line:

addl (%rdi,%rdx,4), %eax

in particluar the (%rdi,%rdx,4) part, which gets added to the value in the %eax register. And on the last line it decrements the counter with 1. Could someone help me out with that part?

Sasha
  • 102
  • 8
sn3jd3r
  • 496
  • 2
  • 18
  • In this line `addl (%rdi,%rdx,4), %eax` you add to `eax` value which stored by address calculated as `(%rdi,%rdx,4)`. Also, I recommend using https://godbolt.org/ – funnydman Jan 19 '19 at 17:07

2 Answers2

1
.L3:
    movslq  %esi, %rdx           /* sign extend counter<%esi> to 64bit %rdx */
    addl    (%rdi,%rdx,4), %eax  /* res<%eax> += b<%rdi>[counter<%rdx>]; */
    subl    $1, %esi             /* counter<%esi> -= 1              */
.L2:
    testl   %esi, %esi           /* do counter<%esi> & counter<%esi> */
    jns     .L3                  /* if result is no 0, jump to L3  */

Basically addl (%rdi,%rdx,4), %eax is where you access the array (%rdi) with the index of counter (%rdx) and add the value of the element to res (%eax), the 4 is just the multiply of counter (%rdx) for the memory access as each address in the int array consume 4 bytes in memory in your system.

The line basically says res += MEMORY[addrssOf(b) + counter*4]

BTW, I believe you want to check that size > 0 before line int counter = size-1;, and also as P__J__ mentioned in his answer, your res can overflow as it have the same type of each element in the array you summing.

izac89
  • 3,790
  • 7
  • 30
  • 46
  • Thank you. Great explanation. The code is from a book i have, but i see you point with the overflow issue. – sn3jd3r Jan 20 '19 at 00:58
-1

in this form it is easier to understand:

sum_arr:
        sub     esi, 1
        js      .L4
        movsx   rsi, esi
        mov     eax, 0
.L3:
        add     eax, DWORD PTR [rdi+rsi*4]
        sub     rsi, 1
        test    esi, esi
        jns     .L3
        ret
.L4:
        mov     eax, 0
        ret

Two remarks: your integer is very likely to overflow so you should use long long as temporary & return value. It can be shortened as well

long long sum_arr(const int *b, size_t size){
      long long res = 0;
      while(size--){
          res = res + *b++;
       }
      return res;
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    It only depends on which syntax you like more. – funnydman Jan 19 '19 at 17:40
  • @FUNNYDMAN: Well, no. If you're not familiar with any syntax but have done basic algebra at school, the meaning of `rdi+rsi*4` looks obvious while `(%rdi,%rdx,4)` is far less intuitive. – Brendan Jan 19 '19 at 18:33