嵌入式ARM平台调试方法的讨论
,并在栈中开辟空间(用于局部变量或返回值)。
4、子函数完成自己的功能,恢复之前寄存器的数值(第三步备份的寄存器)并返回调用者。
因此对于每一级函数调用,C语言编译器都会在栈中生成一个固定的结构。这个结构就是传说中的“栈帧”。
4.2. 栈的结构
一图胜千言,如上结构是ARMv5的栈帧结构,对于现在我司常用的ARMv7 M系列而言,结构有点不同,但是还是可以解释如何使用栈来实现函数调用和参数、返回值的传递的。
4.3. 关于frame pointer
如上图所示,在函数执行的过程中除了SP固定指示当前的栈顶之外,还有一个FP指针,固定指定栈帧的起始位置。通过FP指针,我们就可以像遍历链表一样回溯整个调用堆栈。
但是对于FP指针的使用,在新的v7系统山是可选的,且默认情况下编译器不适用FP指针,而是根据SP寄存器间接的计算存储在栈中数据的位置。且由于每个函数使用的寄存器数量不同,使用栈的大小不同,因此根据SP查找栈帧起始位置就必须结合汇编代码。因此在不使用FP的情况下,要实现栈的回溯必须依赖对反汇编代码的分析(自行计算每个函数中对栈的使用,然后计算下一层函数的栈帧的偏移),因此就无法在设备端直接进行了。
启用栈帧时针对Cortext-M4处理器,armcc生成的代码:
编译器使用r11保存frame pointer,栈中保存有frame pointer。
;;;209
0002ae
;;;210
0002b2
0002b6
;;;211
;;;212
;;;213
;;;214
0002b8
0002ba
;;;215
0002be
0002c0
L1.706
;;;216
0002c2
0002c4
0002c6
0002c8
;;;217
0002ca
0002ce
0002d2
L1.726
0002d6
L1.728
0002d8
0002da
;;;218
;;;219
;;;220
;;;221
0002dc
0002de
;;;222
0002e0
;;;223
ENDP
不启用栈帧时针对Cortext-M4处理器,armcc生成的代码:
栈中仅有备份的通用寄存器和返回地址,并没有FP。
;;;209
00022e
;;;210
000230
;;;211
;;;212
;;;213
;;;214
000232
000234
;;;215
000238
00023a
L1.572
;;;216
00023c
00023e
000240
000242
;;;217
000244
000248
00024c
L1.592
000250
L1.594
000252
000254
;;;218
;;;219
;;;220
;;;221
;;;222
000256
;;;223
ENDP
5. 在实际项目中的应用情况
当前几种新调试方法中,第一种“出错时打印寄存器信息”已经在现有设备中得到应用。其余调试方法,经过初步的调研是可行的,但是项目进度和实现难度的综合考量,暂没有在实践中投入使用。但如果项目时间允许,我们会将实验上述集中调试方式。
Plus,最后补充一句,如上这些调试方式在当今程序的操作系统上(Linux、Windows等)已经悉数实现,但在嵌
嵌入式ARM平台调试方 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)