gpt4 book ai didi

c - MSP430程序集堆栈指针行为

转载 作者:太空宇宙 更新时间:2023-11-03 23:26:23 25 4
gpt4 key购买 nike

在试图分析通过msp430 gcc生成的简单程序集文件时,我无意中发现了一组指令,我不理解如何处理帧指针和msp430的堆栈指针。
C程序:

#include "msp430g2553.h"

int main()
{
int i;

for(i = 0; i < 3; i++);

}

程序集减号指令:
main:
mov r1, r4 ;Stores address of stack pointer in r4(frame pointer)
add #2, r4 ; ?
sub #2, r1 ; subtract 2 to allocate int i
mov #0, -4(r4) ; assign 0 to i
jmp .L2 ; start loop
.L3:
add #1, -4(r4) ; Adds one to int i
.L2:
cmp #3, -4(r4) ; Compare to #3
jl .L3 ; jump to .L3 if true
add #2, r1 ; deallocate int i
.Lfe1:
.size main,.Lfe1-main

我试图注释代码以跟踪程序的执行,但我不理解 add #2, r4这一行这里到底发生了什么,为什么 int i被引用到 -4(r4)

最佳答案

通常,在函数中要做的第一件事是:

push r4

要将当前帧指针保存在堆栈上,以便可以为要调用的函数设置新的帧指针,然后还原旧的帧指针 push将自动将堆栈指针减小2,因此在执行此操作时:
mov r1, r4

被推到 r4上的地址将高于刚才推到堆栈上的值(这里是“上面”,意思是堆栈向下增长,实际上是数字内存地址的下面)您将希望帧指针实际指向您刚刚推送到堆栈上的值的下方,因此您将它增加两个值以实现此目的:
add #2, r4

因为 main()是执行的第一个函数,所以没有保存的现有框架指针,所以你在这里看到的是 movadd没有的 push
当您进行实际的函数调用时,它会更有意义,您将看到整个过程:
push r4
mov r1, r4
add #2, r4

完成此操作后, -2(r4)将引用刚才推送到堆栈上的帧指针的上一个值,并且由于尚未向堆栈指针的值添加两个值, -2(r4)也将等于该值。
现在为局部变量分配16位时,必须从堆栈指针中减去 i以腾出空间,因此 2的地址将为 i
例子
例如,假设堆栈指针包含 -4(r4),而帧指针包含 0x200,然后要调用函数从这样的堆栈开始:
      r4 --> 0x202    ---------------------
<empty>
r1 --> 0x200 ---------------------

从函数返回后,您将要还原帧指针的当前值,因此首先要将其推送到堆栈上保存因此,在 0x202之后,值 push r4被推送到内存位置 0x202(即由 0x200指向的堆栈顶部),堆栈指针被 r1递减以腾出空间,因此您可以:
      r4 --> 0x202    ---------------------
<empty>
0x200 ---------------------
0x202
r1 --> 0x1FE ---------------------

将帧指针的上一个值推送到堆栈上后,现在要将帧指针的当前值设置到当前堆栈帧的基部,因此可以通过将新堆栈指针移到 2中来开始此操作,然后得到:
             0x202    ---------------------
<empty>
0x200 ---------------------
0x202
r1 == r4 --> 0x1FE ---------------------

帧指针的旧值是当前堆栈帧中的第一个值,因此您希望 r4在此之前指向,而不是在它之后指向为此,将 r4添加到 2,您将得到:
             0x202    ---------------------
<empty>
r4 --> 0x200 ---------------------
0x202
r1 --> 0x1FE ---------------------

您现在所处的位置是 r4指向堆栈帧的底部,而 r4指向堆栈帧的顶部,这是您想要的位置此时,当前堆栈帧中唯一实际存在的是在函数开始时推送到它上面的帧指针的上一个值。
然后将堆栈指针减小 r1以腾出空间给新的局部变量,最后得到:
             0x202    ---------------------
<empty>
r4 --> 0x200 ---------------------
0x202
0x1FE ---------------------
<uninitialized i>
r1 --> 0x1FC ---------------------

您可以看到 2存储在 i中,即 0x1FC再次指出,您所处的位置 -4(r4)指向堆栈帧的底部, r4指向堆栈帧的顶部,但现在您在当前堆栈帧中有两个16位值,因此两个指针相距4字节。
当您准备好在函数结束时返回时,您将 r1来“释放”局部变量 add #2, r1的内存这将给你:
             0x202    ---------------------
<empty>
r4 --> 0x200 ---------------------
0x202
r1 --> 0x1FE ---------------------

然后您将 i,它将从堆栈中弹出最后一个值(现在是帧指针的原始值 pop r4),将其放入 0x202,并将堆栈指针增加 r4,以反映该值已从堆栈中删除,这将使您处于:
      r4 --> 0x202    ---------------------
<empty>
r1 --> 0x200 ---------------------

这正是您开始的地方,并且您已经在函数调用之后完全清理了堆栈。
注意,这是稍微简化的,因为当你做一个函数调用时,程序计数器也会被推到堆栈上,然后在你返回时再次弹出并恢复,上面的例子并没有显示这一点,但是那里发生的是完全相同的事情。

关于c - MSP430程序集堆栈指针行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26374287/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com