Windows 为什么在x64汇编程序中调用printf时需要“mov rcx,rax”?
我正在努力学习x64汇编程序。我编写了hello world并尝试使用以下代码调用printf:Windows 为什么在x64汇编程序中调用printf时需要“mov rcx,rax”?,windows,assembly,x86-64,calling-convention,Windows,Assembly,X86 64,Calling Convention,我正在努力学习x64汇编程序。我编写了hello world并尝试使用以下代码调用printf: EXTERN printf: PROC PUBLIC hello_world_asm .data hello_msg db "Hello world", 0 .code hello_world_asm PROC push rbp ; save frame pointer mov rbp, rsp ; fix stack pointer sub rsp, 8 * (4 + 2) ; shado
EXTERN printf: PROC
PUBLIC hello_world_asm
.data
hello_msg db "Hello world", 0
.code
hello_world_asm PROC
push rbp ; save frame pointer
mov rbp, rsp ; fix stack pointer
sub rsp, 8 * (4 + 2) ; shadow space (32bytes)
lea rax, offset hello_msg
mov rcx, rax ; <---- QUESTION ABOUT THIS LINE
call printf
; epilog. restore stack pointer
mov rsp, rbp
pop rbp
ret
hello_world_asm ENDP
END
起初,我在没有mov rcx、rax的情况下调用printf,最终导致访问冲突。让我感到沮丧的是,我刚刚用C++写了一个调用PrtTf,然后在反汇编程序中查看。在那里我看到了mov rcx,rax这条线,它修复了一切,但是为什么我需要将rax移动到rcx???很明显,我遗漏了一些基本的东西
谢谢你的帮助
p、 欢迎参考优秀的x64汇编程序教程:-找不到。RCX、RDX、R8和R9中的过程
返回值存储在RAX中,且不稳定,因此允许C/C++编译器将其用作函数中的通用存储。这不是必需的,这段代码只是浪费了一条指令,将lea写入RAX,然后在可能的情况下复制到RCX
lea rcx, hello_msg
call printf ; printf(rcx, rdx, r8, r9, stack...)
64位Windows上的printf忽略RAX作为输入;RAX是中的返回值寄存器,也可以被void函数删除。前4个参数是RCX、RDX、R8和R9,如果它们是像这里这样的整数/指针
还要注意,xmm0..3中的FP args必须镜像到可变函数(如printf)的相应整数寄存器,但对于整数args,不需要movq xmm0,rcx
在x86-64 System V调用约定中,可变函数希望al=传入寄存器的FP arg数。所以你要对eax,eax进行异或,使其为零。但x64 Windows约定不需要这样做;它经过优化,使可变函数易于实现,而不是用于普通函数的更高性能/更多寄存器参数
一些32位调用约定在EAX中传递参数,例如Irvine32或gcc-m32-mregparm=1。但没有标准的x86-64调用约定可以做到这一点。您可以使用自己编写的私有asm函数执行任何操作,但在调用库函数时必须遵循标准的调用约定
还要注意的是lea rax,offset hello_msg很奇怪;LEA使用内存操作数语法和机器编码,并提供地址而不是数据。偏移量hello_msg是立即数,而不是内存操作数。但在这种情况下,MASM接受它作为内存操作数
您可以在位置相关代码中使用mov ecx、offset hello_msg,否则您需要一个RIP相对LEA。我不确定MASM的语法是什么。rax是不稳定的。printf使用rcx来加载字符串,所以在我的理解中,这只是调用约定的错误。非常好的解释,因为x64 printf的第一个参数在rcx中,而不是在rax中。有关文档和教程的链接,请参阅。由于您使用的是Windows,这可能是一个好方法。与问题无关,但在我看来,您可以使用lea将offset hello_msg加载到RCX中,而不是将RAX用作中间步骤。lea RAX,偏移量hello_msg会在我使用过的每个版本的MASM和TASM上组装,这可以追溯到80年代,当然是16位地址。MASM对括号的使用是可选的,因此它与lea-rax[offset-hello\u-msg]相同,并且偏移量被有效地丢弃,因此相当于lea-rax[hello\u-msg]