assembly - 在 x64 上,每个 PUSH 指令是否推送 8 字节的倍数?

标签 assembly x86-64 calling-convention

在 x64 上,每个 PUSH 指令是否推送 8 字节的倍数?如果没有,它会推多少?

另外,每个函数参数占用多少堆栈空间?

最佳答案

64 位模式下的 PUSH 操作数大小

压入堆栈的值的大小以及堆栈指针调整的量取决于PUSH指令的操作数大小。在 64 位模式下,操作数大小只能是 16 位或 64 位。无法在 64 位模式下编码 32 位 PUSH 指令,也不可能在任何模式下编码 8 位 PUSH 指令。

例如,这些都是 64 位 PUSH 指令:

push    rax
push    1              ; 8-bit immediate sign-extended to 64 bits
push    65536          ; 32-bit immediate sign-extended to 64 bits
push    QWORD PTR[0]
push    fs             ; 16-bit segment register zero-extended to 64 bits

以上指令都是将RSP减去8,然后将64位值写入RSP指向的位置。

这些都是 16 位 PUSH 指令:

push    ax
push    WORD PTR[0]

这些指令从 RSP 中减去 2,然后将 16 位值写入 RSP 指向的位置。因为它们严重错位堆栈,所以在 64 位模式下使用 16 位 PUSH 几乎总是一个错误。相反,您应该将 16 位值加载到寄存器中(如果尚未存在),根据需要扩展它,然后使用 64 位 PUSH。

以下指令是非法的,无法在 64 位模式下进行编码:

push    al
push    eax
push    BYTE PTR[0]
push    DWORD PTR[0]
push    0100000000h    ; 64-bit immediate value isn't supported

将 8 位或 32 位值压入堆栈需要将该值加载到寄存器中,扩展它,然后使用 64 位 PUSH,就像处理 16 位值一样。

64位模式参数传递

一般来说,在 64 位模式下,函数参数不会在堆栈上传递。 Microsoft 和 Linux 64 位 x86 调用约定都在寄存器中传递大多数参数。仅当寄存器中没有足够的空间来将参数传递给函数时才使用堆栈。在这种情况下,每个参数占用一个或多个 8 字节堆栈槽。请注意,编译器不一定使用 PUSH 指令将这些参数放入堆栈中。常见的策略是在堆栈上为函数序言中的所有函数传出参数分配足够的空间,然后根据需要使用 MOV 指令将参数放入堆栈中。

关于assembly - 在 x64 上,每个 PUSH 指令是否推送 8 字节的倍数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40305965/

相关文章:

assembly - 通过 USB 驱动器启动的自定义引导加载程序在某些计算机上产生不正确的输出

c++ - vector 异常处理程序中的 EXCEPTION_ACCESS_VIOLATION 异常

c - 汇编中有关 win32 api 的帮助

assembly - 用更少的指令对 64 位寄存器中的所有字节进行异或

c - 使用 gdb 访问命令行参数

c++ - GCC 代码生成器:pthread_create_key() 与 std::shared_ptr 复制有什么关系?

assembly - 在长模式下更改 GDT 并更新 CS

c++ - 没有溢出的无限递归 - 这可能吗?

assembly - 无堆栈函数的跳转/跳转编译策略。 (手动使用链接注册而不是调用/返回)

c - 从 C 语言传递 64 位汇编函数中的参数。哪个寄存器接收这些参数?