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

End.

                             转石头大哥

使用Keil的MicroLIB时自动设置堆大小——玩嵌入式以来最高难度的更多相关文章

  1. Unity3D 导入贴图、模型等资源文件时自动设置参数

    脚本继承至AssetPostprocessor, 存放在Editor目录下! using UnityEngine; using System.Collections; using UnityEdito ...

  2. java 中 SVN 设置所有文件及子目录 needs-lock, svn 提交时自动设置 needs-lock, 及版本不一致问题

    摘自: http://my.oschina.net/zhangzhihao/blog/72177 设置后的效果:文件会自动带上svn:needs-lock属性,默认是只读的要签出才能修改以防止修改完后 ...

  3. 自动设置iframe大小的jQuery代码

    自动设置iframe的宽度,如何用jquery来实现呢? 代码: <iframe src="main_folder.aspx" class="global_main ...

  4. java -jar 运行springboot项目时内存设置

    java -Xms64m #JVM启动时的初始堆大小 -Xmx128m #最大堆大小 -Xmn64m #年轻代的大小,其余的空间是老年代 -XX:MaxMetaspaceSize=128m # -XX ...

  5. Hadoop作业JVM堆大小设置优化 [转]

    前段时间,公司Hadoop集群整体的负载很高,查了一下原因,发现原来是客户端那边在每一个作业上擅自配置了很大的堆空间,从而导致集群负载很高.下面我就来讲讲怎么来现在客户端那边的JVM堆大小的设置.我们 ...

  6. T450设置插入USB鼠标时自动禁用触摸板

    刚入手T450,打字时经常碰到触摸板,很是恼火,于是求助万能的度娘,找了卡饭基佬的教程,实测可行,大家可以试试.<win7下如何设置插入USB鼠标时自动禁用触摸板>,地址:www.kafa ...

  7. DEDECMS织梦全站动态化访问(包括自由列表freelist)及发布内容时自动动态化设置

    DEDECMS织梦 - 全站已有内容全部设置为动态化访问(包括自由列表freelist),以及发布内容时自动为动态化,设置分为三个步骤: 1.将所有文档设置为“仅动态”:执行以下mysql语句:upd ...

  8. [UE4]工程设置:自动捕获鼠标、通过代码设置鼠标显示隐藏、输入模式、编译时自动保存

    一.在4.20版本中运行游戏,在没有进行任何设置的情况下,游戏不会自动捕获鼠标,游戏不会接受输入,需要手动点一下游戏界面才行.如果要跟老版本一样运行游戏自动捕获鼠标,需要进行设置 二.也可以通过代码的 ...

  9. 设置Myeclipse中的代码格式化、注释模板及保存时自动格式化

    1:设置注释的模板: 下载此模板:  codetemplates.xml 搜索Dangzhang,将其改为你自己的姓名,保存 打开eclipse/myeclipse选择 window-->Pre ...

随机推荐

  1. 2-sat 输出任意一组可行解&拓扑排序+缩点 poj3683

    Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8170   Accept ...

  2. zjuoj 3610 Yet Another Story of Rock-paper-scissors

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3610 Yet Another Story of Rock-paper-sc ...

  3. CCF真题之Z字形扫描

    201412-2 问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan).给定一个n×n的矩阵,Z字形扫描的过程如下图所示: 对于下面的4×4的矩阵, 1 5 ...

  4. paper 40 :鲁棒性robust

    最近只想安心.安静的科研,不想被任何人打扰,继续做自己,不忘初心,方得始终! 首先了解下鲁棒性这个词的定义.鲁棒性是指控制系统在一定(结构,大小)的参数摄动下,维持某些性能的特性.根据对性能的不同定义 ...

  5. VS2013中的快捷键

    在VS2012中Ctrl+E+D 是对齐代码,然而在VS2013中变成了Ctrl+K+F #region的快捷键 Ctrl+K+S /// <summary> 快捷键 先写好函数或方法,然 ...

  6. HTML5的自定义属性data-* 的用法解析

    人们总喜欢往HTML标签上添加自定义属性来存储和操作数据.但这样做的问题是,你不知道将来会不会有其它脚本把你的自定义属性给重置掉,此外,你这样做也会导致html语法上不符合Html规范,以及一些其它副 ...

  7. yii2多语言设置

    yii2的多语言切换功能 1.页面添加语言切换按钮,如下图: 代码如下: <ul>       <li>           <a href="javascri ...

  8. UIViewController卸载过程(ios6.0以后)

    在ios6.0以后,废除了viewWillUnload方法和viewDidUnload方法. 在ios6以后,当收到didReceiveMemoryWarning消息调用之后,程序会自动调用didRe ...

  9. ch1:python3 查看版本号、安装目录和工作空间目录

    查看python版本: 每次打开python顶端会显示版本号 在程序中判断版本号可以通过import sys  sys.version 在dos下可以通过python -V查看 安装目录:C:\Pyt ...

  10. 创建laravel项目时打开浏览器常见错误

    1.Whoops, looks like something went wrong. 打开:D:\java\wamp\www\subway\app\config\app.php 修改:'debug' ...