From df616f8adcbf52fe6f39fe43b618bcd8b511f886 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 26 Sep 2012 18:55:48 -0700
Subject: [PATCH 3/6] Add x86_64 multiarch __libc_func

---
 ChangeLog.test-ifunc                    |  21 +
 sysdeps/x86_64/multiarch/libc-func.c    | 950 ++++++++++++++++++++++++++++++++
 sysdeps/x86_64/multiarch/memcmp.S       |   2 +
 sysdeps/x86_64/multiarch/memcpy.S       |   2 +
 sysdeps/x86_64/multiarch/mempcpy.S      |   2 +
 sysdeps/x86_64/multiarch/rawmemchr.S    |   4 +
 sysdeps/x86_64/multiarch/strcat.S       |   2 +
 sysdeps/x86_64/multiarch/strchr.S       |   4 +
 sysdeps/x86_64/multiarch/strcmp-sse42.S |   2 +
 sysdeps/x86_64/multiarch/strcmp.S       |   6 +
 sysdeps/x86_64/multiarch/strcpy.S       |   2 +
 sysdeps/x86_64/multiarch/strlen.S       |   2 +
 sysdeps/x86_64/multiarch/strrchr.S      |   4 +
 13 files changed, 1003 insertions(+)
 create mode 100644 sysdeps/x86_64/multiarch/libc-func.c

diff --git a/ChangeLog.test-ifunc b/ChangeLog.test-ifunc
index be024fe..c678d42 100644
--- a/ChangeLog.test-ifunc
+++ b/ChangeLog.test-ifunc
@@ -1,5 +1,26 @@
 2012-09-26  H.J. Lu  <hongjiu.lu@intel.com>
 
+	* sysdeps/x86_64/multiarch/libc-func.c: New file.
+	* sysdeps/x86_64/multiarch/memcmp.S (__memcmp_sse2): Make it
+	global and hidden.
+	* sysdeps/x86_64/multiarch/memcpy.S (__memcpy_sse2): Likewise.
+	* sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy_sse2): Likewise.
+	* sysdeps/x86_64/multiarch/rawmemchr.S (__rawmemchr_sse42):
+	Likewise.
+	(__rawmemchr_sse2): Likewise.
+	* sysdeps/x86_64/multiarch/strcat.S (STRCAT_SSE2): Likewise.
+	* sysdeps/x86_64/multiarch/strchr.S (__strchr_sse42): Likewise.
+	(__strchr_sse2): Likewise.
+	* sysdeps/x86_64/multiarch/strcmp-sse42.S (STRCMP_SSE42): Likewise.
+	* sysdeps/x86_64/multiarch/strcmp.S (STRCMP_SSE2): Likewise.
+	(__strcasecmp_sse2): Likewise.
+	(__strncasecmp_sse2): Likewise.
+	* sysdeps/x86_64/multiarch/strcpy.S (STRCPY_SSE2): Likewise.
+	* sysdeps/x86_64/multiarch/strlen.S (__strlen_sse2): Likewise.
+	global and hidden.
+	* sysdeps/x86_64/multiarch/strrchr.S (__strrchr_sse42): Likewise.
+	(__strrchr_sse2): Likewise.
+
 	* sysdeps/i386/i686/multiarch/bcopy.S (__bcopy_ia32): Make it
 	global and hidden.
 	* sysdeps/i386/i686/multiarch/bzero.S (__bzero_ia32): Likewise.
diff --git a/sysdeps/x86_64/multiarch/libc-func.c b/sysdeps/x86_64/multiarch/libc-func.c
new file mode 100644
index 0000000..0a1ed36
--- /dev/null
+++ b/sysdeps/x86_64/multiarch/libc-func.c
@@ -0,0 +1,950 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <libc-func.h>
+#include "init-arch.h"
+
+#define find_memcmp()		NULL
+#define find_memcpy()		NULL
+#define find_memmove()		NULL
+#define find_mempcpy()		NULL
+#define find___memcpy_chk()	NULL
+#define find___memmove_chk()	NULL
+#define find___mempcpy_chk()	NULL
+#define find_memset()		NULL
+#define find_rawmemchr()	NULL
+#define find_stpcpy()		NULL
+#define find_stpncpy()		NULL
+#define find_strcpy()		NULL
+#define find_strncpy()		NULL
+#define find_strcasecmp()	NULL
+#define find_strcasecmp_l()	NULL
+#define find_strcat()		NULL
+#define find_strncat()		NULL
+#define find_strcmp()		NULL
+#define find_strncasecmp()	NULL
+#define find_strncasecmp_l()	NULL
+#define find_strncmp()		NULL
+#define find_strcasestr()	NULL
+#define find_strchr()		NULL
+#define find_strcspn()		NULL
+#define find_strlen()		NULL
+#define find_strpbrk()		NULL
+#define find_strrchr()		NULL
+#define find_strspn()		NULL
+#define find_strstr()		NULL
+#define find_wcscpy()		NULL
+#define find_wmemcmp()		NULL
+
+#ifndef NOT_IN_libc
+
+extern __typeof (memmove) __memmove_sse2 attribute_hidden;
+extern __typeof (memmove) __memmove_ssse3 attribute_hidden;
+extern __typeof (memmove) __memmove_ssse3_back attribute_hidden;
+
+static struct libc_func_test memmove_list[4];
+
+# undef find_memmove
+
+static struct libc_func_test *
+find_memmove (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      memmove_list[0] = LIBC_FUNC_INIT (__memmove_ssse3_back);
+      memmove_list[1] = LIBC_FUNC_INIT (__memmove_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  memmove_list[i] = LIBC_FUNC_INIT (__memmove_sse2);
+  return memmove_list;
+}
+
+extern void *__memmove_chk (void *, const void *, size_t, size_t);
+extern __typeof (__memmove_chk) __memmove_chk_sse2 attribute_hidden;
+extern __typeof (__memmove_chk) __memmove_chk_ssse3 attribute_hidden;
+extern __typeof (__memmove_chk) __memmove_chk_ssse3_back attribute_hidden;
+
+static struct libc_func_test __memmove_chk_list[4];
+
+# undef find___memmove_chk
+
+static struct libc_func_test *
+find___memmove_chk (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      __memmove_chk_list[0] = LIBC_FUNC_INIT (__memmove_chk_ssse3_back);
+      __memmove_chk_list[1] = LIBC_FUNC_INIT (__memmove_chk_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  __memmove_chk_list[i] = LIBC_FUNC_INIT (__memmove_chk_sse2);
+  return __memmove_chk_list;
+}
+
+extern __typeof (memset) __memset_x86_64 attribute_hidden;
+extern __typeof (memset) __memset_sse2 attribute_hidden;
+
+static struct libc_func_test memset_list[3];
+
+# undef find_memset
+
+static struct libc_func_test *
+find_memset (void)
+{
+  memset_list[0] = LIBC_FUNC_INIT (__memset_sse2);
+  memset_list[1] = LIBC_FUNC_INIT (__memset_x86_64);
+  return memset_list;
+}
+
+extern __typeof (rawmemchr) __rawmemchr_sse2 attribute_hidden;
+extern __typeof (rawmemchr) __rawmemchr_sse42 attribute_hidden;
+
+static struct libc_func_test rawmemchr_list[3];
+
+# undef find_rawmemchr
+
+static struct libc_func_test *
+find_rawmemchr (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      rawmemchr_list[0] = LIBC_FUNC_INIT (__rawmemchr_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  rawmemchr_list[i] = LIBC_FUNC_INIT (__rawmemchr_sse2);
+  return rawmemchr_list;
+}
+
+extern __typeof (stpcpy) __stpcpy_sse2 attribute_hidden;
+extern __typeof (stpcpy) __stpcpy_sse2_unaligned attribute_hidden;
+extern __typeof (stpcpy) __stpcpy_ssse3 attribute_hidden;
+
+static struct libc_func_test stpcpy_list[4];
+
+# undef find_stpcpy
+
+static struct libc_func_test *
+find_stpcpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      stpcpy_list[0] = LIBC_FUNC_INIT (__stpcpy_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  stpcpy_list[i] = LIBC_FUNC_INIT (__stpcpy_sse2);
+  i++;
+  stpcpy_list[i] = LIBC_FUNC_INIT (__stpcpy_sse2_unaligned);
+  return stpcpy_list;
+}
+
+extern __typeof (stpncpy) __stpncpy_sse2 attribute_hidden;
+extern __typeof (stpncpy) __stpncpy_sse2_unaligned attribute_hidden;
+extern __typeof (stpncpy) __stpncpy_ssse3 attribute_hidden;
+
+static struct libc_func_test stpncpy_list[4];
+
+# undef find_stpncpy
+
+static struct libc_func_test *
+find_stpncpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      stpncpy_list[0] = LIBC_FUNC_INIT (__stpncpy_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  stpncpy_list[i] = LIBC_FUNC_INIT (__stpncpy_sse2);
+  i++;
+  stpncpy_list[i] = LIBC_FUNC_INIT (__stpncpy_sse2_unaligned);
+  return stpncpy_list;
+}
+
+extern __typeof (strcpy) __strcpy_sse2 attribute_hidden;
+extern __typeof (strcpy) __strcpy_sse2_unaligned attribute_hidden;
+extern __typeof (strcpy) __strcpy_ssse3 attribute_hidden;
+
+static struct libc_func_test strcpy_list[4];
+
+# undef find_strcpy
+
+static struct libc_func_test *
+find_strcpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      strcpy_list[0] = LIBC_FUNC_INIT (__strcpy_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  strcpy_list[i] = LIBC_FUNC_INIT (__strcpy_sse2);
+  i++;
+  strcpy_list[i] = LIBC_FUNC_INIT (__strcpy_sse2_unaligned);
+  return strcpy_list;
+}
+
+extern __typeof (strncpy) __strncpy_sse2 attribute_hidden;
+extern __typeof (strncpy) __strncpy_sse2_unaligned attribute_hidden;
+extern __typeof (strncpy) __strncpy_ssse3 attribute_hidden;
+
+static struct libc_func_test strncpy_list[4];
+
+# undef find_strncpy
+
+static struct libc_func_test *
+find_strncpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      strncpy_list[0] = LIBC_FUNC_INIT (__strncpy_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  strncpy_list[i] = LIBC_FUNC_INIT (__strncpy_sse2);
+  i++;
+  strncpy_list[i] = LIBC_FUNC_INIT (__strncpy_sse2_unaligned);
+  return strncpy_list;
+}
+
+extern __typeof (strcasecmp) __strcasecmp_sse2 attribute_hidden;
+extern __typeof (strcasecmp) __strcasecmp_ssse3 attribute_hidden;
+extern __typeof (strcasecmp) __strcasecmp_sse42 attribute_hidden;
+extern __typeof (strcasecmp) __strcasecmp_avx attribute_hidden;
+
+static struct libc_func_test strcasecmp_list[5];
+
+# undef find_strcasecmp
+
+static struct libc_func_test *
+find_strcasecmp (void)
+{
+  size_t i;
+  if (HAS_AVX)
+    {
+      strcasecmp_list[0] = LIBC_FUNC_INIT (__strcasecmp_avx);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSE4_2)
+    {
+      strcasecmp_list[i] = LIBC_FUNC_INIT (__strcasecmp_sse42);
+      i++;
+    }
+  if (HAS_SSSE3)
+    {
+      strcasecmp_list[i] = LIBC_FUNC_INIT (__strcasecmp_ssse3);
+      i++;
+    }
+  strcasecmp_list[i] = LIBC_FUNC_INIT (__strcasecmp_sse2);
+  return strcasecmp_list;
+}
+
+extern __typeof (strcasecmp_l) __strcasecmp_l_sse2 attribute_hidden;
+extern __typeof (strcasecmp_l) __strcasecmp_l_ssse3 attribute_hidden;
+extern __typeof (strcasecmp_l) __strcasecmp_l_sse42 attribute_hidden;
+extern __typeof (strcasecmp_l) __strcasecmp_l_avx attribute_hidden;
+
+static struct libc_func_test strcasecmp_l_list[5];
+
+# undef find_strcasecmp_l
+
+static struct libc_func_test *
+find_strcasecmp_l (void)
+{
+  size_t i;
+  if (HAS_AVX)
+    {
+      strcasecmp_l_list[0] = LIBC_FUNC_INIT (__strcasecmp_l_avx);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSE4_2)
+    {
+      strcasecmp_l_list[i] = LIBC_FUNC_INIT (__strcasecmp_l_sse42);
+      i++;
+    }
+  if (HAS_SSSE3)
+    {
+      strcasecmp_l_list[i] = LIBC_FUNC_INIT (__strcasecmp_l_ssse3);
+      i++;
+    }
+  strcasecmp_l_list[i] = LIBC_FUNC_INIT (__strcasecmp_l_sse2);
+  return strcasecmp_l_list;
+}
+
+extern __typeof (strcat) __strcat_sse2 attribute_hidden;
+extern __typeof (strcat) __strcat_sse2_unaligned attribute_hidden;
+extern __typeof (strcat) __strcat_ssse3 attribute_hidden;
+
+static struct libc_func_test strcat_list[4];
+
+# undef find_strcat
+
+static struct libc_func_test *
+find_strcat (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      strcat_list[0] = LIBC_FUNC_INIT (__strcat_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  strcat_list[i] = LIBC_FUNC_INIT (__strcat_sse2);
+  i++;
+  strcat_list[i] = LIBC_FUNC_INIT (__strcat_sse2_unaligned);
+  return strcat_list;
+}
+
+extern __typeof (strncat) __strncat_sse2 attribute_hidden;
+extern __typeof (strncat) __strncat_sse2_unaligned attribute_hidden;
+extern __typeof (strncat) __strncat_ssse3 attribute_hidden;
+
+static struct libc_func_test strncat_list[4];
+
+# undef find_strncat
+
+static struct libc_func_test *
+find_strncat (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      strncat_list[0] = LIBC_FUNC_INIT (__strncat_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  strncat_list[i] = LIBC_FUNC_INIT (__strncat_sse2);
+  i++;
+  strncat_list[i] = LIBC_FUNC_INIT (__strncat_sse2_unaligned);
+  return strncat_list;
+}
+
+extern __typeof (strcmp) __strcmp_sse2 attribute_hidden;
+extern __typeof (strcmp) __strcmp_ssse3 attribute_hidden;
+extern __typeof (strcmp) __strcmp_sse42 attribute_hidden;
+
+static struct libc_func_test strcmp_list[4];
+
+# undef find_strcmp
+
+static struct libc_func_test *
+find_strcmp (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strcmp_list[0] = LIBC_FUNC_INIT (__strcmp_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSSE3)
+    {
+      strcmp_list[i] = LIBC_FUNC_INIT (__strcmp_ssse3);
+      i++;
+    }
+  strcmp_list[i] = LIBC_FUNC_INIT (__strcmp_sse2);
+  return strcmp_list;
+}
+
+extern __typeof (strncasecmp) __strncasecmp_sse2 attribute_hidden;
+extern __typeof (strncasecmp) __strncasecmp_ssse3 attribute_hidden;
+extern __typeof (strncasecmp) __strncasecmp_sse42 attribute_hidden;
+extern __typeof (strncasecmp) __strncasecmp_avx attribute_hidden;
+
+static struct libc_func_test strncasecmp_list[5];
+
+# undef find_strncasecmp
+
+static struct libc_func_test *
+find_strncasecmp (void)
+{
+  size_t i;
+  if (HAS_AVX)
+    {
+      strncasecmp_list[0] = LIBC_FUNC_INIT (__strncasecmp_avx);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSE4_2)
+    {
+      strncasecmp_list[i] = LIBC_FUNC_INIT (__strncasecmp_sse42);
+      i++;
+    }
+  if (HAS_SSSE3)
+    {
+      strncasecmp_list[i] = LIBC_FUNC_INIT (__strncasecmp_ssse3);
+      i++;
+    }
+  strncasecmp_list[i] = LIBC_FUNC_INIT (__strncasecmp_sse2);
+  return strncasecmp_list;
+}
+
+extern __typeof (strncasecmp_l) __strncasecmp_l_sse2 attribute_hidden;
+extern __typeof (strncasecmp_l) __strncasecmp_l_ssse3 attribute_hidden;
+extern __typeof (strncasecmp_l) __strncasecmp_l_sse42 attribute_hidden;
+extern __typeof (strncasecmp_l) __strncasecmp_l_avx attribute_hidden;
+
+static struct libc_func_test strncasecmp_l_list[5];
+
+# undef find_strncasecmp_l
+
+static struct libc_func_test *
+find_strncasecmp_l (void)
+{
+  size_t i;
+  if (HAS_AVX)
+    {
+      strncasecmp_l_list[0] = LIBC_FUNC_INIT (__strncasecmp_l_avx);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSE4_2)
+    {
+      strncasecmp_l_list[i] = LIBC_FUNC_INIT (__strncasecmp_l_sse42);
+      i++;
+    }
+  if (HAS_SSSE3)
+    {
+      strncasecmp_l_list[i] = LIBC_FUNC_INIT (__strncasecmp_l_ssse3);
+      i++;
+    }
+  strncasecmp_l_list[i] = LIBC_FUNC_INIT (__strncasecmp_l_sse2);
+  return strncasecmp_l_list;
+}
+
+extern __typeof (strncmp) __strncmp_sse2 attribute_hidden;
+extern __typeof (strncmp) __strncmp_ssse3 attribute_hidden;
+extern __typeof (strncmp) __strncmp_sse42 attribute_hidden;
+
+static struct libc_func_test strncmp_list[4];
+
+# undef find_strncmp
+
+static struct libc_func_test *
+find_strncmp (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strncmp_list[0] = LIBC_FUNC_INIT (__strncmp_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSSE3)
+    {
+      strncmp_list[i] = LIBC_FUNC_INIT (__strncmp_ssse3);
+      i++;
+    }
+  strncmp_list[i] = LIBC_FUNC_INIT (__strncmp_sse2);
+  return strncmp_list;
+}
+
+extern __typeof (strcasestr) __strcasestr_sse2 attribute_hidden;
+extern __typeof (strcasestr) __strcasestr_sse42 attribute_hidden;
+
+static struct libc_func_test strcasestr_list[3];
+
+# undef find_strcasestr
+
+static struct libc_func_test *
+find_strcasestr (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strcasestr_list[0] = LIBC_FUNC_INIT (__strcasestr_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strcasestr_list[i] = LIBC_FUNC_INIT (__strcasestr_sse2);
+  return strcasestr_list;
+}
+
+extern __typeof (strchr) __strchr_sse2 attribute_hidden;
+extern __typeof (strchr) __strchr_sse2_no_bsf attribute_hidden;
+extern __typeof (strchr) __strchr_sse42 attribute_hidden;
+
+static struct libc_func_test strchr_list[4];
+
+# undef find_strchr
+
+static struct libc_func_test *
+find_strchr (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strchr_list[0] = LIBC_FUNC_INIT (__strchr_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strchr_list[i] = LIBC_FUNC_INIT (__strchr_sse2);
+  i++;
+  strchr_list[i] = LIBC_FUNC_INIT (__strchr_sse2_no_bsf);
+  return strchr_list;
+}
+
+extern __typeof (strcspn) __strcspn_sse2 attribute_hidden;
+extern __typeof (strcspn) __strcspn_sse42 attribute_hidden;
+
+static struct libc_func_test strcspn_list[3];
+
+# undef find_strcspn
+
+static struct libc_func_test *
+find_strcspn (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strcspn_list[0] = LIBC_FUNC_INIT (__strcspn_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strcspn_list[i] = LIBC_FUNC_INIT (__strcspn_sse2);
+  return strcspn_list;
+}
+
+extern __typeof (strpbrk) __strpbrk_sse2 attribute_hidden;
+extern __typeof (strpbrk) __strpbrk_sse42 attribute_hidden;
+
+static struct libc_func_test strpbrk_list[3];
+
+# undef find_strpbrk
+
+static struct libc_func_test *
+find_strpbrk (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strpbrk_list[0] = LIBC_FUNC_INIT (__strpbrk_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strpbrk_list[i] = LIBC_FUNC_INIT (__strpbrk_sse2);
+  return strpbrk_list;
+}
+
+extern __typeof (strrchr) __strrchr_sse2 attribute_hidden;
+extern __typeof (strrchr) __strrchr_sse2_no_bsf attribute_hidden;
+extern __typeof (strrchr) __strrchr_sse42 attribute_hidden;
+
+static struct libc_func_test strrchr_list[4];
+
+# undef find_strrchr
+
+static struct libc_func_test *
+find_strrchr (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strrchr_list[0] = LIBC_FUNC_INIT (__strrchr_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strrchr_list[i] = LIBC_FUNC_INIT (__strrchr_sse2);
+  i++;
+  strrchr_list[i] = LIBC_FUNC_INIT (__strrchr_sse2_no_bsf);
+  return strchr_list;
+}
+
+extern __typeof (strspn) __strspn_sse2 attribute_hidden;
+extern __typeof (strspn) __strspn_sse42 attribute_hidden;
+
+static struct libc_func_test strspn_list[3];
+
+# undef find_strspn
+
+static struct libc_func_test *
+find_strspn (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strspn_list[0] = LIBC_FUNC_INIT (__strspn_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strspn_list[i] = LIBC_FUNC_INIT (__strspn_sse2);
+  return strspn_list;
+}
+
+extern __typeof (strstr) __strstr_sse2 attribute_hidden;
+extern __typeof (strstr) __strstr_sse42 attribute_hidden;
+
+static struct libc_func_test strstr_list[3];
+
+# undef find_strstr
+
+static struct libc_func_test *
+find_strstr (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strstr_list[0] = LIBC_FUNC_INIT (__strstr_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strstr_list[i] = LIBC_FUNC_INIT (__strstr_sse2);
+  return strstr_list;
+}
+
+extern __typeof (wcscpy) __wcscpy_sse2 attribute_hidden;
+extern __typeof (wcscpy) __wcscpy_ssse3 attribute_hidden;
+
+static struct libc_func_test wcscpy_list[3];
+
+# undef find_wcscpy
+
+static struct libc_func_test *
+find_wcscpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      wcscpy_list[0] = LIBC_FUNC_INIT (__wcscpy_ssse3);
+      i = 1;
+    }
+  else
+    i = 0;
+  wcscpy_list[i] = LIBC_FUNC_INIT (__wcscpy_sse2);
+  return wcscpy_list;
+}
+
+extern __typeof (wmemcmp) __wmemcmp_sse2 attribute_hidden;
+extern __typeof (wmemcmp) __wmemcmp_ssse3 attribute_hidden;
+extern __typeof (wmemcmp) __wmemcmp_sse4_1 attribute_hidden;
+
+static struct libc_func_test wmemcmp_list[4];
+
+# undef find_wmemcmp
+
+static struct libc_func_test *
+find_wmemcmp (void)
+{
+  size_t i;
+  if (HAS_SSE4_1)
+    {
+      wmemcmp_list[0] = LIBC_FUNC_INIT (__wmemcmp_sse4_1);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSSE3)
+    {
+      wmemcmp_list[i] = LIBC_FUNC_INIT (__wmemcmp_ssse3);
+      i++;
+    }
+  wmemcmp_list[i] = LIBC_FUNC_INIT (__wmemcmp_sse2);
+  return wmemcmp_list;
+}
+
+# ifdef SHARED
+extern __typeof (memcmp) __memcmp_sse2 attribute_hidden;
+extern __typeof (memcmp) __memcmp_ssse3 attribute_hidden;
+extern __typeof (memcmp) __memcmp_sse4_1 attribute_hidden;
+
+static struct libc_func_test memcmp_list[4];
+
+#  undef find_memcmp
+
+static struct libc_func_test *
+find_memcmp (void)
+{
+  size_t i;
+  if (HAS_SSE4_1)
+    {
+      memcmp_list[0] = LIBC_FUNC_INIT (__memcmp_sse4_1);
+      i = 1;
+    }
+  else
+    i = 0;
+  if (HAS_SSSE3)
+    {
+      memcmp_list[i] = LIBC_FUNC_INIT (__memcmp_ssse3);
+      i++;
+    }
+  memcmp_list[i] = LIBC_FUNC_INIT (__memcmp_sse2);
+  return memcmp_list;
+}
+
+extern __typeof (memcpy) __memcpy_sse2 attribute_hidden;
+extern __typeof (memcpy) __memcpy_ssse3 attribute_hidden;
+extern __typeof (memcpy) __memcpy_ssse3_back attribute_hidden;
+
+static struct libc_func_test memcpy_list[4];
+
+#  undef find_memcpy
+
+static struct libc_func_test *
+find_memcpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      memcpy_list[0] = LIBC_FUNC_INIT (__memcpy_ssse3_back);
+      memcpy_list[1] = LIBC_FUNC_INIT (__memcpy_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  memcpy_list[i] = LIBC_FUNC_INIT (__memcpy_sse2);
+  return memcpy_list;
+}
+
+extern __typeof (mempcpy) __mempcpy_sse2 attribute_hidden;
+extern __typeof (mempcpy) __mempcpy_ssse3 attribute_hidden;
+extern __typeof (mempcpy) __mempcpy_ssse3_back attribute_hidden;
+
+static struct libc_func_test mempcpy_list[4];
+
+#  undef find_mempcpy
+
+static struct libc_func_test *
+find_mempcpy (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      mempcpy_list[0] = LIBC_FUNC_INIT (__mempcpy_ssse3_back);
+      mempcpy_list[1] = LIBC_FUNC_INIT (__mempcpy_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  mempcpy_list[i] = LIBC_FUNC_INIT (__mempcpy_sse2);
+  return mempcpy_list;
+}
+
+extern void *__memcpy_chk (void *, const void *, size_t, size_t);
+extern __typeof (__memcpy_chk) __memcpy_chk_sse2 attribute_hidden;
+extern __typeof (__memcpy_chk) __memcpy_chk_ssse3 attribute_hidden;
+extern __typeof (__memcpy_chk) __memcpy_chk_ssse3_back attribute_hidden;
+
+static struct libc_func_test __memcpy_chk_list[4];
+
+#  undef find___memcpy_chk
+
+static struct libc_func_test *
+find___memcpy_chk (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      __memcpy_chk_list[0] = LIBC_FUNC_INIT (__memcpy_chk_ssse3_back);
+      __memcpy_chk_list[1] = LIBC_FUNC_INIT (__memcpy_chk_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  __memcpy_chk_list[i] = LIBC_FUNC_INIT (__memcpy_chk_sse2);
+  return __memcpy_chk_list;
+}
+
+extern void *__mempcpy_chk (void *, const void *, size_t, size_t);
+extern __typeof (__mempcpy_chk) __mempcpy_chk_sse2 attribute_hidden;
+extern __typeof (__mempcpy_chk) __mempcpy_chk_ssse3 attribute_hidden;
+extern __typeof (__mempcpy_chk) __mempcpy_chk_ssse3_back attribute_hidden;
+
+static struct libc_func_test __mempcpy_chk_list[4];
+
+#  undef find___mempcpy_chk
+
+static struct libc_func_test *
+find___mempcpy_chk (void)
+{
+  size_t i;
+  if (HAS_SSSE3)
+    {
+      __mempcpy_chk_list[0] = LIBC_FUNC_INIT (__mempcpy_chk_ssse3_back);
+      __mempcpy_chk_list[1] = LIBC_FUNC_INIT (__mempcpy_chk_ssse3);
+      i = 2;
+    }
+  else
+    i = 0;
+  __mempcpy_chk_list[i] = LIBC_FUNC_INIT (__mempcpy_chk_sse2);
+  return __mempcpy_chk_list;
+}
+
+extern __typeof (strlen) __strlen_sse2 attribute_hidden;
+extern __typeof (strlen) __strlen_sse2_no_bsf attribute_hidden;
+extern __typeof (strlen) __strlen_sse2_pminub attribute_hidden;
+extern __typeof (strlen) __strlen_sse42 attribute_hidden;
+
+static struct libc_func_test strlen_list[5];
+
+#  undef find_strlen
+
+static struct libc_func_test *
+find_strlen (void)
+{
+  size_t i;
+  if (HAS_SSE4_2)
+    {
+      strlen_list[0] = LIBC_FUNC_INIT (__strlen_sse42);
+      i = 1;
+    }
+  else
+    i = 0;
+  strlen_list[i] = LIBC_FUNC_INIT (__strlen_sse2);
+  i++;
+  strlen_list[i] = LIBC_FUNC_INIT (__strlen_sse2_no_bsf);
+  i++;
+  strlen_list[i] = LIBC_FUNC_INIT (__strlen_sse2_pminub);
+  return strlen_list;
+}
+# endif /* SHARED */
+#endif /* NOT_IN_libc */
+
+struct libc_func_test *
+__libc_func (const char *name)
+{
+  if (strcmp (name, "memcmp") == 0)
+    return find_memcmp ();
+
+  if (strcmp (name, "memcpy") == 0)
+    return find_memcpy ();
+
+  if (strcmp (name, "memmove") == 0)
+    return find_memmove ();
+
+  if (strcmp (name, "mempcpy") == 0)
+    return find_mempcpy ();
+
+  if (strcmp (name, "__memcpy_chk") == 0)
+    return find___memcpy_chk ();
+
+  if (strcmp (name, "__memmove_chk") == 0)
+    return find___memmove_chk ();
+
+  if (strcmp (name, "__mempcpy_chk") == 0)
+    return find___mempcpy_chk ();
+
+  if (strcmp (name, "memset") == 0)
+    return find_memset ();
+
+  if (strcmp (name, "rawmemchr") == 0)
+    return find_rawmemchr ();
+
+  if (strcmp (name, "stpcpy") == 0)
+    return find_stpcpy ();
+
+  if (strcmp (name, "stpncpy") == 0)
+    return find_stpncpy ();
+
+  if (strcmp (name, "strcpy") == 0)
+    return find_strcpy ();
+
+  if (strcmp (name, "strncpy") == 0)
+    return find_strncpy ();
+
+  if (strcmp (name, "strcasecmp") == 0)
+    return find_strcasecmp ();
+
+  if (strcmp (name, "strcasecmp_l") == 0)
+    return find_strcasecmp_l ();
+
+  if (strcmp (name, "strcat") == 0)
+    return find_strcat ();
+
+  if (strcmp (name, "strcmp") == 0)
+    return find_strcmp ();
+
+  if (strcmp (name, "strncasecmp") == 0)
+    return find_strncasecmp ();
+
+  if (strcmp (name, "strncasecmp_l") == 0)
+    return find_strncasecmp_l ();
+
+  if (strcmp (name, "strncat") == 0)
+    return find_strncat ();
+
+  if (strcmp (name, "strncmp") == 0)
+    return find_strncmp ();
+
+  if (strcmp (name, "strcasestr") == 0)
+    return find_strcasestr ();
+
+  if (strcmp (name, "strchr") == 0)
+    return find_strchr ();
+
+  if (strcmp (name, "strcspn") == 0)
+    return find_strcspn ();
+
+  if (strcmp (name, "strlen") == 0)
+    return find_strlen ();
+
+  if (strcmp (name, "strpbrk") == 0)
+    return find_strpbrk ();
+
+  if (strcmp (name, "strrchr") == 0)
+    return find_strrchr ();
+
+  if (strcmp (name, "strspn") == 0)
+    return find_strspn ();
+
+  if (strcmp (name, "strstr") == 0)
+    return find_strstr ();
+
+  if (strcmp (name, "wcscpy") == 0)
+    return find_wcscpy ();
+
+  if (strcmp (name, "wmemcmp") == 0)
+    return find_wmemcmp ();
+
+  return NULL;
+}
diff --git a/sysdeps/x86_64/multiarch/memcmp.S b/sysdeps/x86_64/multiarch/memcmp.S
index b2bc4d7..f2c9b30 100644
--- a/sysdeps/x86_64/multiarch/memcmp.S
+++ b/sysdeps/x86_64/multiarch/memcmp.S
@@ -48,6 +48,8 @@ END(memcmp)
 # define ENTRY(name) \
 	.type __memcmp_sse2, @function; \
 	.p2align 4; \
+	.globl __memcmp_sse2; \
+	.hidden __memcmp_sse2; \
 	__memcmp_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S
index a77cdfb..0c1c1e6 100644
--- a/sysdeps/x86_64/multiarch/memcpy.S
+++ b/sysdeps/x86_64/multiarch/memcpy.S
@@ -45,6 +45,8 @@ END(__new_memcpy)
 # undef ENTRY
 # define ENTRY(name) \
 	.type __memcpy_sse2, @function; \
+	.globl __memcpy_sse2; \
+	.hidden __memcpy_sse2; \
 	.p2align 4; \
 	__memcpy_sse2: cfi_startproc; \
 	CALL_MCOUNT
diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S
index caa435b..2fac9d7 100644
--- a/sysdeps/x86_64/multiarch/mempcpy.S
+++ b/sysdeps/x86_64/multiarch/mempcpy.S
@@ -43,6 +43,8 @@ END(__mempcpy)
 # define ENTRY(name) \
 	.type __mempcpy_sse2, @function; \
 	.p2align 4; \
+	.globl __mempcpy_sse2; \
+	.hidden __mempcpy_sse2; \
 	__mempcpy_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/rawmemchr.S b/sysdeps/x86_64/multiarch/rawmemchr.S
index c4157ad..ebcc17e 100644
--- a/sysdeps/x86_64/multiarch/rawmemchr.S
+++ b/sysdeps/x86_64/multiarch/rawmemchr.S
@@ -44,6 +44,8 @@ strong_alias (rawmemchr, __rawmemchr)
 	.section .text.sse4.2,"ax",@progbits
 	.align	16
 	.type	__rawmemchr_sse42, @function
+	.globl __rawmemchr_sse42
+	.hidden __rawmemchr_sse42
 __rawmemchr_sse42:
 	cfi_startproc
 	CALL_MCOUNT
@@ -81,6 +83,8 @@ __rawmemchr_sse42:
 # define ENTRY(name) \
 	.type __rawmemchr_sse2, @function; \
 	.align 16; \
+	.globl __rawmemchr_sse2; \
+	.hidden __rawmemchr_sse2; \
 	__rawmemchr_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/strcat.S b/sysdeps/x86_64/multiarch/strcat.S
index 0c256de..1ba69b6 100644
--- a/sysdeps/x86_64/multiarch/strcat.S
+++ b/sysdeps/x86_64/multiarch/strcat.S
@@ -63,6 +63,8 @@ END(STRCAT)
 # define ENTRY(name) \
 	.type STRCAT_SSE2, @function; \
 	.align 16; \
+	.globl STRCAT_SSE2; \
+	.hidden STRCAT_SSE2; \
 	STRCAT_SSE2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/strchr.S b/sysdeps/x86_64/multiarch/strchr.S
index b9f88e4..5c8aa7c 100644
--- a/sysdeps/x86_64/multiarch/strchr.S
+++ b/sysdeps/x86_64/multiarch/strchr.S
@@ -82,6 +82,8 @@ END(strchr)
 	.section .text.sse4.2,"ax",@progbits
 	.align	16
 	.type	__strchr_sse42, @function
+	.globl	__strchr_sse42
+	.hidden	__strchr_sse42
 __strchr_sse42:
 	cfi_startproc
 	CALL_MCOUNT
@@ -164,6 +166,8 @@ L(loop_exit):
 # define ENTRY(name) \
 	.type __strchr_sse2, @function; \
 	.align 16; \
+	.globl __strchr_sse2; \
+	.hidden __strchr_sse2; \
 	__strchr_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S
index 9d00bbc..4fadfcb 100644
--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S
+++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S
@@ -48,6 +48,8 @@
 	.section .text.SECTION,"ax",@progbits
 	.align	16
 	.type	STRCMP_SSE42, @function
+	.globl	STRCMP_SSE42
+	.hidden	STRCMP_SSE42
 #ifdef USE_AS_STRCASECMP_L
 ENTRY (GLABEL(__strcasecmp))
 	movq	__libc_tsd_LOCALE@gottpoff(%rip),%rax
diff --git a/sysdeps/x86_64/multiarch/strcmp.S b/sysdeps/x86_64/multiarch/strcmp.S
index d366d09..fb9b0fb 100644
--- a/sysdeps/x86_64/multiarch/strcmp.S
+++ b/sysdeps/x86_64/multiarch/strcmp.S
@@ -171,6 +171,8 @@ weak_alias (__strncasecmp, strncasecmp)
 # define ENTRY(name) \
 	.type STRCMP_SSE2, @function; \
 	.align 16; \
+	.globl STRCMP_SSE2; \
+	.hidden STRCMP_SSE2; \
 	STRCMP_SSE2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
@@ -181,6 +183,8 @@ weak_alias (__strncasecmp, strncasecmp)
 #  define ENTRY2(name) \
 	.type __strcasecmp_sse2, @function; \
 	.align 16; \
+	.globl __strcasecmp_sse2; \
+	.hidden __strcasecmp_sse2; \
 	__strcasecmp_sse2: cfi_startproc; \
 	CALL_MCOUNT
 #  define END2(name) \
@@ -191,6 +195,8 @@ weak_alias (__strncasecmp, strncasecmp)
 #  define ENTRY2(name) \
 	.type __strncasecmp_sse2, @function; \
 	.align 16; \
+	.globl __strncasecmp_sse2; \
+	.hidden __strncasecmp_sse2; \
 	__strncasecmp_sse2: cfi_startproc; \
 	CALL_MCOUNT
 #  define END2(name) \
diff --git a/sysdeps/x86_64/multiarch/strcpy.S b/sysdeps/x86_64/multiarch/strcpy.S
index 7be1b8b..b97215e 100644
--- a/sysdeps/x86_64/multiarch/strcpy.S
+++ b/sysdeps/x86_64/multiarch/strcpy.S
@@ -77,6 +77,8 @@ END(STRCPY)
 # define ENTRY(name) \
 	.type STRCPY_SSE2, @function; \
 	.align 16; \
+	.globl STRCPY_SSE2; \
+	.hidden STRCPY_SSE2; \
 	STRCPY_SSE2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/strlen.S b/sysdeps/x86_64/multiarch/strlen.S
index 0c46b4f..bab0ac3 100644
--- a/sysdeps/x86_64/multiarch/strlen.S
+++ b/sysdeps/x86_64/multiarch/strlen.S
@@ -49,6 +49,8 @@ END(strlen)
 # define ENTRY(name) \
 	.type __strlen_sse2, @function; \
 	.align 16; \
+	.globl __strlen_sse2; \
+	.hidden __strlen_sse2; \
 	__strlen_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
diff --git a/sysdeps/x86_64/multiarch/strrchr.S b/sysdeps/x86_64/multiarch/strrchr.S
index c87d8fa..1ccaf4a 100644
--- a/sysdeps/x86_64/multiarch/strrchr.S
+++ b/sysdeps/x86_64/multiarch/strrchr.S
@@ -87,6 +87,8 @@ END(strrchr)
 	.section .text.sse4.2,"ax",@progbits
 	.align	16
 	.type	__strrchr_sse42, @function
+	.globl	__strrchr_sse42
+	.hidden	__strrchr_sse42
 __strrchr_sse42:
 	cfi_startproc
 	CALL_MCOUNT
@@ -265,6 +267,8 @@ L(psrldq_table):
 # define ENTRY(name) \
 	.type __strrchr_sse2, @function; \
 	.align 16; \
+	.globl __strrchr_sse2; \
+	.hidden __strrchr_sse2; \
 	__strrchr_sse2: cfi_startproc; \
 	CALL_MCOUNT
 # undef END
-- 
1.7.11.4

