"registers are preserved across function calls" 是什么意思?
What does it mean that "registers are preserved across function calls"?
根据这个问题,What registers are preserved through a linux x86-64 function call,它说以下寄存器在函数调用中保存:
r12, r13, r14, r15, rbx, rsp, rbp
因此,我继续进行以下测试:
.globl _start
_start:
mov , %r12
mov , %r13
mov , %r14
mov , %r15
call get_array_size
mov , %eax
syscall
get_array_size:
mov [=12=], %r12
mov [=12=], %r13
mov [=12=], %r14
mov [=12=], %r15
ret
而且,我在想,在 call get_array_size
之后,我的寄存器会自动(并且有点神奇地)恢复为值 5
。 gdb
表明这是不正确的。
但我认为我可能误解了这一点。我想这只是意味着任何“符合 x86-64 ABI”的函数都应该在完成后恢复这些寄存器(换句话说,我的 get_array_size
函数在 linux ABI),或者有人可以向我解释我在理解中似乎遗漏了什么。
此外,当有人说一个函数应该符合 ABI
时,非全局函数也应该这样做吗?还是 'internal-implementations' 根本不重要,只有我向 public(通过 globl
)公开的函数应该遵守它?是否有通常用于表示函数是局部函数还是全局函数的符号(例如在命名方案中?)。
当然,我是 asm
的初学者,非常感谢您解释我可能遗漏的内容。
正确,您的 hand-written asm get_array_size
不遵循 ABI,因为它破坏了 call-preserved 寄存器。这意味着它的调用者需要特殊对待它,而不是遵循通常的 ABI 保证。
ABI 文档是 compiler-generated 函数遵循的标准,大多数 hand-written 函数也应该遵循,除非您想制定自己的自定义调用约定。有关 call-preserved 与 call-clobbered 对调用者的意义以及函数本身的实现(如果它想要遵循 ABI)的更多详细信息,请参阅 What are callee and caller saved registers?。
具有自定义调用约定的小型私有“帮助程序”函数很好,只要您对它们进行注释(并且永远不要尝试从 C 调用它们)。特别是当你在优化时,例如代码大小(参见 codegolf x86-64 tips)
asm 中没有魔法,每条指令仅对架构状态有其记录的影响。(寄存器和内存的内容)。
正如您从 Intel 的 call
and ret
文档中看到的那样,他们修改的唯一整数寄存器是 RSP。 NASM 和 GAS 等普通汇编程序不会神奇地向您的函数添加指令。 (MASM 可能有所不同,但如果您查看反汇编,您仍然可以看到真正的代码。)
根据这个问题,What registers are preserved through a linux x86-64 function call,它说以下寄存器在函数调用中保存:
r12, r13, r14, r15, rbx, rsp, rbp
因此,我继续进行以下测试:
.globl _start
_start:
mov , %r12
mov , %r13
mov , %r14
mov , %r15
call get_array_size
mov , %eax
syscall
get_array_size:
mov [=12=], %r12
mov [=12=], %r13
mov [=12=], %r14
mov [=12=], %r15
ret
而且,我在想,在 call get_array_size
之后,我的寄存器会自动(并且有点神奇地)恢复为值 5
。 gdb
表明这是不正确的。
但我认为我可能误解了这一点。我想这只是意味着任何“符合 x86-64 ABI”的函数都应该在完成后恢复这些寄存器(换句话说,我的 get_array_size
函数在 linux ABI),或者有人可以向我解释我在理解中似乎遗漏了什么。
此外,当有人说一个函数应该符合 ABI
时,非全局函数也应该这样做吗?还是 'internal-implementations' 根本不重要,只有我向 public(通过 globl
)公开的函数应该遵守它?是否有通常用于表示函数是局部函数还是全局函数的符号(例如在命名方案中?)。
当然,我是 asm
的初学者,非常感谢您解释我可能遗漏的内容。
正确,您的 hand-written asm get_array_size
不遵循 ABI,因为它破坏了 call-preserved 寄存器。这意味着它的调用者需要特殊对待它,而不是遵循通常的 ABI 保证。
ABI 文档是 compiler-generated 函数遵循的标准,大多数 hand-written 函数也应该遵循,除非您想制定自己的自定义调用约定。有关 call-preserved 与 call-clobbered 对调用者的意义以及函数本身的实现(如果它想要遵循 ABI)的更多详细信息,请参阅 What are callee and caller saved registers?。
具有自定义调用约定的小型私有“帮助程序”函数很好,只要您对它们进行注释(并且永远不要尝试从 C 调用它们)。特别是当你在优化时,例如代码大小(参见 codegolf x86-64 tips)
asm 中没有魔法,每条指令仅对架构状态有其记录的影响。(寄存器和内存的内容)。
正如您从 Intel 的 call
and ret
文档中看到的那样,他们修改的唯一整数寄存器是 RSP。 NASM 和 GAS 等普通汇编程序不会神奇地向您的函数添加指令。 (MASM 可能有所不同,但如果您查看反汇编,您仍然可以看到真正的代码。)