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的红区是如何实现的的主要内容,如果未能解决你的问题,请参考以下文章

x86-64 System V ABI 记录在哪里?

libstdc++ 静态链接和 System V ABI

linux用的是posix还是system v

ABI与编译器:ABI是由内核和工具链定义和实现的

COM如何实现语言互操作?

使用web3j实现abi转java