4

我有 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

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

movaps %xmm15,-0x18(%rsp)

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

4

1 回答 1

7

在汇编级别没有“未定义的内存”之类的东西。gcc 可以自由地发出以任何它认为合适的方式访问堆栈的代码,只要行为符合预期。

我对为什么会发生这种情况的猜测是,这是一个叶子函数,调整堆栈指针是徒劳的。您可以尝试通过检查程序集是否有任何call说明来验证这一点。(您也可以检查 C 源代码,但内联可能会降低可靠性。)

某些平台的 ABI 明确允许这种欺骗,包括 x86-64。来自AMD64 ABI 文档

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

这篇博客文章可能会引起有关该主题的有趣阅读。

于 2013-12-18T16:32:28.483 回答