avr-gcc 中 Y 寄存器与调用/堆栈帧的偏移量来自哪里?

问题描述 投票:0回答:1

在 avr-gcc 网站(https://gcc.gnu.org/wiki/avr-gcc#Frame_Layout)上,它说帧指针(Y 寄存器)偏移了一个字节,因此 Y+1 指向框架的底部。然而,当我将测试 C 函数编译到汇编文件并查看序言时,在我看来,Y 和 SP 似乎指向同一位置,并且与框架没有偏移。

但是在主体中,它确实看起来像使用Y,就好像它刚刚脱离框架一样。
我不确定这个偏移量是从哪里来的。这是编译器为我提供的函数的汇编代码,上面标记了我的问题:

func:
  push r29
  push r28 <- save Y as it is preserved
  rcall . <- this seems to be used to decrement the stack pointer to allocate stack space 2 bytes at a time
  rcall .
  rcall .

  in r28,__SP_L__
  in r29,__SP_H__ <- the stack pointer and Y should be aligned and both pointing to last local
/* prologue: function */

/* frame size = 6 */
  std Y+4,r24
  std Y+6,r23 <- should this not be overwriting the saved r28 register?
  std Y+5,r22
  ldi r24,lo8(97)
  std Y+3,r24
  ldi r24,lo8(23)
  ldi r25,hi8(23)
  std Y+2,r25
  std Y+1,r24 <- does seem to use Y as if it is one less than the stack frame. but after the decrements

  ldd r24,Y+4
  mov r18,r24
  clr r19
  sbrc r18,7
  com r19
  ldd r24,Y+5
  ldd r25,Y+6
  add r18,r24
  adc r19,r25
  ldd r24,Y+3
  clr r25
  sbrc r24,7
  com r25
  add r18,r24
  adc r19,r25
  ldd r24,Y+1
  ldd r25,Y+2
  add r24,r18
  adc r25,r19

/* epilogue start */
  adiw r28,6
  in __tmp_reg__,__SREG__
  cli
  out __SP_H__,r29
  out __SREG__,__tmp_reg__
  out __SP_L__,r28
  pop r28
  pop r29
  ret

我希望 Y 会有额外的减量,或者主体使用

Y
..
Y+3
而不是
Y+1
..
Y+4
。在我看来,偏移或减少似乎并不明显。我已经检查了指令集手册,但假设我理解它告诉我的内容,似乎没有任何指令以有意义的方式工作。

我知道这可能是一个愚蠢的问题,但我通常不明白这个偏移量来自哪里。我什至问过克劳德,它也听不懂。

assembly avr calling-convention avr-gcc frame-pointer
1个回答
0
投票

在我看来,Y 和 SP 似乎指向同一个位置

是的。 这就是函数序言如何设置帧指针(假设需要 FP)。 这是一个小例子:

void fn_frame (void)
{
    int volatile x; // Forces a frame
    x = 0;
}

使用

-S -Os
和 avr-gcc v8 生成程序集如下:

fn_frame:
    push r28
    push r29
    rcall .
    in r28,__SP_L__
    in r29,__SP_H__
/* prologue: function */
/* frame size = 2 */
/* stack size = 4 */
.L__stack_usage = 4
    std Y+2,__zero_reg__
    std Y+1,__zero_reg__
/* epilogue start */
    pop __tmp_reg__
    pop __tmp_reg__
    pop r29
    pop r28
    ret

这意味着

x
位于
Y+1
...
Y+2
,并且框架的底部是
Y+1
,而不是
Y

这是关于avr-gcc中框架如何实现的决定。 虽然我不知道这一设计决定的确切原因,但有一点支持它:

  • 帧指针的初始化只是设置 FP = SP 的两条

    IN
    指令,以便代码可以访问堆栈帧。 当 FP 设置在框架底部的
    SP + 1
    处时,设置 FP 将需要针对该测试用例的 3 条指令:

    in r28,__SP_L__
    in r29,__SP_H__
    adiw r28,1
    

    另一方面,地址

    Y+1
    Y
    一样有效;仅当上述寻址模式用尽时,差异才变得相关
    Y+63

© www.soinside.com 2019 - 2024. All rights reserved.