Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: memmove: use frame pointer as unwind anchor

The memmove routine is a bit unusual in the way it manages the stack
pointer: depending on the execution path through the function, the SP
assumes different values as different subsets of the register file are
preserved and restored again. This is problematic when it comes to EHABI
unwind info, as it is not instruction accurate, and does not allow
tracking the SP value as it changes.

Commit 207a6cb06990c ("ARM: 8224/1: Add unwinding support for memmove
function") addressed this by carving up the function in different chunks
as far as the unwinder is concerned, and keeping a set of unwind
directives for each of them, each corresponding with the state of the
stack pointer during execution of the chunk in question. This not only
duplicates unwind info unnecessarily, but it also complicates unwinding
the stack upon overflow.

Instead, let's do what the compiler does when the SP is updated halfway
through a function, which is to use a frame pointer and emit the
appropriate unwind directives to communicate this to the unwinder.

Note that Thumb-2 uses R7 for this, while ARM uses R11 aka FP. So let's
avoid touching R7 in the body of the function, so that Thumb-2 can use
it as the frame pointer. R11 was not modified in the first place.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Keith Packard <keithpac@amazon.com>
Tested-by: Marc Zyngier <maz@kernel.org>
Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M

+20 -40
+20 -40
arch/arm/lib/memmove.S
··· 31 31 subs ip, r0, r1 32 32 cmphi r2, ip 33 33 bls __memcpy 34 - 35 - stmfd sp!, {r0, r4, lr} 36 34 UNWIND( .fnend ) 37 35 38 36 UNWIND( .fnstart ) 39 - UNWIND( .save {r0, r4, lr} ) @ in first stmfd block 37 + UNWIND( .save {r0, r4, fpreg, lr} ) 38 + stmfd sp!, {r0, r4, UNWIND(fpreg,) lr} 39 + UNWIND( .setfp fpreg, sp ) 40 + UNWIND( mov fpreg, sp ) 40 41 add r1, r1, r2 41 42 add r0, r0, r2 42 43 subs r2, r2, #4 ··· 49 48 bne 10f 50 49 51 50 1: subs r2, r2, #(28) 52 - stmfd sp!, {r5 - r8} 53 - UNWIND( .fnend ) 54 - 55 - UNWIND( .fnstart ) 56 - UNWIND( .save {r0, r4, lr} ) 57 - UNWIND( .save {r5 - r8} ) @ in second stmfd block 51 + stmfd sp!, {r5, r6, r8, r9} 58 52 blt 5f 59 53 60 54 CALGN( ands ip, r0, #31 ) ··· 68 72 PLD( pld [r1, #-96] ) 69 73 70 74 3: PLD( pld [r1, #-128] ) 71 - 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} 75 + 4: ldmdb r1!, {r3, r4, r5, r6, r8, r9, ip, lr} 72 76 subs r2, r2, #32 73 - stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} 77 + stmdb r0!, {r3, r4, r5, r6, r8, r9, ip, lr} 74 78 bge 3b 75 79 PLD( cmn r2, #96 ) 76 80 PLD( bge 4b ) ··· 84 88 W(ldr) r4, [r1, #-4]! 85 89 W(ldr) r5, [r1, #-4]! 86 90 W(ldr) r6, [r1, #-4]! 87 - W(ldr) r7, [r1, #-4]! 88 91 W(ldr) r8, [r1, #-4]! 92 + W(ldr) r9, [r1, #-4]! 89 93 W(ldr) lr, [r1, #-4]! 90 94 91 95 add pc, pc, ip ··· 95 99 W(str) r4, [r0, #-4]! 96 100 W(str) r5, [r0, #-4]! 97 101 W(str) r6, [r0, #-4]! 98 - W(str) r7, [r0, #-4]! 99 102 W(str) r8, [r0, #-4]! 103 + W(str) r9, [r0, #-4]! 100 104 W(str) lr, [r0, #-4]! 101 105 102 106 CALGN( bcs 2b ) 103 107 104 - 7: ldmfd sp!, {r5 - r8} 105 - UNWIND( .fnend ) @ end of second stmfd block 106 - 107 - UNWIND( .fnstart ) 108 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 108 + 7: ldmfd sp!, {r5, r6, r8, r9} 109 109 110 110 8: movs r2, r2, lsl #31 111 111 ldrbne r3, [r1, #-1]! ··· 110 118 strbne r3, [r0, #-1]! 111 119 strbcs r4, [r0, #-1]! 112 120 strbcs ip, [r0, #-1] 113 - ldmfd sp!, {r0, r4, pc} 121 + ldmfd sp!, {r0, r4, UNWIND(fpreg,) pc} 114 122 115 123 9: cmp ip, #2 116 124 ldrbgt r3, [r1, #-1]! ··· 129 137 ldr r3, [r1, #0] 130 138 beq 17f 131 139 blt 18f 132 - UNWIND( .fnend ) 133 140 134 141 135 142 .macro backward_copy_shift push pull 136 143 137 - UNWIND( .fnstart ) 138 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 139 144 subs r2, r2, #28 140 145 blt 14f 141 146 ··· 141 152 CALGN( subcc r2, r2, ip ) 142 153 CALGN( bcc 15f ) 143 154 144 - 11: stmfd sp!, {r5 - r9} 145 - UNWIND( .fnend ) 146 - 147 - UNWIND( .fnstart ) 148 - UNWIND( .save {r0, r4, lr} ) 149 - UNWIND( .save {r5 - r9} ) @ in new second stmfd block 155 + 11: stmfd sp!, {r5, r6, r8 - r10} 150 156 151 157 PLD( pld [r1, #-4] ) 152 158 PLD( subs r2, r2, #96 ) ··· 151 167 PLD( pld [r1, #-96] ) 152 168 153 169 12: PLD( pld [r1, #-128] ) 154 - 13: ldmdb r1!, {r7, r8, r9, ip} 170 + 13: ldmdb r1!, {r8, r9, r10, ip} 155 171 mov lr, r3, lspush #\push 156 172 subs r2, r2, #32 157 173 ldmdb r1!, {r3, r4, r5, r6} 158 174 orr lr, lr, ip, lspull #\pull 159 175 mov ip, ip, lspush #\push 160 - orr ip, ip, r9, lspull #\pull 176 + orr ip, ip, r10, lspull #\pull 177 + mov r10, r10, lspush #\push 178 + orr r10, r10, r9, lspull #\pull 161 179 mov r9, r9, lspush #\push 162 180 orr r9, r9, r8, lspull #\pull 163 181 mov r8, r8, lspush #\push 164 - orr r8, r8, r7, lspull #\pull 165 - mov r7, r7, lspush #\push 166 - orr r7, r7, r6, lspull #\pull 182 + orr r8, r8, r6, lspull #\pull 167 183 mov r6, r6, lspush #\push 168 184 orr r6, r6, r5, lspull #\pull 169 185 mov r5, r5, lspush #\push 170 186 orr r5, r5, r4, lspull #\pull 171 187 mov r4, r4, lspush #\push 172 188 orr r4, r4, r3, lspull #\pull 173 - stmdb r0!, {r4 - r9, ip, lr} 189 + stmdb r0!, {r4 - r6, r8 - r10, ip, lr} 174 190 bge 12b 175 191 PLD( cmn r2, #96 ) 176 192 PLD( bge 13b ) 177 193 178 - ldmfd sp!, {r5 - r9} 179 - UNWIND( .fnend ) @ end of the second stmfd block 180 - 181 - UNWIND( .fnstart ) 182 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 194 + ldmfd sp!, {r5, r6, r8 - r10} 183 195 184 196 14: ands ip, r2, #28 185 197 beq 16f ··· 191 211 192 212 16: add r1, r1, #(\pull / 8) 193 213 b 8b 194 - UNWIND( .fnend ) 195 214 196 215 .endm 197 216 ··· 201 222 202 223 18: backward_copy_shift push=24 pull=8 203 224 225 + UNWIND( .fnend ) 204 226 ENDPROC(memmove) 205 227 ENDPROC(__memmove)