zoukankan      html  css  js  c++  java
  • Zephyr libc简介和malloc分析【转】

    转自:https://lgl88911.gitee.io/2019/10/29/Zephyr-libc%E7%AE%80%E4%BB%8B%E5%92%8Cmalloc%E5%88%86%E6%9E%90/

    本文简要介绍Zephyr的标准C库,并基于nrf52832分析malloc的heap来源。

    本文只对开启了用户模式(CONFIG_USERSPACE)的情况进行分析,未开启的情况也大致相似,只是heap所在section会有所变化

    标准C库

    zephyr支援下面2种标准C库:

    • minimal: 由zephyr实现的libc库
    • newlib: 由编译工具链提供的libc库

    minimal libc

    minimal libc库是zephyr提供源代码,部分实现了常用的标准C函数,代码路径为zephyr/lib/libc/minimal,可以从下图大致看到minimal libc支援那些标准C API:
    minimal
    与minimal libc配置有关的是下面两项

    • CONFIG_MINIMAL_LIBC_LL_PRINTF: printf支援%L,也就是long long的格式化打印
    • CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE:malloc 使用heap的大小,如果不配置,无法使用malloc函数

    zephyr默认情况下使用minimal libc, minimal libc在cortex-m4下只占用6K的size
    m_size

    newlib

    Newlib是一个面向嵌入式系统的C运行库, 在arm提供的交叉编译工具集下面就包含了newlib的发行库,zephyr的lib/libc/newlib/libc-hooks.c中实现了newlib的桩函数,完成了对newlib的移植。
    zephyr链接的时候会链接newlib的libm,libc,libgcc,因此这里面的函数在zephyr都可以用。
    当配置了CONFIG_NEWLIB_LIBC=y后zephyr就使用newlib的标准C函数,和newlib配置相关的有下面几项

    • CONFIG_NEWLIB_LIBC_FLOAT_PRINTF 在链接时加-u_printf_float, 支持printf浮点输出
    • CONFIG_NEWLIB_LIBC_FLOAT_SCANF 在链接时加-u_scanf_float, 支持scanf浮点输入
    • CONFIG_NEWLIB_LIBC_NANO 使用-specs=nano.specs进行编译链接,让导入的newlib更小
    • CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE 指定malloc使用heap的大小,同时会改变heap的位置,后文详述

    malloc heap

    这里并不说明malloc实现的具体算法,只是对比看一下minimal和newlib在heap alloc上的差异

    minimal malloc

    实现

    minimal 的malloc实现的代码在zephyr/lib/libc/minimal/source/stdlib/malloc.c下,可以从代码看出malloc是直接依赖于sys_mem_pool_alloc对heap的管理

    void *malloc(size_t size)
    {
    void *ret;

    ret = sys_mem_pool_alloc(&z_malloc_mem_pool, size);
    if (ret == NULL) {
    errno = ENOMEM;
    }

    return ret;
    }

    heap

    heap的定义如下

    K_APPMEM_PARTITION_DEFINE(z_malloc_partition);
    #define POOL_SECTION K_APP_DMEM_SECTION(z_malloc_partition)

    //heap z_malloc_mem_pool被放在z_malloc_partition
    SYS_MEM_POOL_DEFINE(z_malloc_mem_pool, NULL, 16,
    CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE, 1, 4, POOL_SECTION);

    由K_APP_DMEM_SECTION产生的section会被放到app_smem section中,过程简要如下:

    #define K_APP_DMEM_SECTION(id) data_smem_##id##_data  --> z_malloc_mem_pool 在section data_smem_*中

    //下面过程说明app_smem的产生
    zephyr/include/arch/arm/cortex_m/scripts/linker.ld #include <app_smem.ld>
    zephyr/include/linker/app_smem.ld #include <app_smem_aligned.ld>
    zephyr/include/linker/app_smem_aligned.ld APP_SMEM_SECTION()
    zephyr/include/linker/linker-defs.h #define APP_SMEM_SECTION() KEEP(*(SORT("data_smem_*")))

    脚本/home/frank/work/project/westz/zephyr/scripts/gen_app_partitions.py将上面信息解析后生成连接脚本build/zephyr/include/generated/app_smem_aligned.ld可以看到app_smem中包含了z_malloc_partition

    SECTION_PROLOGUE(_APP_SMEM_SECTION_NAME,,)
    {
    APP_SHARED_ALIGN;
    _app_smem_start = .;

    /* Auto generated code do not modify */
    SMEM_PARTITION_ALIGN(z_data_smem_z_malloc_partition_bss_end - z_data_smem_z_malloc_partition_part_start);
    z_data_smem_z_malloc_partition_part_start = .;
    KEEP(*(data_smem_z_malloc_partition_data))

    z_data_smem_z_malloc_partition_bss_start = .;
    KEEP(*(data_smem_z_malloc_partition_bss))

    因此可知minimal malloc使用的heap被放在app_smem section中。在nrf52832的SRAM map中,app_smem section是被放在内存的最开始处
    m_heap

    newlib malloc

    实现

    newlib malloc是newlib内自己实现了内存管理算法,只是使用桩函数_sbrk来管理堆,代码在zephyr/lib/libc/newlib/libc-hooks.c中

    void *_sbrk(int count)
    {
    void *ret, *ptr;

    sys_sem_take(&heap_sem, K_FOREVER);

    #if CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
    ptr = heap_base + heap_sz;
    #else
    ptr = ((char *)HEAP_BASE) + heap_sz;
    #endif

    if ((heap_sz + count) < MAX_HEAP_SIZE) {
    heap_sz += count;
    ret = ptr;
    } else {
    ret = (void *)-1;
    }

    sys_sem_give(&heap_sem);

    return ret;
    }
    FUNC_ALIAS(_sbrk, sbrk, void *);

    heap

    zephyr为newlib提供的heap会由于CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE的配置而不同,当配置了CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE, heap将会被放到app_smem section, 代码如下,分析过程可以参考前文的minimal

    #if CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
    K_APPMEM_PARTITION_DEFINE(z_malloc_partition);
    #define MALLOC_BSS K_APP_BMEM(z_malloc_partition)

    /* Compiler will throw an error if the provided value isn't a power of two */
    MALLOC_BSS static unsigned char __aligned(CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE)
    heap_base[CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE];
    #define MAX_HEAP_SIZE CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE

    当不配置CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE时代码如下

    #define USED_RAM_END_ADDR   POINTER_TO_UINT(&_end)

    #define HEAP_BASE ((USED_RAM_END_ADDR +
    CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE) &
    (~(CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE - 1)))
    #else
    #define HEAP_BASE USED_RAM_END_ADDR
    #endif /* CONFIG_USERSPACE*/
    #define USED_RAM_SIZE (HEAP_BASE - CONFIG_SRAM_BASE_ADDRESS)
    #define MAX_HEAP_SIZE ((KB(CONFIG_SRAM_SIZE)) - USED_RAM_SIZE)

    可以看到heap是从_end开始,占用剩余所有的内存
    n_heap

    参考

    https://www.cs.ccu.edu.tw/~pahsiung/courses/esd/resources/newlib.pdf

    【作者】张昺华
    【大饼教你学系列】https://edu.csdn.net/course/detail/10393
    【新浪微博】 张昺华--sky
    【twitter】 @sky2030_
    【微信公众号】 张昺华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    080626 雨(近期目标)
    6月25日 多云
    火一样的冷
    sgu107. 987654321 problem 简单打表 难度:0
    快速切题 sgu 111.Very simple problem 大数 开平方 难度:0 非java:1
    sgu114. Telecasting station 难度:1
    109. Magic of David Copperfield II 构造 难度:2
    sgu108. Selfnumbers 2 滚动数组 打表 难度:1
    快速切题 sgu115. Calendar 模拟 难度:0
    快速切题 sgu117. Counting 分解质因数
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/13475768.html
Copyright © 2011-2022 走看看