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

标签 c++ assembly x86-64 masm

我一直对将参数从 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 个整数/指针中的任何一个)。

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 约定中的调用保留(也称为非 volatile )寄存器。 (https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx)。除非您用完并需要保存/恢复一些调用保留的寄存器,否则请将调用破坏的寄存器用于暂存寄存器。另请参阅 Agner Fog 的调用约定文档 ( http://agner.org/optimize/ ),以及 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 编写代码,那么浪费的指令会影响您获得的任何加速。

关于c++ - 混合使用 C++ 和程序集无法将多个参数从 C++ 函数传递给程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50501291/

相关文章:

c++ - 函数模板和 "normal"函数奇怪的不一致

linux - ASM printf : no output if string doesn't include\n newline

visual-c++ - 使用 Visual C++ Express 2010 64 位编译程序集

c++ - 具有非原子大小项目的无锁双端队列

c++ - 编译和链接错误

c++ - g++ 在 ‘(’ token 之前预期不合格 ID

c++ - 试图用我对 CPP 中构造函数的理解来理解

winapi - 如何在64位Windows Assembly中使用 "GS:"(例如,移植TLS代码)

c - 强制 2 函数对齐的幂 s.t 对齐 % 其他值 == 对齐

assembly - 将 Rust 数组的指针传递到 x86-64 Asm 中——指针减一