Мы на машине x86-64. Рассмотрим
int foo(int a) {
if( a > 0)
foo(a-1);
return 0;
}
в сборке, вот:
foo:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
cmpl $0, -4(%rbp)
jle .L2
movl -4(%rbp), %eax
subl $1, %eax
movl %eax, %edi
call foo
.L2:
movl $0, %eax
leave
ret
Теперь я пытаюсь выяснить, что именно здесь происходит. Я получаю общую сборку, вопрос относится к строке 2,3 и 4 фрагмента кода сборки.
Мы запускаем нашу программу. Мы получаем виртуальную память. Затем происходит следующее, когда функция foo()
вызывается в первый раз:
pushq %rbp
Мы помещаем sh 8-байтов в стек, тогда как стек начинается с% rbp.
movq %rsp, %rbp
Мы позволяем% rsp указывать на% rbp, то есть на начало стека. Вот почему мы сначала выдвинули эти 8 байтов - нам нужно хранилище для $ rsp. Правильно?
subq $16, %rsp
Мы перемещаем% rsp вниз на 16 байт.
Теперь я не думаю, что понял это правильно. В чем конкретно разница между pushq
и просто перемещением %rsp
напрямую?
Когда тогда в основном выполняются условие if и рекурсия. Рекурсия приводит к повторению вышеупомянутых трех строк. Теперь, не приводит ли это к последовательному перемещению указателя базы и стека на 16 байт? Как мы узнаем, с чего мы начинали?