堆栈指针指向保留内存

Stack Pointer points to reserved Memory

我正在 Infineon(reference 汇编语言)的 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是这样调用的,均匀采样一些均匀的随机数

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);
}

此代码在我的主机 machine 上运行,但在我的三核微控制器上它在第一个 mac() 函数调用中失败。

由于"stack pointer"a10之前是0xD0000600,而本平台栈向下增长,分配给该区域的内存芯片从0xD0000000开始=>您只有 0x600 字节的堆栈内存可用于局部变量和其他函数调用(及其局部变量!)。

Does anybody know what I might be doing wrong here?

但是您正在尝试分配 0x9C0 字节(加上 bc 的更多字节,除非它们以寄存器结尾,并且优化器足够聪明,不会分配堆栈 space 对他们来说),这会导致超出设计的内存区域,并且首先写入指令然后会崩溃。实际上,如果您请求更多字节,您可能会不小心从暂存器 RAM 开始(结果地址非常接近 0xC0000000),然后代码会在清除数组时崩溃,一旦它离开了暂存区-焊盘面积。

But the generated assembly code tries to do in line 5?

生成的代码不检查 C 中的内存可用性,与此类问题相关的 C 是 "unsafe" 编程语言,程序员 + maintainer/operator 有责任构建代码并且 运行 它在堆栈有足够 space 的环境中。或者在动态代码中添加检查,以至于无法在开发期间评估堆栈使用情况,并且代码应该优雅地处理全堆栈情况。

I also tried to use calloc to allocate memory on the heap (instead of the stack like the code above does right?) but the programm still crashed.

似乎是不同的问题,或者您也有完整的堆(来自评论 "heap should be 4k" - 这听起来像非常小的堆,也许您已经用其他动态分配耗尽了它,而且碎片可能会阻止您的内存分配器return 数组的连续有效 3k 块)。堆分配器倾向于 return NULL 当他们的池耗尽时,但也许你的平台非常有限,以至于内存分配器在实现中缺少这样的安全代码,以使其更小。

I also copied the line dslimb_t accum[2*DIGITS] = {0} to the start of the program where it was executed without an error.

然后是全局变量,被放入.data类段,被放入足够大的内存区

是的,624 个 32 位整数至少需要 2496 (624*4) 字节的内存(在 C 语言中,您通常为抽象支付零价格,因此在这种情况下,任何一块 2496 字节长的内存,即根据您的平台要求对齐,足以使这成为可能,在 Java 等其他语言中,此类阵列的总成本要高得多,因为还有 GC 内务管理和阵列管理数据,因此您可能可以数出大约 3000这种平台需要 -3500 字节)。


通常当一个人在如此多的受限系统上开发时(要求 3k 堆栈 space 对于本地人来说听起来在 desktop/web 编程世界中完全可以忽略不计,但在小型嵌入式系统或旧 8 /16 位计算机可能会占用大量内存),它可能有助于以 "data driven" 方式设计代码和算法,即您完全计划内存使用,包括代码所在的位置(以及它可以有多大) ),local/global 变量所在的位置,并了解通过代码的所有状态 运行 所需的最大堆栈是多少。

您可以首先检查为什么堆栈如此之低 - "local data RAM" 似乎有 ~110k 大,所以也许您那里有足够的 space,并且在构建过程中有一些选项调整堆栈大小(或可以调整链接描述文件)。

实际上你应该检查你的整个内存消耗设计,即你真正需要在内存中有哪些数据,它在哪里,哪些是临时的,它们的生命周期是多少,等等(至少粗略估计千字节),并根据芯片上的物理可用内存进行检查,这样您就可以了解您编写代码的粗心程度,或者最终您是否已经超出了您的特定任务的内存,甚至在实施开始之前。 (您可以从检查链接器映射文件开始,查看生成了多少代码,以及 .data/.bss/.rodata/etc 部分中的固定变量有多大,然后检查所有局部变量和堆分配)

然后可能会在某种结构中分配所需的内存。你甚至需要任何动态分配吗?难道你不能简单地将代码中已有的整个 .data 段设计为几个全局 struct 变量,根据它们所属的抽象对各种数据进行分组,并在其他代码中使用这些全局变量,而无需任何动态分配完全没有?

此外,如果您正在编写某种 library/support 函数,请确保您没有耗尽平台的所有资源,否则不清楚人们将如何在实际任务中使用您的功能。 :)