嵌入式linux应用开发完全手册第三章的链接问题讨论

        书中,首先是 用GNU ARM汇编写了一个小程序,代码如下,下面我们就对这个代码进行仔细的剖分。把书中没讲清楚的东西给搞透彻一点。

.text
.global _start
_start:
    b step1
step1:
    ldr pc,=step2
step2:
    b step2

    这里有个问题必须先搞清楚:在ARM处理器中的b指令的寻址方式在杜春蕾老师的《ARM体系结构与编程》这本书中讲它的寻址方式是<target_address>,但是,书中并没有把它提出来,其实,它应该算是一种比较特殊的寻址方式。我们看b指令的机器码就可以明白。cond   1  0  1  L   offset 。其中的offset是一个有符号的24位数。这里处理offset的方式很不同,arm处理器会取走这个24位的带符号数把它算数扩展(带符号位的扩展)为32位,并且再左移2位,再加到pc(程序计数器)上。为什么要这么做呢?因为arm处理器是定长的指令,arm指令集定长32位,thumb为16位。所以,这里只能用3B作为操作数。那里左移2位是因为一个字是4B,所以,左移两位指向字地址。记住,这是cpu的内部处理细节,我们能理解就够了,它不会影响我们编码。

    上面说到不会影响我们编码,那还去管他干什么?但是,当我们用objdump工具打开机器码文件,明白这一点就很重要了。这段代码对应的机器码如下。下面我们详细分析这段机器码。
00000000 <_start>:
   0:    eaffffff     b    4 <step1>
00000004 <step1>:
   4:    e59ff000     ldr    pc, [pc, #0]    ; c <step2+0x4>
00000008 <step2>:
   8:    eafffffe     b    8 <step2>
   c:    00000008     .word    0x00000008

代码中加黄底的是b step1所对应的机器码。其中的后3个字节(ffffff)为机器指令的操作数。为什么会是ffffff呢?这就是汇编程序在做的事情。为了让机器执行这段机器码的时候,按照它的那套方式去处理,汇编程序就会在汇编的时候把b指令的这个操作数这么处理。你看由汇编程序生成的这个24位地址0xffffff,按符号位扩展为32位为0xffffffff,左移两位为0xfffffffc(-4的补码),这时候再加到pc上,由于这里的cpu是5级流水线,所以,pc指向当前执行指令的后两条,也就是为当前执行指令的地址+8,所以,这么-4就让pc指向了4(绝对地址,也就是0x00000004)。这里,可以明白,所谓的地址无关其实是汇编程序完成了这么一个转换地址的过程,使得这段代码在被cpu执行的时候与地址无关。也就是说b指令是相对pc在跳转,但是这里的ldr指令就不同,我们在调用ld程序时,使用-Ttext=0x30000000那么,.text节的起始地址就是这个指定的地址,我们这时候指令的跳转地址就是地址相关了,而且完全取决于链接时指定的地址。大体就是这个意思,明白了么?

你可能感兴趣的:(嵌入式linux应用开发完全手册第三章的链接问题讨论)