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

重定位和链接脚本

(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

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

时间: 2024-12-24 18:02:10

第二部分:S5PV210_重定位和链接脚本_2的相关文章

重定位与链接脚本

1.为什么需要重定位 位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执

重定位和链接脚本

大部分指令是"位置有关编码" 位置无关编码:汇编源文件编码成二进制可执行程序时,编码方式与位置无关. 在我们写程序时,必须给编译器链接器指定地址.将来的程序被执行时必须放在当时编译链接时给定的地址才能运行. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 但是也有一种特别的指令他可以跟指定的链接地址没有关系,这些代码不管放在哪里都可以正常运行. 分析: 之前的裸机程序中,makefile中用-Ttext 0x0来指定链接地址是0x0;这意味着我们认为将来这个程序会被

S5PV210裸机程序之重定位与链接脚本

s5pv210开发板要求代码在0xD0020010处开始执行(BL1),但是有时我们的程序需要重定位在另外一个地址执行(如uboot),这个时候需要我们在汇编代码处加入重定位操作的代码,使得程序能够长跳转到另外一个地址继续执行代码而不会因为执行了与地址有关编码而导致执行错误. 链接脚本如下: SECTIONS {     . = 0xD0024000;     .text : {         start.o         * (.text)         }     .data : {

[CSAPP-II] 链接[符号解析和重定位] 静态链接 动态链接 动态链接接口

1 平台 1.1 硬件 Table 1. 硬件(lscpu) Architecture: i686(Intel 80386) Byte Order: Little Endian 1.2 操作系统 Table 2. 操作系统类型 操作系统(cat /proc/version) 位数(uname -a) Linux version 3.2.0-4-686-pae i686(32bit) 1.3 编译器 Table 3. 编译器信息 编译器(gcc -v) gcc (Debian 4.7.2-5) 4

SDRAM和重定位(四)---链接地址和运行地址

在了解重定位之前,必须先区分开链接地址和运行地址,位置有关代码和位置无关代码 ========================================================= 链接地址和运行地址: 链接地址:指在链接时指定的地址,是我们设想的将来程序要运行的地址.程序中所有标号的地址在链接后便确定了,不管程序在哪运行,都不会改变.使用arm-linux-objdump反汇编查看的就是链接地址. 运行地址:指程序在板子中实际运行的地址 从上面的定义可以看出,链接地址和运行地址可以

链接脚本与重定位

目录 链接脚本与重定位 总结 链接脚本格式 COMM段BSS段 elf和bin文件 获得链接脚本的值 重定位 1-直接指定数据段位置(代码黑洞) 2-分散加载(数据段) 3-全局重定位(一体式) BL跳转指令 bss段处理 汇编处理 C处理 位置无关码 title: 链接脚本与重定位 tags: ARM date: 2018-10-12 19:25:53 --- 链接脚本与重定位 学习视频 韦东山 总结 尽量使用一体式的链接脚本,方便简单,灵活 学会使用链接脚本的值 bss段和comm段是需要我

共享库加载时重定位

原作者:Eli Bendersky http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries 本文的目的是解释现代操作系统怎样使得共享库加载时重定位成为可能.它关注执行在32位x86的LinuxOS.但通用的原则也适用于其它OS与CPU. 共享库有很多名字--共享库,共享对象,动态共享对象(DSO),动态链接库(DLL--假设你有Windows背景).为了统一起见.我将尽量在本文里使用"共享库

共享库载入时重定位

原作者:Eli Bendersky http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries 本文的目的是解释现代操作系统如何使得共享库载入时重定位成为可能.它关注运行在32位x86的LinuxOS,但通用的原则也适用于其他OS与CPU. 共享库有许多名字--共享库,共享对象,动态共享对象(DSO),动态链接库(DLL--如果你有Windows背景).为了统一起见,我将尽量在本文里使用"共享库

重定位引入和链接脚本

1.一个事实:大部分指令是位置有关编码位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关.位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将