Skip to content

Commit

Permalink
x86-64: Modify memcpy()/memset() alternatives mechanism
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jan Beulich authored and Ingo Molnar committed Dec 30, 2009
1 parent 1b1d925 commit 7269e88
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 27 deletions.
23 changes: 8 additions & 15 deletions arch/x86/lib/memcpy_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,8 +34,8 @@ memcpy_c:
movl %edx, %ecx
rep movsb
ret
CFI_ENDPROC
ENDPROC(memcpy_c)
.Lmemcpy_e:
.previous

ENTRY(__memcpy)
ENTRY(memcpy)
Expand Down Expand Up @@ -128,23 +127,17 @@ 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

/*
* Replace only beginning, memcpy is used to apply alternatives,
* 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
18 changes: 6 additions & 12 deletions arch/x86/lib/memset_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,8 +28,8 @@ memset_c:
rep stosb
movq %r9,%rax
ret
CFI_ENDPROC
ENDPROC(memset_c)
.Lmemset_e:
.previous

ENTRY(memset)
ENTRY(__memset)
Expand Down Expand Up @@ -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

0 comments on commit 7269e88

Please sign in to comment.