是否有不同 x86_64 操作和 C std lib 函数使用的寄存器列表?

3 assembly x86-64 nasm calling-convention

我开始在 ubuntu linux 上使用 NASM 汇编器学习 x86_64 汇编编程。我遇到的问题之一是弄清楚操作神奇地使用了哪些寄存器。

我正在阅读的书有这样的代码示例:

mov    rdi, fmt1
mov    rsi, strng
mov    rax, 0
call   printf

; How am I supposed to know which registers are used by the call to printf? 
; The libc printf function supports an arbitrary number of parameters. 
; Clearly there aren't an unlimited number of registers in x86_64 so how does this work
; as the parameter list grows?
Run Code Online (Sandbox Code Playgroud)

代码示例的另一部分是这样的:

xor    rax, rax
mov    rbx, strng
mov    rcx, strLen
mov    r12, 0
pushLoop:
    mov    al, byte[rbx + r12]
    push   rax
    inc    r12
    loop   pushLoop
; It took me a few seconds to find out where the exit condition is. I realized that
; rcx is being compared to r12 in some way, but I'm not sure how. Is it explained anywhere?
Run Code Online (Sandbox Code Playgroud)

我不确定我应该在哪里寻找我的第一个问题的答案。我的预感是我的第二个问题的答案在 NASM 文档中的某个地方,但我不确定在哪里可以找到它。我试图将这些结构与我在高级语言中所知道的联系起来,但我很挣扎。

谢谢!

Pet*_*des 5

第一部分:所有库函数都遵循标准调用约定。在除 Windows 之外的所有 x86-64 平台上,这是 x86-64 System V ABI。

在编写自己的 asm 函数时,您可以制定自己的约定,例如在多个寄存器中返回多个不同的值,而不是将自己限制为只能让 C 编译器执行的操作。

(例如,您可以编写一个memcmp返回 RDI 中第一个差异的位置和 FLAGS 中实际 < = 或 > 的位置,例如从不cmp匹配的字节上执行 a 。)

但是您可以从 asm 调用的编译器生成的函数(包括 C 标准库函数)将始终遵循 ABI。


第二部分:某些指令隐式使用寄存器:查看ISA手册以获取相关指令。如果您不知道,请不要仅从名称中进行假设。

您可以单步调试一个突出显示寄存器值更改的调试器,以帮助您注意到任何您根本没有预料到的寄存器更改的情况。

在 Intel 的 vol.2 手册(或 AMD 的等效手册)中查找说明。例如英特尔在https://www.felixcloutier.com/x86/ 上的 PDF 的 HTML 摘录 ,特别是loop. 另外x86 LOOP 指令究竟是如何工作的?解释说它就像一个dec rcx / jnz没有设置 FLAGS的except。

没有那么多带有隐式操作数的指令。最常用的是堆栈指令,如以明显的方式隐式使用 RSP 的 push/pop。

其他值得注意的包括 E/RAX 和 E/RDX 被单操作数[i]mul和 使用[i]div。(cdq并将 EAX 符号扩展到 EDX:EAX 以设置 idiv,或cdqe到 RAX)

用于可变移位计数的 CL 隐含在机器代码中,但在 asm 源代码中是显式的(如shr rdx, cl)。

rep-"string" 指令隐式使用 RCX,加上 RSI 和/或 RDI。

大多数这些隐含用途来自旧的 8086 历史。请参阅为什么没有包含 EAX 高字节的寄存器?. 编译器不使用likeloopjrcxznot指令,因为它们很慢,并且当您不需要 EDX/RDX 中的高半结果时,imullike的 2 操作数形式imul ecx, edx更快。

进一步阅读:

这不是一个详尽的清单。cmpxchg / cmpxchg16b、xlat、cpuid、rdtsc、rdpmc 和许多其他指令都有隐式操作数,但只有少数编译器经常使用的指令可以。

请注意, FLAGS 是许多指令的隐式输入,例如adccmov


NASM 有一个附录列出了所有指令,但通常汇编程序将其留给 CPU 供应商。所有 x86-64 汇编器都为相同的指令生成机器代码。该文档旧版本的这个错误修复分支保留了英文说明说明。(在添加 SSE 指令后,主线 NASM 删除了它以节省空间;如今,对于 AVX2,尤其是 AVX512,除了在一个平面页面中列出之外,要做的事情太多了。)


归档时间:

查看次数:

452 次

最近记录:

5 年,9 月 前