我知道我需要在函数调用开始时推送链接寄存器,并在返回之前将该值弹出到程序计数器,以便执行可以从函数调用之前的位置携带一个。
我不明白为什么大多数人会通过在 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还是什么?)