您的位置:首页 > 其它

Keil的堆设置

2016-05-24 15:40 302 查看
【原文
使用Keil的MicroLIB时自动设置堆大小】

Keil编译项目,如果使用微库MicroLIB,就可以使用malloc。微库内部位置一个堆管理模块。

芯片的RAM大小是固定了的,前面分为全局变量,后面分给堆和栈,这是一般开发方式。

但是我们在开发项目的过程中,市场遇到各种各样问题,栈穿透到堆里面,或者堆不够大,相当烦人!

有时候就在想,何不让全局变量以外的所有RAM给堆栈共用?

因为堆从低到高分配,而栈从高到低分配,理论上是可行的!

但是堆的分配由__heap_base和__heap_limit两个标签决定,不是变量又不能改!

因为我们使用很多种芯片,每一种芯片的RAM大小都有可能不同。

而SmartOS追求跨平台,不想为不同芯片做太多设置。

之前我们已经实现了通过修改MSP把栈顶移到RAM最高处,这样子栈可以得到最大利用!

但是堆还是不好搞!

今晚再次遇到堆不够用的情况,__heap_limit如果分配过大,在小容量芯片就会出错。

忍无可忍,决定分析一下微库是怎么管理堆的。

首先打开项目编译后生成的链接地址映射文件Linker Address Map,我们这里是SmartOSF0_Debug.map

找到符号表段Global Symbols

    __heap_base                              0x200005a0   Data           0  startup_stm32f0xx.o(HEAP)

    __heap_limit                             0x200005a0   Data           0  startup_stm32f0xx.o(HEAP)

    __initial_sp                             0x200005c0   Data           0  startup_stm32f0xx.o(STACK)

从这里可以看出,堆栈已经分配好了。



堆分配使用的是malloc函数,上图找到它位于Keil库文件mc_p.l中

我的目录是D:\Keil\ARM\ARMCC\lib\armlib

轮到法宝IDA上阵,选择malloc.o,太简单了,只有malloc/free两个函数

汇编图形界面如下:





手头的IDA没有ARM插件,否则一个F5就可以得到malloc的C源代码。

好好工作赚钱卖ARM插件吧。。。

没有工具辅助,那就自己来写吧!





上面是手工写的C代码,被注释的是最原始的汇编写法,然后逐步精简优化。

大概摸清楚了malloc的机制,关键点在于初始化那里,用到了__heap_limit

而__heap_limit作为常量被编译到Flash里面去了,内存里面无法动态修改。

实在没办法,只好字节写代码来接替它初始化整个堆了。

我写的初始化代码如下:



附上malloc/free代码,不完整,只能大概了解它的机制:

void free(void* p) {     if(!p) return 0;          r3 = __microlib_freelist;     void* r2 = 0;     p -= 4;     void* r1 = *r3; // r1 = r3->node     while(r1)     {         if(r1 > p) break;         r2 = r1;         r1 = *(r1 + 4); // r1 = r1->next     }     if(!r2)         r3->node = p;     else     {         r3 = *r2;         r4 = p - r2;         if(r4 != r3)             *(r2 + 4) = p;         else         {             p = *p;             p += r3;                      }     } } typedef struct {     uint size;     void* next; } Node; __microlib_freelist:     Node* _freelist; __microlib_freelist_initialised:     int _freelist_initialised = 0; void* malloc(int size) {     /*r0 += 0x0b;     r0 >>= 3;     r0 <<= 3;*/     r1 = (size + 11) & 0xFFFFFFF8;     r7 = __microlib_freelist_initialised;     r6 = 0;     /*r2 = __microlib_freelist;     if(!*r2 && !*r7)*/     if(!_freelist && !_freelist_initialised)     {         /*r2 = __microlib_freelist;         r0 = __heap_base + 4;         *r2 = r0;         r2 = __heap_limit;         r2 -= r0;         r2 &= 0xFFFFFFF0;         *r0 = r2;         *(r0 + 4) = 0;         *r7 = 1;*/         _freelist = (Node*)(__heap_base + 4);         _freelist->size = (__heap_limit - __heap_base - 4) & 0xFFFFFFF8;         _freelist->next = 0;         _freelist_initialised = 1;     }     //r2 = __microlib_freelist;     r0 = _freelist;     while(true)     {         /*r0 = *r2;         if(!r0)         {             r0 = r6;             break;         }*/         //r0 = *r2;         if(!r0) return 0;         //r3 = *r0;         r3 = r0->size;         if(r3 <= r1) break;                  //r2 = r0 + 4;         //r2 = r0->next;         r0 = *(r0->next);     }     if(r3 <= r1)     {         //r3 = *(r0 + 4);         /*r3 = _freelist->next;         *r2 = r3;*/         _freelist->size = r1;         _freelist = _freelist->next;         return &;     }     else     {         /*r4 = r3 - r1;         r3 = r0 + r1;         r5 = *(r0 + 4);         *r3 = r4;         r3 +=4 ;         *(r3 + 4) = r5;         r3 +=4 ;         r3 -= 8;// 减8为了回到r3开始*/                  Node* lst = (void*)_freelist + r1;         lst->size = _freelist->size - r1;         lst->next = _freelist->next;                  _freelist->size = r1;         _freelist = lst;                  return &lst->next;     }          return r0; }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: