VxWorks函数栈帧剖析

VxWorks任务内存地址空间布局

VxWorks系统中,所有Tasks(包括系统任务和用户任务)都工作在特权模式,共享所有内存。A任务可以直接访问B任务的内存地址空间而不会触发任何“异常”。下图为单个任务的内存地址空间布局,任务ID(Task ID)分割任务控制块(TCB)和任务栈,任务栈中压栈函数栈帧,从高地址向低地址增长。

首先,我们查看任务列表

-> i

  NAME        ENTRY       TID    PRI   STATUS      PC       SP     ERRNO  DELAY
---------- ------------ -------- --- ---------- -------- -------- ------- -----
^@tExcTask   excTask      87df85b0   0 PEND       8178f244 87df8490   3006b     0
tLogTask   logTask      87df5a00   0 PEND       8178f244 87df58e8       0     0
tCPUIdlCaptmeasureCPUId 57beefb0   1 DELAY      8173ad78 57beef28       0    17
tShell     shell        878aea90   1 READY      8173c008 878ae6a8       0     0
active_shelshell_task   57b5ac40   2 PEND       80168bec 57b5abc8       0     0
tWdbTask   wdbTask      878d1700   3 PEND       80168bec 878d1470  3d0002     0
Timer      8175f730     57bed110   5 DELAY      8173ad78 57bed088       0    55
keep_alive 810f90a4     5ee7e900   6 PEND       8178f244 5ee7e1b8       0     0
oind       810f829c     5eeaf260   7 PEND+T     80168bec 5eeaef08  3d0002    30
hind       810f8d64     5ee9eea0   8 PEND       8178f244 5ee9e1d0  3d0002     0
Co00       810f960c     5ee6e630   9 PEND       8178f244 5ee6e4f0  3d0002     0

我们以Timer为例,分析函数栈帧结构

-> ti Timer
^@
  NAME        ENTRY       TID    PRI   STATUS      PC       SP     ERRNO  DELAY
---------- ------------ -------- --- ---------- -------- -------- ------- -----
Timer      8175f730     57bed110   5 DELAY      8173ad78 57bed088       0    22

stack: base 0x57bed110  end 0x57beb110  size 8176   high 292    margin 7884 

options: 0xc
VX_DEALLOC_STACK    VX_FP_TASK          

VxWorks Events
--------------
Events Pended on    : Not Pended
Received Events     : 0x0
Options             : N/A

$0    =        0   t0    =        0   s0    =        0   t8    =        0
at    =        0   t1    =        0   s1    =        0   t9    =        0
v0    =        0   t2    =        0   s2    =        0   k0    =        0
v1    =        0   t3    =        0   s3    =        0   k1    =        0
a0    =        0   t4    =        0   s4    =        0   gp    = 82d6cba0
a1    =        0   t5    =        0   s5    = 57bed110   sp    = 57bed088
a2    =        0   t6    =        0   s6    =       3c   s8    = 57bed0d0
a3    =        0   t7    =        0   s7    = 832bb500   ra    =        0
divlo =        0   divhi =        0   sr    = 1000fc01   pc    = 8173ad78
value = 0 = 0x0

从上面可以看出,tLogTask任务的栈空间为0x57bed110~0x57beb110地址段,栈顶指针SP值为0x57bed088。

继续查看函数调用栈

-> tt Timer
^@80169604 vxTaskEntry    +c  : TmrStopTimer (0, 0, 0, 0)
8175f768 TmrStopTimer   +410: taskDelay (eeeeeeee, eeeeeeee, eeeeeeee, eeeeeeee)
value = 0 = 0x0

此处,分析TmrStopTimer函数的栈帧

-> l TmrStopTimer,20
^@                      TmrStopTimer:
0x8175f358  27bdffd8    addiu           sp,sp,65496(-40)                   // sp = sp - 40
0x8175f35c  afbf0024    sw              ra,36(sp)                          // [sp + 36] = ra
0x8175f360  afbe0020    sw              s8,32(sp)                          // [sp + 32] = s8
0x8175f364  03a0f025    move            s8,sp                              // s8 = sp
0x8175f368  afc40028    sw              a0,40(s8)                          // [s8 + 40] = a0   第一个参数
0x8175f36c  afc5002c    sw              a1,44(s8)                          // [s8 + 44] = a1   第二个参数
0x8175f370  8fc20028    lw              v0,40(s8)                          // v0 = [s8 + 40]
0x8175f374  afc20014    sw              v0,20(s8)                          // [s8 + 20] = v0
0x8175f378  afc00010    sw              zero,16(s8)                        // [s8 + 16] = 0
0x8175f37c  3c0282ca    lui             v0,0x82ca
0x8175f380  8c422088    lw              v0,8328(v0)
0x8175f384  10400008    beqz            v0,0x8175f3a8
0x8175f388  00000000    nop     
0x8175f38c  3c0482ca    lui             a0,0x82ca
0x8175f390  8c842088    lw              a0,8328(a0)
0x8175f394  2405ffff    li              a1,65535
0x8175f398  0c05a189    jal             semTake
0x8175f39c  00000000    nop     
0x8175f3a0  085d7ced    j               0x8175f3b4
0x8175f3a4  00000000    nop     
value = -2122976344 = 0x8175f3a8 = TmrStopTimer + 0x50

第一行指令表示把栈顶指针sp下移40个字节,表示TmrStopTimer函数的栈帧大小为40字节。

如上所示,TmrStopTimer函数栈帧的底部压栈返回地址ra和返回函数的栈顶指针。

对于叶子函数(不调用其他函数的函数),可能不会压栈ra,因为ra寄存器值不会被改写。此外,编译器的优化选项-O指定的优化级别,也会影响栈帧结构。

打印从sp~s8地址空间的栈数据:

-> d 0x57bed088,20,4
^@57bed080:                    eeeeeeee eeeeeeee   *            ....*
57bed090:  57bed098 8175f834 82eaa780 0000001d   *W....u.4........*
57bed0a0:  eeeeeeee eeeeeeee 0000000f 00000001   *................*
57bed0b0:  0000001d 82eaaff8 eeeeeeee 8175f770   *.............u.p*
57bed0c0:  00000000 00000000 00000000 57bed0d0   *............W...*

可以看到,s8为0x57bed0d0,ra为0。(此处有点诡异,居然是反的,有可能函数汇编代码中移位了sp指针,待商榷)

原文地址:https://www.cnblogs.com/justin-y-lin/p/15750608.html