http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29963649&id=5765650
1.为什么写这篇文章
前段时间在做一个ARMv8的u-boot移植工作,接触到新版的u-boot2016,对其编译rela.dyn段摸摸索索一段时间,在网上找这方面的资料感觉不是很多。在移植基本完成后,想对其一番理解总结出来,对自己算是一个总结的过程,对大家若有遇到类似的问题或许有帮助。一举两得之事,何乐不为?
2.这方面的总结文章以前有哪些?
以下是我看到过的对此文阅读有帮助的博文:
《uboot的relocation原理详细分析 》博主:做一个有技术追求的人
http://blog.csdn.net/skyflying2012/article/details/37660265
这篇博文写得不错,对ARM relocation原理的理解不仅有详细描述而且用实例测验了这些原理,很是深刻。非常推荐阅读并深入一番。
而我所接触的问题不仅仅是relocation原理理解的问题,还有ARMv8编译过程参数的问题。
_main:
bl board_init_f_alloc_reserve
bl board_init_f_init_reserve
bl board_init_f
adr lr, relocation_return
ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd-="">reloc_off */
add lr, lr, x9 /* new return address after relocation */
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd-="">relocaddr */
b relocate_code //进入relocation,但是relocation返回后仍是返回relocation_return,也就是这个语句之后
ENTRY(relocate_code)
copy_loop: //实现对代码段的copy到RAM
ldp x10, x11, [x1], #16 /* copy from source address [x1] */
stp x10, x11, [x0], #16 /* copy to target address [x0] */
cmp x1, x2 /* until source end address [x2] */
b.lo copy_loop
str x0, [sp, #24]
/*
* Fix .rela.dyn relocations
*/
ldr x2, =__rel_dyn_start /* x2 <- SRC &__rel_dyn_start */
ldr x3, =__rel_dyn_end /* x3 <- SRC &__rel_dyn_end */
fixloop: //以下这段就是对rela.dyn的内容重定向
ldp x0, x1, [x2], #16 /* (x0,x1) <- (SRC location, fixup) ,x0=[x2], x1=[x2+8],x2+=16*/
ldr x4, [x2], #8 /* x4 <- addend */ x4=[x2],x2+=8
and x1, x1, #0xffffffff
cmp x1, #1027 /* relative fixup? 1027=0x403*/
bne fixnext
由上可知x9 <- relocation offset
/* relative fix: store addend plus offset at dest location */
add x0, x0, x9
add x4, x4, x9
str x4, [x0] //*(x0+offs)=(x4+offs)
fixnext:
cmp x2, x3
b.lo fixloop
以下是rela.dyn的数据,
60144c00: 601001b0
60144c04: 00000000 x0=0x00000000601001b0,address
60144c08: 00000403
60144c0c: 00000000 x1=0x0000000000000403,type
60144c10: 601003d0 x2=0x0000000060344c10
60144c14: 00000000 x4=0x00000000601003d0,data
上面最后fixloop就是个根据rela.dyn段修复代码中的label(就是address的位置),address+offset后的值进行重定向,*(address+offset)=(data+offset)
对于AArch64架构,一组rela.dyn数据有3个64位数据组成,从上到下分别是需要重定向的原始地址,重定向类型,重定向的原始数据。
有了需要重定向的原始地址和重定向的原始数据、offset(偏移)就可以对需要重定向的标号,为什么还是type呢?原因是有很多类型的重定向,比如R_ARM_RELATIVE,R_ARM_ABS64。这些内容在百度可以查到。
1.链接参数-pie
链接器根据-pie参数才会生成rela.dyn段,若移植的时候发生没有生成rela.dyn段,检查这个参数是否包含。
# needed for relocation
LDFLAGS_u-boot += -pie
本人在做项目的时候,因为是移植一个厂家的驱动到低版本的uboot,还不支持ARMv8架构,所以arch/arch目录也要移植,移植的时候加了这个参数,但是还是出现了问题。就是移植时没加这个参数时本身代码是可以运行到打印的,加了这个参数直接不能打印了。最后发现的原因就是下面要说的第二点静态rela.dyn修复这段命令没有增加。
2.静态rela.dyn修复
当时出现的现象生成的u-boot.bin中label直接为0,如下bin文件反汇编示意
bin文件反汇编示意
601001b0: 00000000 //称之为label
601001b4: 00000000
rela.dyn段
60144c00: 601001b0
60144c04: 00000000 x0=0x00000000601001b0,address
60144c08: 00000403
60144c0c: 00000000 x1=0x0000000000000403,type
60144c10: 601003d0 x2=0x0000000060344c10
60144c14: 00000000 x4=0x00000000601003d0,data
最后是通过Demo u-boot的编译过程发现了,还有使用relocate-rela工具对对u-boot.bin静态reloc的过程。命令如下:
# Statically apply RELA-style relocations (currently arm64 only)
ifneq ($(CONFIG_STATIC_RELA),)
# $(1) is u-boot ELF, $(2) is u-boot bin, $(3) is text base
DO_STATIC_RELA = \
start=$$($(NM) $(1) | grep __rel_dyn_start | cut -f 1 -d ' '); \
end=$$($(NM) $(1) | grep __rel_dyn_end | cut -f 1 -d ' '); \
tools/relocate-rela $(2) $(3) $$start $$end
else
DO_STATIC_RELA =
Endif
DO_STATIC_RELA动作生成的目标是u-boot-nodtb.bin
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
3.c文件定义__bss_start等符号
除了上面两部,还有要注意的一点就是不能在lds链接文件中定义__bss_start,__bss_end等符号,一定要在c文件中定义。
char __bss_start[0] __attribute__((section(".__bss_start")));
char __bss_end[0] __attribute__((section(".__bss_end")));
char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
原因从arch/arm/lib/section.c文件的注释中可以得知
/**
* These two symbols are declared in a C file so that the linker
* uses R_ARM_RELATIVE relocation, rather than the R_ARM_ABS32 one
* it would use if the symbols were defined in the linker file.
* Using only R_ARM_RELATIVE relocation ensures that references to
* the symbols are correct after as well as before relocation.
链接规则决定了c文件中定义的符号按R_ARM_RELATIVE类型链接,否则会按R_ARM_ABS32类型链接。使用R_ARM_RELATIVE类型才能确保引用这些符号的地方在搬移前也是正确的。