在 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/