summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--string/test-strcmp.c89
-rw-r--r--sysdeps/i386/i686/multiarch/wcscmp-sse2.S158
-rw-r--r--sysdeps/x86_64/wcscmp.S109
-rw-r--r--wcsmbs/wcscmp.c4
5 files changed, 239 insertions, 132 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c234d5b85..c8f504ca11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-09-22  Liubov Dmitrieva  <liubov.dmitrieva@gmail.com>
+
+	* sysdeps/x86_64/wcscmp.S: Update.
+	Fix wrong comparison semantics.
+	wcscmp shall use signed comparison not unsigned.
+	Don't use substraction to avoid overflow bug.
+	* sysdeps/i386/i686/multiarch/wcscmp-sse2.S: Likewise.
+	* wcsmbc/wcscmp.c: Likewise.
+	* string/test-strcmp.c: Likewise.
+	Add new tests to check cases with negative values.
+
 2011-10-23  Ulrich Drepper  <drepper@gmail.com>
 
 	* sysdeps/ieee754/dbl-64/dla.h: Move DLA_FMA definition to...
diff --git a/string/test-strcmp.c b/string/test-strcmp.c
index b8d85dca79..0e43f85542 100644
--- a/string/test-strcmp.c
+++ b/string/test-strcmp.c
@@ -1,4 +1,4 @@
-/* Test and measure STRCMP functions.
+/* Test and measure strcmp and wcscmp functions.
    Copyright (C) 1999, 2002, 2003, 2005, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Jakub Jelinek <jakub@redhat.com>, 1999.
@@ -23,7 +23,6 @@
 #include "test-string.h"
 
 #ifdef WIDE
-# include <inttypes.h>
 # include <wchar.h>
 
 # define L(str) L##str
@@ -34,12 +33,53 @@
 # define SIMPLE_STRCMP simple_wcscmp
 # define STUPID_STRCMP stupid_wcscmp
 # define CHAR wchar_t
-# define UCHAR uint32_t
+# define UCHAR wchar_t
 # define CHARBYTES 4
 # define CHARBYTESLOG 2
 # define CHARALIGN __alignof__ (CHAR)
 # define MIDCHAR 0x7fffffff
 # define LARGECHAR 0xfffffffe
+# define CHAR__MAX WCHAR_MAX
+# define CHAR__MIN WCHAR_MIN
+
+/* Wcscmp uses signed semantics for comparison, not unsigned */
+/* Avoid using substraction since possible overflow */
+
+int
+simple_wcscmp (const wchar_t *s1, const wchar_t *s2)
+{
+  wchar_t c1, c2;
+  do
+    {
+      c1 = *s1++;
+      c2 = *s2++;
+      if (c2 == L'\0')
+      return c1 - c2;
+    }
+  while (c1 == c2);
+
+  return c1 < c2 ? -1 : 1;
+}
+
+int
+stupid_wcscmp (const wchar_t *s1, const wchar_t *s2)
+{
+  size_t ns1 = wcslen (s1) + 1;
+  size_t ns2 = wcslen (s2) + 1;
+  size_t n = ns1 < ns2 ? ns1 : ns2;
+  int ret = 0;
+  
+  wchar_t c1, c2;
+
+  while (n--) {
+    c1 = *s1++;
+    c2 = *s2++;
+    if ((ret = c1 < c2 ? -1 : c1 == c2 ? 0 : 1) != 0)
+      break;
+  }
+  return ret;
+}
+
 #else
 # define L(str) str
 # define STRCMP strcmp
@@ -55,31 +95,35 @@
 # define CHARALIGN 1
 # define MIDCHAR 0x7f
 # define LARGECHAR 0xfe
-#endif
-typedef int (*proto_t) (const CHAR *, const CHAR *);
+# define CHAR__MAX CHAR_MAX
+# define CHAR__MIN CHAR_MIN
 
+/* Strcmp uses unsigned semantics for comparison. */
 int
-SIMPLE_STRCMP (const CHAR *s1, const CHAR *s2)
+simple_strcmp (const char *s1, const char *s2)
 {
   int ret;
 
-  while ((ret = *(UCHAR *) s1 - *(UCHAR *) s2++) == 0 && *s1++);
+  while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++);
   return ret;
 }
 
 int
-STUPID_STRCMP (const CHAR *s1, const CHAR *s2)
+stupid_strcmp (const char *s1, const char *s2)
 {
-  size_t ns1 = STRLEN (s1) + 1;
-  size_t ns2 = STRLEN (s2) + 1;
+  size_t ns1 = strlen (s1) + 1;
+  size_t ns2 = strlen (s2) + 1;
   size_t n = ns1 < ns2 ? ns1 : ns2;
   int ret = 0;
 
   while (n--)
-    if ((ret = *(UCHAR *) s1++ - *(UCHAR *) s2++) != 0)
+    if ((ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) != 0)
       break;
   return ret;
 }
+#endif
+
+typedef int (*proto_t) (const CHAR *, const CHAR *);
 
 IMPL (STUPID_STRCMP, 1)
 IMPL (SIMPLE_STRCMP, 1)
@@ -276,14 +320,31 @@ check (void)
   STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs"));
   STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV"));
 
+  /* Check correct working for negatives values */
+
+  s1[0] = 1;
+  s2[0] = 1;
+  s1[1] = 1;
+  s2[1] = 1;
+  s1[2] = -1;
+  s2[2] = 3;
+  s1[3] = 0;
+  s2[3] = -1;
+
+  /* Check possible overflow bug, actual more for wcscmp */
+
+  s1[7] = CHAR__MIN;
+  s2[7] = CHAR__MAX;
+
   size_t l1 = STRLEN (s1);
   size_t l2 = STRLEN (s2);
+
   for (size_t i1 = 0; i1 < l1; i1++)
     for (size_t i2 = 0; i2 < l2; i2++)
       {
-	int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2);
-	FOR_EACH_IMPL (impl, 0)
-	  check_result (impl, s1 + i1, s2 + i2, exp_result);
+	        int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2);
+	        FOR_EACH_IMPL (impl, 0)
+	        check_result (impl, s1 + i1, s2 + i2, exp_result);
       }
 }
 
diff --git a/sysdeps/i386/i686/multiarch/wcscmp-sse2.S b/sysdeps/i386/i686/multiarch/wcscmp-sse2.S
index 404a9a4d4c..cca0d8340b 100644
--- a/sysdeps/i386/i686/multiarch/wcscmp-sse2.S
+++ b/sysdeps/i386/i686/multiarch/wcscmp-sse2.S
@@ -21,7 +21,6 @@
 #ifndef NOT_IN_libc
 
 # include <sysdep.h>
-# include "asm-syntax.h"
 
 # define CFI_PUSH(REG)	\
 	cfi_adjust_cfa_offset (4);	\
@@ -34,18 +33,16 @@
 # define PUSH(REG) pushl REG; CFI_PUSH (REG)
 # define POP(REG) popl REG; CFI_POP (REG)
 
-# ifndef STRCMP
-# define STRCMP __wcscmp_sse2
-# endif
-
 # define ENTRANCE PUSH(%esi); PUSH(%edi)
 # define RETURN  POP(%edi); POP(%esi); ret; CFI_PUSH(%esi); CFI_PUSH(%edi);
 # define PARMS  4
 # define STR1  PARMS
 # define STR2  STR1+4
 
+/* Note: wcscmp uses signed comparison, not unsugned as in strcmp function. */
+
 	.text
-ENTRY (STRCMP)
+ENTRY (__wcscmp_sse2)
 /*
 	* This implementation uses SSE to compare up to 16 bytes at a time.
 */
@@ -131,7 +128,7 @@ L(continue_48_48):
 	jne	L(nequal)
 	test	%ecx, %ecx
 	jz	L(equal)
-
+	
 	movdqu	16(%edi), %xmm1
 	movdqu	16(%esi), %xmm2
 	pcmpeqd	%xmm1, %xmm0		/* Any null double_word? */
@@ -264,21 +261,21 @@ L(continue_00_48):
 	test	%ecx, %ecx
 	jnz	L(less4_double_words1)
 
-	sub	(%esi), %eax
-	jnz	L(return)
-
+	cmp	(%esi), %eax
+	jne	L(nequal)
+	
 	mov	4(%edi), %eax
-	sub	4(%esi), %eax
-	jnz	L(return)
+	cmp	4(%esi), %eax
+	jne	L(nequal)
 
 	mov	8(%edi), %eax
-	sub	8(%esi), %eax
-	jnz	L(return)
+	cmp	8(%esi), %eax
+	jne	L(nequal)
 
 	mov	12(%edi), %eax
-	sub	12(%esi), %eax
-	jnz	L(return)
-
+	cmp	12(%esi), %eax
+	jne	L(nequal)
+	
 	movdqu	16(%esi), %xmm2
 	pcmpeqd	%xmm2, %xmm0		/* Any null double_word? */
 	pcmpeqd	16(%edi), %xmm2		/* compare first 4 double_words for equality */
@@ -381,7 +378,7 @@ L(continue_32_48):
 	movdqu	48(%esi), %xmm2
 	pcmpeqd	%xmm1, %xmm0		/* Any null double_word? */
 	pcmpeqd	%xmm2, %xmm1		/* compare first 4 double_words for equality */
-	psubb	%xmm0, %xmm1		/* packed sub of comparison results*/
+	psubb	%xmm0, %xmm1		/* packed sub of comparison results */
 	pmovmskb %xmm1, %edx
 	sub	$0xffff, %edx		/* if first 4 double_words are same, edx == 0xffff */
 	jnz	L(less4_double_words_48)
@@ -585,21 +582,21 @@ L(continue_48_00):
 	test	%ecx, %ecx
 	jnz	L(less4_double_words1)
 
-	sub	(%esi), %eax
-	jnz	L(return)
-
+	cmp	(%esi), %eax
+	jne	L(nequal)
+	
 	mov	4(%edi), %eax
-	sub	4(%esi), %eax
-	jnz	L(return)
+	cmp	4(%esi), %eax
+	jne	L(nequal)
 
 	mov	8(%edi), %eax
-	sub	8(%esi), %eax
-	jnz	L(return)
+	cmp	8(%esi), %eax
+	jne	L(nequal)
 
 	mov	12(%edi), %eax
-	sub	12(%esi), %eax
-	jnz	L(return)
-
+	cmp	12(%esi), %eax
+	jne	L(nequal)
+	
 	movdqu	16(%edi), %xmm1
 	pcmpeqd	%xmm1, %xmm0		/* Any null double_word? */
 	pcmpeqd	16(%esi), %xmm1		/* compare first 4 double_words for equality */
@@ -839,142 +836,161 @@ L(less4_double_words1):
 	test	%ecx, %ecx
 	jz	L(equal)
 
-	mov	12(%esi), %edx
-	mov	12(%edi), %eax
-	sub	%edx, %eax
+	mov	12(%esi), %ecx
+	cmp	%ecx, 12(%edi)
+	jne	L(nequal)
+	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(less4_double_words):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words)
 	and	$15, %dl
 	jz	L(second_double_word)
-	mov	(%edi), %eax
-	sub	(%esi), %eax
+	mov	(%esi), %ecx
+	cmp	%ecx, (%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(second_double_word):
-	mov	4(%edi), %eax
-	sub	4(%esi), %eax
+	mov	4(%esi), %ecx
+	cmp	%ecx, 4(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(next_two_double_words):
 	and	$15, %dh
 	jz	L(fourth_double_word)
-	mov	8(%edi), %eax
-	sub	8(%esi), %eax
+	mov	8(%esi), %ecx
+	cmp	%ecx, 8(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(fourth_double_word):
-	mov	12(%edi), %eax
-	sub	12(%esi), %eax
+	mov	12(%esi), %ecx
+	cmp	%ecx, 12(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(less4_double_words_16):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_16)
 	and	$15, %dl
 	jz	L(second_double_word_16)
-	mov	16(%edi), %eax
-	sub	16(%esi), %eax
+	mov	16(%esi), %ecx
+	cmp	%ecx, 16(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(second_double_word_16):
-	mov	20(%edi), %eax
-	sub	20(%esi), %eax
+	mov	20(%esi), %ecx
+	cmp	%ecx, 20(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(next_two_double_words_16):
 	and	$15, %dh
 	jz	L(fourth_double_word_16)
-	mov	24(%edi), %eax
-	sub	24(%esi), %eax
+	mov	24(%esi), %ecx
+	cmp	%ecx, 24(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(fourth_double_word_16):
-	mov	28(%edi), %eax
-	sub	28(%esi), %eax
+	mov	28(%esi), %ecx
+	cmp	%ecx, 28(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(less4_double_words_32):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_32)
 	and	$15, %dl
 	jz	L(second_double_word_32)
-	mov	32(%edi), %eax
-	sub	32(%esi), %eax
+	mov	32(%esi), %ecx
+	cmp	%ecx, 32(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(second_double_word_32):
-	mov	36(%edi), %eax
-	sub	36(%esi), %eax
+	mov	36(%esi), %ecx
+	cmp	%ecx, 36(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(next_two_double_words_32):
 	and	$15, %dh
 	jz	L(fourth_double_word_32)
-	mov	40(%edi), %eax
-	sub	40(%esi), %eax
+	mov	40(%esi), %ecx
+	cmp	%ecx, 40(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(fourth_double_word_32):
-	mov	44(%edi), %eax
-	sub	44(%esi), %eax
+	mov	44(%esi), %ecx
+	cmp	%ecx, 44(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(less4_double_words_48):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_48)
 	and	$15, %dl
 	jz	L(second_double_word_48)
-	mov	48(%edi), %eax
-	sub	48(%esi), %eax
+	mov	48(%esi), %ecx
+	cmp	%ecx, 48(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(second_double_word_48):
-	mov	52(%edi), %eax
-	sub	52(%esi), %eax
+	mov	52(%esi), %ecx
+	cmp	%ecx, 52(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(next_two_double_words_48):
 	and	$15, %dh
 	jz	L(fourth_double_word_48)
-	mov	56(%edi), %eax
-	sub	56(%esi), %eax
+	mov	56(%esi), %ecx
+	cmp	%ecx, 56(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(fourth_double_word_48):
-	mov	60(%edi), %eax
-	sub	60(%esi), %eax
-	RETURN
-
-	.p2align 4
-L(return):
+	mov	60(%esi), %ecx
+	cmp	%ecx, 60(%edi)
+	jne	L(nequal)
 	RETURN
 
 	.p2align 4
 L(nequal):
 	mov	$1, %eax
-	ja	L(nequal_bigger)
+	jg	L(return)
 	neg	%eax
+	RETURN
 
-L(nequal_bigger):
+	.p2align 4
+L(return):
 	RETURN
 
 	.p2align 4
@@ -988,7 +1004,7 @@ L(equal):
 	.p2align 4
 L(neq):
 	mov	$1, %eax
-	ja	L(neq_bigger)
+	jg	L(neq_bigger)
 	neg	%eax
 
 L(neq_bigger):
@@ -999,5 +1015,5 @@ L(eq):
 	xorl	%eax, %eax
 	ret
 
-END (STRCMP)
+END (__wcscmp_sse2)
 #endif
diff --git a/sysdeps/x86_64/wcscmp.S b/sysdeps/x86_64/wcscmp.S
index 991ecb2cab..12bfdafd41 100644
--- a/sysdeps/x86_64/wcscmp.S
+++ b/sysdeps/x86_64/wcscmp.S
@@ -20,6 +20,8 @@
 
 #include <sysdep.h>
 
+/* Note: wcscmp uses signed comparison, not unsighed as in strcmp function. */
+
 	.text
 ENTRY (wcscmp)
 /*
@@ -76,7 +78,7 @@ L(continue_48_48):
 	jne	L(nequal)
 	test	%ecx, %ecx
 	jz	L(equal)
-
+	
 	movdqu	16(%rdi), %xmm1
 	movdqu	16(%rsi), %xmm2
 	pcmpeqd	%xmm1, %xmm0		/* Any null double_word? */
@@ -209,21 +211,21 @@ L(continue_00_48):
 	test	%ecx, %ecx
 	jnz	L(less4_double_words1)
 
-	sub	(%rsi), %eax
-	jnz	L(return)
-
+	cmp	(%rsi), %eax
+	jne	L(nequal)
+	
 	mov	4(%rdi), %eax
-	sub	4(%rsi), %eax
-	jnz	L(return)
+	cmp	4(%rsi), %eax
+	jne	L(nequal)
 
 	mov	8(%rdi), %eax
-	sub	8(%rsi), %eax
-	jnz	L(return)
+	cmp	8(%rsi), %eax
+	jne	L(nequal)
 
 	mov	12(%rdi), %eax
-	sub	12(%rsi), %eax
-	jnz	L(return)
-
+	cmp	12(%rsi), %eax
+	jne	L(nequal)
+	
 	movdqu	16(%rsi), %xmm2
 	pcmpeqd	%xmm2, %xmm0		/* Any null double_word? */
 	pcmpeqd	16(%rdi), %xmm2		/* compare first 4 double_words for equality */
@@ -530,21 +532,21 @@ L(continue_48_00):
 	test	%ecx, %ecx
 	jnz	L(less4_double_words1)
 
-	sub	(%rsi), %eax
-	jnz	L(return)
-
+	cmp	(%rsi), %eax
+	jne	L(nequal)
+	
 	mov	4(%rdi), %eax
-	sub	4(%rsi), %eax
-	jnz	L(return)
+	cmp	4(%rsi), %eax
+	jne	L(nequal)
 
 	mov	8(%rdi), %eax
-	sub	8(%rsi), %eax
-	jnz	L(return)
+	cmp	8(%rsi), %eax
+	jne	L(nequal)
 
 	mov	12(%rdi), %eax
-	sub	12(%rsi), %eax
-	jnz	L(return)
-
+	cmp	12(%rsi), %eax
+	jne	L(nequal)
+	
 	movdqu	16(%rdi), %xmm1
 	pcmpeqd	%xmm1, %xmm0		/* Any null double_word? */
 	pcmpeqd	16(%rsi), %xmm1		/* compare first 4 double_words for equality */
@@ -784,25 +786,29 @@ L(less4_double_words1):
 	test	%ecx, %ecx
 	jz	L(equal)
 
-	mov	12(%rsi), %edx
-	mov	12(%rdi), %eax
-	sub	%edx, %eax
+	mov	12(%rsi), %ecx
+	cmp	%ecx, 12(%rdi)
+	jne	L(nequal)
+	xor	%eax, %eax
 	ret
 
 	.p2align 4
 L(less4_double_words):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words)
 	and	$15, %dl
 	jz	L(second_double_word)
 	mov	(%rdi), %eax
-	sub	(%rsi), %eax
+	cmp	(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(second_double_word):
 	mov	4(%rdi), %eax
-	sub	4(%rsi), %eax
+	cmp	4(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
@@ -810,29 +816,34 @@ L(next_two_double_words):
 	and	$15, %dh
 	jz	L(fourth_double_word)
 	mov	8(%rdi), %eax
-	sub	8(%rsi), %eax
+	cmp	8(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(fourth_double_word):
 	mov	12(%rdi), %eax
-	sub	12(%rsi), %eax
+	cmp	12(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(less4_double_words_16):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_16)
 	and	$15, %dl
 	jz	L(second_double_word_16)
 	mov	16(%rdi), %eax
-	sub	16(%rsi), %eax
+	cmp	16(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(second_double_word_16):
 	mov	20(%rdi), %eax
-	sub	20(%rsi), %eax
+	cmp	20(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
@@ -840,29 +851,34 @@ L(next_two_double_words_16):
 	and	$15, %dh
 	jz	L(fourth_double_word_16)
 	mov	24(%rdi), %eax
-	sub	24(%rsi), %eax
+	cmp	24(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(fourth_double_word_16):
 	mov	28(%rdi), %eax
-	sub	28(%rsi), %eax
+	cmp	28(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(less4_double_words_32):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_32)
 	and	$15, %dl
 	jz	L(second_double_word_32)
 	mov	32(%rdi), %eax
-	sub	32(%rsi), %eax
+	cmp	32(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(second_double_word_32):
 	mov	36(%rdi), %eax
-	sub	36(%rsi), %eax
+	cmp	36(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
@@ -870,29 +886,34 @@ L(next_two_double_words_32):
 	and	$15, %dh
 	jz	L(fourth_double_word_32)
 	mov	40(%rdi), %eax
-	sub	40(%rsi), %eax
+	cmp	40(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(fourth_double_word_32):
 	mov	44(%rdi), %eax
-	sub	44(%rsi), %eax
+	cmp	44(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(less4_double_words_48):
+	xor	%eax, %eax
 	test	%dl, %dl
 	jz	L(next_two_double_words_48)
 	and	$15, %dl
 	jz	L(second_double_word_48)
 	mov	48(%rdi), %eax
-	sub	48(%rsi), %eax
+	cmp	48(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(second_double_word_48):
 	mov	52(%rdi), %eax
-	sub	52(%rsi), %eax
+	cmp	52(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
@@ -900,23 +921,21 @@ L(next_two_double_words_48):
 	and	$15, %dh
 	jz	L(fourth_double_word_48)
 	mov	56(%rdi), %eax
-	sub	56(%rsi), %eax
+	cmp	56(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(fourth_double_word_48):
 	mov	60(%rdi), %eax
-	sub	60(%rsi), %eax
-	ret
-
-	.p2align 4
-L(return):
+	cmp	60(%rsi), %eax
+	jne	L(nequal)
 	ret
 
 	.p2align 4
 L(nequal):
 	mov	$1, %eax
-	ja	L(nequal_bigger)
+	jg	L(nequal_bigger)
 	neg	%eax
 
 L(nequal_bigger):
diff --git a/wcsmbs/wcscmp.c b/wcsmbs/wcscmp.c
index 6c93f702f6..ddbd4aa93f 100644
--- a/wcsmbs/wcscmp.c
+++ b/wcsmbs/wcscmp.c
@@ -37,11 +37,11 @@ WCSCMP (s1, s2)
     {
       c1 = (wint_t) *s1++;
       c2 = (wint_t) *s2++;
-      if (c1 == L'\0')
+      if (c2 == L'\0')
 	return c1 - c2;
     }
   while (c1 == c2);
 
-  return c1 - c2;
+  return c1 < c2 ? -1 : 1;
 }
 libc_hidden_def (WCSCMP)