下面是一个简单的lds链接脚本,用来将两个以上的.o文件合并在一起,并且用来指定链接后的代码加载到内存中的起始地址。
SECTIONS @说明这是段的描述脚本
{. = 0xD0020010; @加载代码到内存中的起始地址为0xD0020010.text : { @代码段mystart.o @mystart.o中的代码段放在最前面,因为mystart.o最前面是中断向量* (.text) @其它.o文件代码段位置可以任意放置}.data : { @数据段* (.data) @*号说明各个.o文件的数据段位置无关}.bss_start = .; @定义一个bss_start标号,可以给其它程序使用.bss : { @未初始化数据段* (.bss) @*号说明各个.o文件的数据段位置无关}.bss_end = .; @定义一个bss_end标号,可以给其它程序使用
}
1.机器码如何看含义
首先我们使用arm-linux-objdump -S mystart.o查看一下mystart.o的机器码和汇编码:
ea000006是机器码,也就是最后会被添加到.bin文件中的代码; b 20 reset是汇编代码,这部分不会被添加最后的.bin文件中。
那么机器码如何看呢?
我们把ea000006展开为二进制,如下:
查看ARM手册:
可以知道cond=1110 op1=101,说明ea000006是一个Branch指令(意思就是PC相对跳转指令),我们跳转到手册的A5-212去看下。
对应的op是100000,我们跳转到ARM手册A8-332去看一下
以为我们用的是arm指令集,所以看Encoding A1.
imm32 = SignExtend(imm24:’00’, 32);这句说明要讲imm24后面添加两个00.也就是imm24 * 4.
ea000006的imm24是0x6, 也就是pc指针会在当前位置往前跳转0x6 * 4行。
Armv7是三级流水线,在执行ea000006这条指令是,pc指针中指向的是后面第三行指令ea000004,当执行完ea000006指令后pc加0x6*4行,指向eb000006. 同b 20 reset指令一样。这也就b 20 reset汇编指令的来源。
ea000006后面几条也都是这样解释的。
特别要说的是eaffffff这条。imm24: ffffff是-1的补码,执行完eafffffff后pc指针要从ffffffe调回到ea000006。
2.汇编后的代码
然讲下ebfffffe为何汇编为 bl 0 led2_on,跳转到0呢?那时因为led2_on没有在mystart.o中,编译器暂时用0代替。当包含led2_on函数的.o文件被链接后,这条指令会被重新编译。
led2_on函数在mylowlevel_init.o中,我们使用objdump查看一下:
然后使用我们最开始写的链接脚本将两个文件链接在一起,连接后的文件是 myboot.
从中我们可以看到bl 0 led2_on 已经被修改为bl d00200a0 led2_on. 同时也可以看到myboot的程序入库已经被修改为了0xD0020010了。