这次来看看PowerPC体系架构CPU的栈帧布局和操作方法。PowerPC用得不多,有不对的地方大家拍砖啊~~
1. PowerPC的栈帧
先来看看PowerPC的栈帧布局图:
上图描述的是PowerPC的栈帧布局方式,PowerPC的栈生长方向也是由高到低,caller是调用者,current是被调用者。压栈的顺序依次是FPR、GPR、CR、Local Variable、Function Parameters、Padding、LR和Back Chain Word。具体涵义如下:
(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:也就是ra寄存器,是指返回时的函数指针。
(8)Back Chain Word:是调用者函数帧的栈顶esp,即上一个栈帧的低地址,当前函数栈帧的基址ebp。
跟x86和ARM一样,压栈的顺序有一定的规律,一个栈空间内的地址前面,必然有一个代码地址明确标示着调用函数位置内的某个地址。而且很容易发现,跟x86一样(如果x86中ebp算是调用者栈帧的话),栈帧的最后两个位置存储的也是ra和ebp。所以可以考虑向x86学习,根据当前ebp的值回溯出整个任务的调用栈,如图中蓝箭头所示,具体操作后面再专门讲述。
2. PowerPC的寄存器
PowerPC的ABI规定的寄存器的使用规则如下:
(1)GPR0:属于易失性寄存器,ABI规定普通用户不能使用此寄存器。GCC编译器用此寄存器来保存LR寄存器,Linux PowerPC用此寄存器来传递系统调用号码。
(2)GPR1:属于专用寄存器,ABI规定用次寄存器来保存堆栈的栈顶指针。注:PowerPC构架没有独立的栈顶指针,这一点和X86体系结构是不同的!
(3)GPR2:属于专用寄存器,ABI规定普通用户不使用才寄存器,Linux PowerPC用此寄存器来保存当前进程的进程描述符地址。
(4)GPR3-GPR4:属于易失性寄存器,ABI使用这两个寄存器来保存函数的返回值,或者用来传递参数。
(5)GPR5-GPR10:也属于易失性寄存器,加上GPR3和GPR4共8个寄存器用来传递函数的参数。当函数的参数超过八个时使用堆栈来传递。
(6)GPR11-GPR12:属于易失性寄存器,ABI规定普通用户不使用该寄存器,Linux PowerPC有时用这两个寄存器来存放临时变量,但是GCC编译器没有使用这两个寄存器。
(7)GPR13:属于专用寄存器,ABI规定该寄存器sdata段的基地址指针。Linux PowerPC在系统初始化时使用该寄存器来存放临时变量。GCC有时会根据某些规则将一些常用的数据放入sdata或者sbss段中。应用程序对sdata或者sbss段数据的访问与对data和bss段数据的访问机制不同,访问sdata段的数据速度更快。
(8)GPR14-GPR31:属于非易失性寄存器。ABI使用这些寄存器来存放一些临时变量,在应用程序中可以自由使用这些变量。
3. PowerPC的汇编指令和栈操作
PowerPC寄存器没有专用的push和pop指令来执行堆栈操作,所以PowerPC构架使用存储器访问指令stwu、lwzu来代替push和pop指令。
下面我们通过一个例子来说明堆栈帧的建立、使用和移除过程:
func1中开始几行汇编会为自己建立栈帧:
func1: mflr %r0 ;Get link register
stwu %r1,-88(%r1) ;Save back chain then move sp
stw %r0,+92(%r1) ;Save link register
stmw %r28,+72(%r1) ;Save 4 non-volatiles r28-r31
func1的结尾几行,会移除前面建立的栈帧,并使得SP(即GPR1)寄存器指向上一个栈帧的栈顶(即栈帧的最低地址处,也就是back chair)
如下所示:
lwz %r0,+92(%r1) ;Get saved link register
mtlr %r0 ;Restore link register
lmw %r28,+72(%r1) ;Restore non-volatiles
addi %r1,%r1,88 ;Remove frame from stack
blr ;Return to caller function
阅读(648) | 评论(0) | 转发(0) |