首页 > 解决方案 > “在函数调用中保留寄存器”是什么意思?

问题描述

从这个问题, What registers are reserved through a linux x86-64 function call,它说以下寄存器在函数调用中保存:

r12, r13, r14, r15, rbx, rsp, rbp

因此,我继续进行了以下测试:

.globl _start
_start:
    mov $5, %r12
    mov $5, %r13
    mov $5, %r14
    mov $5, %r15
    call get_array_size
    mov $60, %eax
    syscall

get_array_size:
    mov $0, %r12
    mov $0, %r13
    mov $0, %r14
    mov $0, %r15
    ret

而且,我在想​​,在那之后call get_array_size,我的寄存器会自动(并且有点神奇地)恢复为 values 5gdb表明这是不正确的。

但我想我可能误解了这一点。我想这只是意味着“符合 x86-64 ABI”的任何函数都应该在完成后恢复这些寄存器(换句话说,我的get_array_size函数是 linux ABI 中的无效函数),或者有人可以解释一下我在我的理解中似乎缺少什么。

此外,当有人说函数应该符合 时ABI,非全局函数也应该这样做吗?或者“内部实现”根本不重要,只有我向公众公开的功能(通过globl)应该遵守它?是否有一种通常用于表示函数是局部函数还是全局函数的符号(例如在命名方案中?)。

当然,我是初学者,asm非常感谢您解释我可能遗漏的内容。

标签: assemblyx86x86-64calling-conventionabi

解决方案


正确,您的手写 asmget_array_size不遵循 ABI,因为它正在破坏调用保留寄存器。这意味着它的调用者需要特别对待它,而不是遵循通常的 ABI 保证。

ABI 文档是编译器生成的函数遵循的标准,大多数手写函数也应遵循该标准,除非您想制定自己的自定义调用约定。请参阅什么是被调用者和调用者保存的寄存器?有关调用保留与调用破坏对调用者意味着什么的更多详细信息,以及函数本身的实现(如果它想遵循 ABI)。

只要您对它们进行注释(并且永远不要尝试从 C 调用它们),具有自定义调用约定的小型私有“帮助器”函数就可以了。尤其是在优化时,例如代码大小(请参阅codegolf x86-64 提示


asm 没有魔法,每条指令只对架构状态有其记录的影响。 (寄存器和内存的内容)。

正如您从英特尔的文档中看到的那样callret他们修改的唯一整数寄存器是 RSP。像 NASM 和 GAS 这样的普通汇编程序不会神奇地向您的函数添加指令。(MASM 可以不同,但​​是如果你看反汇编你仍然可以看到真正的代码。)


推荐阅读