转载地址:https://blog.csdn.net/qingkongyeyue/article/details/52298640
1、概念理解
运行地址<--->链接地址:他们两个是等价的,只是两种不同的说法。
加载地址<--->存储地址:他们两个是等价的,也是两种不同的说法。
运行地址:程序在SRAM、SDRAM中执行时的地址。就是执行这条指令时,PC应该等于这个地址,换句话说,PC等于这个地址时,这条指令应该保存在这个地址内。
加载地址:程序保存在Nand flash中的地址。
位置无关码:B、BL、MOV都是位置位置无关码。
位置有关码:LDR PC,=LABEL等类似的代码都是位置有关码。
2、链接脚本格式
<SECTIONS>基本命令
SECTIONS描述输出文件的映射图:->输出文件各段、各文件怎么放置
一个SECTIONS命令内部包含一个或多个段,段是连接脚本的基本单元,它表示输入文件某部分怎么放置;
格式:
SECTIONS{
...
secname start ALIGN(align)(NOLOAD):AT(ldadr)
{contents}>region:phdr=fill
...
}
secname:命名这个段
contents:用来确定代码的什么部分放在这个段
start:是这个段的重定位地址,也叫运行地址。如果代码中有位置无关的指令,程序在运行时必须放在这个地址上。
ALIGN(align):虽然指定了运行地址,但仍可以使用ALIGN(align)来指定对齐的要求---这个对齐的地址才是真正的地址
(NOLOAD):来告诉加载器,在运行时不用加载这个段
AT(ldadr):指定这个段在编译出来的映像文件中的地址——加载地址
3、链接脚本分析
先看一个链接脚本:
SECTIONS{
first 0x00000000 : {head.o init.o}
second 0xB0004000 : AT(2048){leds.o}
}
链接脚本将程序分为两个段:first和second。前者由head.o和init.o组成,它的加载地址和运行地址都是0,所以在运行时不需要移动代码,后者由leds.o组成,它的加载地址为2048,重定位地址为0xB0004000,这表明段second存放在编译所得的映像文件的2048处,在运行前需要将它复制到地址0xB0004000(MMU映射),将编译所得的映像文件烧入到nand flash后,head.o和init.o依次从0x00000000处存放,而leds.o存放在2048处。从nand flash启动时,cpu首先将nand flash的前4KB复制到cpu自身的ram(steppingstone)中去,这样leds.o存放在地址为2048处,而运行的时候需要将steppingstone中2048 - 4096的内容复制到sdram中起始地址0xB0004000处,从而使用ldr跳转时才会正确执行下去。
4、假若程序不位于链接地址时程序会出现什么问题
去访问某些全局变量时就会出错,因为访问这些全局变量时用的是它的链接地址,我去链接地址访问你,你就必须位于链接地址上。如下图,程序应该位于SDRAM上的某个地方,但是一上电是从2440的片内4K RAM 的0地址开始执行的,为什么从0地址执行的一小段代码能够正确运行,这一小段代码用到位置无关码写