c - 堆栈指针指向保留的内存
问题描述
我正在调试来自 Infineon(参考汇编语言)的 Tricore TC275 上的加密实现代码。
PMI_PSPR (wx!p): org = 0xC0000000, len = 24K /*Scratch-Pad RAM (PSPR)*/
DMI_DSPR (w!xp): org = 0xD0000000, len = 112K /*Local Data RAM (DSPR)*/
在调用 mac 函数后,堆栈指针a[10]始终指向保留的内存区域。
###### typedefs ######
typedef uint16_t limb_t;
typedef limb_t gf_t[DIGITS]; //DIGITS=312
typedef int32_t dslimb_t;
################################
/**Multiply and accumulate c += a*b*/
void mac(gf_t c, const gf_t a, const gf_t b)
1: 0xC0000812: D9 AA 40 9F LEA a10,[a10]-0x9C0 //Load eff. addr.
/*Reference non-Karatsuba MAC */
dslimb_t accum[2*DIGITS] = {0};
2: 0xC0000816: 40 A2 MOV.AA a2,a10
3: 0xC0000818: D2 02 MOV e2,0x0 //move 0x0 to d2 and d3
4: 0xC000081A: C5 03 37 40 LEA a3,0x137 // 0.5*length of accum
5: 0xC000081E: 89 22 48 01 ST.D [a2+]0x8,e2 //<= fails here
6: 0xC0000822: FC 3E LOOP a3,0xC000081E
7: 0xC0000824: 40 AF MOV.AA a15,a10
###contents of relevant registers###
before after
1: a[10] D000 0600 CFFF FC40 (not definend in memory map?)
2: a[2] D000 0A06 CFFF FC40
3: d[2] 0000 0002 0000 0000
3: d[3] 0000 0000 0000 0000 (would have been set to zero too)
4: a[3] 0000 0186 0000 0137 (#of iterations in loop)
5: a[2] CFFF FC40 (store failed here)
value@CFFF FC40 ???? ???? ???? ???? (write is not allowed I guess)
0x9C0 = 2496 (base10)
并且数组 accum 的长度是624
,每个元素包含一个int32_t
. 因此624*4 = 2496 Bytes
得到分配还是什么?
但是在内存中的这个地址上,就我理解给链接器的内存映射而言,不允许写入......但是生成的汇编代码试图在第 5 行执行?
有人知道我在这里可能做错了什么吗?我还尝试使用 calloc 在堆上分配内存(而不是像上面的代码那样的堆栈,对吗?)但程序仍然崩溃。
我还将该行复制dslimb_t accum[2*DIGITS] = {0}
到程序的开头,它在没有错误的情况下执行。
非常感谢您的帮助!
编辑
mac 就是这样调用的,uniform 采样一些统一的随机数
gf_t sk_expanded[DIM],b,c;
for (unsigned i=0; i<DIM; i++) {
noise(sk_expanded[i],ctx,i);
}
for (unsigned i=0; i<DIM; i++) {
noise(c,ctx,i+DIM); //noisy elements in c after call
for (unsigned j=0; j<DIM; j++) {
uniform(b,pk,i+DIM*j); //uniform random numbers in b after call
mac(c,b,sk_expanded[j]); //fails here on first call
}
contract(&pk[MATRIX_SEED_BYTES+i*GF_BYTES], c);
}
此代码在我的主机上运行,但在我的三核微控制器上,它在第一个 mac() 函数调用中失败。
解决方案
正如“堆栈指针”a10
之前0xD0000600
一样,堆栈在这个平台上向下增长,分配给这个区域的内存芯片从0xD0000000
=> 开始,你只有 0x600 字节的堆栈内存可用于本地和其他函数调用(以及它们的本地!) .
有人知道我在这里可能做错了什么吗?
但是您正在尝试分配 0x9C0 字节(加上更多的b
and c
,除非它们以寄存器结尾,并且优化器足够聪明,不会为它们分配堆栈空间),这会导致超出设计的内存区域,并首先写入然后指令会崩溃。实际上,如果您要请求更多字节,您可能会不小心从暂存器 RAM 内部开始(结果地址非常接近0xC0000000
),然后代码将在清除数组时崩溃,一旦它离开暂存器区域。
但是生成的汇编代码试图在第 5 行做什么?
生成的代码不会检查 C 中的内存可用性,这与 C 是“不安全”的编程语言的此类问题有关,程序员 + 维护者/操作员有责任构建代码并在堆栈所在的环境中运行它有足够的空间。或者将检查添加到动态代码中,以至于在开发过程中无法评估堆栈使用情况,并且代码应该优雅地处理全堆栈情况。
我还尝试使用 calloc 在堆上分配内存(而不是像上面的代码那样的堆栈,对吗?)但程序仍然崩溃。
似乎是不同的问题,或者你也有完整的堆(来自评论“堆应该是 4k” - 这听起来像非常小的堆,也许你已经用其他动态分配耗尽了它,碎片也可能会阻止你的内存分配器返回连续有效的 3k块为您的阵列)。堆分配器往往会NULL
在其池耗尽时返回,但也许您的平台非常有限,以至于内存分配器在实现中缺少此类安全代码,以使其更小。
我还将 dslimb_t accum[2*DIGITS] = {0} 行复制到程序的开头,在该程序的开头没有错误地执行它。
然后是全局变量,它被放置到.data
类似的段中,该段被放置到足够大的内存区域中。
是的,624 个 32 位整数至少需要 2496 (624*4) 字节的内存(在 C 语言中,您通常为抽象付出零代价,因此在这种情况下,任何一块 2496 字节长的内存都需要根据您的平台需要对齐, 足以使这成为可能,在 Java 等其他语言中,此类数组的总成本要高得多,因为还有 GC 内务和数组管理数据,因此您可能可以计算出此类平台上所需的大约 3000-3500 字节)。
通常当一个人在这么多受限的系统上开发时(为本地人要求 3k 的堆栈空间在桌面/网络编程世界中听起来完全可以忽略不计,但在小型嵌入式系统或旧的 8/16 位计算机上可能会占用大量内存),它可能有助于以“数据驱动”的方式设计代码和算法,即您完全计划内存使用,包括代码驻留的位置(以及它可以有多大),局部/全局变量的位置,以及请注意运行代码的所有状态所需的最大堆栈是多少。
您可以首先检查堆栈为何如此之低-“本地数据 RAM”似乎约为 110k 大,因此您可能有足够的空间,并且在构建期间有一些选项可以调整堆栈的大小(或链接描述文件可以进行调整)。
实际上你应该检查你的整个内存消耗设计,即你真正需要在内存中拥有哪些数据,它在哪里,哪些是临时的,它们的生命周期是什么等(至少在粗略的千字节估计),并对照芯片上的物理可用内存,因此您可以了解编写代码是多么粗心,或者最终如果您的特定任务已经内存不足,甚至在开始实施之前。(您可以从检查链接器映射文件开始,查看生成了多少代码,以及.data/.bss/.rodata/etc
部分中的固定变量有多大,然后检查所有局部变量和堆分配)
然后可能会在某种结构中分配所需的内存。你甚至需要任何动态分配吗?您不能简单地.data
将代码中的整个段设计为几个全局struct
变量,通过它们所属的抽象对各种数据进行分组,并在其他代码中使用这些全局变量,而根本没有任何动态分配吗?
此外,如果您正在编写某种库/支持功能,请确保您不会耗尽平台的所有资源,否则不清楚如何将您的功能与他们的实际任务一起使用。:)
推荐阅读
- python - Python 包内导入失败
- javascript - 卸载时反应组件未运行清理功能。使用 Firestore
- asp.net - ASP 页面加载时间设备到设备
- python - 使用 configparser 从配置文件中解析数字和列表
- javascript - ChartJS 和 Flask,如何传递数据?
- android - 导航组件 currentDestination 按下后退按钮后为空
- pandas - 我如何用熊猫数据框中另一行中的值替换一行中的 NaN
- visual-studio - 如何使用 Visual Studio 在真实域上调试应用程序
- regex - 移动到子程序时,PCRE 正则表达式的行为不同
- python - 使用 PySFTP 和 putfo 上传字节