#include <machine/asm.h>
#define ALIGN_TEXT .p2align 4,0x90
ENTRY(timingsafe_memcmp)
cmp $16, %rdx # at least 17 bytes to process?
ja .Lgt16
cmp $8, %edx # at least 9 bytes to process?
ja .L0916
cmp $4, %edx # at least 5 bytes to process?
ja .L0508
cmp $2, %edx # at least 3 bytes to process?
ja .L0304
test %edx, %edx # buffer empty?
jnz .L0102
xor %eax, %eax # empty buffer always matches
ret
.L0102: movzbl -1(%rdi, %rdx, 1), %eax # load 1--2 bytes from first buffer
movzbl -1(%rsi, %rdx, 1), %ecx
mov (%rdi), %ah # in big endian
mov (%rsi), %ch
sub %ecx, %eax
ret
.L0304: movzwl -2(%rdi, %rdx, 1), %ecx
movzwl -2(%rsi, %rdx, 1), %edx
movzwl (%rdi), %eax
movzwl (%rsi), %esi
bswap %ecx # convert to big endian
bswap %edx # dito for edx, (e)ax, and (e)si
rol $8, %ax # ROLW is used here so the upper two
rol $8, %si # bytes stay clear, allowing us to
sub %edx, %ecx # save a SBB compared to .L0508
sbb %esi, %eax
or %eax, %ecx # nonzero if not equal
setnz %al
ret
.L0508: mov -4(%rdi, %rdx, 1), %ecx
mov -4(%rsi, %rdx, 1), %edx
mov (%rdi), %edi
mov (%rsi), %esi
bswap %ecx # compare in big endian
bswap %edx
bswap %edi
bswap %esi
sub %edx, %ecx
sbb %esi, %edi
sbb %eax, %eax # -1 if less, 0 if greater or equal
or %edi, %ecx # nonzero if not equal
setnz %al # negative if <, 0 if =, 1 if >
ret
.L0916: mov -8(%rdi, %rdx, 1), %rcx
mov -8(%rsi, %rdx, 1), %rdx
mov (%rdi), %rdi
mov (%rsi), %rsi
bswap %rcx # compare in big endian
bswap %rdx
bswap %rdi
bswap %rsi
sub %rdx, %rcx
sbb %rsi, %rdi
sbb %eax, %eax # -1 if less, 0 if greater or equal
or %rdi, %rcx # nonzero if not equal
setnz %al # negative if <, 0 if =, 1 if >
ret
.Lgt16: mov (%rdi), %r8 # process first 16 bytes
mov (%rsi), %r9
mov $32, %ecx
cmp %r8, %r9 # mismatch in head?
cmove 8(%rdi), %r8 # if not, try second pair
cmove 8(%rsi), %r9
cmp %rdx, %rcx
jae .Ltail
ALIGN_TEXT
0: mov -16(%rdi, %rcx, 1), %r10
mov -16(%rsi, %rcx, 1), %r11
cmp %r10, %r11 # mismatch in first pair?
cmove -8(%rdi, %rcx, 1), %r10 # if not, try second pair
cmove -8(%rsi, %rcx, 1), %r11
cmp %r8, %r9 # was there a mismatch previously?
cmove %r10, %r8 # apply new pair if there was not
cmove %r11, %r9
add $16, %rcx
cmp %rdx, %rcx
jb 0b
.Ltail: mov -8(%rdi, %rdx, 1), %r10
mov -8(%rsi, %rdx, 1), %r11
cmp %r8, %r9
cmove -16(%rdi, %rdx, 1), %r8
cmove -16(%rsi, %rdx, 1), %r9
bswap %r10 # compare in big endian
bswap %r11
bswap %r8
bswap %r9
sub %r11, %r10
sbb %r9, %r8
sbb %eax, %eax # -1 if less, 0 if greater or equal
or %r10, %r8 # nonzero if not equal
setnz %al # negative if <, 0 if =, 1 if >
ret
END(timingsafe_memcmp)
.section .note.GNU-stack,"",%progbits