Commit d1196787 authored by Ard Biesheuvel's avatar Ard Biesheuvel
Browse files

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
Loading
Loading
Loading
Loading
+22 −29
Original line number Diff line number Diff line
@@ -22,10 +22,7 @@
 * 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
 * callee: the original lr needs to be restored when leaving mcount, and no
 * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
 * 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.)
 * registers should be clobbered.
 *
 * 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).
@@ -70,24 +67,23 @@

.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

	add 	ip, sp, #12	@ move in IP the value of SP as it was
				@ before the push {lr} of the mcount mechanism

	str     lr, [sp, #0]    @ store LR instead of PC

	ldr	lr, [sp, #8]    @ get previous LR

	str	r0, [sp, #8]	@ write r0 as OLD_R0 over previous LR

	stmdb   sp!, {ip, lr}
	stmdb   sp!, {r0-r11, lr}
	str	lr, [sp, #-4]!	@ store previous LR as LR

	add 	lr, sp, #16	@ move in LR the value of SP as it was
				@ before the push {lr} of the mcount mechanism

	push	{r0-r11, ip, lr}

	@ stack content at this point:
	@ 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*

@@ -112,11 +108,9 @@ ftrace_graph_regs_call:
#endif

	@ pop saved regs
	ldmia   sp!, {r0-r12}			@ restore r0 through r12
	ldr	ip, [sp, #8]			@ restore PC
	ldr	lr, [sp, #4]			@ restore LR
	ldr	sp, [sp, #0]			@ restore SP
	mov	pc, ip				@ return
	pop	{r0-r11, ip, lr}		@ restore r0 through r12
	ldr	lr, [sp], #4			@ restore LR
	ldr	pc, [sp], #12
.endm

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -132,11 +126,9 @@ ftrace_graph_regs_call:
	bl	prepare_ftrace_return

	@ pop registers saved in ftrace_regs_caller
	ldmia   sp!, {r0-r12}			@ restore r0 through r12
	ldr	ip, [sp, #8]			@ restore PC
	ldr	lr, [sp, #4]			@ restore LR
	ldr	sp, [sp, #0]			@ restore SP
	mov	pc, ip				@ return
	pop	{r0-r11, ip, lr}		@ restore r0 through r12
	ldr	lr, [sp], #4			@ restore LR
	ldr	pc, [sp], #12

.endm
#endif
@@ -202,16 +194,17 @@ ftrace_graph_call\suffix:
.endm

.macro mcount_exit
	ldmia	sp!, {r0-r3, ip, lr}
	ret	ip
	ldmia	sp!, {r0-r3}
	ldr	lr, [sp, #4]
	ldr	pc, [sp], #8
.endm

ENTRY(__gnu_mcount_nc)
UNWIND(.fnstart)
#ifdef CONFIG_DYNAMIC_FTRACE
	mov	ip, lr
	ldmia	sp!, {lr}
	ret	ip
	push	{lr}
	ldr	lr, [sp, #4]
	ldr	pc, [sp], #8
#else
	__mcount
#endif