这种方法好吗?

对于某些功能,我需要切换堆栈,以使原始堆栈保持不变.为此,我编写了两个宏,如下所示.

#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,直到函数尾声中将rsp相加,然后将其恢复为原始值.因此,我在这里看不到任何问题.

我不确定在上下文切换和信号存在的情况下是否正确.另外,我不确定函数是否内联或者是否应用了尾部调用优化(使用jmp代替call)是否正确.您认为这种方法有任何问题或副作用吗?

解决方法:

使用上面显示的代码,我可以想到以下损坏:

>在x86 / x64上,如果GCC认为合适,GCC会使用序言/结尾对您的函数进行“装饰”,并且您不能阻止它执行此操作(例如在ARM上,__attribute __((__ naked__))会强制创建没有序言/的代码/尾声,也就是没有堆栈框架设置).
这可能最终会在切换堆栈之前为堆栈内存位置分配堆栈/创建引用.更糟糕的是,如果再次由于编译器的选择,在切换堆栈之前将这样的地址放入非易失性寄存器中,则该地址可能会别名到两个位置(与堆栈指针相对的一个已更改,而另一个相对于一个的相对地址)一样).
>同样,在x86 / x64上,ABI建议对叶子函数(“红色区域”)进行优化,在该叶子函数中未分配堆栈帧,但在该函数“下方”可以使用128字节的堆栈.除非您的内存缓冲区考虑到了这一点,否则可能会发生您意料之外的溢出.
>信号在备用堆栈上处理(请参见sigaltstack()),并且自己进行堆栈切换可能会使您的代码无法从信号处理程序中调用.它肯定会使其成为不可重入的,并且取决于在何处/如何检索“堆栈位置”,也肯定会使它成为非线程安全的.

通常,如果要在不同的堆栈上运行特定的代码段,为什么不这样做:

>在不同的线程中运行它(每个线程获得不同的堆栈)?
>触发例如SIGUSR1并在信号处理程序中运行代码(可以将其配置为使用其他堆栈)?
>通过makecontext()/ swapcontext()运行它(请参见联机帮助页中的示例)?

编辑:

同样,由于您说“您想比较两个进程的内存”,因此有不同的方法,特别是外部进程跟踪-附加“调试器”(可以是您编写的使用ptrace()控制的进程)您要监视的内容,并使其代表所跟踪的对象处理断点/检查点,以执行所需的验证).这也将更加灵活,因为它不需要更改您检查的代码.

上一篇:中断发生或进程调度时,是否需要保存标志寄存器?


下一篇:VS中怎样使用Nuget添加MQTTnet依赖