编译器如何确保红色区域不被破坏?是否存在空间过度分配?
什么因素导致选择128字节作为红色区域的大小?
答案 0 :(得分:3)
编译器不会,只是利用了保证的优势 ,即RSP下的空间不会被异步破坏(例如,信号处理程序)。当然,进行函数调用将同步破坏它。
实际上,在Linux上,仅 信号处理程序在用户空间代码中异步运行。 (内核堆栈获得中断:Why can't kernel code use a Red Zone)
内核在向用户空间传递信号时实现了红色区域。真的很容易实现。
另一件事是相关的,当您在GDB中执行诸如print foo(123)
之类的操作时,调试器将运行一个函数。 GDB实际上将使用当前线程的堆栈来运行该功能。在带有红色区域的ABI中,GDB(或任何其他调试器)在保存寄存器状态后通过执行rsp -= 128
来调用该功能时必须尊重该功能,以便在用户执行continue
或单步操作时进行还原
在i386 System V中,print foo(123)
将使用当前ESP下方的空间,然后踩到ESP下方的空间。 (我认为;未经测试)。
什么因素导致选择128字节作为红色区域的大小?
在像[rsp - 128]
这样的寻址模式下,有符号字节位移可以达到这一程度。 IIRC是我在回答Why does Windows64 use a different calling convention from all other OSes on x86-64?时正在查看的amd64.org邮件存档,实际上包含一条消息,指出这是做出此特定选择的原因。
您希望它足够大,以至于许多简单的叶子函数不需要移动RSP。例如至少16或32个字节,例如MS的Windows x64调用约定中的32个字节的影子空间。
您希望它足够小,以使其跳过以调用信号处理程序,而无需占用大量空间,例如新页面。远远小于4kB。
需要超过128个字节的局部变量的叶子函数可能足够大,以至于移动RSP简直是九牛一毛。然后,+-disp8寻址模式的优势开始发挥作用,它可以使用byte [rsp+127]
到byte [rsp-128]
或dword / qword块中的紧凑寻址模式访问整个256字节的空间。
了解为什么在Windows或没有红区的Linux上使用ESP下方的空间不是安全的。
Raymond Chen的博客:Why do we even need to define a red zone? Can’t I just use my stack for anything?
我的SO答案也涵盖了一些相同的地方:Is it valid to write below ESP?(但比Raymond猜测更多,Windows细节也更少有趣)。