Commit d1196787 authored by Ard Biesheuvel's avatar Ard Biesheuvel

ARM: ftrace: avoid redundant loads or clobbering IP

Tweak the ftrace return paths to avoid redundant loads of SP, as well as
unnecessary clobbering of IP.

This also fixes the inconsistency of using MOV to perform a function
return, which is sub-optimal on recent micro-architectures but more
importantly, does not perform an interworking return, unlike compiler
generated function returns in Thumb2 builds.

Let's fix this by popping PC from the stack like most ordinary code
does.
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Reviewed-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent dc438db5
...@@ -22,10 +22,7 @@ ...@@ -22,10 +22,7 @@
* mcount can be thought of as a function called in the middle of a subroutine * mcount can be thought of as a function called in the middle of a subroutine
* call. As such, it needs to be transparent for both the caller and the * call. As such, it needs to be transparent for both the caller and the
* callee: the original lr needs to be restored when leaving mcount, and no * callee: the original lr needs to be restored when leaving mcount, and no
* registers should be clobbered. (In the __gnu_mcount_nc implementation, we * registers should be clobbered.
* clobber the ip register. This is OK because the ARM calling convention
* allows it to be clobbered in subroutines and doesn't use it to hold
* parameters.)
* *
* When using dynamic ftrace, we patch out the mcount call by a "add sp, #4" * When using dynamic ftrace, we patch out the mcount call by a "add sp, #4"
* instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
...@@ -70,26 +67,25 @@ ...@@ -70,26 +67,25 @@
.macro __ftrace_regs_caller .macro __ftrace_regs_caller
sub sp, sp, #8 @ space for PC and CPSR OLD_R0, str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0,
@ OLD_R0 will overwrite previous LR @ OLD_R0 will overwrite previous LR
add ip, sp, #12 @ move in IP the value of SP as it was ldr lr, [sp, #8] @ get previous LR
@ before the push {lr} of the mcount mechanism
str lr, [sp, #0] @ store LR instead of PC str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
ldr lr, [sp, #8] @ get previous LR str lr, [sp, #-4]! @ store previous LR as LR
str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR add lr, sp, #16 @ move in LR the value of SP as it was
@ before the push {lr} of the mcount mechanism
stmdb sp!, {ip, lr} push {r0-r11, ip, lr}
stmdb sp!, {r0-r11, lr}
@ stack content at this point: @ stack content at this point:
@ 0 4 48 52 56 60 64 68 72 @ 0 4 48 52 56 60 64 68 72
@ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 |
mov r3, sp @ struct pt_regs* mov r3, sp @ struct pt_regs*
ldr r2, =function_trace_op ldr r2, =function_trace_op
ldr r2, [r2] @ pointer to the current ldr r2, [r2] @ pointer to the current
...@@ -112,11 +108,9 @@ ftrace_graph_regs_call: ...@@ -112,11 +108,9 @@ ftrace_graph_regs_call:
#endif #endif
@ pop saved regs @ pop saved regs
ldmia sp!, {r0-r12} @ restore r0 through r12 pop {r0-r11, ip, lr} @ restore r0 through r12
ldr ip, [sp, #8] @ restore PC ldr lr, [sp], #4 @ restore LR
ldr lr, [sp, #4] @ restore LR ldr pc, [sp], #12
ldr sp, [sp, #0] @ restore SP
mov pc, ip @ return
.endm .endm
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
...@@ -132,11 +126,9 @@ ftrace_graph_regs_call: ...@@ -132,11 +126,9 @@ ftrace_graph_regs_call:
bl prepare_ftrace_return bl prepare_ftrace_return
@ pop registers saved in ftrace_regs_caller @ pop registers saved in ftrace_regs_caller
ldmia sp!, {r0-r12} @ restore r0 through r12 pop {r0-r11, ip, lr} @ restore r0 through r12
ldr ip, [sp, #8] @ restore PC ldr lr, [sp], #4 @ restore LR
ldr lr, [sp, #4] @ restore LR ldr pc, [sp], #12
ldr sp, [sp, #0] @ restore SP
mov pc, ip @ return
.endm .endm
#endif #endif
...@@ -202,16 +194,17 @@ ftrace_graph_call\suffix: ...@@ -202,16 +194,17 @@ ftrace_graph_call\suffix:
.endm .endm
.macro mcount_exit .macro mcount_exit
ldmia sp!, {r0-r3, ip, lr} ldmia sp!, {r0-r3}
ret ip ldr lr, [sp, #4]
ldr pc, [sp], #8
.endm .endm
ENTRY(__gnu_mcount_nc) ENTRY(__gnu_mcount_nc)
UNWIND(.fnstart) UNWIND(.fnstart)
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
mov ip, lr push {lr}
ldmia sp!, {lr} ldr lr, [sp, #4]
ret ip ldr pc, [sp], #8
#else #else
__mcount __mcount
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment