对%esp的修改会导致SIGSEGV

时间:2013-03-27 10:41:49

标签: linux assembly g++ 64-bit x86-64

有时我会在参与编码竞争时使用以下代码来避免堆栈溢出。

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):);并且它似乎运行良好?

1 个答案:

答案 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