Объяснение доступа к массиву в сборке X86 - PullRequest
0 голосов
/ 19 января 2019

У меня есть следующая функция C:

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;
}

Из которого я сгенерировал следующий код сборки, используя:

gcc -Og -S file.c

Вышел следующий код сборки (я включил только представляющие интерес детали):

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

У меня проблемы с .L3. Насколько я понимаю, он начинается с перемещения счетчика int из 32-разрядного регистра %esi в 64-разрядный регистр %rdx. Тогда я не понимаю следующую строку:

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

в частности часть (%rdi,%rdx,4), которая добавляется к значению в регистре %eax. И в последней строке счетчик уменьшается на 1. Может ли кто-нибудь помочь мне с этой частью?

Ответы [ 2 ]

0 голосов
/ 19 января 2019
.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  */

В основном addl (%rdi,%rdx,4), %eax - это когда вы обращаетесь к массиву (%rdi) с индексом счетчика (%rdx) и добавляете значение элемента в res (%eax), 4это просто умножение счетчика (%rdx) для доступа к памяти, поскольку каждый адрес в массиве int занимает 4 байта в памяти вашей системы.

Строка в основном говорит: res += MEMORY[addrssOf(b) + counter*4]

Кстати, я полагаю, вы хотите проверить, что size > 0 перед строкой int counter = size-1;, а также, как P__J__ упоминается в его ответе, ваш res может переполниться, так как имеет одинаковый тип каждого элемента в массиве, который высуммирование.

0 голосов
/ 19 января 2019

в этой форме легче понять:

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

Два замечания: очень вероятно, что ваше целое число переполнится, поэтому вы должны использовать long long как временное и возвращаемое значение.Его также можно укоротить

long long sum_arr(const int *b, size_t size){
      long long res = 0;
      while(size--){
          res = res + *b++;
       }
      return res;
}
...