了解ARM gcc到函数调用的编译

时间:2015-11-16 04:38:02

标签: c gcc assembly arm

我有这个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?两者都不是用于输入参数吗?

感谢您的帮助,

的问候,

罗布。

1 个答案:

答案 0 :(得分:1)

这有点取决于代码没有(完全)优化,使它看起来相当混乱。

  

为什么我从sp中减去12然后不使用它?为什么12?

这是为堆栈帧分配空间,它认为它需要12个字节的原因是它将使用一个字来保存帧指针,一个字用于存储局部变量port,一个可能用于存储保存返回地址(如果它调用另一个函数)。

  

fp注册的目的究竟是什么?

这是帧指针。它使用它来访问局部变量。实际上它实际上是冗余的,如果启用优化,可能会被优化掉。

帧指针的一个用途是,如您所见,调用帧的帧指针存储在帧指针的偏移0处。这意味着您可以按照堆栈帧进行调试。

  

为什么r0写在堆栈上并读到r3?两者都不是用于输入参数吗?

缺乏优化。 r0是第一个输入参数,它存储在port变量的帧分配空间中,当使用该变量时,它将从帧中读取。执行此操作后重用r3没有问题,因为编译器会将r3中传递的参数保存到该参数的帧分配空间。

再次,如果你打开了优化,编译器就会意识到它不需要将变量port存储在堆栈框架中,而是让它存在于r0中。