ARM:为什么我需要在函数调用时推送/弹出两个寄存器?

时间:2013-04-20 12:03:10

标签: assembly arm

我知道我需要在函数调用开始时推送链接寄存器,并在返回之前将该值弹出到Program Couter,以便执行可以从函数调用之前的位置开始执行。

我不明白为什么大多数人通过在push / pop中添加额外的寄存器来实现这一点。例如:

push {ip, lr}
...
pop {ip, pc}

例如,这是ARM中的Hello World,由official ARM blog提供:

.syntax unified

    @ --------------------------------
    .global main
main:
    @ Stack the return address (lr) in addition to a dummy register (ip) to
    @ keep the stack 8-byte aligned.
    push    {ip, lr}

    @ Load the argument and perform the call. This is like 'printf("...")' in C.
    ldr     r0, =message
    bl      printf

    @ Exit from 'main'. This is like 'return 0' in C.
    mov     r0, #0      @ Return 0.
    @ Pop the dummy ip to reverse our alignment fix, and pop the original lr
    @ value directly into pc — the Program Counter — to return.
    pop     {ip, pc}

    @ --------------------------------
    @ Data for the printf calls. The GNU assembler's ".asciz" directive
    @ automatically adds a NULL character termination.
message:
    .asciz  "Hello, world.\n"

问题1 :他们称之为“虚拟注册”的原因是什么?为什么不简单地推{lr}和pop {pc}?他们说这是保持堆栈8字节对齐,但不是堆栈4字节对齐?

问题2 :什么寄存器是“ip”(即r7或什么?)

3 个答案:

答案 0 :(得分:6)

8字节对齐是符合AAPCS的对象之间互操作性的要求。

ARM有关于此主题的咨询说明:

ABI for the ARM® Architecture Advisory Note – SP must be 8-byte aligned on entry to AAPCS-conforming functions

文章提到使用8字节对齐的两个原因

  • 对齐错误或UNPREDICTABLE行为。 (硬件/体系结构相关原因 - LDRD / STRD可能导致对齐错误或在ARMv7以外的体系结构上显示UNPREDICTABLE行为)

  • 申请失败。 (编译器 - 运行时假设差异,他们以va_startva_arg为例)

当然这都是关于公共接口的,如果你创建一个没有额外链接的静态可执行文件,你可以将堆栈对齐为4个字节。

答案 1 :(得分:5)

  

他们称之为“虚拟注册”的原因是什么?为什么不简单地推{lr}和pop {pc}?他们说这是保持堆栈8字节对齐,但不是堆栈4字节对齐?

堆栈只需要4字节对齐;但如果数据总线是64位宽(就像在许多现代ARM上一样),将它保持在8字节对齐更有效。然后,例如,如果您调用需要的函数来堆叠两个寄存器,那么可以在一次64位写入而不是两次32位写入中完成。

更新:显然,这不仅仅是为了提高效率;正如评论中所述,这是官方程序调用标准的要求。

如果您的目标是较旧的32位ARM,那么额外的堆叠寄存器可能会略微降低性能。

  

什么寄存器是“ip”(即r7或什么?)

r12。例如,请参阅过程调用标准使用的完整寄存器别名集here

答案 2 :(得分:3)

因为您希望在执行功能后存储和恢复它们。 在函数entrence上,它保存iplr寄存器(名为prolog)。 完成该功能后,它会分配两个(epilog):

pc <- lr

ip <- old_ip

修改

寄存器r12也称为IP,用作过程内调用暂存寄存器,请参阅also

惯例是被调用者函数可以更改ip,r0-r3,因此您必须根据calling convention

恢复它们的相关性

<强> EDIT2: Why we might want the stack to be 8 aligned on ARM

  

如果堆栈不是八字节对齐,则可能使用LDRD和STRD(load and store doubleword)   导致对齐故障,具体取决于目标和配置   使用

注意that we have the same issue on X86Mac OS we have 16 bytes alignment