assembly - 为什么函数参数在 x86 上占用至少 4 个字节的堆栈?

标签 assembly x86 calling-convention

如果函数参数在 x86 的堆栈中分配,则通过 push/pop 分配至少 4 个字节。如果每个函数调用有许多大小小于 4 字节的参数,这会浪费内存。一个原因可能是 push and pop work on 4 bytes least ,但是为什么不直接对 esp 进行操作以节省堆栈空间,可以将 1 个字节中的 4 个参数打包到一个 4 个字节的内存中,如下所示?

sub esp, 4
mov byte ptr [esp], para1
mov byte ptr [esp+1], para2
mov byte ptr [esp+2], para3
mov byte ptr [esp+3], para4
call func

最佳答案

这种行为通常由应用程序二进制接口(interface) (ABI) 控制,而最常用的 x86 ABI(Win32 和 Sys V)只要求每个参数至少占用 4 个字节。这主要是因为如果数据没有正确对齐,大多数 x86 实现都会遭受性能损失。虽然您的示例不会“取消对齐”堆栈,但仅采用三个字节大小的参数的子例程会这样做。当然,可以在 ABI 中定义特殊规则来克服这一点,但这会使事情变得复杂而收效甚微。

还要记住,x86 ABI 是在 1990 年左右设计的。当时,指令的数量是衡量某段代码速度的一个很好的衡量标准。如果 para1-para4 位于寄存器中,则与四个推送相比,您的示例需要一个额外的指令,在最坏的情况下需要五个额外的指令,所有参数都必须从内存中加载(x86 支持直接推送内存位置)。

此外,在您的示例中,您可以在堆栈上节省 12 个字节以换取 14 个额外的代码字节:如果 para1-para4(例如 al-dl)位于寄存器中,而四次推送需要,您的代码序列需要 18 个字节的代码4字节。所以总的来说,只有在代码中有递归时,才能减少内存占用。

关于assembly - 为什么函数参数在 x86 上占用至少 4 个字节的堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30679702/

相关文章:

windows - MASM32 - "Unresolved external symbols"链接时带有下划线

c++ - 如何将 float 作为参数传递(内联汇编)?

c++ - Thunking __stdcall 函数与堆栈调整

c - 在 MSP430 软件中缩短 2 个不同的端口

assembly - 在 SASM 中显示寄存器值的二进制表示

assembly - INT 13h 无法读取超出特定扇区的数据

c++ - 从 IA-32 中的程序集访问 C++ 中的函数参数

c - 用更大数组的字符填充 char 数组 | @ assembly IA32

assembly - x86-64 MOV r/m64,imm32 = io?

gcc - 如何使用单个 GCC(交叉)编译器(交叉)编译为 ARM 硬浮点和软浮点 (softfp)?