[Linux 调用] 约定比 Unix 方式有很大的缺点,至少就汇编语言编程而言是这样:每次进行内核调用时,都必须压入寄存器,然后再弹出它们。这会使您的代码变得更庞大且更慢。
继续说 FreeBSD 支持 Linux 约定和“Unix 约定”
如果您专门针对 FreeBSD 进行编码,则应始终使用 Unix 约定:速度更快,您可以将全局变量存储在寄存器中,不必为可执行文件添加品牌,并且不必强行安装 Linux 模拟包目标系统。
我觉得奇怪的是 Linux 方式会更笨重、更慢。好像有两个选择,
- 仅保存您需要保留的寄存器,它们是
- 那些可能被系统调用破坏的易失性寄存器(据我所知
ecx
) - 或者,需要将适当的参数发送到内核以生成的寄存器
syscall
(可能是eax
,ecx
,edx
,esi
,edi
,ebp
)
- 那些可能被系统调用破坏的易失性寄存器(据我所知
- 将 100% 的内核参数保存在堆栈上。
看起来 FreeBSD 就是最糟糕的Linux 约定的案例场景。我缺少什么? FreeBSD 约定(他们称之为“Unix 方式”)如何变得更小、更快?
答案1
在我看来,这实际上归结为作者的观点。
在 FreeBSD(“Unix”)约定中,将参数压入堆栈,在 中指定系统调用号EAX
,然后调用中断 0x80(在堆栈上有一个额外的操作数,因为它期望从单独的函数调用)。
在 Linux i386 约定中,您将参数放置在适当的寄存器中,并调用中断 0x80。
体积大/速度慢的争论大概来自这样一个事实:按照 Linux 惯例,呼叫者需要处理其寄存器的使用。如果系统调用需要寄存器中包含调用者关心的值的参数,则需要保留它们,这会导致额外的跑腿工作;请参阅 C 库中的示例。在此示例中,系统调用需要 EAX、EBX、EDX、EDI 和 ESI 中的值;但调用者只关心保留 EBX、EDI 和 ESI,因此它只将它们推送到堆栈。一般情况是相当复杂一点(但这也是处理 C 和汇编语言混合的结果,试图在所有情况下生成最佳代码),但是当用汇编语言编写时,这就是您所指的站点的要点,那就不会了这不是什么大问题。
在我看来,有六个半:在 FreeBSD 约定中,您在所有情况下都会推送到堆栈,在 Linux 约定中,您会推送到堆栈(或其他地方),具体取决于您正在做什么呼叫站点。您可能会说 Linux 约定可以实现更快的代码,因为您可以在寄存器中执行所有计算......抢然而指出,在 Linux 上,寄存器最终仍然会被压入(构建struct pt_regs
用于向处理系统调用的 C 函数提供参数的实例),因此 Linux 端的总体成本高于 Linux 端的总体成本。 FreeBSD 端。
无论如何,考虑到执行系统调用本身的成本,在围绕系统调用谈论堆栈或基于寄存器的代码时争论性能似乎相当迂腐。从绝对意义上来说,任何节省的周期当然都是好的,但相对的改进将会很小。