u-boot relocate_code原理简单说明

本文详细介绍了U-Boot的重定位(relocate)过程,包括重定位的基本概念、旧版与新版U-Boot的不同重定位策略,以及relocate_code函数的具体实现原理,特别是对于函数调用与全局变量地址调整的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了u-boot的relocate_code函数,以及查了网上其他人的帖子后,写一下自己对relocate_code的理解。


参考文章

http://blog.youkuaiyun.com/skyflying2012/article/details/37660265

http://blog.youkuaiyun.com/gjq_1988/article/details/22315913


1. 重定向

uboot最重要的一个功能就是relocate,重定向。重定向最通俗的说,就是把NAND Flash上程序搬到内存中。重定向涉及到三个地址,链接地址、加载地址和运行地址。我们先假设这三个地址都是0x32000000。

链接地址是我们在uboot里面配置的,由链接器读取并用于生成uboot的二进制。

加载地址是uboot重定向时,拷贝源码的目的地址。通俗地讲,就是把NAND Flash里的uboot代码拷贝到内存的哪个地址上。

运行地址是指uboot在内存中运行的地址。uboot运行时的一些寻址操作,就跟运行地址有关系。

由于uboot的二进制文件直接或间接地包括了内存的绝对物理地址,所以以上三个地址一般是一样的。通俗地讲,uboot把内存的绝对物理地址固定在了二进制文件里,所以uboot应该被拷贝到内存哪个地方,下一条指令应该跳转到哪个物理地址都是在编译的时候就已经固定的。


2. 旧版本uboot的重定向

旧版本的uboot只有一个重定向,而且这个重定向是由移植uboot的工程师,根据具体的板子配置来编写的。比如从NAND Flash拷贝0x32000000开始的内存地址;或者从NOR Flash拷贝到0x80800000开始的内存地址。这都是由CPU和板子配置决定的。


3. 新版本uboot的重定向

新版本的uboot有两个重定向,第一个重定向跟老版本是一模一样的,目的就是从NAND Flash或者NOR Flash这些存储设备中把代码拷贝到内存地址(destA)中。还有第二个重定向,这个重定向函数就是relocate_code。这部分代码是uboot官方做好的,我们并不需要修改。它的作用就是把uboot从当前的位置(destA)拷贝到内存的高端地址(destB)上。Linux内核一般用的低端的内存地址,所以uboot选了一个高端地址。但至于为什么还得有第二次的重定向,原因我并不清楚。即使把第二次的重定向屏蔽,uboot还是可以正常运行的。


4.relocate_code函数原理

relocate_code并不是简单的把destA的内容拷贝到destB就完事这么简单的。如果就这样直接拷贝,uboot是运行不了的,原因如第1点所述。

看了别人的文章以后,有了大致的概念。这里我假设要把0x32000000地址上的uboot重定向到0x80000000。

1)链接器要加上-pie的选项,这样生成的代码就是位置无关的。通俗地讲,就是以前我要跳转到一个函数,可能我就直接一条语句,就跳过去了。

320068c8:	eb001688 	bl	320068e4 <funcA> ;funcA在0x320068e4的地址,直接跳转到0x320068e4的绝对地址
....
320068e4 <funcA>:
320068e4:	e59f0000 	mov r0, r1
....

但位置无关的代码,就会根据PC的值,做一个相对位置的跳转,而PC值是可以在运行时被修改的。

320068c8:	eb001688        ldr  r0, [pc,  #20];这里表示是把将要跳转的地址放到r0中,没有把绝对地址固定在命令里。r0=pc+8+20=0x320068c8+8+20。这个8是由ARM的流水线机制决定的,PC里的值是当前地址+8.
320068cc:       e3a00000        mov pc, r0; 把r0的值赋给pc,实现跳转                         
....
320068e4 <funcA>:
320068e4:	e59f0000 	mov r0, r1
....

上面的代码在relocate_code之后,直接修改pc到新位置0x80000000,这个时候由于funcA的位置已经变为0x800068e4,而pc的值也变为0x800068c8,所以经过计算以后的跳转是不会出错的。


2) 有了上面的一点还不够,上面只实现了重定向以后函数的跳转,但一些全局变量的位置还是不正确。

全局变量的重定向,借助了一个叫GOT(Global Offset Table)的表。每一条GOT Entry记录了一个对象的地址,这个对象可以是变量或者函数。

320068f0 <test_rel_dyn>:
....
320068f8:	e59f3028 	ldr	r3, [pc, #40];计算全局变量global_var对应的GOT entry=pc+40=0x320068f8+8+40=0x32006928
320068fc:	e3a02014 	mov	r2, #20
....
32006908:	e5832000 	str	r2, [r3];对全局变量global_var进行赋值
....
32006928:	32028bfc 	andcc	r8, r2, #252, 22;函数结尾附加的GOT,通过这个entry,我们就可以知道global_var实际位置在0x32028bfc


32028bfc <global_var>:
32028bfc:	0000000a 	andeq	r0, r0, sl;global_var的实际存放位置,初始值为0x0a

怎样通过GOT找到global_var呢?我们在读写global_var的时候,先通过pc相对寻址找到GOT中glabal_var的entry在0x32006928,然后就知道global_var实际的保存地址在在0x32028bfc,然后我们就可以读写global_var了。

重定向的时候,relocate_code除了把uboot从0x32000000拷贝到0x80000000以外,还需要修改GOT中每个entry的值。怎么改?就是把原值加上(0x80000000-0x32000000)。

global_var第一次重定向以后在0x32028bfc的位置,第二次重定向被拷贝到0x80028bfc。那么读写global_var就变成:

查找global_var对应的GOT entry=pc+40=0x800068f8+8+40=0x80006928。这个时候0x80006928中保存的值应该是0x32028bfc+(0x80000000-0x32000000)=80028bfc!没错,跟global_var的新位置对上了!


3)函数可以跳转了,全局变量也可以读写了,那是不是就完了呢?其实不是,还有汇编部分的变量需要relocate,这部分的原理跟第2点中的全局变量relocate是差不多的,但细节有点不一样。具体可以参考上面引用的两篇文章。


<think>好的,我现在需要解决用户在构建U-Boot时遇到的&ldquo;ERROR: Nopython2”错误。用户之前的问题是关于缺少Python2导致的问题,所以我得先回想一下常见的解决方法。首先,用户可能在系统里没有安装Python2,或者默认的Python指向了Python3。现在很多Linux发行版默认使用Python3,而U-Boot的某些构建脚本可能依赖Python2。所以第一步应该是检查系统是否安装了Python2。可以通过在终端输入`python2--version`来确认。如果提示命令未找到,说明需要安装Python2。接下来,安装Python2。不同的Linux发行版有不同的包管理工具。例如,Ubuntu或Debian可以使用`sudo aptinstall python2`,而CentOS或Fedora可能需要用`yum`或`dnf`。安装完成后,再次检查版本确保安装成功。 然后,可能需要设置Python2为默认版本。因为系统可能默认使用Python3,导致构建脚本找不到Python2。这里可以使用`update-alternatives`命令来配置默认的Python版本。例如,运行`sudoupdate-alternatives--configpython`并选择Python2的路径。不过需要注意的是,更改系统默认Python版本可能会影响其他依赖Python3的应用程序,所以需要谨慎操作,或者仅在构建U-Boot时临时切换。另一种方法是在构建U-Boot时指定Python2的路径。如果用户不想更改系统默认设置,可以通过环境变量或构建参数告诉U-Boot使用特定的Python解释器。例如,在make命令中添加`PYTHON=python2`,这样构建脚本就会使用指定的Python2执行相关任务。 另外,用户可能需要安装Python2的相关开发工具或库。有时候,构建过程不仅需要Python解释器,还需要某些模块或头文件。例如,安装`python2-dev`或类似的包,确保所有依赖项都满足。还有可能的情况是U-Boot的版本问题。如果用户使用的是较新的U-Boot版本,可能已经开始支持Python3。这时候,可以查看官方文档或更新日志,确认是否有相关改动。如果有,可以尝试升级U-Boot到支持Python3的版本,避免安装旧的Python2环境。最后,用户可能遇到环境变量的问题。例如,PATH变量中没有包含Python2的路径,或者虚拟环境配置不正确。检查环境变量,确保构建脚本能够正确找到Python2的位置。总结下来,步骤大概是:安装Python2,设置默认版本或指定路径,安装相关依赖,检查U-Boot版本,处理环境变量。需要根据具体情况选择合适的方法,同时注意系统兼容性,避免影响其他应用。</think>### 解决构建 u-boot 时因缺少 Python2 导致的错误 #### 问题根源分析 u-boot 部分构建脚本依赖 Python2 解释器,当系统默认配置为 Python3 或未安装 Python2 时,会触发`ERROR: No python2`报错[^1]。 #### 逐步解决方案 1. **验证 Python2 是否存在** 终端输入: ```bash python2 --version ``` 若返回`Python 2.x.x`则跳过安装步骤,否则继续 2. **安装 Python2** - Ubuntu/Debian: ```bash sudo apt install python2 ``` - CentOS/RHEL: ```bash sudo yum install python2 ``` 3. **创建软链接(关键步骤)** ```bash sudo ln -s /usr/bin/python2 /usr/bin/python # 强制指定python指向python2 ``` > *注意:此操作会暂时覆盖系统默认python解释器,建议完成u-boot构建后恢复原配置* 4. **验证配置有效性** ```bash python --version # 应显示Python 2.x.x ``` 5. **恢复系统默认配置(可选)** 构建完成后执行: ```bash sudo ln -sf /usr/bin/python3 /usr/bin/python # 重新指向Python3 ``` #### 替代方案(推荐) 通过环境变量直接指定 Python2 路径,避免修改系统配置: ```bash export PYTHON=python2 make [your_target] # 构建时自动调用指定解释器 ``` #### 注意事项 - 若遇到`ImportError: No module named...`,需安装 Python2 的额外模块: ```bash sudo apt install python2-dev # 开发依赖包 ``` - 部分旧版 u-boot 可能要求特定 Python2 版本(如 2.7),可通过`python2 -V`确认版本 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值