编译器如何确保红色区域不被破坏?是否存在空间过度分配的情况?
是什么因素导致选择128字节作为红色区域的大小?
最佳答案
编译器不会,它只是利用保证,即 RSP 下面的空间不会异步被破坏(例如,通过信号处理程序)。进行函数调用当然会同步破坏它。
事实上,在 Linux 上只有信号处理程序在用户空间代码中异步运行。 (内核堆栈获得中断:Why can't kernel code use a Red Zone)
内核在向用户空间传递信号时实现红区。我认为就是这样;它真的很容易实现。
另一件事是,当您在 GDB 中执行诸如 print foo(123)
之类的操作时,调试器会运行函数。 GDB 实际上将使用当前线程的堆栈来运行该函数。在具有红色区域的 ABI 中,GDB(或任何其他调试器)在调用该函数时必须尊重它,方法是在保存寄存器状态以在用户执行 时恢复后执行
或单步执行。rsp -= 128
继续
在 i386 System V 中,print foo(123)
将使用当前 ESP 正下方的空间,踩在 ESP 下方的任何位置。 (我认为;未测试)。
And what factors lead to choosing 128 byte as the size of red zone?
像[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] 的紧凑寻址模式来访问整个 256 字节的空间
或以 dword/qword block 的形式。
进一步阅读
了解为什么在 Windows 上使用 ESP 下面的空间不安全,或者在没有红区的 Linux 上使用,是有启发性的。
陈雷蒙的博客:Why do we even need to define a red zone? Can’t I just use my stack for anything?
我的回答也涵盖了一些相同的基础:Is it valid to write below ESP? (但与 Raymond 相比,猜测更多,Windows 细节也不那么有趣。)
关于linux - 系统V ABI的红色区域是如何实现的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57465132/