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

Dan*_*cco 12 assembly arm

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

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

push {ip, lr}
...
pop {ip, pc}
Run Code Online (Sandbox Code Playgroud)

例如,这是ARM的官方ARM博客提供的ARM Hello世界:

.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"
Run Code Online (Sandbox Code Playgroud)

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

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

aus*_*len 6

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

ARM就此主题提供了一份咨询说明:

用于ARM®体系结构的ABI建议 - 在进入符合AAPCS的功能时,SP必须是8字节对齐的

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

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

  • 应用失败.(编译器 - 运行时假设差异,他们给出va_startva_arg作为例子)

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


Mik*_*our 5

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

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

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

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

什么寄存器是"ip"(即,r7或什么?)

r12.见,例如,这里的全套由程序调用标准使用的寄存器的别名.

  • 这个答案具有误导性且危险。8 字节对齐是所有 EABI 兼容代码的要求,并且不在所有外部边界上维护它可能会导致运行时故障 - 更糟糕的是,当在某些处理器上执行的某些版本的编译器上构建时,它可能会导致运行时故障。 (2认同)
  • 只是回应@ unixsmurf的回应.AAPCS的5.2.1.2声明"SP mod 8 = 0.堆栈必须是双字对齐的".用于公共接口.除非你知道自己在做什么,否则你真的想一直关注这一点.ARM有一篇关于[8字节堆栈对齐]的知识文章(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html). (2认同)
  • @unixsmurf:对不起,我对程序调用标准的了解有点过时了; 我没有意识到现在需要8字节对齐.我想我最好不要再回答有关ARM的问题了.我已经更新了答案以反映出来; 希望现在可以接受,但不幸的是,只要它被接受,我就无法删除它. (2认同)