我正在使用 IAR EWARM IDE 和编译器为 Cortex-M3 嵌入式微控制器 (Atmel SAM3S) 开发软件。我怀疑由于某种原因,我有缓冲区溢出或内存泄漏,导致堆栈损坏,因为我突然发现自己卡在了代码空间之外。
我问这个问题的原因是,很难找出究竟是什么导致了这个混乱,我想知道当你想找出问题的原因时你使用了哪些技术。
您是否使用内存调试器、在线跟踪调试硬件等?
您应该尝试使用金丝雀值。基本上就是这样 - 假设你有一些struct
:
struct foo {
unsigned long bar;
void * baz;
};
修改它,使它看起来像这样:
struct foo {
unsigned long canary1;
unsigned long bar;
void * baz;
unsigned long canary2;
};
初始化 时struct
,将一些任意值放入canary1
和canary2
中。每当您对 进行一些操作时struct
,请检查值是否保持不变。这样,如果您有缓冲区溢出或堆栈粉碎,您将检测到它。您可以使用自动变量执行相同的内部函数:
int foo(int bar) {
unsigned long canary1 = 0xDEADBABE;
char baz[20];
unsigned long canary2 = 0xBAD0C0DE;
...
}
等等。不要忘记在您之前检查这些值是否保持不变return
。此外,如果您可以让代码始终跳转到同一位置,请尝试将一些代码放在那里(或断点)并获取堆栈跟踪。
GCC 知道如何自己添加这些金丝雀值,但我不知道您的编译器是否可以这样做。但你仍然可以手动完成。
程序计数器是一个寄存器,因此它不能被“覆盖”。正如您所说,可能发生的情况是堆栈被覆盖,然后您执行返回指令,该指令从堆栈中读取无效的返回地址,从而导致跳转到 la-la-land。
我最喜欢的调试方法是打印出来,当然这在嵌入式目标上可能很困难。第二好的方法是逐步检查可疑的例程。
您还应该调查已知会导致跳转的事物,例如中断服务例程。
我在 STM32 上使用 IAR EWARM 时遇到了类似的问题。内存转储、反汇编、金丝雀,都一无所获。最后回滚到 EWARM 的早期版本,问题就消失了。我向 IAR 支持发送了一条消息,但从未收到回复。抱歉,我不记得这是哪个版本的 EWARM。这是之前的几个项目。
我会保持一个内存窗口打开并首先尝试金丝雀测试。如果它仍然随机跳出代码空间,请尝试安装旧版本的 EWARM。
我可以补充的一件事是,对于 ARM 芯片,某处可能存在 BL 而不是 BX 或 BLX,从而导致芯片进入错误的 Thumb/ARM 模式。不像后来的芯片那么常见,但仍然......
当我发现无处跳转时,我会寻找错误的函数指针表、任何中断向量表的覆盖,以及是最容易测试的堆栈溢出。将已知字节值放入您的堆栈区域,当崩溃发生时,查看调试器还剩下多少堆栈。如果没有,那就去吧。
我也会按照标准查看过去 X 天的内容发生了什么变化,以尝试隔离任何问题。最后,只需从代码中 printf 尝试缩小错误跳转发生的位置。如果您可以将其归结为一两个函数,您可以跟踪汇编程序并很快查看它是编译器问题、内存问题还是中断问题。祝你好运!