MSDN 说
Integer valued arguments in the leftmost four positions are passed in left-to-right order in RCX, RDX, R8, and R9, respectively. Space is allocated on the call stack as a shadow store for callees to save those registers. Remaining arguments get pushed on the stack in right-to-left order.
所以,我尝试调用 CreateFileW
函数,这是我的代码:
sub rsp, 20h ; Allocate 32 bytes because 4 registers 8 byte each
mov rcx, offset filename ; lpFileName
mov rdx, GENERIC_READ or GENERIC_WRITE ; dwDesiredAccess
mov r8, FILE_SHARE_DELETE ; dwShareMode
xor r9, r9 ; LpSecurityAttributes
;__And right-to-left order remaining arguments__
push 0 ; hTemplateFile
push FILE_ATTRIBUTE_NORMAL ;dwFlagsAndAttributes
push CREATE_ALWAYS ; dwCreationDisposition
call CreateFileW
它可以组装,但不起作用,win64dbg 会导致下一个错误:
00000057 (ERROR_INVALID_PARAMETER)
参数 100% 正确,因为它与 Invoke
宏配合使用,只是生成的代码不同。
mov rcx,src.403000 ;name
mov edx,C0000000 ;GENERIC_READ or GENERIC_WRITE
mov r8d,4 ;FILE_SHARE_DELETE
xor r9d,r9d ;0
mov qword ptr ss:[rbp-20],2; ;CREATE_ALWAYS
mov qword ptr ss:[rbp-18],80 ;FILE_ATTRIBUTE_NORMAL
and qword ptr ss:[rbp-10],0 ;0
call qword ptr ds:[<&CreateFileW>]
所以我的问题是为什么它使用 RBP 寄存器而不是 push
并且不为“shadow-store”分配 32 个字节?
注释
由于 Microsoft 的 64 位 MASM 不再具有 invoke
指令,我正在使用俄语 MASM64 SDK具有 invoke
宏的项目。该项目大致基于 MASM32 SDK .
最佳答案
如果您想push
args,您必须在sub rsp,20h
之前进行。 (这效果不好,因为通常您只需要一个 sub rsp,20h
来完成整个函数,而不是每次调用一个)。并且您必须正确计数才能在最后一次推送
后使 RSP%16 == 0。通常,您不想更改 RSP,除了 Windows x64 中的函数序言/结尾之外,alloca 类型的事物除外。
堆栈参数位于影子空间上方,因此,如果函数将其寄存器参数转储到影子空间中的“主空间”,它将有一个连续的参数数组。 (像 printf 这样的可变参数函数实际上会这样做;普通函数不会,除非它是调试版本。)
使用调试器在调用
之前查看堆栈内存的内容(高于RSP),以您的方式与将mov
存储到堆栈的正常方式进行比较影子空间上方的 arg 空间。
请注意,sub rsp,20h
不够大,无法为影子空间和堆栈参数保留空间,因此您显示的“调用宏”代码必须保留该函数开头有更多空间。
Why it use RBP register instead of push and does not allocate 32 bytes for "shadow-store"?
它使用 RBP,因为如果您已经使用指令将 RBP 设置为帧指针,那么这是访问堆栈空间的正常方式。
这会更清晰、更容易地看到相对于 RSP 的寻址模式发生了什么,例如 [rsp+20h]
访问影子空间上方的第一个插槽,您想要的位置存储第一个堆栈参数。
如果您分配了可变数量的空间,因此从 RBP 到阴影空间上方的距离未知,则这是必要的,但您无论如何都可以这样做,只是为了清晰和易于获得偏移正确。但是,如果编译器或聪明的宏可以计算正确的偏移量,并且您已经使用指令将 RBP 设置为帧指针,那么使用它会稍微更有效,因为它在机器代码中节省了一个字节( [rsp+constant]
需要 SIB 字节进行编码。)
常规 MASM 在 64 位模式下没有调用
。我不知道你在用什么。也许您需要手动保留堆栈空间,或者它可能在函数顶部为您执行此操作,但您将其遗漏了。 Michael Petch 说 MASM64 附带了一个 invoke
宏,它确实向您的代码添加了一个 sub rsp
。
关于assembly - x64 fastcall 调用者堆栈管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74247426/