【发布时间】:2012-01-11 11:54:44
【问题描述】:
对于某些功能,我需要切换堆栈,以使原始堆栈保持不变。为此,我编写了如下所示的两个宏。
#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 和 saved_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 并且直到在添加它的函数尾声中才被触及使其恢复到原来的值。因此,我认为这里没有问题。
我不确定,但在存在上下文切换和信号的情况下这是否正确。 (在 Linux 上)。此外,如果函数是内联的,或者是否应用了尾调用优化(使用 jmp 而不是 call),我也不确定这是否正确。您认为这种方法有什么问题或副作用吗?
【问题讨论】:
-
请问您希望通过这样做实现什么目标?
-
@aix:我正在努力实现我所说的,即不更改原始堆栈。基本上我有两个相同的进程,我需要定期比较它们的内存(包括堆栈)。对于某些函数,这两个进程将采用不同的执行路径,因此我们将无法正确比较它们的内存,因为它们会变得不同。所以对于这样的功能,如果没有其他分歧发生,我需要切换堆栈,以便两个进程的原始堆栈相同。
-
警告:GCC 4.7 将包含一个新的“收缩包装”优化,可能会打破你的假设;它将函数序言的一部分延迟到真正需要它们之前,因此如果函数提前退出,程序运行效率会更高。 Ubuntu GCC 已经有这个功能,虽然它默认是禁用的(由于稳定性问题)。
-
您是否考虑过使用longjmp 或swapcontext?
-
@MetallicPriest:请给你的问题一个更具体的标题。
标签: c gcc x86-64 inline-assembly stack-pointer