GCC访问堆栈顶部的内存

Ale*_*oba 4 assembly gcc sse x86-64 sse2

我有C函数做一些SSE计算.当我用GCC编译它时,我得到下一个代码

/* Start of function */
mov    (%rdi),%rax
movslq %ecx,%rcx
...
mov    0x8(%rdi),%rax
pxor   %xmm12,%xmm3
movaps %xmm0,-0x28(%rsp)
movaps %xmm6,%xmm1
...
movaps 0x50(%rax,%rcx,1),%xmm2
movaps 0x60(%rax,%rcx,1),%xmm15
pxor   %xmm2,%xmm0
pxor   %xmm2,%xmm6
movaps -0x28(%rsp),%xmm2
pxor   %xmm15,%xmm5
pxor   %xmm15,%xmm2
movaps 0x70(%rax,%rcx,1),%xmm15
movaps (%rax,%rcx,1),%xmm11
mov    0x10(%rdi),%rax
movaps %xmm15,-0x18(%rsp)
pxor   %xmm11,%xmm4
pxor   %xmm12,%xmm11
pxor   %xmm15,%xmm12
Run Code Online (Sandbox Code Playgroud)

查看movaps说明 - 它是堆栈顶部的访问内存:

movaps %xmm15,-0x18(%rsp)
Run Code Online (Sandbox Code Playgroud)

它不是访问未定义的内存吗?为什么GCC生成了这样不正确的代码?

gsg*_*gsg 6

在装配级别没有"未定义的内存"这样的东西.只要行为符合预期,gcc就可以自由发出以其认为合适的方式访问堆栈的代码.

我猜测为什么会这样,这是一个叶子函数,调整堆栈指针是徒劳的.您可以尝试通过检查程序集的任何call指令来验证.(您也可以检查C源,但内联可能会使其不那么可靠.)

某些平台的ABI明确允许这种欺骗,包括x86-64.从AMD64 ABI文档:

超出%rsp指向的位置的128字节区域被认为是保留的,不应被信号或中断处理程序修改.因此,函数可以将此区域用于函数调用不需要的临时数据.特别是,叶子函数可以将这个区域用于它们的整个堆栈帧,而不是调整序言和尾声中的堆栈指针.这个区域被称为红区.

这篇博客文章可能会对这个主题进行有趣的阅读.

  • 你是对的,非常感谢你!问题在于数据损坏,因为中断处理程序正在覆盖堆栈帧.来自[LKD](http://www.makelinux.net/books/lkd2)的引用:_Historically,中断处理程序没有收到自己的堆栈.相反,他们将共享他们中断的进程堆栈.所以,当我使用`-mno-red-zone`编译代码时,它开始正常工作. (5认同)