Почему мой ассемблерный код входит в бесконечный цикл? - PullRequest
0 голосов
/ 30 сентября 2018

Я пытаюсь создать for loop в сборке.

Вот то, чего я пытаюсь добиться, написав на C:

#include <stdio.h>
int main(){
    for(int i = 0; i < 10; i++){
        printf("%d\n", i);
    }
    return 0;
}

Вот так выглядит мой ассемблерный код:

.text
.globl _main


loop0.0:
  movl -4(%rbp), %eax           #eax = i
  cmpl $10, %eax                #compare i with 10
  jg loop0.2                    #if 10 > i goto loop0.2

loop0.1:
  leaq _format(%rip), %rdi      #set arg1 to format
  movl -4(%rbp), %esi           #set arg2 to i
  call _printf                  #printf(format, i)

  movl -4(%rbp), %esi           #set esi to i
  addl $1, %esi                 #esi++
  movl %esi, -4(%rbp)           #i = esi
  jmp loop0.0

_main:                           #int main
  pushq %rbp
  movq %rsp, %rbp

  movl $0, -4(%rbp)              #i = 0
  jmp loop0.0                    #goto  loop0.0
  loop0.2:

  xor %eax, %eax                 #return 0;

  popq %rbp
  retq


.data
  _format:
    .asciz "%d\n"

Когда я запускаю этот код, я получаю текущий вывод:

0
2
2
2
2
2
2

и т. Д.



Почему это такмой код сначала показывает 0 (как и должно быть), а затем два в течение бесконечного количества времени?Я надеюсь, что мои комментарии точны, так как это то, что я думаю, что каждая строка кода делает.

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Вместо того, чтобы хранить i в красной зоне, где он перекрыт call (см. Ответ @ prl), сохраняет i в регистре .

Itпохоже, что вы следуете (ужасному) стилю антиоптимизированного вывода компилятора, который сохраняет все в памяти для отладки.

Сохраните / восстановите rbx вокруг вашей функции и используйте ebx для i.(Чтобы сохранить 16-байтовое выравнивание стека до call _printf, не создавайте фрейм стека, потому что вам не нужно никакого стекового пространства для местных жителей.)

Кстати, это не так, но это очень нетрадиционноиметь часть тела функции (вашего цикла) перед точкой входа в функцию.Ваш код в общем случае слишком сложен.Это что-то вроде того, что вы получите от оптимизирующего компилятора для вашей C-функции.(Я не проверял https://godbolt.org/,, но я бы порекомендовал посмотреть.)

_main:                   #int main
    push  %rbx           # save RBX and realign the stack by 16

    xor   %ebx, %ebx
.loop:                    # do {
    mov   %ebx, %esi
    lea   _format(%rip), %rdi
    xor   %eax,%eax          # %al = 0 FP args in XMM registers
    call  _printf            # printf(format, i)

    inc   %ebx               # i++

    cmp   $10, %ebx
    jl  .loop             # }while(i<10)

    xor   %eax, %eax                 #return 0;
    pop   %rbx
    ret

 # Read-only data can go in .rodata
 # only mutable static data needs to go in .data
.section .rodata
  _format:    .asciz "%d\n"
0 голосов
/ 30 сентября 2018

Main не выделяет место в стеке для i, поэтому вызов printf перезаписывает i.

Добавьте инструкцию

sub $16, %rsp

сразу после

mov %rsp, %rbp

и добавьте

add $16, %rsp

прямо перед

pop %rbp

Причина вычитания 16 вместо 4 заключается в поддержании выравнивания стека.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...