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)
__ini
tial_sp 0x200005c0 Data 0 startup_stm32f0xx.o(STACK)
从这里可以看出,堆栈已经分配好了。
堆分配使用的是malloc函数,上图找到它位于Keil库文件mc_p.l中
我的目录是D:KeilARMARMCClibarmlib
轮到法宝IDA上阵,选择malloc.o,太简单了,只有malloc/free两个函数
汇编图形界面如下:
手头的IDA没有ARM插件,否则一个F5就可以得到malloc的C源代码。
好好工作赚钱卖ARM插件吧。。。
没有工具辅助,那就自己来写吧!
上面是手工写的C代码,被注释的是最原始的汇编写法,然后逐步精简优化。
大概摸清楚了malloc的机制,关键点在于初始化那里,用到了__heap_limit
而__heap_limit作为常量被编译到Flash里面去了,内存里面无法动态修改。
实在没办法,只好字节写代码来接替它初始化整个堆了。
- 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;
- }