【问题标题】:Push an argument into stack?将参数推入堆栈?
【发布时间】:2013-05-02 10:43:15
【问题描述】:

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

问题:

如何将参数压入堆栈?我尝试使用 (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 更相关,而这不是。

【问题讨论】:

  • 我认为你从 rsp 中减去了太多。请改用sub rsp, 20h。原因是调用者需要在堆栈上为 4 个寄存器 (rcx,rdx,r8,r9) 分配“寄存器主(或溢出)空间”,即 4 * 8 = 0n32 = 0x20。第 5 个(以及随后的 args)出现在这个空间之后,所以这就是为什么我建议从 rsp 中减去 0x20 字节而不是 0x38。
  • Windows ABI 不允许堆栈指针在函数执行期间更改(至少在不做额外工作的情况下不会更改),并且您要更改它两次(一次是推送,一次是外部添加结语),您的函数缺少正确的序言声明,并且您将第五个参数放在堆栈中的错误位置。我认为最简单的解决方案是只用 C 编写程序,然后查看编译器生成的内容。
  • 你需要小心所谓的影子空间。我在一个简单的 Windows 应用程序中实现了两个子例程。一个用于 MessageBoxA,另一个用于 ShellAboutA.(对话框)。虽然我到处读到两者都需要 20 小时的阴影空间,但 MessageBox 需要 28 小时的阴影空间。看起来很正常,因为 rcx、rdx、r8 和 r9 的 4x8 字节加上堆栈上调用者的额外返回地址。我对 ShellAbout 使用了相同的逻辑。返回地址也是 4 x 8 + 8,应用程序的那部分崩溃。它只需要 4 x 8 字节的影子空间。多也少是好的。

标签: windows assembly x86-64 masm


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    您可能想到的是 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 中运行良好

    【讨论】:

    • 试试 ShellAbout。 4个寄存器。把它放在一个子程序中,你会发现它会按照你的方式工作。在子例程中使用 MessageBoxA,我的应用程序崩溃。我想知道为什么。也许来自微软的不一致编码?我还在寻找
    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2018-03-27
    相关资源
    最近更新 更多