13

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

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

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

例如,这里有一个 ARM 中的 Hello World,由ARM 官方博客提供:

.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:他们称之为“虚拟寄存器”的原因是什么?为什么不简单地 push{lr} 和 pop{pc}?他们说这是保持堆栈 8 字节对齐,但堆栈不是 4 字节对齐吗?

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

4

3 回答 3

7

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

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

ARM® 架构咨询说明的 ABI – SP 在进入符合 AAPCS 的函数时必须是 8 字节对齐的

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

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

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

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

于 2013-04-22T09:09:35.363 回答
5

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

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

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

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

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

r12. 例如,请参见此处以了解过程调用标准使用的完整寄存器别名集。

于 2013-04-20T12:32:49.583 回答
4

因为您想在执行函数后存储和恢复它们。在函数 entrence 上,它保存iplr寄存器(命名为prolog)。完成函数后,它同时分配 ( epilog) :

pc <- lr

ip <- old_ip

编辑

寄存器r12也称为IP,并用作过程内调用临时寄存器,另请参见

约定是被调用函数可以更改ip,r0-r3,因此您必须根据调用约定恢复它们

EDIT2: 为什么我们可能希望堆栈在 ARM 上对齐 8

如果堆栈不是八字节对齐的,则使用 LDRD 和 STRD(加载和存储双字)可能会导致对齐错误,具体取决于使用的目标和配置。

请注意,我们在 X86 上遇到了同样的问题,在Mac OS 上我们有 16 字节对齐

于 2013-04-20T12:06:08.653 回答