您的位置:首页 > 运维架构 > Linux

arm-linux-ld lds脚本文件

2012-11-30 09:54 316 查看
 

 

arm-linux-ld

 

1:b和ld的差异

  在开始后续实验之前,我们得了解一下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 跳转指令:它是个相对跳转指令,其机器码格式如下:

 

[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 中,我们就是使用这种方法来指定连接参数的。

 

 

 

 

2:lds脚本文件

 

 

1 SECTIONS { 

2   firtst   0x00000000 : { head.o init.o }

3   second  0x30000000 : AT(4096) { main.o }

4 } 

 

 完整的连接脚本文件形式如下:

SECTIONS {

...

secname start BLOCK(align) (NOLOAD) : AT ( ldadr )

  { contents } >region :phdr =fill

...

}

并非每个选项都是必须的,仅介绍nand.lds用到的:

1、secname:段名,对于nand.lds,段名为first和second

2、start:本段运行时的地址,如果没有使用AT(xxx),则本段存储的地址

也是start

3、AT( ldadr ):定义本段存储(加载)的地址

4、{ contents }:决定哪些内容放在本段,可以是整个目标文件,也可以

是目标文件中的某段(代码段、数据段等)

 

nand.lds的含义是:head.o放在0x00000000地址开始处,init.o放在hean.o

后面,它们的运行地址是0x00000000;main.o放在地址4096(0x1000)开始处,但

是它的运行地址在0x30000000,在运行前需要从4096处复制到0x30000000处。为

了更形象一点,您可以打开反汇编文件ttt.s,现摘取部分内容如下:

00000000 <.data>:

1      0: e3a0da01  mov sp, #4096 ; 0x1000

2      4: eb00000b  bl 0x38

3      8: eb000011  bl 0x54

4      c: eb000042  bl 0x11c

 ...

5   1000: e1a0c00d  mov ip, sp

6   1004: e92dd800  stmdb sp!, {fp, ip, lr, pc}

7   1008: e24cb004  sub fp, ip, #4 ; 0x4

8  100c: e59f1058  ldr r1, [pc, #88] ; 0x106c

 ...

 

上面的第1-4行与head.s中的前面4行代码对应,第2-4行调用init.c中的函

数disable_watch_dog、memsetup、init_nand;再看看第5行,“1000”的得来

正是由于设置了“AT(4096)”,这行开始的是main.c中的第一个函数Rand()。

如果您想进一步了解连接脚本如何编写,请参考《Using ld The GNU linker》

(在目录“参考资料”下)。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: