有时我会在参与编码竞争时使用以下代码来避免堆栈溢出。
int main()
{
static const int _STACK_SIZE = MAXN*10;
static int _STACK[_STACK_SIZE*2], _ESP;
__asm__ __volatile__
(
"movl %%esp, %0\n"
"movl %1, %%esp\n":
"=g"(_ESP):
"g"(_STACK + _STACK_SIZE):
);
// Do Something..
__asm__ __volatile__
(
"movl %0, %%esp\n":
:
"g"(_ESP):
);
}
据我所知,这个asm代码备份%esp
并将堆栈移动到_STACK[]
。
我的问题:为什么这个代码在x86-64 Linux服务器上导致SIGSEGV
(它在我自己的x86 Linux上运行良好)?以及如何解决它?
我猜,也许是因为%esp
是一个64位指针??
我试图删除__asm__ __volatile__("movl %0, %%esp\n": : "g"(_ESP):);
并且它似乎运行良好?
答案 0 :(得分:2)
这是因为在x86-64程序集中修改32位寄存器(例如esp
)会将相应64位寄存器的最高32位归零,在这种情况下为rsp
。在x86-64中,堆栈指针rsp
是64位寄存器。该问题应仅在超过4 GiB 虚拟内存地址空间的计算机中发生,因为2 ^ 32字节= 4 GiB,因此在少于4的计算机中虚拟内存地址空间的GiB,无论如何最高的32位将为零。
因此,通过修改esp
,您可以使rsp
指向您的程序无权访问的地址,从而导致分段错误。在x86-64代码中,您通常不会使用esp
,并且应该在x86-64代码中将esp
的所有实例替换为rsp
。