aaa1982 发表于 2011-2-20 14:21:05

关于MIPS调用栈的打印问题,请教FFXX及各位高手

看了一篇关于MIPS调用栈的文章觉得不错,主要是讲对于GCC 的O2级别优化的时候会不使用mips的FP寄存器,在这种情况下应该怎么打印调用栈。

文章出处:
http://blog.csdn.net/jerryutscn/archive/2010/03/10/5365263.aspx

我对不优化的时候怎么打印调用栈还有一些问题,但是没办法给博主留言,放到这里请教一下大家,希望高手能帮忙解释一下。


就算用了O0的优化级别,下面的程序

   400e0c: 3c1c0fc0 luigp,0xfc0

400e10: 279c79b4 addiu    gp,gp,31156

400e14: 0399e021 addu gp,gp,t9

400e18: 27bdffd8 addiu    sp,sp,-40

400e1c: afbc0010 sw   gp,16(sp)

400e20: afbf0020 sw   ra,32(sp)

400e24: afbe001c sw   s8,28(sp)

400e28: afbc0018 sw   gp,24(sp)

400e2c: 03a0f021 move s8,sp

400e30: afc40028 sw   a0,40(s8)

400e34: afc5002c sw   a1,44(s8)

我想问当在这个函数里面想查看调用栈的时候,所有寄存器的信息都是放在 栈底 固定位置的,而SP和FP都指向了 栈顶 位置,我们怎么知道从哪里去取那些上一级函数的寄存器的值呢?或者说我们怎么知道开始那个移动sp的立即数是多少呢(addiu sp,sp,-40)?

我一直按照x86的ebp esp来理解 fp和sp的,但是现在觉得不对。

请帮忙讲讲我哪里理解错了,谢谢

aozima 发表于 2011-2-20 16:01:48

楼主链接里面的文章不错,有空细看.

但对楼主的问题,没有明白,楼主需要做什么?

aaa1982 发表于 2011-2-20 16:16:43

感谢 回复

问题是怎么在mips架构下面打印调用栈,就是在程序出现异常的时候,或者在打断言的时候希望把出错误程序的调用关系打印出来。

引用那篇文章主要讲的就是mips结构下面怎么得到调用栈的问题

这是里面的一个问题
How to traceback call stack on MIPS arch?
Gcc saves the frame pointer to fp(s8) register at the beginning of each function if compiling source with -O0. Butit won't do so if compiling source with -O2. Without frame pointers, can I trace back call stacks in current function context? Or is there any option which forces gcc to save frame pointers for MIPS arch?
大概意思是如果采用O2优化,编译完成的程序会不使用FP(S8),这样该如何traceback 的问题 。



可是我想问的问题是就算用了O0优化,也就是就算用了FP,我也没弄清楚怎么才能得到调用栈(也就是怎么才能traceback)。主要的问题就在上面的帖子里面。

ffxz 发表于 2011-2-21 21:29:10

有了FP就可以做栈回溯了,这个需要看相关指令构架的过程调用标准。类似于ARM指令,它也有一个这样的东西。

但是用了FP,那么栈就会需要更多,所以当做优化时(或为了体积考虑时,例如thumb/thumb2),这个时候FP就不再使用了,这样的话要做栈回溯就比较困难了。

aaa1982 发表于 2011-2-21 22:40:52

文章也是这个意思,我也觉得应该是这个意思。但是您看这个程序

400e18: 27bdffd8 addiu    sp,sp,-40

400e1c: afbc0010 sw   gp,16(sp)

400e20: afbf0020 sw   ra,32(sp)

400e24: afbe001c sw   s8,28(sp)


每个函数开头的移动SP的立即数都是不一样的(比如这里面的-40),而存储FP的地址都是相对于移动以后的SP的地址(这里面是28)

看了几个函数,相对固定的是距离SP移动前的值的位置(估计这也是规范规定的),也就是说所有函数的FP都存在这个新开辟的内存空

间里面距离顶端12个字节的位置。

但是我想问,在程序中想打印调用栈的时候,无论是FP还是SP都已经移动了一个立即数了,这个数的大小肯定是没有规律的,你也就没

办法知道新开辟的堆栈空间的顶端在哪个位置,那你怎么能找到FP的值呢?

ffxz 发表于 2011-2-22 12:52:22

MIPS的帧回溯还真没研究过,

说说ARM的,ARM的仅指ARM指令部分,THUMB指令部分没这个东西。

ARM上把几个寄存器重命名了:
R14         lr
R13         sp
R11         fp

这三个寄存器在每次做标准过程调用时都需要最后压栈,即压入栈的最底端。每次标准过程调用时,压入栈的部分称为一帧。一帧的最底端就是上面的三个寄存器。

然后当前运行时,fp寄存器要么是0(当前过程无被调用),要么指向最后的一个帧。通过这样,将在栈上面建立一个帧的链表,而链表的表头则是当前的fp寄存器指向。ARM指令的在RT-Thread的arm\common目录下有实现相应的栈回溯代码,可以配合参考一起看。

aaa1982 发表于 2011-2-22 23:03:49

感谢ffxx 详细的解释 !!!

还有以下问题

不知道thumb2指令集和arm的一样不一样。

随便找了一个cortex-m3 函数调用的例子(thumb2和arm不一样么? 我没看见保存sp和FP的值啊,而且我已经是O0优化了)。

0x00002320 E92D4FF7PUSH   {r0-r2,r4-r11,lr}    //这里怎么没保存SP的值啊?而却也没看到保存FP的值,这样可怎么traceback呀
0x00002324 B082      SUB      sp,sp,#0x08
0x00002326 4604      MOV      r4,r0
0x00002328 460D      MOV      r5,r1
   553:          unsigned short cnt,total_cnt=0,xtra,alloced=0;
   554:          BYTE i;
   555:          char ret;
   556:          dir_entry* entry;
0x0000232A 2700      MOVS   r7,#0x00
0x0000232C 2000      MOVS   r0,#0x00
0x0000232E 9000      STR      r0,
   557:         if(!f->isopen || !count) return 0;      // 文件没打开或数据量为0
0x00002330 7F20      LDRB   r0,
0x00002332 B108      CBZ      r0,0x00002338
0x00002334 9804      LDR      r0,
0x00002336 B918      CBNZ   r0,0x00002340
0x00002338 2000      MOVS   r0,#0x00

【引用】这三个寄存器在每次做标准过程调用时都需要最后压栈,即压入栈的最底端。每次标准过程调用时,压入栈的部分称为一帧。一帧的最底端就是上面的三个寄存器。

有以下问题想请教

1 请问到底什么是帧,从上面的程序看,是说PUSH   {r0-r2,r4-r11,lr} 压入的 r0-r2,r4-r11,lr叫一帧还是说整个为这个函数开辟的堆栈空间(r0-r2,r4-r11,lr加上后面为局部变量开辟的8个字节)叫一帧。(应该是前面的叫一帧吧)

2 根据理解和您上面讲的,应该有一个帧指针指向PUSH   {r0-r2,r4-r11,lr}以后SP的值(我这种理解对么?)但为什么从程序里面看不到呢?thumb2 怎么traceback呢?

3 您能提供一个类似上面的例子么 ,可以看到保存SP和FP的?

问题有点基础,希望ffxx能不吝赐教。感谢

ffxz 发表于 2011-2-23 06:54:06

我上面也说了,thumb是没有这个东西的,所以在thumb下搞这个东西比较困难。当然thumb也有它的特点,即压入栈的函数调用(或回溯地址)是奇地址,那么奇地址 + 在代码段内,能够近似的获得回溯调用关系。

你可以找个ARM模式的看看,例如AT91SAM7、s3c2440等。

BTW, my name is ffxz.

aaa1982 发表于 2011-2-23 22:12:55

真不好意思哈 ffxz。



我用的是MDK3.8 没找到相关的例子,

我这里有一个svn的分支http://rt-thread.googlecode.com/svn/branches/rtt_0_3_1 取下来的代码,看bsp目录里面有一个mini2440,但是打不开工程啊,现在这个分支也更新不了了。

请问现在最新分支的地址是多少呢? 看了一下置顶的帖子没找到。


感谢

ffxz 发表于 2011-2-24 09:12:29

是这个地址:http://rt-thread.googlecode.com/svn/trunk

不过mini2440都无配套的工程文件(不知道现在svn上自动生成的工程文件是否能够编译通过),用mini2440还是使用命令行编译吧
页: [1]
查看完整版本: 关于MIPS调用栈的打印问题,请教FFXX及各位高手