从最终的链接命令查看
查看.lds,可以看到确实可以从0地址开始运行
uboot 应该做的事情:
start_code
设置管理模式
关看门狗
关中断
设置时钟分频系数
cpu_init_crit 底层初始化
flush caches
禁止mmu
lowlevel_init 底层初始化
初始化内存(memory control configuration)
设置栈 ldr sp, = (CONFIG_SYS_INIT_SP_ADDR)【1】
board_init_f()
gd指向的位置【2】
调用函数数组init_sequence 里个各个函数【3】
board_early_init_f
设置时钟
设置GPIO端口
timer_init初始化定时器
get_PCLK
依次为kernel log buffer, protected RAM,LCD display,U-Boot code, data & bss,malloc() arena等等预留内存(ram)
relocate_code() 重定位代码【4】
【1】通过反汇编
arm-linux-objdum -D u-boot >u-boot.dis
可以看到sp从478的位置取值
可以看到478位置的值为 0X30000f80
【2】gd为寄存器变量
编译时就保留了r8寄存器。
内存使用图
【3】这种函数数组,通过for循环遍历调用的巧妙之处在于,如果添加一个函数,只需要将需要添加的函数放到这个数组里就可以了。通过宏来控制这些函数的开关也十分方便。这些函数包括以下
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
#ifdef CONFIG_OF_CONTROL
fdtdec_check_fdt,
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
NULL,
};
【4】在链接时,pie 参数生成了位置无关可执行程序。
可以看到 -pie参数的帮助。