【问题标题】:Understanding compilation of ARM gcc to function call理解 ARM gcc 编译到函数调用
【发布时间】:2016-02-17 03:37:58
【问题描述】:

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

感谢您的帮助,

问候,

罗伯。

【问题讨论】:

  • 这是没有优化的吗?
  • 未优化它将为传入的参数和中间值腾出空间(并且可能根据 abi 在两个字的边界上对齐)。 fp 是帧指针,烧录一个寄存器而不是使用 sp 来引用。并不少见,某些指令集需要。在这种情况下,它还保存了 sp 的值,因此您不必在后端进行数学运算,尽管即使在这种情况下也会更便宜。尝试优化。

标签: c gcc assembly arm


【解决方案1】:

这在某种程度上取决于代码没有(完全)优化,这使它看起来相当混乱。

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

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

fp寄存器的作用到底是什么?

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

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

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

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

同样,如果您打开了优化,编译器会意识到它不需要将变量 port 存储在堆栈帧中,而是让它存在于 r0 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    相关资源
    最近更新 更多