混合使用 C++ 和程序集无法将多个参数从 C++ 函数传递给程序集

Mixing c++ and assembly cant pass multiple paramaters from C++ function to assembly

我一直对将参数从 C++ 函数传递到程序集感到沮丧。我找不到任何对 Google 有帮助的东西,真的很想得到你的帮助。我正在使用 Visual Studio 2017 和 masm 来编译我的汇编代码。

这是我的 c++ 文件的简化版本,我在其中调用了汇编程序 set_clock

int main()
{
    TimeInfo localTime;
    char clock[4] = { 0,0,0,0 };
    set_clock(clock,&localTime); 
    system("pause");
    return 0;
}

我运行在汇编文件中遇到问题。我不明白为什么传递给函数的第二个参数变得很大。我正在离开我的教科书,它显示了带有 PROC 后跟参数的类似代码。我不知道为什么第一个参数传递成功而第二个参数传递不成功。谁能告诉我传递多个参数的正确方法?

.code
set_clock PROC, 
    array:qword,address:qword
    mov rdx,array   ; works fine memory address: 0x1052440000616
    mov rdi,address ; value of rdi is 14757395258967641292
    mov al, [rdx] 
    mov [rdi],al    ; ERROR: cant access that memory location
    ret
set_clock ENDP
END

MASM 的高级废话正在咬你的屁股。 x64 Windows 在 rcxrdxr8r9 中传递前 4 个参数(对于其中任何一个4 个 integer/pointer).

mov rdx,array
mov rdi,address

组装成

mov  rdx, rcx    ; clobber 2nd arg with a copy of the 1st
mov  rdi, rdx    ; copy array again

自己用反汇编器检查一下。如果汇编程序宏发生任何奇怪的事情,通过反汇编或使用调试器反汇编而不是源模式来检查真实机器代码总是一个好主意。


我不确定为什么这会导致无法访问内存位置。如果两个 args 确实是指向局部变量的指针,那么它应该只是加载并存储回相同的堆栈位置。但是,如果 char clock[4] 是静态存储中的 const,它可能位于只读内存页面中,这将解释存储失败。

无论哪种方式,使用调试器找出答案。


顺便说一句,rdi 是 x64 Windows 约定中的调用保留(也称为非易失性)寄存器。 (https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx). Use call-clobbered registers for scratch regs unless you run out and need to save/restore some call-preserved regs. See also Agner Fog's calling conventions doc (http://agner.org/optimize/), and other links in the x86 tag wiki.

它在 x86-64 系统 V 中被调用破坏,它还在不同的寄存器中传递参数。也许你在看一个不同的例子?


希望修复版本,使用 movzx 以避免加载字节时对 RAX 的错误依赖。

set_clock PROC, 
    array:qword,address:qword
    movzx    eax, byte ptr [array] 
    mov      [address], al
    ret
set_clock ENDP

我不使用 MASM,但我认为 array:qword 使 array 成为 rcx 的别名。或者您可以跳过声明参数,直接使用 rcxrdx,并用注释记录下来。这样大家就更容易理解了。

您绝对不希望无用的 mov reg,reg 指令使您的代码混乱;如果您首先使用 asm 编写,浪费的指令会减少您获得的任何加速。