一:为什么需要进行重定位

我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址)。就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行。最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执行时必须放在当时编译链接时给定的那个地址(链接地址)下才行,否则不能运行(就叫位置有关代码)。但是有个别特别的指令他可以跟指定的地址(链接地址)没有关系,也就是说这些代码实际运行时不管放在哪里都能正常运行。


二:重定位的过程

重定位就是通过一段位置无关码将我们的当前运行地址处的代码复制一份到我们的链接地址处,并且在我们重定位代码的最后通过长跳转指令跳转到链接地址的那一份代码中去执行。比如我们设置的链接地址是0xd0024000,但是我们下载时是下载到0xd0021000这个地址里面的,所以我们就需要重定位将我们的代码复制一份到我们的0xd0024000这个地址,并跳转到这里去执行。


三:重定位实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
adr r0 _start   //adr指令用于加载_start当前的运行地址
ldr r1, =_strat  //ldr指令用于加载_start的链接地址:0xd0024000
//bss段的起始地址,链接是的顺序为 代码段  数据段  bss段
ldr r2,=bss_start   //重定位只需要重定位代码段和数据段即可。
cmp r0, r1
beq clean_bss
 
copy_loop:
   ldr r3, [r0], #4   //r0地址中的内容存入r3中同时,r0=r0+4
   str r3, [r1], #4   //r3的内容写到r1所指的地址中,同时r1=r1+4
   cmp r1, r2
   bne copy_loop
//copy_loop就完成了代码的拷贝
 
clean_bss:
   ldr r0, =bss_start
   ldr r1, =bss_end
   cmp r0, r1
   beq run_on_dram
   mov r2, #0
  
cleatr_loop:
   str r2, [r0], #4
   cmp r0, r1
   bne clear_loop
   
run_on_dram
   ldr pc,=led_blink


本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1827364