一,前言
我之前一篇《uboot的重定向汇编》文中说明有一个不理解的疑问项,我需要获取更多理论知识支撑及做实验来理解验证,我先快速的看了《程序员的自我修养》前4章节,于是又了解了些重定向的细节。
二,对uboot重定向继续实验来解惑
- 我想做的一件事就是先确认之前有0x17,重定向后无0x17了,变成0即可。
于是我重新开始调试,目的是看下copy后的数据信息是否有0x17若没有,是否值为0。发现0x7ff55021居然有值,不是我想想中的0,这段地址不是没人用吗?我再仔细看看这个地址,如下图,我突然意识到这个地址不就是image搬移过去的开头吗?而我一直理解的是image结束后的地址,也就是我理解的一直都是rel.dyn中的地址。
那么原来我又一部分内容理解错误了,r0的值是符号表的内容,不是符号表的地址。所以r0加上offset的地址是image中的符号位置,而r0的内容就是map文件中重定向的符号表地址信息,也可以说是之前image中的内容,
add r0, r0, r4 // r0=0x7ff55020
ldr r1, [r0] // r1=0x60800060
add r1, r1, r4 // r1=0服务器托管网x7ff55060
str r1, [r0] // r0地址内容从原来的0x60800060变成了7FF55060
所以如上4句就是修改重定向地址,修改的对象是image中的内容,而仅仅依赖了.rel.dyn中内容来寻找罢了,寻找的过程就是模仿了加载器修复重定向地址的过程(这个0x17就是,动态加载的时候,加载器扫描到有动态段需要重定向地址,然后根据符号表,将elf中的地址进行填充)。这个过程简单描述就是通过符号信息地址找到跳转对象,然后将跳转对象符号改成绝对地址。
- 另外一个问题,就是这到底算动态链接还是静态链接。
因为我理解静态链接是编译过程就完成了重定向地址修复。因为把每个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 :
。。。
60800510: e59f3014 ldr r3, [pc, #20] ; 6080052c
。。。
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 :
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 :
。。。
60800510: e59f3014 ldr r3, [pc, #20] ; 6080052c
。。。
6080052c: 608003ac .word 0x608003ac
对比段map文件,发现除了rel.dyn少了,还少了.hash段,但是这样对比麻烦,因为.hash后地址错位了,看起来不太容易。
直接打印elf的段arm-linux-gnueabihf-readelf -S u-boot后对比,发现少了如下7个段。
证明我服务器托管网的理解正确,-pie主要为了增加rel.dyn段,这样才可以通过汇编代码实现运行时候的重定向。
三,小结
好了,昨天的问题已解决,通过做实验闭环理解,把我之前的错误理解项给纠正了,对于o文件链接后的地址重定向也有了更多的了解。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: CSDN打出各种数学符号和数学公式
1、基本四则运算
2、指数对数
3、根号、省略号、向量
4、大(小)于等于号
5、特殊符号、希腊字母符号
6、累加累乘
7、矩阵
8、更改公式中的颜色目录 1、基本四则运算 2、指数对数 3、根号、省略号、向量 4、大(小)于等于号 5、特殊符号、希腊字母符号 6、累加累乘 7、矩阵 8、更改公式中的颜色 我们在用CSDN打出各种数学符号和数学公式时,需要学习一些关于LaTex的语法,在此做一个记录: 1、…