为什么要"mov rcx,rax"在x64汇编器中调用printf时需要什么? [英] Why "mov rcx, rax" is required when calling printf in x64 assembler?

查看:866
本文介绍了为什么要"mov rcx,rax"在x64汇编器中调用printf时需要什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习x64汇编程序.我编写了"hello world",并尝试使用以下代码调用printf:

I am trying to learn x64 assembler. I wrote "hello world" and tried to call printf using the following code:

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"行,该行修复了所有问题,但是 WHY 我需要将RAX移至RCX吗???显然,我缺少一些基本知识.

At the beginning I called printf without "mov rcx, rax", which ended up with access violation. Getting all frustrated I just wrote in C++ a call to printf and looked in the disassembler. There I saw the line "mov rcx, rax" which fixed everything, but WHY do I need to move RAX to RCX ??? Clearly I am missing something fundamental.

感谢您的帮助!

p.s.好的x64汇编程序教程的参考不受欢迎:-)找不到.

p.s. a reference to good x64 assembler tutorial is more than welcome :-) couldn't find one.

推荐答案

这不是必需的,该代码只是通过在RAX中执行lea然后复制到RCX来浪费指令.什么时候可以做

It isn't required, this code just wastes an instruction by doing an lea into RAX and then copying to RCX, when it could do

lea   rcx, hello_msg
call  printf              ; printf(rcx, rdx, r8, r9, stack...)

在64位Windows上,

printf忽略RAX作为输入; RAX是 Windows x64调用约定(也可以通过void函数破坏).前四个参数进入RCX,RDX,R8和R9(如果它们是整数/指针,如此处所示).

printf on 64-bit Windows ignores RAX as an input; RAX is the return-value register in the Windows x64 calling convention (and can also be clobbered by void functions). The first 4 args go in RCX, RDX, R8, and R9 (if they're integer/pointer like here).

还请注意,必须将xmm0..3中的FP args镜像到诸如printf(

Also note that FP args in xmm0..3 have to be mirrored to the corresponding integer register for variadic functions like printf (MS's docs), but for integer args it's not required to movq xmm0, rcx.

在x86-64 System V调用约定中,可变参数函数希望al =在寄存器中传递的FP args的数量. (因此,您可以xor eax,eax将其清零).但是x64 Windows约定不需要它.它经过了优化,使可变参数函数易于实现(而不是为了获得更高的性能/为正常函数提供更多的寄存器参数).

In the x86-64 System V calling convention, variadic functions want al = the number of FP args passed in registers. (So you'd xor eax,eax to zero it). But the x64 Windows convention doesn't need that; it's optimized to make variadic functions easy to implement (instead of for higher performance / more register args for normal functions).

一些32位调用约定在EAX中传递了arg,例如Irvine32或gcc -m32 -mregparm=1.但是没有标准的x86-64调用约定.您可以使用自己编写的私有asm函数执行任何操作,但是在调用库函数时必须遵循标准的调用约定.

A few 32-bit calling conventions pass an arg in EAX, for example Irvine32, or gcc -m32 -mregparm=1. But no standard x86-64 calling conventions do. You can do whatever you like with private asm functions you write, but you have to follow the standard calling conventions when calling library functions.

还请注意,lea rax, offset hello_msg很奇怪; LEA使用内存操作数语法和机器编码(并为您提供地址而不是数据). offset hello_msg是立即数,而不是内存操作数.但是在这种情况下,MASM仍将其作为内存操作数来接受.

Also note that lea rax, offset hello_msg was weird; LEA uses memory-operand syntax and machine encoding (and gives you the address instead of the data). offset hello_msg is an immediate, not a memory operand. But MASM accepts it as a memory operand anyway in this context.

您可以在与位置相关的代码中使用mov ecx, offset hello_msg,否则,您需要RIP相对的LEA.我不确定MASM的语法.

You could use mov ecx, offset hello_msg in position-dependent code, otherwise you want a RIP-relative LEA. I'm not sure of the MASM syntax for that.

这篇关于为什么要"mov rcx,rax"在x64汇编器中调用printf时需要什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆