从零开始的理解代码重定位

从零开始的理解代码重定位

--参考朱有鹏ARM裸机编程

1、什么是重定位?

重定位就是代码搬移到你想要的地址,本来程序是运行在运行地址处的,

你可以通过重定位搬移到链接地址处。


2、为什么需要重定位?

大部分的程序是不需要重定位的,但是有时候需要进行重定位,最常见的例子就是

我们的UBOOT,因为我们的UBOOT有200多KB,但是我们开始BL0的地方只有96KB。

所以我们需要在96KB之前进行重定位,使开发板能够进行重定位。


3、重定位的基础知识

(1)一个事实:大部分指令是位置有关编码。

位置无关码:(PIC position independent code):

汇编源文件被编码成二进制可执行程序后与位置无关


位置有关码:汇编编码成二进制可执行程序后和内存地址是有关的。


PS:我们在设计一个程序时,会给这个程序指定一个运行地址。

就是说我们在写程序时,其实我们是知道我们程序将来被运行的地址的。


必须给编译器和链接器指定这个地址才行,最后得到二进制程序。

理论上和你指定的运行地址是有关的,这就叫做位置有关代码。


但是有些特别的指令,他可以跟地址没有关系。

也就是说这些代码实际运行时,不管放在哪里都能正常运行。


链接地址:你认为将来运行的地址:

运行地址:真实在程序中运行的地址:


(2)对于位置有关码来说:最终执行时的运行地址和编译链接时给定的链接地址必须

相同,否则一定会出错。


我们之前的裸机程序中Makefile中用-Ttext 0x0来指定链接地址是0x0

这意味着我们认为这个程序将来会放在这个内存地址中运行。


但是实际上我们运行的地址是下载在开发板的地址0xd0020010

因为是位置无关码,所以运行程序来是没有什么问题的。


而且我们开发板对这些程序进行了映射,所以说这是一个偶然的情况。


(3)我们再来分析一下S5PV210的启动过程。

BL1就是我们外部的前16KB进来,剩下的80K读了进来。


三星推荐的启动方式:

假定你的BootLoader必须小于96KB,并大于16KB。

然后假定Bootloader为80KB:


启动过程模拟:

先开机启动,BL0上电,BL0会加载外部启动设备中的bootloader的前16KB到SRAM,运行BL1


BL1在运行时要加载BL2(bootloader中80 - 16KB = 64KB)

到SRAM的16KB的开始用,去运行BL2会初始化DDR。

并且将OS搬运到DDR去执行OS,启动完成。


UBOOT实际上的启动的方法:

UBOOT的大小随意,假定是200KB

启动过程是这样子的:

先开机上电,BL0运行,BL0会加载外部启动设备中的UBOOT

的前16KB(BL1)到SRAM中去运行,BL1运行会初始化DDR。

然后将整个UBOOT,搬运到我们的DDR中。


然后用一条长跳转指令从SRAM中直接跳转到DDR中继续执行我们的UBOOT。

直到UBOOT完全启动。


长跳转的意思就是从SRAM中跳转到DDR中。
UBOOT启动后在命令行中去执行OS。


4、从源码到可执行程序的步奏:预编译、编译,链接、strip


首先要经过一个预编译的过程。
预编译是在编译之前做的事情,
宏定义就是由预编译来处理的。
注释等也是由预编译处理的。


预编译:比如C中的宏定义就是由预编译器处理的,注释等也是由预编译器处理的。
编译:编译器来执行,把源码中的.c/.s文件转换为.o文件。
把这些汇编的程序变为.o文件。
编译阶段是各自编译各自的文件。
f1段还有很多f2,还有f3段,我们编程是以函数为单位的
每一个函数。



链接:链接器来执行,
把.o文件中的各种函数(段)按照一定的规则(链接脚本来指定)累积到一起,形成可执行程序。
PS:把上面的各种文件链接到一起,类似于炒菜的过程。
要按照一定的顺序来编译。


就是听链接脚本来工作的,形成最后的可执行文件。
按说最后就是生成了可执行程序。
后面还有一些可选步奏。


strip:是把可执行程序中的符号信息给拿掉,
以节省空间,一般可以节省3分之一的空间。


Linux系统启动的时候,会失败的时候会有一些调试的符号信息。




objcopy:由可执行程序生成可烧录的镜像bin文件。


5、链接脚本存在的意义:


1、代码段
(.text)文本段
代码段其实就是函数编译后生成的东西。




2、数据段
(.data):数据段就是C语言中有显示的初始化为非0的全局变量。




3、BSS段
(.bss) :又叫做ZI段,零初始化段,就是初始化为0的全局变量。
C语言中把他放在了BSS段里面


后天的:


4、自定义段


由我们程序员自己定义,段的属性和特征也由我们自己定义。


我们分析一些东西,让你试图明白事物的本质:
1、C语言中如果没有显示初始化,值为0:     因为C语言会把没有初始化的全局变量放到了BSS段里面去。


2、局部变量如果没有初始化的话,值是随机的。


3、C运行时环境如果显示初始化为非0的全局变量的值在main之前放在了.data 中,会在main执行之前就会处理。(初始化)


链接脚本究竟在干神马?


链接的本质是规则文件,他指明了一种行动的规则,他是我们程序员用来指挥链接器工作的。
链接器会参考链接脚本来处理我们.o文件哪些段,将其链接成一个可执行程序。





  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值