2

我知道这个话题很模糊......所以我会试着解释一下。

我正在 IAR Workbench 中开发一个项目。我已经到了如果我添加一个新特性,比如一个简单的 if 语句,整个代码结构就会中断的地步。代码可以正常编译并下载到 8051 设备,但是在代码启动序列的中途,我失去了连接。好像发生了堆栈溢出。如果我暂停调试器,我会看到我的 XdataStack 和 IdataStack 值很低(小于 50%)并且没有要报告的堆栈溢出。

事实上,导致问题的代码甚至没有被应用程序调用。

如果我启用代码中的调试#define 常量,这一点会更加明显。启用此功能会导致将更多字符串常量内置到 UART 调试代码中。

我执行的另一个测试是在一个已经存在的函数中创建一个包含 100 个字符的数组

char hello[100];
memset(hello, 0x00, 100);

这似乎也破坏了代码。

我想知道是否有我应该查看的内存区域,看看我是否已经填满了这个设备(CC2540,闪存大小为 128Kb)

IAR 让我调查:

  • IDATA
  • XDATA
  • SFR
  • 逻辑代码
  • 代码
  • 数据
  • 数据

就我的项目配置而言:

堆栈大小:

  • 数据:0xC0
  • 数据:0x00
  • X数据:0x280

堆大小:

  • XDATA:0xFF
  • 远:0xFFF
  • Far22:0xFFF 巨大:0xFFF
4

1 回答 1

0

好像发生了堆栈溢出。

这在 8051 中是不太可能的,因为堆栈没有被大量使用。如果没有有效的间接寻址模式,它主要限于保存返回地址(由 MCU 自动管理)和保存的寄存器(主要在 ISR 中)。

我执行的另一个测试是在一个已经存在的函数中创建一个包含 100 个字符的数组 [...] 这似乎也破坏了代码。

您的代码基本上等同于: f() { static char hello[100]; ... }编译器通过覆盖管理所有这些“本地”变量,以便这 100 个字节仅在f()执行时才能安全使用。这只有在编译器可以判断在f()执行时可能会调用哪些函数时才有效。如果编译器对调用树的分析是错误的,它将导致以意想不到的方式覆盖局部变量(包括函数的参数需要太多参数来传递寄存器)。

编译器应该足够聪明,可以将main()所有 ISR 视为独立调用树的根。它很容易被计算的跳转、通过函数指针的调用以及 RTOS 中的“任务”等概念所愚弄。例如,如果您使用函数指针,则必须告诉编译器(可能作为链接器选项)所有可能从通过指针调用的函数中调用的函数。

于 2014-02-24T16:19:03.470 回答