uboot的重定向原理分析--Apple的学习笔记
  2Nv1H5BMjysw 2023年11月05日 40 0

一,前言

我之前一篇《uboot的重定向汇编》文中说明有一个不理解的疑问项,我需要获取更多理论知识支撑及做实验来理解验证,我先快速的看了《程序员的自我修养》前4章节,于是又了解了些重定向的细节。


二,对uboot重定向继续实验来解惑

  1. 我想做的一件事就是先确认之前有0x17,重定向后无0x17了,变成0即可。

于是我重新开始调试,目的是看下copy后的数据信息是否有0x17若没有,是否值为0。发现0x7ff55021居然有值,不是我想想中的0,这段地址不是没人用吗?我再仔细看看这个地址,如下图,我突然意识到这个地址不就是image搬移过去的开头吗?而我一直理解的是image结束后的地址,也就是我理解的一直都是rel.dyn中的地址。

uboot的重定向原理分析--Apple的学习笔记_绝对地址

那么原来我又一部分内容理解错误了,r0的值是符号表的内容,不是符号表的地址。所以r0加上offset的地址是image中的符号位置,而r0的内容就是map文件中重定向的符号表地址信息,也可以说是之前image中的内容,

add	r0, r0, r4             // r0=0x7ff55020
	ldr	r1, [r0]               // r1=0x60800060
	add	r1, r1, r4             // r1=0x7ff55060
	str	r1, [r0]               // r0地址内容从原来的0x60800060变成了7FF55060

所以如上4句就是修改重定向地址,修改的对象是image中的内容,而仅仅依赖了.rel.dyn中内容来寻找罢了,寻找的过程就是模仿了加载器修复重定向地址的过程(这个0x17就是,动态加载的时候,加载器扫描到有动态段需要重定向地址,然后根据符号表,将elf中的地址进行填充)。这个过程简单描述就是通过符号信息地址找到跳转对象,然后将跳转对象符号改成绝对地址。


  1. 另外一个问题,就是这到底算动态链接还是静态链接。

因为我理解静态链接是编译过程就完成了重定向地址修复。因为把每个o模块合并起来就等于做了重定向地址修复。但是动态编译的地址修复是在加载过程中,具体这个动态加载过程包括具体哪些内容,及用了哪些程序,我还不是很清楚。但是我理解应该就是加载so文件的。但是我是的uboot,此时都没有linux系统,u-boot的elf就和普通单片机程序一样,按地址烧录后,pc就按地址运行了。所以我理解我的代码不需要加载so,链接的都是静态库文件生成的elf,仅仅为了模仿加载器的重定向修复,所以ld的参加了-pie,目的就是为了多生成.rel.dyn段而已,所以若不用这个段,也就是说作为程序员写c代码过程中不做重定向功能,代码依然可以运行的,因为编译完elf已经完成了绝对地址的写入,所以如上4句也就是先找到之前的绝对地址,再加上offset。 答:我理解这算是静态编译,且增加了动态编译需要的rel.dyn段,而这4行汇编中r0其实是符号,符号在image内,所以一起迁移了,才需要加offset r4。然后符号中的值是之前计算的绝对地址。我需要实验对我的理解进行闭环验证。

实验1:证明-pie和不带-pie编译的在image中通过编译elf就已经完成了地址修复 arm-linux-gnueabihf-objdump -s -d u-boot > u-boot.dump 分析rel.dyn中的内容。

Contents of section .rel.dyn:
 608919f4 20008060 17000000 24008060 17000000   ..`....$..`....
 60891a04 28008060 17000000 2c008060 17000000  (..`....,..`....
 60891a14 30008060 17000000 34008060 17000000  0..`....4..`....
 60891a24 38008060 17000000 a0038060 17000000  8..`.......`....
 60891a34 24058060 17000000 28058060 17000000  $..`....(..`....
 60891a44 2c058060 17000000 30058060 17000000  ,..`....0..`....

来看看汇编,首先重定向符号中有2c058060,也就是地址0x6080502C。搜索到如下2行。

60800500 <efi_runtime_detach>:
。。。
60800510:	e59f3014 	ldr	r3, [pc, #20]	; 6080052c <efi_runtime_detach+0x2c>
。。。
6080052c:	608003ac 	.word	0x608003ac

这段代码理解为efi_runtime_detach函数中会调用外部符号pc, #20,0x60800510是PC地址加上20就是0x60800524,还需要加8,也就是0x6080052c(因为是arm的三级流水线,“PC = PC + 8”真正含义应该是: 执行处代码地址 = PC - 8),里面的要跳转的绝对地址是608003ac 也就是调用了函数efi_get_time。

608003ac <efi_get_time>:
608003ac:	e3a0010e 	mov	r0, #-2147483645	; 0x80000003
608003b0:	e12fff1e 	bx	lr

在map文件中也可以找到 0x00000000608003ac efi_get_time我再来看看代码是否这样调用的,果然把函数地址赋值给了get_time,efi_get_time算一个外部引用符号,所以出现在了rel.dyn段中。

void efi_runtime_detach(void)
{
	efi_runtime_services.reset_system = efi_reset_system;
	efi_runtime_services.get_time = efi_get_time;
	efi_runtime_services.set_time = efi_set_time;
...
}

证明elf中都是绝对地址,没有相对地址的,在编译后就完成了地址修复,我的理解是正确的。

实验2:不加-pie唯一的区别应该就是少了rel.dyn段,这些o文件之间依然有绝对地址。 我开始做实验,验证自己的猜测,先注释掉makefile中的-pie #LDFLAGS_u-boot += -pie // by apple 接着checkarmreloc报错,无法编译u-boot,所以我把此目标也注释掉

INPUTS-y += checkarmreloc  // by apple

接着dump出来看到内容是一样的,绝对地址也是有的

60800500 <efi_runtime_detach>:
。。。
60800510:	e59f3014 	ldr	r3, [pc, #20]	; 6080052c <efi_runtime_detach+0x2c>
。。。
6080052c:	608003ac 	.word	0x608003ac

对比段map文件,发现除了rel.dyn少了,还少了.hash段,但是这样对比麻烦,因为.hash后地址错位了,看起来不太容易。 直接打印elf的段arm-linux-gnueabihf-readelf -S u-boot后对比,发现少了如下7个段。

uboot的重定向原理分析--Apple的学习笔记_符号表_02

证明我的理解正确,-pie主要为了增加rel.dyn段,这样才可以通过汇编代码实现运行时候的重定向。

三,小结

好了,昨天的问题已解决,通过做实验闭环理解,把我之前的错误理解项给纠正了,对于o文件链接后的地址重定向也有了更多的了解。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

2Nv1H5BMjysw