码迷,mamicode.com
首页 > 其他好文 > 详细

第二部分:S5PV210_重定位和链接脚本_2

时间:2016-08-01 22:29:05      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:

重定位和链接脚本

(1)重定位:分为静态重定位和动态重定位

  静态重定位:静态重定位是在程序执行之前进行重定位,它根据装配模块将要装入的内存起始位置,直接修改装配模块中的有关使用地址的指令

  我们下面要分析就是静态重定位的情况。

  动态重定位:动态重定位是指,不是在程序执行之前而是在程序执行过程中进行地址重定位。更确切地说,是在每次访问内存单元前才进行地址变换。动态重定位可使装配模块不加任何修改而装入内存,但是它需要硬件——定位寄存器的支持。

技术分享

图片的参考来源:http://c.biancheng.net/cpp/html/2608.html

上面重定位的定义的参考来源:http://bbs.pediy.com/showthread.php?t=76876

(2)为什么需要重定位呢?

  我们的程序中的代码可分为:位置无关码和位置有关码。顾名思义,位置无关码就是代码在哪个地址运行都行的。那么位置有关码呢?就必须在规定的地址处执行才可以,这个规定的地址就是链接地址,而我们代码执行时候的地址是运行地址,位置有关码就要求链接地址和运行地址必须一致,执行的时候才不会出错。但由于某些原因(譬如,我们在用裸机的时候,我的DRAM还没初始化,而我们的代码又必须要在DRAM上才可以继续运行,那么直接下载肯定就是不行的了),我们又不能把程序下载到相应的地址处去执行,所以,这时候就要用到重定位了。

(3)在说重定位的具体实现之前,我们先来说一下链接脚本(文件.lds)

  链接脚本的代码如下:看懂下面的代码我们还需要了解:bss段,数据段(.data),代码段(.text)等知识,可以参考我的这篇博客:

  程序中的bss段,数据段(.data),代码段(.text):http://www.cnblogs.com/nibuyaoni/p/5724013.html

  然后,我们通过Makefile,编译链接程序时可以指定按照链接脚本的顺序来链接代码:arm-linux-ld -Tlink.lds -o led.elf $^

  link.lds为链接脚本的名字

 1 SECTIONS
 2 {
 3     . = 0x20000000;      //指定链接地址为0x20000000
 4     
 5     .text : {         //代码段
 6         start.o        //指定链接的顺序为:start.o->sdram_init.o->其他的一些文件
 7         sdram_init.o
 8         * (.text)       //这里表示其他的一些.o文件
 9     }
10             
11     .data : {          //数据段
12         * (.data)        //这里表示所有的数据段的文件
13     }
14     
15     bss_start = .;       //把当前的地址赋值给bss_start
16     .bss : {          //bss段
17         * (.bss)        //所有bss段的文件
18     }
19     
20     bss_end  = .;          //把当前的地址赋值给bss_end
21 }

(4)下面,我们就来看看重定位代码的具体实现

 2     // adr指令用于加载_start当前运行地址
 3     adr r0, _start          // adr加载时就叫短加载        
 4                   // ldr指令用于加载_start的链接地址:0x20000000
 5     ldr r1, =_start     // ldr加载时如果目标寄存器是pc就叫长跳转,如果目标寄存器是r1等就叫长加载    
 6     // bss段的起始地址
 7     ldr r2, =bss_start    // 就是我们重定位代码的结束地址,重定位只需重定位代码段和数据段即可
 8     cmp r0, r1            // 比较_start的运行时地址和链接地址是否相等
 9     beq clean_bss        // 如果相等说明不需要重定位,所以跳过copy_loop,直接到clean_bss
10                         // 如果不相等说明需要重定位,那么直接执行下面的copy_loop进行重定位
11                         // 重定位完成后继续执行clean_bss。
12 
13 // 用汇编来实现的一个while循环
14 copy_loop:
15     ldr r3, [r0], #4    // 源,后面的#4就是:地址在不断的加4
16     str r3, [r1], #4    // 目的   这两句代码就完成了4个字节内容的拷贝
17     cmp r1, r2            // r1和r2都是用ldr加载的,都是链接地址,所以r1不断+4总能等于r2
18     bne copy_loop
19 
20     // 清bss段,其实就是在链接地址处把bss段全部清零
21 clean_bss:
22     ldr r0, =bss_start                    
23     ldr r1, =bss_end
24     cmp r0, r1                // 如果r0等于r1,说明bss段为空,直接下去
25     beq run_on_dram            // 清除bss完之后的地址
26     mov r2, #0
27 clear_loop:
28     str r2, [r0], #4        // 先将r2中的值放入r0所指向的内存地址(r0中的值作为内存地址),
29     cmp r0, r1                // 然后r0 = r0 + 4
30     bne clear_loop
31 
32 run_on_dram:    
33     // 长跳转到led_blink开始第二阶段
34     ldr pc, =led_blink                // ldr指令实现长跳转和bl是短加载
35     //最后这里跳转,是跳转到重定位的代码所对应的led_blink这个函数那里去执行的
36     
37 // 汇编最后的这个死循环不能丢
38     b .

总结:由上面我们可以看到:重定位的时候,先使用一段位置无关码来对重定位的地址那里的内存进行一些操作:

  (1)把整段代码搬运过重定位的内存那里(用copy_loop来实现)

  (2)清bss段(clean_bss来实现)

  (3)跳转到重定位的那段内存去执行(run_on_dram来实现)

注意:上面那些汇编指令所实现的功能我们可以通过反汇编文件(.dis文件)来验证:arm-linux-objdump -D led.elf > led_elf.dis

参考来源:朱老师物联网大教程

第二部分:S5PV210_重定位和链接脚本_2

标签:

原文地址:http://www.cnblogs.com/nibuyaoni/p/5727278.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!