C 如果程序计数器指向要执行的下一条指令的地址,帧指针做什么?
如果程序计数器指向要执行的下一条指令的地址,帧指针做什么 通常是返回地址(例如,有时刚刚超过最后一个参数)。关键是帧指针在方法的生命周期内是固定的,而堆栈指针在执行期间可能会移动 这非常依赖于实现(更多的是机器概念,而不是真正的语言概念) 摘自您对另一个答案的评论:C 如果程序计数器指向要执行的下一条指令的地址,帧指针做什么?,c,callstack,C,Callstack,如果程序计数器指向要执行的下一条指令的地址,帧指针做什么 通常是返回地址(例如,有时刚刚超过最后一个参数)。关键是帧指针在方法的生命周期内是固定的,而堆栈指针在执行期间可能会移动 这非常依赖于实现(更多的是机器概念,而不是真正的语言概念) 摘自您对另一个答案的评论: 哇。。。堆栈指针?。。。这是程序计数器的同义词吗 阅读关于这个问题的文章。基本上,调用堆栈存储当前方法的本地数据(本地变量、方法的参数和调用方的返回地址)。堆栈指针指向分配新空间的结构的顶部(通过将堆栈指针移到“更高”) 很好的讨论
哇。。。堆栈指针?。。。这是程序计数器的同义词吗 阅读关于这个问题的文章。基本上,调用堆栈存储当前方法的本地数据(本地变量、方法的参数和调用方的返回地址)。堆栈指针指向分配新空间的结构的顶部(通过将堆栈指针移到“更高”) 很好的讨论,包括例子和所有内容
简言之:FP指向堆栈上函数帧内的固定点(并且在函数执行期间不会更改),因此所有传递的参数和函数的局部(“自动”)变量都可以通过FP的偏移量进行访问(而SP可以在函数执行期间更改,PC肯定会更改;-)这不是一个真正的C问题,因为它完全依赖于编译器 但是,堆栈帧是考虑当前函数及其父函数的有用方法。通常,帧指针指向堆栈上的特定位置(对于给定的堆栈深度),从中可以定位传入的参数以及局部变量 这里有一个例子,假设您调用一个函数,该函数接受一个参数并返回1和该参数之间所有数字的总和。C代码类似于:
unsigned int x = sumOf (7);
: :
unsigned int sumOf (unsigned int n) {
unsigned int total = 0;
while (n > 0) {
total += n;
n--;
}
return total;
}
为了调用这个函数,调用者将把7推到堆栈上,然后调用子例程。函数本身设置帧指针并为局部变量分配空间,因此您可以看到以下代码:
mov r1,7 ; fixed value
push r1 ; push it for subroutine
call sumOf ; then call
retLoc: mov [x],r1 ; move return value to variable
: :
sumOf: mov fp,sp ; Set frame pointer to known location
sub sp,4 ; Allocate space for total.
: :
此时(在子sp,4
之后),您有以下堆栈区域:
+--------+
| n(7) |
+--------+
| retLoc |
+--------+
fp -> | total |
+--------+
sp -> | |
+--------+
您可以看到,通过使用帧指针上方的地址和帧指针下方的局部变量,可以找到传入的参数
函数可以通过使用[fp+8]
访问传入值(7),即fp+8
处的内存内容(在本例中,每个单元格为四个字节)。它还可以使用[fp-0]
访问自己的局部变量(total
),即fp-0
处的内存内容。我使用了fp-0
命名法,尽管减去零没有效果,因为其他局部变量将具有相应的较低地址,如fp-4
,fp-8
等等
在堆栈上下移动时,帧指针也会移动,通常在调用函数之前将前一帧指针推到堆栈上,以便在离开该函数时轻松恢复。但是,尽管堆栈指针在函数中可能会剧烈移动,但帧指针通常保持不变,因此您可以始终找到相关变量。帧指针指向当前帧中的内存区域(当前本地函数),通常它指向当前本地函数的返回地址。因为还没有人对此做出响应,所以我将尝试一下。帧指针(如果内存可用)与堆栈指针一起是堆栈的一部分。堆栈由堆栈帧(有时称为激活记录)组成。堆栈指针指向堆栈顶部,而帧指针通常指向帧结构中的某个固定点,例如返回地址的位置。维基百科上有更详细的描述和图片 它就像是堆栈指针的更稳定版本 某些局部变量和参数的存储通常在堆栈帧中分配,只需在函数调用后将堆栈指针弹回到其原始级别,堆栈帧就会自动释放 但是,堆栈指针经常被调整,以便将参数推送到堆栈上以获得新的调用级别,并且在方法的入口上至少调整一次,以便分配它自己的局部变量。调整堆栈指针还有其他更模糊的原因 所有这些调整都使使用偏移量来获取参数、局部变量以及某些语言中的中间词法范围变得复杂。编译器跟踪可能不太难,但如果程序正在调试,那么调试器(人工或程序)也必须跟踪不断变化的偏移量 如果从技术上讲是不必要的开销,那么只分配一个寄存器指向当前帧就更简单了。在x86上,这是
%ebp
。进入函数时,它可能与堆栈指针有固定关系
除了调试之外,这还简化了异常管理,甚至可以通过消除或优化对堆栈指针的一些调整来为自己买单
您提到了程序计数器,因此值得注意的是,通常帧指针完全是一种软件构造,而不是硬件实现的东西,除非几乎每台机器都可以执行寄存器+偏移量寻址模式。有些机器(如x86)确实以寻址模式和宏指令的形式提供了一些硬件支持,用于创建和恢复帧。然而,有时会发现核心指令速度更快,宏操作最终被弃用。Woh。。。堆栈指针?。。。这是程序计数器的同义词吗?不,堆栈指针(SP)与程序计数器(PC)绝不是同一寄存器:PC指向代码空间(指向“当前指令”或下一条指令,具体取决于CPU),SP始终指示“堆栈顶部”。哟