我有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生成了这样不正确的代码?
答案 0 :(得分:5)
在装配级别没有“未定义的内存”这样的东西。只要行为符合预期,gcc就可以自由发出以其认为合适的方式访问堆栈的代码。
我猜测为什么会发生这种情况,这是一个叶子函数,调整堆栈指针是徒劳的。您可以尝试通过检查程序集中的任何call
指令来验证这一点。 (您也可以检查C源,但内联可能会使其不那么可靠。)
某些平台的ABI明确允许这种技巧,包括x86-64。来自the AMD64 ABI documentation:
考虑%rsp指向的位置之外的128字节区域 保留,不得通过信号或中断进行修改 处理程序。因此,函数可以将此区域用于临时数据 在函数调用中不需要。特别是叶子 函数可以将此区域用于整个堆栈帧,而不是 在序言和结语中调整堆栈指针。这个区域是 被称为红区。
This blog post可能会对这个主题进行有趣的阅读。