【发布时间】:2021-01-05 18:42:48
【问题描述】:
从这个问题What registers are preserved 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 之后,我的寄存器会自动(并且有点神奇地)恢复为值5。 gdb 表明这是不正确的。
但我认为我可能误解了这一点。我想这只是意味着“符合 x86-64 ABI”的任何函数都应该在完成后恢复这些寄存器(换句话说,我的 get_array_size 函数在 linux ABI 中是无效的函数),或者可以有人向我解释我的理解中似乎缺少什么。
此外,当有人说函数应该符合ABI 时,非全局函数也应该这样做吗?或者“内部实现”根本不重要,只有我向公众公开的功能(通过globl)应该遵守它?是否有一种通常用来表示函数是局部函数还是全局函数的符号(例如在命名方案中?)。
当然,我是asm 的初学者,非常感谢您解释我可能遗漏的内容。
【问题讨论】:
-
正确,您的手写 asm
get_array_size不遵循 ABI,因为它破坏了调用保留寄存器。这意味着它的调用者需要特别对待它,而不是遵循通常的 ABI 保证。 asm 没有魔法,每条指令只对架构状态有其记录的影响。 -
@PeterCordes 我明白了——所以它更像是一种约定,而不是“由处理器完成”的事情。当您调用 linux x86-64 函数时,它“遵循此约定”。这是更好的理解吗?
-
@samuelbrody1249 完全正确。因此,ABI 通常被称为“调用约定”。您不必为自己的代码遵循它,但如果您不这样做,编译器将无法正确调用您的函数。
-
换句话说,它们被保留在对已编写为符合 ABI 的函数的调用中。
-
永远记住,虽然我们碰巧有像 gcc 这样的工具所遵循的目标定义(ARM、intel 等)调用约定,但真正选择的是编译器作者,所以不要假设任何编译器都符合该特定编译器的语句。同样,从 asm 调用的库,它们是用/为什么构建的。
标签: assembly x86 x86-64 calling-convention abi