背景知识:
大部分指令是位置有关编码
位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关。
位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的。我们在运行这个程序时需要给这个程序指定一个运行地址(链接地址),必须给编译器链接器指定这个地址才行。最后得到的二进制程序理论上是和你指定的运行地址有关。
编译地址和链接地址:不一定相同。
对于位置有关代码来说:最终执行时的运行地址和编译链接时给定的链接地址必须相同,否则会出错。
链接地址与运行地址:
链接地址:链接时指定的地址(指定方式为:Makefile中用-Ttext xxx,或者在链接脚本中指定)
运行地址:程序实际运行时地址(指定方式:由实际运行时被加载到内存的哪个位置说了算,编译链接时是无法绝对确定运行时地址的)
s5pv210的启动方式:三星推荐和uboot的实现是不同的
三星推荐的启动方式:bootloader必须小于96KB并大于16KB,假定bootloader为80KB,启动过程:开机上电后运行BL0,BL0会加载外部启动设备中的bootloader的前16KB(BL1)到SRAM中去运行,BL1运行时会加载BL2(bootloader中80-16=64KB)到SRAM中(从SRAM的16KB处开始用)去运行;BL2运行时会初始化DDR并且将OS搬运到DDR去执行OS,启动完成。
uboot实际使用的方式:uboot大小随意,假定为200KB,启动过程为:先开机上电后BL0运行,BL0会加载外部设备中的bootloader中的前16KB(BL1)到SRAM中运行,BL1运行时会初始化DDR,然后将整个uboot搬运到DDR中,然后用一句长跳转指令从SRAM中直接跳转到DDR中继续执行uboot直到uboot完全启动。uboot启动后在uboot命令行中去启动OS。
链接脚本:
从源码到可执行程序的步骤:预编译、编译、链接、strip
预编译:预编译器执行。比如C中的宏定义就是由预编译器处理,注释等也是预编译器处理的。
编译:编译器执行。把源码.c .s变成机器码.o文件。
链接:链接器执行。把.o文件中的各函数(段)按照一定规则(链接脚本来指定)累积在一起,形成可执行文件。
strip:strip是把可执行程序中的符号信息给拿掉,以节省空间。(Debug版本和Release版本)
objcopy:由可执行程序生成可烧录的镜像bin文件。
程序段的概念:代码段、数据段、bss段(ZI段)、自定义段
段就是程序的一部分,我们把整个程序的所有东西分成了一个一个的段,给每个段起名字,然后在链接时就可以用这个名字来指示这些段,也就是说给段命名就是为了在链接脚本中用段名来让段站在合适的位置。
段名分为2种:1. 编译器内部定好的,先天性的名字;2. 程序员自己指定的、自定义的段名。
先天性段名:
代码段:(.text),又叫文本段,代码段其实就是函数编译后生成的东西。
数据段:(.data),数据段就是C语言中有显示初始化为非0的全局变量。
bss段:(.bss),又叫ZI(zero initial)段,就是零初始化段,对应C语言中初始化为0的全局变量。
后天性段名:
段名由程序员自己定义,段的属性和特性也由程序员自己定义。
链接脚本的作用:
链接脚本其实是个规则文件,他是程序员用来指挥链接器工作的。链接器会参考链接脚本,并且使用其中规定的规则来处理.o文件中的那些段,将其链接成一个可执行程序。
理解链接脚本:
链接脚本的关键内容有2部分:段名+地址(作为链接地址的内存地址)
SECTIONS { ... } 这个是整个链接脚本
. 点号在链接脚本中代表当前位置。
= 等号代表赋值。