secname就是section name,表示段名。
start为起始地址,即运行时的地址(runtime addr),也是重定位地址(relocate addr),程序运行时,会去该跳到该地址去执行。
AT(ldadr)为加载地址(Load Address),不写时,Load Address = runtime address,如果load address不等于runtime address,程序本身要重定位。
contents 表示内容,可以指定文件(比如start.o),也可以指定段(如代码段(.text))*。
**通过设置重定位地址和加载地址,就可以实现将指定段的数据重定位。**如下图,表示在bin文件中,data段处于0x800的位置,但是程序运行时,data段处于0x3000,0000的位置。所以,我们软件上要将0x800的data段重定位到0x3000,0000位置。
如上图所示,其中.表示当前位置。将text代码段放在0x3000,0000,*(.text)表示所有的代码段,ALIGN(4)表示4字节对齐。所以,就是将所有的代码段四字节对齐的形式放在0x3000,0000起始的位置。
然后,是所有的只读数据段,数据段,bss和common,他们都是以四字节对齐的形式排列。
其中,bin文件,elf文件中都不存在bss段,我们软件上要将这个段清零。
重定位之前的代码,与地址无关,叫做位置无关码
怎么写位置无关码的程序(使用位置无关码,不使用绝对地址,最根本的办法是看反汇编):
- 使用相对跳转命令B/BL;
- 重定位前,不可以使用绝对地址,比如,不可以访问全局/静态变量;不可以访问有初始值的数组(rodata,data)。
- 重定位之后,使用绝对跳转命令跳到runtime address,比如,ldr pc, =main
将代码段的runtim address设为0x3000,0000和0x3000,0000,查看反汇编码如上。
**这时候sdram还没有初始化完成,我们跳到sdram上,是不是程序执行会出问题?**其实,这里使用的是相对跳转指令,并不是真的跳到0x3000,xxxx的地方去执行,而是跳转到相对位置去执行,这里的相对位置为PC+offset,是由链接器计算出来。比如,假设程序从0x3000,0000执行,当前指令地址0x3000,005c,那么就会跳到0x3000,0478;如果从0运行,当前指令地址为0x5c,会跳到0x478;如果从0x3200,0000运行,当前指令地址为0x3000,005c,会跳到0x3200,0478;。