Assembly “跨函数调用保留寄存器”是什么意思?

Assembly “跨函数调用保留寄存器”是什么意思?,assembly,x86,x86-64,calling-convention,abi,Assembly,X86,X86 64,Calling Convention,Abi,在这个问题中,它表示以下寄存器跨函数调用保存: 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, %r1

在这个问题中,它表示以下寄存器跨函数调用保存:

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
我在想,在调用get_array_size之后,我的寄存器会自动地、有点神奇地恢复为值5。gdb表明这是不正确的

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

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


当然,我是asm的初学者,因此非常感谢您解释我可能缺少的内容。

正确,您手写的asm get\u array\u大小不符合ABI,因为它会破坏保留调用寄存器。这意味着它的呼叫者需要特别对待它,而不是遵循通常的ABI保证

ABI文档是编译器生成的函数所遵循的标准,因此大多数手工编写的函数都应该遵循ABI文档,除非您想建立自己的自定义调用约定。有关call preserved与call clobbered对调用方意味着什么的更多详细信息,以及函数本身的实现(如果它希望遵循ABI)

具有自定义调用约定的小型私人助手函数是可以使用的,只要您对它们进行注释,并且从不尝试从C调用它们。尤其是在您进行优化时,例如,有关代码大小,请参阅

asm中没有魔力,每一条指令只对体系结构状态有记录在案的影响。寄存器和内存的内容


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

正确,您手工编写的asm get\u array\u大小不符合ABI,因为它正在删除保留调用的寄存器。这意味着它的呼叫者需要特别对待它,而不是遵循通常的ABI保证

ABI文档是编译器生成的函数所遵循的标准,因此大多数手工编写的函数都应该遵循ABI文档,除非您想建立自己的自定义调用约定。有关call preserved与call clobbered对调用方意味着什么的更多详细信息,以及函数本身的实现(如果它希望遵循ABI)

具有自定义调用约定的小型私人助手函数是可以使用的,只要您对它们进行注释,并且从不尝试从C调用它们。尤其是在您进行优化时,例如,有关代码大小,请参阅

asm中没有魔力,每一条指令只对体系结构状态有记录在案的影响。寄存器和内存的内容


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

正确,您手工编写的asm get_array_大小不符合ABI,因为它会破坏保留的调用寄存器。这意味着它的呼叫者需要特别对待它,而不是遵循通常的ABI保证。asm中没有魔力,每一条指令只对体系结构状态有记录在案的影响。@PeterCordes我明白了-所以它更多的是一种约定,而不是“由处理器完成”的事情。当您调用linux x86-64函数时,它“遵循此约定”。这是更好的理解吗?@samuelbrody1249完全正确。因此,ABI通常被称为“调用约定”。您不必为自己的代码遵循它,但如果不这样做,编译器将无法正确调用您的函数。换句话说,它们被保存在对函数的调用中,这些函数是为了符合ABI而编写的。请始终记住,虽然我们碰巧有目标定义的ARM、intel等调用约定,而gcc等工具也遵循这些约定,但真正的选择是编译器作者,因此,如果没有特定编译器的语句,不要假设任何编译器都符合。同样,从asm调用的库,它们是用/for构建的。正确,您手工编写的asm get_array_大小不遵循ABI,因为它会破坏调用保留寄存器。这意味着它的用户需要特别对待它,而不是追随美国
ual ABI担保。asm中没有魔力,每一条指令只对体系结构状态有记录在案的影响。@PeterCordes我明白了-所以它更多的是一种约定,而不是“由处理器完成”的事情。当您调用linux x86-64函数时,它“遵循此约定”。这是更好的理解吗?@samuelbrody1249完全正确。因此,ABI通常被称为“调用约定”。您不必为自己的代码遵循它,但如果不这样做,编译器将无法正确调用您的函数。换句话说,它们被保存在对函数的调用中,这些函数是为了符合ABI而编写的。请始终记住,虽然我们碰巧有目标定义的ARM、intel等调用约定,而gcc等工具也遵循这些约定,但真正的选择是编译器作者,因此,如果没有特定编译器的语句,不要假设任何编译器都符合。同样,从asm调用的库,它们是用/为什么构建的。