堆栈指针指向保留的内存

时间:2018-07-25 11:34:42

标签: c assembly embedded stack-pointer

我正在调试来自英飞凌(enter image description here汇编语言)的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),数组累加的长度为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);
}

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

1 个答案:

答案 0 :(得分:6)

由于“堆栈指针” a100xD0000600之前,并且在该平台上堆栈向下增长,并且分配给该区域的存储芯片从0xD0000000 =>开始, 0x600字节的堆栈内存可用于本地和其他函数调用(及其本地!)。

  

有人知道我在这里做错了吗?

但是您尝试分配0x9C0字节(为bc分配更多字节,除非它们以寄存器结尾,并且优化器足够聪明,不能为它们分配堆栈空间),导致超出设计的存储区域,然后首先写入指令将崩溃。实际上,如果您请求更多的字节,则可能会意外地在暂存器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变量,通过它们所属的抽象将各种数据分组,然后在没有任何动态分配的情况下在其他代码中使用这些全局变量呢?

此外,如果您要编写某种库/支持功能,请确保没有耗尽平台的所有资源,否则不清楚如何将功能与实际任务一起使用。 :)