Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 为什么在x64汇编程序中调用printf时需要“mov rcx,rax”?_Windows_Assembly_X86 64_Calling Convention - Fatal编程技术网

Windows 为什么在x64汇编程序中调用printf时需要“mov rcx,rax”?

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

我正在努力学习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) ; 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]