PowerPC栈帧理解
2015-12-17 20:40
316 查看
因为实验室项目的原因,才开始接触PowerPC,错误的地方还望看到的各位指正。
上面就是IBM的手册上面画的栈帧,他的文字描述也符合这个示意图,理解起来就是栈顶存放的是上一个栈的栈顶的地址。r1寄存器(一般作为默认的堆栈指针)存放自身的栈顶。因为没有push和pop指令,所以是通过stwu和lwzu来进行push和pop的。下面假设调用函数为main(),被调用函数为func()。根据手册上来说:
从栈底到栈顶依次存放的是
(1)函数参数域FPR(Function Parameter Register):这个区域的大小是变化的,当调用者传递给被调用者的参数少于8个时,用GPR3-GPR10这8个寄存器就行,被调用者的栈帧中就可不要这个区域;但如果传递的参数多于8个时就需要这个区域。
(2)通用寄存器GPR(General Parameter Register):当需要保存GPR寄存器中的一个寄存器GPRx时,就需要把从GPRx-GPR31的值都保存到堆栈帧中。
(3)CR寄存器:即使修改了CR寄存器的某一个段CRx(x=0至7),都要保存这个CR寄存器的内容。
(4)局部变量域(Local Variables Area):同上FPR所示,如果临时寄存器的数量不足以提供给被调用者的临时变量使用时,就会使用这个区域。
(5)Function Parameters:跟第一个FPR重复了?暂时不知。
(6)Padding:是补齐字节数,让当前栈帧的长度保持8Bytes的倍数。
(7)LR链接寄存器(Link Register):也就是被调用函数的返回地址,main函数中调用func函数的那条指令的下一条指令的地址。
(8)Back Chain Word:即上一个栈帧的低地址,也是r1存放的地址值,可以把这个作为基址进行自己栈帧内的寻址。
调用的过程举例如下:
func中开始几行汇编会为自己建立栈帧:
func的结尾几行,会移除前面建立的栈帧,并使得SP(即GPR1)寄存器指向上一个栈帧的栈顶(即栈帧的最低地址处,也就是back chair)
如下所示:
用图例来讲就是:
不过有个很奇怪的地方,按照IBM的示例代码,如果是先stwu %r1,-88(%r1);再stw %r0,+92(%r1),也就是保存在栈上的位置加的比栈分配的空间大(分配了88字节,存放的位置是+92),那保存的LR不是变成了在上一个栈帧的内部了么?这个不就跟IBM的栈帧的示意图冲突了么(栈帧示意图中的LR存在的是被调用函数自己的栈内,文字描述也是这个意思)?按代码保存的LR应该是保存在main函数还未调用func时r1+4的位置,示例如下,为了区别,调用func时的r1写成r’:
我去找了人家的反汇编程序看了看:
#include <stdio.h>
void fun()
{
}
int main()
{
fun();
return 0;
}
可以看到,在main函数的跳转的时候用的bl,bl跳转的时候可以存放LR,因为func什么也没有,所以编译器自动把保存LR到栈的部分忽略了,可能是编译器优化的结果?在上图中,func存放调用函数栈顶的方法是用的r31这个寄存器,但是在之前先保存了原先r31的值,而且是在自己的栈内。在main函数里面我们可以看到IBM手册里面说的那种建立栈帧的标准方法,但是存LR还是超过了分配给自己的栈大小(分配了16,存的位置是20(r1))。这个我也不知道是为什么存LR要保存到上一个栈,这跟栈帧示意图里面LR保存的位置不同,只能以后看能不能问到更多的牛人的意见了……
上面就是IBM的手册上面画的栈帧,他的文字描述也符合这个示意图,理解起来就是栈顶存放的是上一个栈的栈顶的地址。r1寄存器(一般作为默认的堆栈指针)存放自身的栈顶。因为没有push和pop指令,所以是通过stwu和lwzu来进行push和pop的。下面假设调用函数为main(),被调用函数为func()。根据手册上来说:
从栈底到栈顶依次存放的是
(1)函数参数域FPR(Function Parameter Register):这个区域的大小是变化的,当调用者传递给被调用者的参数少于8个时,用GPR3-GPR10这8个寄存器就行,被调用者的栈帧中就可不要这个区域;但如果传递的参数多于8个时就需要这个区域。
(2)通用寄存器GPR(General Parameter Register):当需要保存GPR寄存器中的一个寄存器GPRx时,就需要把从GPRx-GPR31的值都保存到堆栈帧中。
(3)CR寄存器:即使修改了CR寄存器的某一个段CRx(x=0至7),都要保存这个CR寄存器的内容。
(4)局部变量域(Local Variables Area):同上FPR所示,如果临时寄存器的数量不足以提供给被调用者的临时变量使用时,就会使用这个区域。
(5)Function Parameters:跟第一个FPR重复了?暂时不知。
(6)Padding:是补齐字节数,让当前栈帧的长度保持8Bytes的倍数。
(7)LR链接寄存器(Link Register):也就是被调用函数的返回地址,main函数中调用func函数的那条指令的下一条指令的地址。
(8)Back Chain Word:即上一个栈帧的低地址,也是r1存放的地址值,可以把这个作为基址进行自己栈帧内的寻址。
调用的过程举例如下:
func中开始几行汇编会为自己建立栈帧:
func的结尾几行,会移除前面建立的栈帧,并使得SP(即GPR1)寄存器指向上一个栈帧的栈顶(即栈帧的最低地址处,也就是back chair)
如下所示:
用图例来讲就是:
不过有个很奇怪的地方,按照IBM的示例代码,如果是先stwu %r1,-88(%r1);再stw %r0,+92(%r1),也就是保存在栈上的位置加的比栈分配的空间大(分配了88字节,存放的位置是+92),那保存的LR不是变成了在上一个栈帧的内部了么?这个不就跟IBM的栈帧的示意图冲突了么(栈帧示意图中的LR存在的是被调用函数自己的栈内,文字描述也是这个意思)?按代码保存的LR应该是保存在main函数还未调用func时r1+4的位置,示例如下,为了区别,调用func时的r1写成r’:
我去找了人家的反汇编程序看了看:
#include <stdio.h>
void fun()
{
}
int main()
{
fun();
return 0;
}
可以看到,在main函数的跳转的时候用的bl,bl跳转的时候可以存放LR,因为func什么也没有,所以编译器自动把保存LR到栈的部分忽略了,可能是编译器优化的结果?在上图中,func存放调用函数栈顶的方法是用的r31这个寄存器,但是在之前先保存了原先r31的值,而且是在自己的栈内。在main函数里面我们可以看到IBM手册里面说的那种建立栈帧的标准方法,但是存LR还是超过了分配给自己的栈大小(分配了16,存的位置是20(r1))。这个我也不知道是为什么存LR要保存到上一个栈,这跟栈帧示意图里面LR保存的位置不同,只能以后看能不能问到更多的牛人的意见了……
相关文章推荐
- 系统时间
- nginx server 中的if与rewrite
- sqlite笔记(akaedu)
- 一键安装lamp系统
- XSS攻击(二)
- regsvr32命令集锦
- javascript大神修炼记(4)——循环
- Ideal Forms响应式表单
- 《Java编程思想》第八章 多态
- 程序员常去的14个顶级开发社区
- HDOJ--2027
- 行情列表重构 TabBar&NavBar&tableView
- 三层C#版实现
- 指向子类对象的基类指针调用非虚函数都是基类的函数吗
- CentOS6.6下配置KMS自动激活服务器虚拟机简化配置
- uva 103
- matlab 比较两个集合是否相等 儿子的papa,papa的儿子
- 学习之旅启动
- 机器手臂(2):机械手臂关节研究
- 第八周 项目五 计数的模式匹配