ARM:为什么我需要的函数调用推/弹出两个寄存器? [英] ARM: Why do I need to push/pop two registers at function calls?
问题描述
我知道我需要把链接寄存器在函数调用的开始,并在返回前弹出该值到Program种台,从而使执行可以携带一个从那里它是在函数调用前。
我不明白的是为什么大多数人做到这一点通过增加一个额外的寄存器来推/ POP。例如:
推{IP,LR}
...
POP {IP,PC}
例如,这里是一个Hello World的ARM,由官方博客ARM :
.syntax统一 @ --------------------------------
。全球主要
主要:
@堆栈除了虚设寄存器(IP)的返回地址(lr),用于
@保持一致堆栈8字节。
推{IP,LR} @加载参数,并进行呼叫。这就像'的printf(...)在C.
LDR R0,=消息
BL的printf @从'主'退出。这就好比C.返回0
MOV R0,#0 @返回0。
@流行的虚拟IP来扭转我们调整修复,并弹出原有LR
@值直接进入PC - 程序计数器 - 返回。
POP {IP,PC} @ --------------------------------
@为printf的调用数据。 GNU汇编的.asciz指令
@自动添加一个空字符终止。
信息:
.asciz你好,世界。\\ n
问题1 :什么是对的虚拟寄存器,因为他们把它叫做什么原因呢?为什么不能简单地推{} LR和流行{PC}?他们说,这是保持堆栈8字节对齐,而不是堆栈4字节对齐?
问题2 :什么寄存器是IP(即,R7还是什么?)
什么是针对假登记,因为他们把它叫做什么原因呢?为什么不能简单地推{} LR和流行{PC}?他们说,这是保持堆栈8字节对齐,而不是堆栈4字节对齐?
块引用><击>堆栈只需要4字节对齐;但击>如果数据总线为64位宽(因为它是许多现代兵种),这是更有效地保持在一个8字节对齐。然后,例如,如果你调用一个函数的需求的堆栈两个寄存器,可以在一个单一的64位写来完成,而不是两个32位写操作。
更新:显然,这不只是为了提高效率;这是官方的过程调用标准的要求,如在评论中指出的。
如果你打靶旧的32位ARM的,那么多余的堆积寄存器可能会略有降低性能。
什么寄存器是IP(即,R7还是什么?)
块引用>
12版
。见,例如,这里一>的全套由程序调用标准中使用的寄存器的别名。I understand that I need to push the Link Register at the beginning of a function call, and pop that value to the Program Couter before returning, so that the execution can carry one from where it was before the function call.
What I don't understand is why most people do this by adding an extra register to the push/pop. For instance:
push {ip, lr} ... pop {ip, pc}
For instance, here's a Hello World in ARM, provided by the 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"
Question 1: what's the reason for the "dummy register" as they call it? Why not simply push{lr} and pop{pc}? They say it's to keep the stack 8-byte aligned, but ain't the stack 4-byte aligned?
Question 2: what register is "ip" (i.e., r7 or what?)
解决方案what's the reason for the "dummy register" as they call it? Why not simply push{lr} and pop{pc}? They say it's to keep the stack 8-byte aligned, but ain't the stack 4-byte aligned?
The stack only requires 4-byte alignment; butif the data bus is 64 bits wide (as it is on many modern ARMs), it's more efficient to keep it at an 8-byte alignment. Then, for example, if you call a function that needs to stack two registers, that can be done in a single 64-bit write rather than two 32-bit writes.UPDATE: Apparently it's not just for efficiency; it's a requirement of the official procedure call standard, as noted in the comments.
If you're targetting older 32-bit ARMs, then the extra stacked register might degrade performance slightly.
what register is "ip" (i.e., r7 or what?)
r12
. See, for example, here for the full set of register aliases used by the procedure call standard.这篇关于ARM:为什么我需要的函数调用推/弹出两个寄存器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!