U-boot version: GIT clone tag v2016.01-rc1
ARM gcc: arm-none-eabi-gcc 5.2.1
Trying to port U-boot to STM32F10x MCU, found U-boot .rel.dyn section is interesting. And it includes .dynsym and .dynstr section.
Now just write down how it works.
First let's see the example C-code.
unsigned long clock_get(enum clock clck)
{
u32 sysclk = 0;
u32 shift = 0;
/* Prescaler table lookups for clock computation */
u8 ahb_psc_table[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
};
/*operations*/
}
注意ahb_psc_table[]数组,relocation的对象就是数据。
The assemble code is:
80005ac: 5cd3 ldrb r3, [r2, r3]
80005ae: 40d8 lsrs r0, r3
80005b0: e000 b.n 80005b4 <clock_get+0x84>
80005b2: 2000 movs r0, #0
80005b4: b004 add sp, #16
80005b6: bd70 pop {r4, r5, r6, pc}
80005b8: 08014766 stmdaeq r1, {r1, r2, r5, r6, r8, r9, sl, lr} /*0x8014766 is the ahb_psc_table[] array.0x80005b8 is the index of the array.*/
80005bc: 40023808 andmi r3, r2, r8, lsl #16
80005c0: 40023804 andmi r3, r2, r4, lsl #16
80005c4: 007a1200 rsbseq r1, sl, r0, lsl #4
80005c8: 0801a7a6 stmdaeq r1, {r1, r2, r5, r7, r8, r9, sl, sp, pc}
可以看到ahb_psc_table[]数组的地址(0x8014766)被存放在函数尾部 0x080005b8的位置。
The ahb_psc_table[] is stored in .rodata section.
8014764: 0000000f andeq r0, r0, pc /*0x8014766 start is ahb_psc_table[]={0,0,0,0,1,2,3,4,6,7,8,9}*/
8014768: 00000000 andeq r0, r0, r0
801476c: 02010000 andeq r0, r1, #0
8014770: 07060403 streq r0, [r6, -r3, lsl #8]
8014774: 00000908 andeq r0, r0, r8, lsl #18
这里是ahb_psc_table[]数据的实际存储位置。
The rel.dyn section is:
Disassembly of section .rel.dyn:
0801c3fc <__rel_dyn_end-0x48e0>:
801c3fc: 08000528 stmdaeq r0, {r3, r5, r8, sl}
801c400: 00000017 andeq r0, r0, r7, lsl r0
801c404: 080005b8 stmdaeq r0, {r3, r4, r5, r7, r8, sl} /*0x80005b8 is the index of ahb_psc_table[]*/
801c408: 00000017 andeq r0, r0, r7, lsl r0
801c40c: 080005c8 stmdaeq r0, {r3, r6, r7, r8, sl}
the relocation table item 0x801c404 is the index of ahb_psc_table[] item.
relocation表里存的是函数后面存放ahb_psc_table[]地址的单元的地址。
Then the question is how to use this relocation table. Let's check the code of arch/arm/lib/relocation.S(removed un-used code)
ENTRY(relocate_code)
ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
subs r4, r0, r1 /* r4 <- relocation offset */
beq relocate_done /* skip relocation */
ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */
copy_loop:
ldmia r1!, {r10-r11} /* copy from source address [r1] */
stmia r0!, {r10-r11} /* copy to target address [r0] */
cmp r1, r2 /* until source end address [r2] */
blo copy_loop
/*
* fix .rel.dyn relocations
*/
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
fixloop:
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
and r1, r1, #0xff
cmp r1, #23 /* relative fixup? */
bne fixnext
/* relative fix: increase location by offset */
add r0, r0, r4 /*calculate 0x80005b8's RAM address*/
ldr r1, [r0] /*read 0x80005b8's content--ahb_psc_table[] address*/
add r1, r1, r4 /*modify ahb_psc_table[] address to RAM(new address)*/
str r1, [r0] /*write back ahb_psc_table[]'s new address to 0x80005b8's RAM address*/
fixnext:
cmp r2, r3
blo fixloop
relocate_done:
bx lr
ENDPROC(relocate_code)
Got it ? It looks complex.
其实relocation函数改变的是函数后面单元中存放的ahb_psc_table[]数组的地址。因为整个image被搬移到了新地址(relocation feature假设整个image都搬移了),所以函数后面单元中存放的ahb_psc_table[]数组的地址必须修改,不然就找不到正确的ahb_psc_table[]数组。
The idea is:
1. Each function has an index for each variable which is bigger than 4 bytes.
2. Put all variables' index into the relocation table. After copy the data section to the new address, the U-boot could easily modify the address of all variables.
Here should insert a picture to make it more clear.
But if you don't need relocation, how to disable it? Open arch/arm/config.mk file.
# needed for relocation
LDFLAGS_u-boot += -pie /*This is for link process*/
This is the first place.
ifneq ($(CONFIG_SPL_BUILD),y)
# Check that only R_ARM_RELATIVE relocations are generated.
ALL-y += checkarmreloc
# The movt / movw can hardcode 16 bit parts of the addresses in the
# instruction. Relocation is not supported for that case, so disable
# such usage by requiring word relocations.
PLATFORM_CPPFLAGS += $(call cc-option, -mword-relocations)
endif
This is the second place and it is for gcc.
So disable these two places, you could disable the relocation feature. Attention, checkarmreloc need disable.