diff options
Diffstat (limited to 'arch/arm/cpu/armv7/start.S')
-rw-r--r-- | arch/arm/cpu/armv7/start.S | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 87329d26e1..698e15b8e1 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -39,6 +39,42 @@ reset: /* Allow the board to save important registers */ b save_boot_params save_boot_params_ret: +#ifdef CONFIG_POSITION_INDEPENDENT + /* + * Fix .rela.dyn relocations. This allows U-Boot to loaded to and + * executed at a different address than it was linked at. + */ +pie_fixup: + adr r0, reset /* r0 <- Runtime value of reset label */ + ldr r1, =reset /* r1 <- Linked value of reset label */ + subs r4, r0, r1 /* r4 <- Runtime-vs-link offset */ + beq pie_fixup_done + + adr r0, pie_fixup + ldr r1, _rel_dyn_start_ofs + add r2, r0, r1 /* r2 <- Runtime &__rel_dyn_start */ + ldr r1, _rel_dyn_end_ofs + add r3, r0, r1 /* r3 <- Runtime &__rel_dyn_end */ + +pie_fix_loop: + ldr r0, [r2] /* r0 <- Link location */ + ldr r1, [r2, #4] /* r1 <- fixup */ + cmp r1, #23 /* relative fixup? */ + bne pie_skip_reloc + + /* relative fix: increase location by offset */ + add r0, r4 + ldr r1, [r0] + add r1, r4 + str r1, [r0] + str r0, [r2] + add r2, #8 +pie_skip_reloc: + cmp r2, r3 + blo pie_fix_loop +pie_fixup_done: +#endif + #ifdef CONFIG_ARMV7_LPAE /* * check for Hypervisor support @@ -340,3 +376,10 @@ ENTRY(cpu_init_crit) b lowlevel_init @ go setup pll,mux,memory ENDPROC(cpu_init_crit) #endif + +#if CONFIG_POSITION_INDEPENDENT +_rel_dyn_start_ofs: + .word __rel_dyn_start - pie_fixup +_rel_dyn_end_ofs: + .word __rel_dyn_end - pie_fixup +#endif |