我有这个C代码:
void initPIO_Port(AT91S_PIO *port)
{
port->PIO_PER=1<<PIN;
port->PIO_OER=1<<PIN;
} // initPIO_Port
int main(void)
{
initPIO_Port(PORT);
/* Loop for ever */
while (1) {
...
};
}
通过arm-gcc翻译成ARM程序集:
main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
@int main(void)
@{
@ initPIO_Port(PORT);
@ while (1) {
....
@ };
@}
stmfd sp!, {fp, lr}
add fp, sp, #4
ldr r0, .L13
bl initPIO_Port
.L12:
...
b .L12
initPIO_Port:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
@ void initPIO_Port(AT91S_PIO *port)
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #12 @ why subtract 12 - we're not using sp in following code ?
str r0, [fp, #-8] @ first empty place is at fp-8? fp points to last full location on stack - is this right ?
@ why is input parameter in r0 saved on stack and then read in r3 ?
ldr r3, [fp, #-8] @ port->PIO_PER=1<<PIN;
mov r2, #2
str r2, [r3, #0]
ldr r3, [fp, #-8] @ port->PIO_OER=1<<PIN;
mov r2, #2
str r2, [r3, #16]
add sp, fp, #0 @ previous value of sp
ldmfd sp!, {fp} @ restore fp
bx lr @ return
我有理解fp和sp寄存器的行为:
为什么我从sp中减去12然后不使用它?为什么12?
fp注册的目的究竟是什么?
为什么r0写在堆栈上并读到r3?两者都不是用于输入参数吗?
感谢您的帮助,
的问候,
罗布。
答案 0 :(得分:1)
这有点取决于代码没有(完全)优化,使它看起来相当混乱。
为什么我从sp中减去12然后不使用它?为什么12?
这是为堆栈帧分配空间,它认为它需要12个字节的原因是它将使用一个字来保存帧指针,一个字用于存储局部变量port
,一个可能用于存储保存返回地址(如果它调用另一个函数)。
fp注册的目的究竟是什么?
这是帧指针。它使用它来访问局部变量。实际上它实际上是冗余的,如果启用优化,可能会被优化掉。
帧指针的一个用途是,如您所见,调用帧的帧指针存储在帧指针的偏移0
处。这意味着您可以按照堆栈帧进行调试。
为什么r0写在堆栈上并读到r3?两者都不是用于输入参数吗?
缺乏优化。 r0
是第一个输入参数,它存储在port
变量的帧分配空间中,当使用该变量时,它将从帧中读取。执行此操作后重用r3
没有问题,因为编译器会将r3
中传递的参数保存到该参数的帧分配空间。
再次,如果你打开了优化,编译器就会意识到它不需要将变量port
存储在堆栈框架中,而是让它存在于r0
中。