我正在尝试学习x64汇编程序。我写了“hello world”并尝试使用以下代码调用printf:
CatWebServiceApplication
一开始我在没有“mov rcx,rax”的情况下调用printf,最终导致访问冲突。让所有人感到沮丧我只是用C ++编写了一个对printf的调用并查看了反汇编程序。在那里,我看到“mov rcx,rax”这一行修复了所有内容,但为什么我需要将RAX移动到RCX ???显然,我遗漏了一些基本的东西。
感谢您的帮助!
P.S。对于优秀的x64汇编程序教程的参考非常受欢迎:-)找不到一个。
答案 0 :(得分:2)
这不是必需的,这段代码只是浪费了一条指令,只需要lea
进入RAX,然后复制到RCX就可以了
lea rcx, hello_msg
call printf ; printf(rcx, rdx, r8, r9, stack...)
64位Windows上的 printf
忽略RAX作为输入; RAX是the Windows x64 calling convention中的返回值寄存器(也可能被void
函数破坏)。前4个参数进入RCX,RDX,R8和R9(如果它们是像这里的整数/指针那样)。
另请注意,xmm0..3中的FP args必须镜像到printf
(MS's docs)等可变函数的相应整数寄存器,但对于整数args,{{1}不需要}}
在x86-64 System V调用约定中,可变参数函数需要movq xmm0, rcx
=寄存器中传递的FP args的数量。 (所以你要al
将它归零)。但是x64 Windows约定并不需要这样;它经过优化,可以使变量函数易于实现(而不是用于普通函数的更高性能/更多寄存器参数)。
一些32位调用约定在EAX中传递一个arg,例如Irvine32或xor eax,eax
。但是没有标准的x86-64调用约定。您可以使用您编写的私有asm函数执行任何操作,但在调用库函数时必须遵循标准调用约定。
另请注意,gcc -m32 -mregparm=1
很奇怪; LEA使用内存操作数语法和机器编码(并为您提供地址而不是数据)。 lea rax, offset hello_msg
是立即操作数,而不是内存操作数。但是MASM在这种情况下接受它作为内存操作数。
您可以在位置相关的代码中使用offset hello_msg
,否则您需要与RIP相关的LEA。我不确定MASM的语法。
答案 1 :(得分:1)
Windows 64-bit (x64/AMD64) calling convention在RCX,RDX,R8和R9中传递the first four integer arguments。
返回值存储在RAX中并且是易失性的,因此允许C / C ++编译器将其用作函数中的通用存储。