System V ABI的红区是如何实现的
Posted
技术标签:
【中文标题】System V ABI的红区是如何实现的【英文标题】:How system V ABI's red zone is implemented 【发布时间】:2019-12-19 06:23:01 【问题描述】:编译器如何确保红色区域没有被破坏?是否有空间过度分配?
以及是什么因素导致选择128字节作为红色区域的大小?
【问题讨论】:
没有何时被破坏?如果一个固定大小的空间,你认为在什么意义上可能会在上下文中过度分配? 【参考方案1】:编译器不会,它只是利用保证低于 RSP 的空间不会被异步破坏(例如,通过信号处理程序)。进行函数调用当然会同步破坏它。
事实上,在 Linux 上只有信号处理程序在用户空间代码中异步运行。 (内核栈得到中断:Why can't kernel code use a Red Zone)
内核在向用户空间传递信号时实现了红色区域。我认为就是这样;这真的很容易实现。
另一件相关的事情是,当您在 GDB 中执行类似 print foo(123)
的操作时,调试器会运行一个函数。 GDB 将使用当前线程的堆栈实际运行该函数。在带有红色区域的 ABI 中,当用户执行 continue
或单步操作时,GDB(或任何其他调试器)在保存寄存器状态后执行 rsp -= 128
调用该函数时必须尊重它以恢复。
在 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 细节更不有趣。)
【讨论】:
以上是关于System V ABI的红区是如何实现的的主要内容,如果未能解决你的问题,请参考以下文章