x86-64: Modify memcpy()/memset() alternatives mechanism
In order to avoid unnecessary chains of branches, rather than implementing memcpy()/memset()'s access to their alternative implementations via a jump, patch the (larger) original function directly. The memcpy() part of this is slightly subtle: while alternative instruction patching does itself use memcpy(), with the replacement block being less than 64-bytes in size the main loop of the original function doesn't get used for copying memcpy_c() over memcpy(), and hence we can safely write over its beginning. Also note that the CFI annotations are fine for both variants of each of the functions. Signed-off-by: Jan Beulich <jbeulich@novell.com> Cc: Nick Piggin <npiggin@suse.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> LKML-Reference: <4B2BB8D30200007800026AF2@vpn.id2.novell.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
1b1d925818
commit
7269e8812a
|
@ -20,12 +20,11 @@
|
|||
/*
|
||||
* memcpy_c() - fast string ops (REP MOVSQ) based variant.
|
||||
*
|
||||
* Calls to this get patched into the kernel image via the
|
||||
* This gets patched over the unrolled variant (below) via the
|
||||
* alternative instructions framework:
|
||||
*/
|
||||
ALIGN
|
||||
memcpy_c:
|
||||
CFI_STARTPROC
|
||||
.section .altinstr_replacement, "ax", @progbits
|
||||
.Lmemcpy_c:
|
||||
movq %rdi, %rax
|
||||
|
||||
movl %edx, %ecx
|
||||
|
@ -35,8 +34,8 @@ memcpy_c:
|
|||
movl %edx, %ecx
|
||||
rep movsb
|
||||
ret
|
||||
CFI_ENDPROC
|
||||
ENDPROC(memcpy_c)
|
||||
.Lmemcpy_e:
|
||||
.previous
|
||||
|
||||
ENTRY(__memcpy)
|
||||
ENTRY(memcpy)
|
||||
|
@ -128,16 +127,10 @@ ENDPROC(__memcpy)
|
|||
* It is also a lot simpler. Use this when possible:
|
||||
*/
|
||||
|
||||
.section .altinstr_replacement, "ax"
|
||||
1: .byte 0xeb /* jmp <disp8> */
|
||||
.byte (memcpy_c - memcpy) - (2f - 1b) /* offset */
|
||||
2:
|
||||
.previous
|
||||
|
||||
.section .altinstructions, "a"
|
||||
.align 8
|
||||
.quad memcpy
|
||||
.quad 1b
|
||||
.quad .Lmemcpy_c
|
||||
.byte X86_FEATURE_REP_GOOD
|
||||
|
||||
/*
|
||||
|
@ -145,6 +138,6 @@ ENDPROC(__memcpy)
|
|||
* so it is silly to overwrite itself with nops - reboot is the
|
||||
* only outcome...
|
||||
*/
|
||||
.byte 2b - 1b
|
||||
.byte 2b - 1b
|
||||
.byte .Lmemcpy_e - .Lmemcpy_c
|
||||
.byte .Lmemcpy_e - .Lmemcpy_c
|
||||
.previous
|
||||
|
|
|
@ -12,9 +12,8 @@
|
|||
*
|
||||
* rax original destination
|
||||
*/
|
||||
ALIGN
|
||||
memset_c:
|
||||
CFI_STARTPROC
|
||||
.section .altinstr_replacement, "ax", @progbits
|
||||
.Lmemset_c:
|
||||
movq %rdi,%r9
|
||||
movl %edx,%r8d
|
||||
andl $7,%r8d
|
||||
|
@ -29,8 +28,8 @@ memset_c:
|
|||
rep stosb
|
||||
movq %r9,%rax
|
||||
ret
|
||||
CFI_ENDPROC
|
||||
ENDPROC(memset_c)
|
||||
.Lmemset_e:
|
||||
.previous
|
||||
|
||||
ENTRY(memset)
|
||||
ENTRY(__memset)
|
||||
|
@ -118,16 +117,11 @@ ENDPROC(__memset)
|
|||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
.section .altinstr_replacement,"ax"
|
||||
1: .byte 0xeb /* jmp <disp8> */
|
||||
.byte (memset_c - memset) - (2f - 1b) /* offset */
|
||||
2:
|
||||
.previous
|
||||
.section .altinstructions,"a"
|
||||
.align 8
|
||||
.quad memset
|
||||
.quad 1b
|
||||
.quad .Lmemset_c
|
||||
.byte X86_FEATURE_REP_GOOD
|
||||
.byte .Lfinal - memset
|
||||
.byte 2b - 1b
|
||||
.byte .Lmemset_e - .Lmemset_c
|
||||
.previous
|
||||
|
|
Loading…
Reference in New Issue