Сейчас я изучаю сборку и ничего не понимаю в (предположительно) стандартном шаблоне функции.
Итак, основываясь на этой замечательной книге, "форма запомнить для функций выглядит следующим образом:"
function_label:
pushl %ebp
movl %esp, %ebp
< normal function code goes here>
movl %ebp, %esp
popl %ebp
ret
Хорошо, меня все устраивает, но есть одна маленькая вещь, которую я не понимаю. После "нормального кода функции" восстанавливаем исходное (до вызова) значение esp
, которое ранее хранилось в ebp
.
Теперь я ясно понимаю, почему мы хотим передать значение esp
обратно в вызывающий контекст нетронутым. Чего я не понимаю, так это при каких условиях значение esp
вообще может быть изменено во время выполнения функции.
Это какая-то защита от нас самих (на случай, если мы каким-то образом испортим стек где-то в нашем коде), включенная в этот шаблон? Или, может быть, изменение значений стека внутри функции — это нормальная практика? Или возможно, что начальное значение esp
может измениться во время выполнения, даже если мы ничего с ним не делаем? (Я не могу понять, как это может быть, на самом деле.)
Я чувствовал себя довольно глупо, думая об этом, и проверил значение esp
с gdb
в этом простом коде:
.section .data
message:
.asciz "> Hello from function #%d\n"
.section .text
.globl main
main:
nop
call overhere
pushl $0
call exit
overhere:
pushl %ebp
movl %esp, %ebp
pushl $1
pushl $message
call printf
add $8, %esp
movl %ebp, %esp
popl %ebp
ret
И esp
(как я и ожидал) остался нетронутым, поэтому перемещение ebp
в esp
на самом деле ничего не изменило.
Теперь, надеюсь, понятно, что я хочу узнать:
- Может ли значение
esp
измениться само по себе? (Готов поспорить, что нельзя.) - Если не может, то этот шаблон выше, очевидно, предполагает, что программист может как-то изменить его внутри функции. Но я не могу понять, с какой стати это может понадобиться, так что изменение значения
esp
является ошибкой?
Заранее спасибо и извините за невежество.