Как указано в спецификации 6.4 DWARF :
[...] Кадр вызова идентифицируется по адресу в стеке.Мы называем этот адрес каноническим адресом кадра или CFA.Как правило, CFA определяется как значение указателя стека на сайте вызова в предыдущем кадре (которое может отличаться от его значения при входе в текущий кадр).
main()
вызывается откуда-то еще (в коде поддержки времени выполнения libc
C), и во время выполнения инструкции call
%rsp
будет указывать на верхнюю частьстека (который является самым низким адресом - стек растет вниз), что бы это ни было (в данном случае это не имеет значения):
: : ^
| whatever | <--- %rsp | increasing addresses
+----------------+ |
Значение %rsp
на данный моментэто «значение указателя стека на сайте вызова», т. е. CFA, как определено в спецификации.
При выполнении инструкции call
он будет выдавать 64-битный (8 байт) возвратадрес в стеке:
: :
| whatever | <--- CFA
+----------------+
| return address | <--- %rsp == CFA - 8
+----------------+
Теперь мы запускаем код на main
, который выполняет subq $8, %rsp
, чтобы зарезервировать для себя еще 8 байтов стека:
: :
| whatever | <--- CFA
+----------------+
| return address |
+----------------+
| reserved space | <--- %rsp == CFA - 16
+----------------+
изменение указателя стека объявляется в отладочной информации с использованием директивы .cfi_def_cfa_offset
, и вы можете видеть, что CFA теперь смещен на 16 байтов от текущего указателя стека.
В конце функции, инструкция addq $8, %rsp
снова изменяет указатель стека, поэтому вставляется еще одна директива .cfi_def_cfa_offset
, указывающая, что CFA теперь смещен только на 8 байтов от указателя стека.
(Число «22» в метках - просто произвольное значение.Компилятор будет генерировать уникальные имена меток на основе некоторых деталей реализации, таких как внутренняя нумерация основных блоков.)