繁体   English   中英

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

[英]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必须镜像到对应的整数寄存器,以实现诸如printfMS'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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM