微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式ARM平台调试方法的讨论

嵌入式ARM平台调试方法的讨论

时间:11-21 来源:互联网 点击:

,并在栈中开辟空间(用于局部变量或返回值)。

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 void GPIO_EnableOpenDrain(GPIO_PortEnum Port, uint32_t Pins)

0002ae e92d4810 PUSH {r4,r11,lr}

;;;210 {

0002b2 f10d0b08 ADD r11,sp,#8

0002b6 4602 MOV r2,r0

;;;211 PORT_MemMapPtr PortBase;

;;;212 int i;

;;;213

;;;214 PortBase = g_PortBase[Port];

0002b8 4c57 LDR r4,|L1.1048

0002ba f8543022 LDR r3,[r4,r2,LSL #2]

;;;215 for (i = 0; i < 32; ++i){

0002be 2000 MOVS r0,#0

0002c0 e00a B |L1.728

L1.706

;;;216 if (Pins & (0x01 < i)){

0002c2 2401 MOVS r4,#1

0002c4 4084 LSLS r4,r4,r0

0002c6 400c ANDS r4,r4,r1

0002c8 b12c CBZ r4,|L1.726

;;;217 PortBase->PCR[i] |= PORT_PDD_OPEN_DRAIN_ENABLE;

0002ca f8534020 LDR r4,[r3,r0,LSL #2]

0002ce f0440420 ORR r4,r4,#0x20

0002d2 f8434020 STR r4,[r3,r0,LSL #2]

L1.726

0002d6 1c40 ADDS r0,r0,#1 ;215

L1.728

0002d8 2820 CMP r0,#0x20 ;215

0002da dbf2 BLT |L1.706

;;;218 }

;;;219 }

;;;220

;;;221 return;

0002dc 46dd MOV sp,r11

0002de b082 SUB sp,sp,#8

;;;222 }

0002e0 e8bd8810 POP {r4,r11,pc}

;;;223

ENDP

不启用栈帧时针对Cortext-M4处理器,armcc生成的代码:

栈中仅有备份的通用寄存器和返回地址,并没有FP。

;;;209 void GPIO_EnableOpenDrain(GPIO_PortEnum Port, uint32_t Pins)

00022e b510 PUSH {r4,lr}

;;;210 {

000230 4602 MOV r2,r0

;;;211 PORT_MemMapPtr PortBase;

;;;212 int i;

;;;213

;;;214 PortBase = g_PortBase[Port];

000232 4c4e LDR r4,|L1.876

000234 f8543022 LDR r3,[r4,r2,LSL #2]

;;;215 for (i = 0; i < 32; ++i){

000238 2000 MOVS r0,#0

00023a e00a B |L1.594

L1.572

;;;216 if (Pins & (0x01 < i)){

00023c 2401 MOVS r4,#1

00023e 4084 LSLS r4,r4,r0

000240 400c ANDS r4,r4,r1

000242 b12c CBZ r4,|L1.592

;;;217 PortBase->PCR[i] |= PORT_PDD_OPEN_DRAIN_ENABLE;

000244 f8534020 LDR r4,[r3,r0,LSL #2]

000248 f0440420 ORR r4,r4,#0x20

00024c f8434020 STR r4,[r3,r0,LSL #2]

L1.592

000250 1c40 ADDS r0,r0,#1 ;215

L1.594

000252 2820 CMP r0,#0x20 ;215

000254 dbf2 BLT |L1.572

;;;218 }

;;;219 }

;;;220

;;;221 return;

;;;222 }

000256 bd10 POP {r4,pc}

;;;223

ENDP

5. 在实际项目中的应用情况

当前几种新调试方法中,第一种“出错时打印寄存器信息”已经在现有设备中得到应用。其余调试方法,经过初步的调研是可行的,但是项目进度和实现难度的综合考量,暂没有在实践中投入使用。但如果项目时间允许,我们会将实验上述集中调试方式。

Plus,最后补充一句,如上这些调试方式在当今程序的操作系统上(Linux、Windows等)已经悉数实现,但在嵌

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top