Для некоторых функций мне нужно переключить стек так, чтобы исходный стек оставался неизменным. Для этой цели я написал два макроса, как показано ниже.
#define SAVE_STACK() __asm__ __volatile__ ( "mov %%rsp, %0; mov %1, %%rsp" : \
"=m" (saved_sp) : "m" (temp_sp) );
#define RESTORE_STACK() __asm__ __volatile__ ( "mov %0, %%rsp" : \
"=m" (saved_sp) );
Здесь temp_sp и сохраненный_sp являются локальными переменными потока. temp_sp указывает на временный стек, который мы используем. Для функции, исходный стек которой я хочу изменить, я помещаю SAVE_STACK в начале и RESTORE_STACK внизу. Например, вот так.
int some_func(int param1, int param2)
{
int a, b, r;
SAVE_STACK();
// Function Body here
.....................
RESTORE_STACK();
return r;
}
Теперь мой вопрос: хорош ли этот подход? В x86 (64 бита) локальные переменные и параметры доступны через регистр rbp , а rsp соответственно вычитается в прологе функции и не затрагивается до тех пор, пока в эпилоге функции, где он добавлен для вывода это вернуться к первоначальному значению. Поэтому я не вижу здесь никаких проблем.
Я не уверен, правильно ли это при наличии переключений контекста и сигналов. Также я не уверен, правильно ли это, если функция встроенная или применяется оптимизация хвостового вызова (где используется jmp вместо call ). Видите ли вы какие-либо проблемы или побочные эффекты при таком подходе?