Вы забыли сделать mov rbp, rsp
(после push rbp
), чтобы сделать RBP указателем кадра на ваш кадр стека.
Ваше "домашнее пространство" или теневое пространство на 32 байта выше вашего обратного адреса, вы просто не используете его. (И вместо этого нарушаете соглашение о вызовах, сохраняя относительно некоторого регистра, который может иметь любое значение. В этом случае ваш вызывающий возможно, также используя RBP для устаревшего указателя кадра, так что вы, вероятно, просто наступаете на домашнее пространство вызывающего абонента.)
Обратите внимание, что 0xCC
- это значение MSV C, используемый в режиме отладки для отравления стек, помогающий обнаруживать чтения неинициализированной памяти. (И если вы случайно выполняете память с этим содержимым, это инструкция отладочной точки останова x86 int3
.)
И кстати, когда вы используете RBP в качестве традиционного указателя кадра, mov rsp, rbp
/ pop rbp
/ ret
более эффективно, чем add rsp, 16
/ pop rbp
. Чуть меньший размер кода, и некоторые процессоры делают исключение mov, чтобы избежать необходимости в исполнительном модуле для mov
. Это было бы для вас более шумным, как, например, возвращение с обратного адреса вашего абонента, который вы могли заметить при пошаговом переходе!
(leave
= mov / pop, так что вы можете использовать его даже для меньший размер кода. Это нормально для производительности, в отличие от enter
; G CC использует leave
в функциях с указателем кадра, который заканчивается RSP, еще не указывающим на сохраненный RBP. Некоторые другие компиляторы предпочитают mov / pop. Но компиляторы обычно используют add rsp, n
только тогда, когда они вообще не используют указатель кадра.)
Указатели кадра являются необязательными и не являются обязательной частью компоновки кадра стека. Такие директивы, как .allocstack 16
, создают метаданные, которые делают возможным разматывание стека без традиционного связанного списка указателей фреймов.