0

我知道前四个参数在寄存器中(RCX, RDX, R8, R9),并且其他参数被压入堆栈。

问题:

如何将参数压入堆栈?我尝试使用 (push 0) 但它不起作用?

代码( MASM64 )

extrn ExitProcess: PROC   
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
  sub    rsp, 38h        
  mov    rcx, 0         ; hWnd = HWND_DESKTOP
  lea    rdx, message   ; LPCSTR lpText
  lea    r8,  caption   ; LPCSTR lpCaption
  mov    r9d, 0         ; uType = MB_OK

  push   0          ; wLanguageId

  call   MessageBoxExA  
  mov    ecx, eax       
  add    rsp, 38h
  call ExitProcess
Start ENDP
End

我知道这一点MessageBoxMessageBoxEx以相同的方式工作,但我尝试使用它,MessageBoxEx因为它需要传递一个参数(用于学习目的)。

我知道我问过类似的问题,但它与 vb.net 更相关,而这不是。

4

2 回答 2

0

参数传递的顺序以及它们是在寄存器中传递还是在堆栈中传递(以及调用者或被调用者是否负责清理)由“调用约定”定义。

您可能想到的是 STDCALL 或 CDECL,它们都是 32 位 Windows 中使用的调用约定,它们以相反的顺序(从右到左)在堆栈上传递参数。x64 已移至 FastCall 调用约定,其中参数按正向传递(从左到右),前 4 个参数在寄存器 RCX、RDX、R8 和 R9 中传递。任何超过 4 的参数都以相同的从左到右的顺序传递到堆栈上。原始海报具有使用 MASM 的 x64 程序集的正确调用约定设置。此外,上述响应者说从 RSP 中减去的阴影空间值应该是 20h (32d) 是正确的。影子空间允许堆栈上的空间用于 FastCall 中的寄存器传入的 4 个参数。

将上面的代码更改为:

extrn ExitProcess: PROC   
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code

Start PROC
  sub    rsp, 20h        
  mov    rcx, 0         ; hWnd = HWND_DESKTOP
  lea    rdx, message   ; LPCSTR lpText
  lea    r8,  caption   ; LPCSTR lpCaption
  mov    r9d, 0         ; uType = MB_OK

  push   0          ; wLanguageId

  call   MessageBoxExA  
  mov    ecx, eax       
  add    rsp, 20h
  call ExitProcess
Start ENDP
End

在 64 位机器上的 Visual Studio 中工作得很好

于 2014-11-11T06:17:13.007 回答
0

我的程序集有点生锈,但我的印象是所有参数都进入了堆栈(以相反的顺序) - 我原以为你想将 r8 和 rdx 以及其他参数推入。坦率地说,尽管您最好继续为每个作为指针的参数做lea rax, param和。push rax

于 2013-05-02T11:02:07.010 回答