本作品采用知识共享署名
发表于 2019-10-29 | 分类于 iot | | 阅读次数: 118
本文简要介绍Zephyr的标准C库,并基于nrf52832分析malloc的heap来源。
本文只对开启了用户模式(CONFIG_USERSPACE)的情况进行分析,未开启的情况也大致相似,只是heap所在section会有所变化
zephyr支援下面2种标准C库:
minimal libc库是zephyr提供源代码,部分实现了常用的标准C函数,代码路径为zephyr/lib/libc/minimal,可以从下图大致看到minimal libc支援那些标准C API:
与minimal libc配置有关的是下面两项
zephyr默认情况下使用minimal libc, minimal libc在cortex-m4下只占用6K的size
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配置相关的有下面几项
这里并不说明malloc实现的具体算法,只是对比看一下minimal和newlib在heap alloc上的差异
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的定义如下
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 |
脚本/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是被放在内存的最开始处
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 *); |
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) |
https://www.cs.ccu.edu.tw/~pahsiung/courses/esd/resources/newlib.pdf