因为内存的执行效率比较高,所以uboot的绝大部分功能应该在SDRAM内存中完成;即uboot在连接时,我们制定它的运行地址是0x30000000。
但CPU复位重启时,PC的默认值是0x00000000;因此,uboot开始部分(4KB)必须在0x00000000处执行;
这就存在PIC,即位置无关代码设计的问题,见ARM位置无关代码设计。
所以,为了让uboot能正常顺利执行;我们必须保证其前4KB部分是位置无关的。
也就是说:连接器armlink指定的程序运行地址、即生成可执行镜像文件中的符号表地址在0x30000000域;但我们要让其前4KB运行在0x00000000域处,这4KB代码只能通过基于当前PC指针的相对寻址!
一、关于编译连接脚本
连接脚本是用来描述输出文件的内存布局,也就是确定程序的运行地址。
gcc等编译器内置有缺省的连接脚本;但采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。
而对于uboot这种需要在嵌入式系统上直接运行的程序,就不能使用编译器缺省脚本、而必须由我们编写连接脚本。
源代码经过编译器编译后包含如下段:
正文段text:包含程序的指令代码;
数据段data:包含固定的数据,如常量和字符串;
未初始化数据段:包含未初始化的变量、数组等。
连接器的任务是将多个编译后的文件的text、data和bass等段连接在一起;而连接脚本文件就是告诉连接器从什么地址(运行时地址)开始放置这些段。
二、GNU对.lds文件形式的描述
arm-linux-ld -o uboot.elf -T uboot.lds *.o
arm-linux-objcopy -Obinary uboot.elf uboot.bin
二、解释uboot.lds
补充:arm程序的加载时域和运行时域
简单地说:程序的加载时域就是指程序被加载到什么地方、是SDRAM还是nor flash,运行时域是指程序执行时的地址。
一、镜像文件的组成
镜像文件包含加载时域和运行时域;
加载时域包含RO和RW段,运行时域包含RO、RW和ZI三个段。
其中RO和RW段的内容在加载时和运行时时一样的,但存储空间可能不同;而ZI段是运行时由初始化函数创建的。
二、代码、数据和变量在镜像文件中的位置
代码:一般是只读的,由编译器分配存储空间并放置镜像文件的RO段。
数据:这里的数据指常量、指针常量,它们属于只读数据、由编译器分配存储空间放在镜像文件的RO段。
变量:主要根据生存期划分;
1.全局变量和静态变量:由编译器分配存储空间,已初始化的放到RW段、未初始化的放置ZI段。
2.动态变量:局部变量,占用栈空间。