首先看一下重定位前,在重定位前也就是第一阶段,u-boot会保留一片内存用于堆,也就是gd->malloc_base这篇区域,其大小为0x400,具体见下面的内存图:
在源码中搜索malloc可以在include/malloc.h中找到下面的宏定义:
/*你可能发现很多重复的宏定义,但是经过分析,最终生效的是下面这些*/
# define cALLOc calloc
# define fREe free
# define mALLOc malloc
# define mEMALIGn memalign
# define rEALLOc realloc
# define vALLOc valloc
# define pvALLOc pvalloc
# define mALLINFo mallinfo
# define mALLOPt mallopt
直接搜malloc的实现是搜不到的,因为它的实现是由mALLOc函数完成的(看上面的宏定义mALLOc会被替换成malloc),其函数体在common/dlmalloc.c文件中:
#if __STD_C
Void_t* mALLOc(size_t bytes)
#else
Void_t* mALLOc(bytes) size_t bytes;
#endif
{
/*定义了一堆变量*/
/*
省略
*/
/*这个宏定义了,才能在重定位前使用malloc来申请内存*/
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
/*这个标志是在board_init_r里面设置的,也就是重定位
完成,所以重定位前使用的就是这种分配方式*/
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
return malloc_simple(bytes);
#endif
/*下面就是重定位后的分配方式,太长了,有200多行,直接省
略,感兴趣的直接看源码吧*/
/*
省略
*/
}
本文不讨论其内存的分配策略,仅为找到malloc的源头。
从下面的代码可以看出重定位前使用的堆内存池是gd->malloc_base这片区域,重定位前使用的策略比较简单,就是分块,一块一块的对外分配就完了:
static void *alloc_simple(size_t bytes, int align)
{
ulong addr, new_ptr;
void *ptr;
addr = ALIGN(gd->malloc_base + gd->malloc_ptr, align);
new_ptr = addr + bytes - gd->malloc_base;
log_debug("size=%zx, ptr=%lx, limit=%lx: ", bytes, new_ptr,
gd->malloc_limit);
if (new_ptr > gd->malloc_limit) {
log_err("alloc space exhausted\n");
return NULL;
}
ptr = map_sysmem(addr, bytes);
gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr));
return ptr;
}
/*common/board_r.c*/
static int initr_malloc(void)
{
ulong malloc_start;
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
gd->malloc_ptr / 1024);
#endif
/* The malloc area is immediately below the monitor copy in DRAM */
/*
* This value MUST match the value of gd->start_addr_sp in board_f.c:
* reserve_noncached().
*/
malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
TOTAL_MALLOC_LEN);
return 0;
}
-->
/*common/dlmalloc.c*/
void mem_malloc_init(ulong start, ulong size)
{
mem_malloc_start = start;
mem_malloc_end = start + size;
mem_malloc_brk = start;
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
mem_malloc_end);
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT
memset((void *)mem_malloc_start, 0x0, size);
#endif
malloc_bin_reloc();
}
由于重定位后的内存分配代码太长了,这里仅仅看下重定位后的malloc使用的哪片内存区域,首先有一个很重要的宏:
#ifndef MORECORE
#define MORECORE sbrk
#endif
sbrk是一个函数,主要操作mem_malloc_brk全局变量,检查新申请内存时,是否落在有效的堆内存空间内,代码如下:
void *sbrk(ptrdiff_t increment)
{
ulong old = mem_malloc_brk;
ulong new = old + increment;
/*
* if we are giving memory back make sure we clear it out since
* we set MORECORE_CLEARS to 1
*/
if (increment < 0)
memset((void *)new, 0, -increment);
if ((new < mem_malloc_start) || (new > mem_malloc_end))
return (void *)MORECORE_FAILURE;
mem_malloc_brk = new;
return (void *)old;
}
和前面的malloc一样,直接搜sbrk是搜不到调用它的函数的,我们要搜索MORECORE,从搜索结果来看,其被mALLOc调用,可以知道重定位后就是使用的内存图中重定位后的那片堆内存空间。
从上面的分析来看,重定位后使用的新的堆内存空间,之前的那片内存相当于就废弃了没用了,也就解释了当时看完board_init_r函数时,发现有两片堆空间的疑惑了。