Проблема с попыткой извлечь указатель стека с помощью вызова функции заключается в том, что указатель стека внутри вызываемой функции указывает на значение, которое будет совершенно другим после возврата функции, и, следовательно, вы захватываете адрес местоположение, которое будет недействительным после звонка. Вы также делаете предположение, что на этой платформе компилятором не был добавлен пролог функции (т. Е. Обе ваши функции в настоящее время имеют пролог, где компилятор устанавливает текущую запись активации в стеке для функции, которая изменит значение RSP, которое вы пытаетесь зафиксировать). По крайней мере, при условии, что компилятором не был добавлен пролог функции, вам нужно будет вычесть размер указателя на платформе, которую вы используете, чтобы фактически получить «истинный» адрес, по которому будет находиться стек указывая после возврата из вызова функции. Это связано с тем, что команда сборки call
помещает адрес возврата указателя инструкции в стек, а ret
в вызываемом вызове выталкивает это значение из стека. Таким образом, внутри вызываемого абонента, по крайней мере, будет инструкция обратного адреса, на которую будет указывать указатель стека, и это местоположение не будет действительным после вызова функции. Наконец, на некоторых платформах (к сожалению, не в x86) вы можете использовать тег __attributes__((naked))
для создания функции без пролога в gcc
. Использование ключевого слова inline
во избежание пролога не совсем надежно, поскольку оно не вынуждает компилятор встроить функцию ... при определенных уровнях низкой оптимизации вставка не произойдет, и вы снова получите пролог и указатель стека не будет указывать на правильное местоположение, если вы решите взять его адрес в этих случаях.
Если у вас должно быть значение указателя стека, то единственным надежным способом будет использование сборки, следование правилам ABI вашей платформы, компиляция в объектный файл с использованием ассемблера, а затем связывание этого объектного файла с Остальные объектные файлы в вашем исполняемом файле. Затем вы можете представить функцию ассемблера остальной части вашего кода, включив объявление функции в заголовочный файл. Таким образом, ваш код может выглядеть так (при условии, что вы используете gcc
для компиляции вашей сборки):
//get_stack_pointer.h
extern "C" void* get_stack_ptr();
//get_stack_pointer.S
.section .text
.global get_stack_ptr
get_stack_ptr:
movq %rsp, %rax
addq $8, %rax
ret