[英]Why “mov rcx, rax” is required when calling printf in x64 assembler?
我正在尝试学习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
一开始,我调用printf时没有“ mov rcx,rax”,最终导致访问冲突。 让一切沮丧的是,我刚刚用C ++编写了对printf的调用,并在反汇编程序中进行了研究。 在那里,我看到了“ mov rcx,rax”行,它固定了所有内容,但是为什么我需要将RAX移至RCX? 显然,我缺少基本的东西。
谢谢你的帮助!
ps很好的参考x64汇编程序教程非常受欢迎:-)找不到一个。
这不是必需的,此代码只是浪费了一条指令 ,方法是先对RAX执行一次lea
,然后将其复制到RCX,
lea rcx, hello_msg
call printf ; printf(rcx, rdx, r8, r9, stack...)
在64位Windows上的printf
忽略RAX作为输入 ; RAX是Windows x64调用约定中的返回值寄存器(也可以由void
函数破坏)。 前四个args进入RCX,RDX,R8和R9(如果它们是整数/指针,如此处所示)。
还要注意,xmm0..3中的FP args必须镜像到对应的整数寄存器,以实现诸如printf
( MS's docs )之类的可变函数,但是对于整数args,则不需要movq xmm0, rcx
。
在x86-64 System V调用约定中,可变参数函数希望al
=在寄存器中传递的FP args的数量。 (因此,您需要对xor eax,eax
进行xor eax,eax
将其清零)。 但是x64 Windows约定不需要它。 它进行了优化,以使可变参数函数易于实现(而不是为了获得更高的性能/正常函数需要更多的寄存器参数)。
一些32位调用约定在EAX中传递了arg,例如Irvine32或gcc -m32 -mregparm=1
。 但是没有标准的x86-64调用约定。 您可以使用自己编写的私有asm函数执行任何操作,但是在调用库函数时必须遵循标准的调用约定。
另请注意, lea rax, offset hello_msg
很奇怪; LEA使用内存操作数语法和机器编码(并为您提供地址而不是数据)。 offset hello_msg
是立即数,不是内存操作数。 但是在这种情况下,MASM仍将其作为内存操作数来接受。
您可以在与位置相关的代码中使用mov ecx, offset hello_msg
,否则您需要相对RIP的LEA。 我不确定MASM语法。
Windows 64位(x64 / AMD64)调用约定在RCX,RDX,R8和R9中传递前四个整数参数 。
返回值存储在RAX中,并且它是易失性的,因此允许C / C ++编译器将其用作函数中的常规存储。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.