代码之家  ›  专栏  ›  技术社区  ›  richq luc

在ARM C调用约定中要保存哪些寄存器?

  •  47
  • richq luc  · 技术社区  · 16 年前

    如果C函数使用任何其他寄存器,它是否负责保存堆栈上的寄存器并恢复它们?换句话说,编译器将为C函数生成这样做的代码。

    这是针对arm eabi gcc 4.3.0的。

    5 回复  |  直到 5 年前
        1
  •  80
  •   Peter Cordes    5 年前

    这取决于天气 ABI here on ARM's infocenter .

    the AAPCS, §5.1.1 :

    • r0-r3 是参数寄存器和暂存器寄存器; 也是结果寄存器
    • 被调用方是否保存寄存器
    • r9
    • r10-r11 被调用方是否保存寄存器

    如果

    您使用的编译器没有区别;特别是gcc可以为几个不同的ABI进行配置,甚至可以在命令行上进行更改。查看它生成的序言/尾声代码并没有多大用处,因为它是为每个函数定制的


    What are callee and caller saved registers?
    在进行函数调用时,您可以假设r4-r11(可能r9除外)中的值在之后仍然存在(保留调用),但r0-r3中的值不存在(调用被关闭/易失性)。

        2
  •  27
  •   Pavel P    5 年前

    32位ARM调用约定由 AAPCS

    从…起 the AAPCS ,§5.1.1核心寄存器:
    • r0-r3 是参数寄存器和暂存器寄存器; r0-r1
    • r4-r8 被调用方是否保存寄存器
    • r9 可能是被叫方保存寄存器,也可能不是(在AAPC的某些变体上,它是一个特殊寄存器)
    • r12-r15 这些是特别登记册

    • 必须保存
    • s0s15(d0d7,q0q3) d16d31(q8q15) 不需要保存


    arm-to-c-calling-convention-neon-registers-to-save


    64位ARM调用约定由指定 AAPCS64

    General-purpose Registers 节指定需要保留的寄存器。
    • r0 - r7
    • r9 - 是临时登记册
    • - 是被调用方保存的寄存器。
    • 所有其他( , r16 r18 r29 , r30 服务提供商

    SIMD and Floating-Point Registers 指定寄存器和浮点寄存器。

        3
  •  19
  •   auselen    10 年前

    (来自ARM 64位体系结构的过程调用标准)

    A64指令集可见31个64位通用(整数)寄存器;这些都有标签 r0-r30 . 在64位上下文中,这些寄存器通常使用名称来引用 ; 在32位上下文中,寄存器通过使用 . 此外,堆栈指针寄存器, ,可与数量有限的指令一起使用。

    • 服务提供商
    • r30 链接寄存器
    • r29 帧指针
    • 被叫保存寄存器
    • r18 平台登记册(如需要);否则,将进行临时登记。
    • IP1第二个过程内调用临时寄存器(可使用 通过调用单板和PLT代码);在其他情况下,可将其用作 临时登记册。
    • IP0第一个过程内调用暂存寄存器(可由调用使用 临时登记册。
    • r9r15
    • r8
    • r0r7 参数/结果寄存器

    前八个寄存器, r0-r7

    登记册 r17(IP1)

    r18

    SIMD

    v0-v31

    注:

    前八个寄存器, v0-v7 ,用于将参数值传递到子例程,并从函数返回结果值。它们也可用于保存例程内的中间值(但通常仅在子例程调用之间)。

    登记册 必须由被调用方跨子例程调用保留;其余的登记册( )不需要保留(或者应该由调用方保留)。此外,仅存储在中的每个值的底部64位 v8-v15 需要保存;调用者有责任保留较大的值。

        4
  •  7
  •   Sven    10 年前

    CesarB和Pavel的回答提供了AAPCS的报价,但仍存在未决问题。被叫方是否保存r9?r12呢?r14呢?此外,答案非常笼统,并非针对要求的arm eabi工具链。这里有一个实用的方法来找出哪些寄存器被调用者保存,哪些不保存。

    void foo() {
      asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
    }
    

    使用命令行 arm-eabi-gcc-4.7 -O2 -S -o - foo.c -mcpu=arm7tdmi 例如)。 该命令将在标准输出上打印生成的汇编代码。它可能看起来像这样:

    foo:
        stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
        nop
        ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
        bx  lr
    

    -mcpu=arm7tdmi -mno-thumb-interwork 或者使用 -mcpu=cortex-m4 -mthumb 我们获得的汇编代码略有不同,如下所示:

    foo:
        stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
        nop
        ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
    

    总结如下:

    • 被叫人保存
    • r4-r11被调用方已保存
    • r12(别名ip)为
    • r13(别名sp)已被调用者保存
    • r14(别名lr)为 被叫人保存
    • r15(别名pc)是程序计数器,在函数调用之前设置为lr值

    这至少适用于arm eabi gcc的默认设置。有一些命令行开关(特别是-mabi开关)可能会影响结果。

        5
  •  0
  •   Frik    7 年前

    对于函数调用和中断,至少在Cortex M3体系结构上也存在差异。

    我不认为这种自动推送和弹出是为函数调用(跳转指令)而设计的。若约定说R0-R3只能用作参数、结果或暂存寄存器,那个么就不需要在函数调用之前存储它们,因为在函数返回之后不应该使用任何值。但和在中断中一样,如果在函数中使用其他CPU寄存器,则必须存储它们。