Save and restore r9 register in arm ubldr. In old gcc 4.2, r9 was a callee-
saved register, but in arm EABI it may be either callee-saved or dedicated to some special purpose (such as a TLS pointer). It appears clang does not treat it as a callee-saved register (instead using it as another work register, similar to r12). Another important side effect of these changes is that saving an extra register in the push/pop statements keeps the stack aligned to an 8-byte boundary during the self_reloc() call, as it always should have been. As stated in the PR... Essentially the important caller-saved registers are pushed (r0, r1, r9, lr) before the relocation call, and popped after. Then r8/r9 are saved as usual for the syscall trampoline, and lr is stored in r8 (now free) as a callee-saved value before calling into `main`. The call to `main` can no longer be a tail call because we must restore r9 especially after main returns (although since we have used r8 to hold lr we must also restore this). PR: 224008
This commit is contained in:
parent
3102bbe940
commit
12b92a343c
@ -46,11 +46,8 @@ _start:
|
|||||||
mcr p15, 0, ip, c1, c0, 0
|
mcr p15, 0, ip, c1, c0, 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Save the arguments and return register before calling self_reloc */
|
||||||
* Save r0 and r1 (argc and argv passed from u-boot), and lr (trashed
|
push {r0, r1, r9, lr}
|
||||||
* by the call to self_reloc below) until we're ready to call main().
|
|
||||||
*/
|
|
||||||
push {r0, r1, lr}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do self-relocation when the weak external symbol _DYNAMIC is non-NULL.
|
* Do self-relocation when the weak external symbol _DYNAMIC is non-NULL.
|
||||||
@ -68,22 +65,31 @@ _start:
|
|||||||
addne r1, r1, r0 /* r1 = dynamic section physaddr. */
|
addne r1, r1, r0 /* r1 = dynamic section physaddr. */
|
||||||
blne _C_LABEL(self_reloc) /* Do reloc if _DYNAMIC is non-NULL. */
|
blne _C_LABEL(self_reloc) /* Do reloc if _DYNAMIC is non-NULL. */
|
||||||
|
|
||||||
|
/* Restore saved arguments */
|
||||||
|
pop {r0, r1, r9, lr}
|
||||||
|
|
||||||
/* Hint where to look for the API signature */
|
/* Hint where to look for the API signature */
|
||||||
ldr ip, =uboot_address
|
ldr ip, =uboot_address
|
||||||
str sp, [ip]
|
str sp, [ip]
|
||||||
|
|
||||||
/* Save U-Boot's r8 and r9 */
|
/* Save U-Boot's r8 and r9 for syscall trampoline */
|
||||||
ldr ip, =saved_regs
|
ldr ip, =saved_regs
|
||||||
str r8, [ip, #0]
|
str r8, [ip, #0] /* old gd pointer (use to hold lr) */
|
||||||
str r9, [ip, #4]
|
str r9, [ip, #4] /* new gd pointer */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First restore argc, argv, and the u-boot return address, then
|
* Start loader. Save return address first (r8 is available from
|
||||||
* Start loader. This is basically a tail-recursion call; if main()
|
* trampoline save).
|
||||||
* returns, it returns to u-boot (which reports the value returned r0).
|
|
||||||
*/
|
*/
|
||||||
pop {r0, r1, lr}
|
mov r8, lr
|
||||||
b main
|
bl main
|
||||||
|
mov lr, r8
|
||||||
|
|
||||||
|
/* Restore U-Boot environment */
|
||||||
|
ldr ip, =saved_regs
|
||||||
|
ldr r8, [ip, #0]
|
||||||
|
ldr r9, [ip, #4]
|
||||||
|
mov pc, lr
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data for self-relocation, in the text segment for pc-rel access.
|
* Data for self-relocation, in the text segment for pc-rel access.
|
||||||
|
Loading…
Reference in New Issue
Block a user