перевод обычной программы на c C++ на ассемблер
помогите,пожалуйста, разобрать код созданный в результате компиляции из C++ в ассемблер при помощи g++. Пытаюсь читать Брюса Эккеля. но видимо компиляторы давно шагнули вперед поэтому описание которое приведено в книге отлично от того, что получается при помощи g++. Итак, вот элементарная программа :
int foo(int i) {
return i+1;
}
int main() {
int y = foo(20);
}
после выполнения:
g++ -E foo.cpp -o foo.ii
g++ -S foo.ii -o foo.s
имеем вот такой ассемблерный код:
.file "foo.cpp"
.text
.globl __Z3fooi
.def __Z3fooi; .scl 2; .type 32; .endef
__Z3fooi:
LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $1, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE0:
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call ___main
movl $20, (%esp)
call __Z3fooi
movl %eax, 28(%esp)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1:
.ident "GCC: (MinGW.org GCC Build-2) 9.2.0"
итак вот эти строки непонятны :
- в этой строке происходит задание параметра, верно ? :
movl $20, (%esp)
- затем вызывается моя функция, её имя тут call __Z3fooi далее переносимся в функцию , вот тут совсем ничего не понятно:
- зачем делать :
pushl %ebp? - верно ли я понимаю, что таким образом мы заносим значение параметра в регистр esp
movl %esp, %ebp? - зачем делается
movl 8(%ebp), %eax? - как я понимаю
addl $1, %eaxэто увеличивает на единицу нашу регистр ? - этим восстанавливается значе
popl %ebp
может быть есть где почитать статьи как передается в функцию параметры и выполняются ?
Ответы (1 шт):
movl $20, (%esp)
esp - это указатель стека. это так изобретательно в стек заталкиваем параметр pushl %ebp
в ebp мы будем хранить указатель на стек до увеличения, но некрасиво просто так менять регистр, поэтому мы его запомним в стеке. А потом
movl %esp, %ebp
запишем esp в ebp (а предыдущее уже сохранено!)
movl 8(%ebp), %eax
а теперь берем 8 байтовое с стека - это наш параметр, который main туда положила.
addl $1, %eax
делаем то, что нас попросили - +1
popl %ebp
и восстановили регистр назад. Мы же его чуть выше попоритили.
а результат по соглашению возвращаем в eax - он уже там.
То есть, код делает ровно то, что его попросили.
Что бы не мучатся с ручной компиляцией, рекомендую сервис https://gcc.godbolt.org/