内容摘自 《S3C2410彻底开发流程》
在开端后续试验之前,咱们得了解一下arm-linux-ld衔接指令的运用。在上述试验中,咱们一向运用相似如下的指令进行衔接:
arm-linux-ld -Ttext 0x00000000 crt0.o led_on_c.o -o led_on_c_tmp.o
咱们看看它是什么意思:-o选项设置输出文件的姓名为led_on_c_tmp.o;“–Ttext 0x00000000”设置代码段的开端地址为0x00000000;这条指令的效果便是将crt0.o和led_on_c.o衔接成led_on_c_mp.o可履行文件,此可履行文件的代码段开端地址为0x00000000。
咱们感兴趣的便是“—Ttext”选项!进入LINK目录,link.s代码如下:
1 .text
2 .global _start
3 _start:
4 b step1
5 step1:
6 ldr pc, =step2
7 step2:
8 b step2
Makefile如下:
1 link:link.s
2 arm-linux-gcc -c -o link.o link.s
3 arm-linux-ld -Ttext 0x00000000 link.o -o link_tmp.o
4 # arm-linux-ld -Ttext 0x30000000 link.o -o link_tmp.o
5 arm-linux-objcopy -O binary -S link_tmp.o link
6 arm-linux-objdump -D -b binary -m arm link >ttt.s
7 # arm-linux-objdump -D -b binary -m arm link >ttt2.s
8 clean:
9 rm -f link
10 rm -f link.o
11 rm -f link_tmp.o
试验过程:
1.进入目录LINK,运转make生成arm-linux-ld选项为“-Ttext 0x00000000”的反汇编码ttt.s
2.make clean
3.修正Makefile:将第4、7行的“#”去掉,在第3、6行前加上“#”
4.运转make生成arm-linux-ld选项为“-Ttext 0x30000000”的反汇编码ttt2.s
link.s程序中用到两种跳转办法:b跳转指令、直接向pc寄存器赋值。咱们先把在不同“—Ttext”选项下,生成的可履行文件的反汇编码列出来,再详细分析这两种不同指令带来的差异。
ttt.s: ttt2.s
0: eaffffff b 0x4 0: eaffffff b 0x4
4: e59ff000 ldr pc, [pc, #0] ; 0xc 4: e59ff000 ldr pc, [pc, #0] ; 0xc
8: eafffffe b 0x8 8: eafffffe b 0x8
c: 00000008 andeq r0, r0, r8 c: 30000008 tsteq r0, #8 ; 0x8
先看看b跳转指令:它是个相对跳转指令,其机器码格局如下:
Cond | 1 | 0 | 1 | L | offset |
[31:28]位是条件码;[27:24]位为“1010”时,表明B跳转指令,为“1011”时,表明BL跳转指令;[23:0]表明偏移地址。运用B或BL跳转时,下一条指令的地址是这样核算的:将指令中24位带符号的补码当即数扩展为32(扩展其符号位);将此32位数左移两位;将得到的值加到pc寄存器中,即得到跳转的方针地址。咱们看看第一条指令“b step1”的机器码eaffffff:
1. 24位带符号的补码为0xffffff,将它扩展为32得到:0xffffffff
2.将此32位数左移两位得到:0xfffffffc,其值便是-4
3.pc的值是当时指令的下两条指令的地址,加上过程2得到的-4,这恰好是第二条指令step1的地址
各位不要被被反汇编代码中的“b 0x4”给利诱了,它可不是说跳到肯定地址0x4处履行,肯定地址得像上述3个过程那样核算。您能够看到b跳转指令是依赖于当时pc寄存器的值的,这个特性使得运用b指令的程序不依赖于代码存储的方位——即不论咱们衔接指令中“–Ttext”为何,都可正确运转。
再看看第二条指令ldr pc, =step2:从反汇编码“ldr pc, [pc, #0]”能够看出,这条指令从内存中某个方位读出数据,并赋给pc寄存器。这个方位的地址是当时pc寄存器的值加上偏移值0,其间寄存的值依赖于衔接指令中的“–Ttext”选项。履行这条指令后,关于ttt.s,pc=0x00000008;关于ttt2.s, pc=0x30000008。所以履行第三条指令“b step2”时,它的肯定地址就不同了:关于ttt.s,肯定地址为0x00000008;关于ttt.s,肯定地址为0x30000008。
ttt2.s上电后寄存的方位也是0,可是它衔接的地址是0x30000000。咱们今后会经常用到“存储地址和衔接地址不同”(术语上称为加载时域和运转时域)的特性:大多机器上电时是从地址0开端运转的,可是从地址0运转程序在功能方面总有许多约束,所以一般在开端的时分,运用与方位无关的指令将程序自身复制到它的衔接地址处,然后运用向pc寄存器赋值的办法跳到衔接地址开端的内存上去履行剩余的代码。在试验5、6中,咱们将会作进一步介绍。
arm-linux-ld指令中选项“-Ttext”也能够运用选项“-Tfilexxx”来替代,在文件filexxx中,咱们能够写出更杂乱的参数来运用arm-linux-ld指令——在试验6中,咱们便是运用这种办法来指定衔接参数的。