PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解

第一部分 概述

应用程序二进制接口(ABI-Application Binary Interface)定义了一组在PowerPC系统软件上编译应用程序所需要遵循的一套规则。主要包括基本数据类型,通用寄存器的使用,参数的传递规则,以及堆栈的使用等等。ABI简单明了,但是比较难以理解的是堆栈帧的使用和维护。本文重点介绍PowerPC平台上堆栈帧的使用和维护,关于ABI其它方面的内容简单的介绍一下,O(∩_∩)O~

第二部分 详细内容

2.1 PowerPC构架使用的基本数据类型

PowerPC构架定义的基本数据类型的格式和标准C相同,具体格式如下:

PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解 

2.2 PowerPC构架寄存器的使用规则

PowerPC的ABI规定的寄存器的使用规则如下:

GPR0:属于易失性寄存器,ABI规定普通用户不能使用此寄存器。GCC编译器用此寄存器来保存LR寄存器,Linux-PowerPC用此寄存器来传递系统调用号码。

GPR1:属于专用寄存器,ABI规定用次寄存器来保存堆栈的栈顶指针。

备注:PowerPC构架没有独立的栈顶指针,这一点和X86体系结构是不同的。

GPR2:属于专用寄存器,ABI规定普通用户不使用才寄存器,Linux PowerPC用此寄存器来保存当前进程的进程描述符地址。

GPR3至GPR4:属于易失性寄存器,ABI使用这两个寄存器来保存函数的返回值,或者用来传递参数。

GPR5值GPR10:也属于易失性寄存器,加上GPR3和GPR4共8个寄存器用来传递函数的参数。当函数的参数超过八个时使用堆栈来传递。

GPR11至GPR12:属于易失性寄存器,ABI规定普通用户不使用该寄存器,Linux PowerPC有时用这两个寄存器来存放临时变量,但是GCC编译器没有使用这两个寄存器

GPR13:属于专用寄存器,ABI规定该寄存器sdata段的基地址指针。Linux PowerPC在系统初始化时使用该寄存器来存放临时变量。GCC有时会根据某些规则将一些常用的数据放入sdata或者sbss段中。应用程序对sdata或者sbss段数据的访问与对data和bss段数据的访问机制不同,访问sdata段的数据速度更快。

GPR14至GPR31:属于非易失性寄存器。ABI使用这些寄存器来存放一些临时变量,在应用程序中可以自由使用这些变量。

总结成一张表格如下所示:

PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解
第二部分 栈帧的使用规则

PowerPC寄存器没有专用的Pop,Push指令来执行堆栈操作,所以PowerPC构架使用存储器访问指令stwu,lwzu来代替Push和Pop指令。PowerPC处理器使用GPR1来将这个堆栈段构成一个单向链表,这个单链表的每一个数据成员,我们称之为堆栈帧(Stack Frame),每一个函数负责维护自己的堆栈帧。

PowerPC体系结构中栈的增长方向是从高地址到低地址,堆的增长方式是从低地址到搞地址,当两者相遇时就会产生溢出。

堆栈帧的格式如下:

PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解
备注:PowerPC构架规定栈帧的长度是8字节对齐的,栈帧的长度是8的倍数,如果不足8的整数倍,就如上图所示来补字节凑8的倍数。

解释: 

函数参数域(Function Parameter Area):这个区域的大小是可选的,即如果如果调用函数传递给被调用函数的参数少于六个时,用GPR4至GPR10这个六个寄存器就可以了,被调用函数的栈帧中就不需要这个区域;但如果传递的参数多于六个时就需要这个区域。

局部变量域(Local Variables Area):通上所示,如果临时寄存器的数量不足以提供给被调用函数的临时变量使用时,就会使用这个域。

CR寄存器:即使修改了CR寄存器的某一个段CRx(x=0至7),都有保存这个CR寄存器的内容。

通用寄存器GPR当需要保存GPR寄存器中的一个寄存器器GPRn时,就需要把从GPRn到GPR31的值都保存到堆栈帧中。

浮点寄存器FPR使用规则共GPR寄存器。

下面我们通过几个例子来说明堆栈帧的建立和使用过程:

例子一:调用Funx()函数

FunX下中开始几行汇编会为自己建立堆栈帧:

FunX:    mflr %r0               ;Get Link register

          stwu %r1,-88(%r1)      ;Save Back chain and move SP

         stw %r0,+92(%r1)       ;Save Link register

          stmw %r28,+72(%r1)     ;Save 4 non-volatiles r28-r31

FunX的结尾几行,会移除面建立的堆栈帧,并使得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 calling function

例子二:

#include <stdio.h>

void fun()

{

}

int main()

{

      fun();

      return 0;

}

建立堆栈帧和移除堆栈帧的汇编语言:

100004f4 <fun>:

100004f4:      94 21 ff f0    stwu   r1,-16(r1)

100004f8:      93 e1 00 0c   stw    r31,12(r1)

100004fc:      7c 3f 0b 78   mr     r31,r1

10000500:     39 7f 00 10   addi   r11,r31,16

10000504:     83 eb ff fc    lwz    r31,-4(r11)

10000508:     7d 61 5b 78  mr     r1,r11

1000050c:     4e 80 00 20    blr

 

10000510 <main>:

10000510:     94 21 ff f0    stwu   r1,-16(r1)

10000514:     7c 08 02 a6   mflr   r0

10000518:     90 01 00 14  stw    r0,20(r1)

1000051c:     93 e1 00 0c   stw    r31,12(r1)

10000520:     7c 3f 0b 78   mr     r31,r1

10000524:     4b ff ff d1    bl     100004f4 <fun>

10000528:     38 00 00 00  li     r0,0

1000052c:     7c 03 03 78  mr     r3,r0

10000530:     39 7f 00 10   addi   r11,r31,16

10000534:     80 0b 00 04  lwz    r0,4(r11)

10000538:     7c 08 03 a6   mtlr   r0

1000053c:     83 eb ff fc    lwz    r31,-4(r11)

10000540:     7d 61 5b 78  mr     r1,r11

10000544:     4e 80 00 20    blr

10000548:     00 01 81 a0    .long 0x181a0

分析如下图所示:

PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解
 

备注:

当前函数(比如上面的fun)所维护堆栈帧中的backchain存放的是调用它的函数(即main函数)堆栈帧的栈顶地址。

另外,很多C程序中进行的汇编语言函数调用比较简单,例如汇编函数的参数个数一般少于八个,使用临时的通用寄存器GPR14至GPR31就足够了。所以在这种情况下,我们只要保持堆栈中的LR和Back Chain就足够用的了。

但是正如例子二所示:虽然只需要8个字节来保存LR和和Back Chain就行了,但是GCC编译器在建立堆栈帧时还额外分配了8个字节,其中的4个字节来保存r31的值,另外4个字节的空间并没有使用起来。

备注:例子二中所描述的帧结构是PowerPC构架中最小帧结构,这种帧结构的大小为16字节。

 

参考资料:

Developing PowerPC Embedded Application Binary Interface (EABI) Compliant Programs

转自:http://blog.sina.com.cn/s/blog_70dd16910100ypf2.html

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值