arm-linux-ld实验

来源:互联网 发布:unity3d光源性能消耗 编辑:程序博客网 时间:2024/04/28 16:38
本文转自《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



6    00000000 <.data>:                                    |  6    00000000 <.data>:
7    0:   eaffffff    b   0x4                              |  7    0:   eaffffff    b   0x4
8    4:   e59ff000    ldr pc, [pc, #0]    ; 0xc       |  8    4:   e59ff000    ldr pc, [pc, #0]    ; 0xc
9    8:   eafffffe    b   0x8                              |  9    8:   eafffffe    b   0x8
10    c:   30000008    andcc   r0, r0, r8              | 10    c:   00000008    andeq   r0, r0, r8

先看看b跳转指令:它是个相对跳转指令,其机器码格式如下:

[31:28]位是条件码;[27:24]位为“1010”(0xeaffffff)时,表示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寄存器赋值的方法跳到连接地址开始的内存上去执行剩下的代码。

arm-linux-ld命令中选项“-Ttext”也可以使用选项“-Tfilexxx”来代替,在文件filexxx中,我们可以写出更复杂的参数来使用arm-linux-ld命令