b/bl解析

   sdram.lds:

      SECTIONS

      {

         . = 0X30000000;

         ...

      }


   start.S:

      ...

      bl main


   sdram.dis:

      3000005c:   eb000105    bl   30000478

      ...

      30000478 :

   将sdram.lds进行修改:. = 0X32000000; 重新编译,查看sdram.dis:

      3200005c:   eb000105    bl   32000478

      ...

      32000478


      可得,这个跳转不是跳到0X30000478去执行,而是相对地址,即:   跳到当前pc+offset(也就

   是sdram_init的位置)去执行。

       b/bl指令不关心运行(链接)地址,它只是找到想要跳转的目标, 然后用pc进行偏移来过去执行,

  不关心目标的链接地址:如果程序是从0X30000000开始执行,则跳到0X30000478 去执行;如果程序是从

   0 开始执行,则跳到0X478去执行。看上边链接地址不同时,机器码却是相同的。

       反汇编文件.dis中左边那一列地址,仅仅是供我们查看。


ldr解析

   sdram.lds:

      SECTIONS

      {

         . = 0X30000000;

         ...

      }


   start.S:

      ...

      ldr pc, =main


   sdram.lds

      300000a0:   e59ff01c    ldr   pc, [pc, #28]    ; 300000c4 <.text+0xc4>

      ...

      3000062c :

      3000062c:   e1a0c00d    mov   ip, sp


   用ldr伪指令时,它是跳到pc+offset地址处的值来执行,即执行*(pc + offset),而b/bl指令执行(pc + offset)


怎么写位置无关的程序

   使用位置无关码,不使用绝对地址,最根本的办法是看反汇编

    a. 调用程序时使用B/BL相对跳转指令,而不是ldr pc, =main这种

    b. 重定位之前, 不可使用绝对地址,比如:

        不可访问全局变量/静态变量

        不可访问有初始值的数组(因为初始值放在rodata里,使用绝对地址来访问)

    c. 重定位之后, 使用绝对跳转命令跳到Runtime Addr,比如:

          ldr pc, =main