xref: /kernel/linux/linux-6.6/arch/x86/lib/string_32.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Most of the string-functions are rather heavily hand-optimized,
462306a36Sopenharmony_ci * see especially strsep,strstr,str[c]spn. They should work, but are not
562306a36Sopenharmony_ci * very easy to understand. Everything is done entirely within the register
662306a36Sopenharmony_ci * set, making the functions fast and clean. String instructions have been
762306a36Sopenharmony_ci * used through-out, making for "slightly" unclear code :-)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * AK: On P4 and K7 using non string instruction implementations might be faster
1062306a36Sopenharmony_ci * for large memory blocks. But most of them are unlikely to be used on large
1162306a36Sopenharmony_ci * strings.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define __NO_FORTIFY
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/export.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRCPY
1962306a36Sopenharmony_cichar *strcpy(char *dest, const char *src)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int d0, d1, d2;
2262306a36Sopenharmony_ci	asm volatile("1:\tlodsb\n\t"
2362306a36Sopenharmony_ci		"stosb\n\t"
2462306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
2562306a36Sopenharmony_ci		"jne 1b"
2662306a36Sopenharmony_ci		: "=&S" (d0), "=&D" (d1), "=&a" (d2)
2762306a36Sopenharmony_ci		: "0" (src), "1" (dest) : "memory");
2862306a36Sopenharmony_ci	return dest;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ciEXPORT_SYMBOL(strcpy);
3162306a36Sopenharmony_ci#endif
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCPY
3462306a36Sopenharmony_cichar *strncpy(char *dest, const char *src, size_t count)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	int d0, d1, d2, d3;
3762306a36Sopenharmony_ci	asm volatile("1:\tdecl %2\n\t"
3862306a36Sopenharmony_ci		"js 2f\n\t"
3962306a36Sopenharmony_ci		"lodsb\n\t"
4062306a36Sopenharmony_ci		"stosb\n\t"
4162306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
4262306a36Sopenharmony_ci		"jne 1b\n\t"
4362306a36Sopenharmony_ci		"rep\n\t"
4462306a36Sopenharmony_ci		"stosb\n"
4562306a36Sopenharmony_ci		"2:"
4662306a36Sopenharmony_ci		: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
4762306a36Sopenharmony_ci		: "0" (src), "1" (dest), "2" (count) : "memory");
4862306a36Sopenharmony_ci	return dest;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciEXPORT_SYMBOL(strncpy);
5162306a36Sopenharmony_ci#endif
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRCAT
5462306a36Sopenharmony_cichar *strcat(char *dest, const char *src)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int d0, d1, d2, d3;
5762306a36Sopenharmony_ci	asm volatile("repne\n\t"
5862306a36Sopenharmony_ci		"scasb\n\t"
5962306a36Sopenharmony_ci		"decl %1\n"
6062306a36Sopenharmony_ci		"1:\tlodsb\n\t"
6162306a36Sopenharmony_ci		"stosb\n\t"
6262306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
6362306a36Sopenharmony_ci		"jne 1b"
6462306a36Sopenharmony_ci		: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
6562306a36Sopenharmony_ci		: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu) : "memory");
6662306a36Sopenharmony_ci	return dest;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ciEXPORT_SYMBOL(strcat);
6962306a36Sopenharmony_ci#endif
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCAT
7262306a36Sopenharmony_cichar *strncat(char *dest, const char *src, size_t count)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int d0, d1, d2, d3;
7562306a36Sopenharmony_ci	asm volatile("repne\n\t"
7662306a36Sopenharmony_ci		"scasb\n\t"
7762306a36Sopenharmony_ci		"decl %1\n\t"
7862306a36Sopenharmony_ci		"movl %8,%3\n"
7962306a36Sopenharmony_ci		"1:\tdecl %3\n\t"
8062306a36Sopenharmony_ci		"js 2f\n\t"
8162306a36Sopenharmony_ci		"lodsb\n\t"
8262306a36Sopenharmony_ci		"stosb\n\t"
8362306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
8462306a36Sopenharmony_ci		"jne 1b\n"
8562306a36Sopenharmony_ci		"2:\txorl %2,%2\n\t"
8662306a36Sopenharmony_ci		"stosb"
8762306a36Sopenharmony_ci		: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
8862306a36Sopenharmony_ci		: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu), "g" (count)
8962306a36Sopenharmony_ci		: "memory");
9062306a36Sopenharmony_ci	return dest;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ciEXPORT_SYMBOL(strncat);
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRCMP
9662306a36Sopenharmony_ciint strcmp(const char *cs, const char *ct)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int d0, d1;
9962306a36Sopenharmony_ci	int res;
10062306a36Sopenharmony_ci	asm volatile("1:\tlodsb\n\t"
10162306a36Sopenharmony_ci		"scasb\n\t"
10262306a36Sopenharmony_ci		"jne 2f\n\t"
10362306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
10462306a36Sopenharmony_ci		"jne 1b\n\t"
10562306a36Sopenharmony_ci		"xorl %%eax,%%eax\n\t"
10662306a36Sopenharmony_ci		"jmp 3f\n"
10762306a36Sopenharmony_ci		"2:\tsbbl %%eax,%%eax\n\t"
10862306a36Sopenharmony_ci		"orb $1,%%al\n"
10962306a36Sopenharmony_ci		"3:"
11062306a36Sopenharmony_ci		: "=a" (res), "=&S" (d0), "=&D" (d1)
11162306a36Sopenharmony_ci		: "1" (cs), "2" (ct)
11262306a36Sopenharmony_ci		: "memory");
11362306a36Sopenharmony_ci	return res;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ciEXPORT_SYMBOL(strcmp);
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCMP
11962306a36Sopenharmony_ciint strncmp(const char *cs, const char *ct, size_t count)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	int res;
12262306a36Sopenharmony_ci	int d0, d1, d2;
12362306a36Sopenharmony_ci	asm volatile("1:\tdecl %3\n\t"
12462306a36Sopenharmony_ci		"js 2f\n\t"
12562306a36Sopenharmony_ci		"lodsb\n\t"
12662306a36Sopenharmony_ci		"scasb\n\t"
12762306a36Sopenharmony_ci		"jne 3f\n\t"
12862306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
12962306a36Sopenharmony_ci		"jne 1b\n"
13062306a36Sopenharmony_ci		"2:\txorl %%eax,%%eax\n\t"
13162306a36Sopenharmony_ci		"jmp 4f\n"
13262306a36Sopenharmony_ci		"3:\tsbbl %%eax,%%eax\n\t"
13362306a36Sopenharmony_ci		"orb $1,%%al\n"
13462306a36Sopenharmony_ci		"4:"
13562306a36Sopenharmony_ci		: "=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
13662306a36Sopenharmony_ci		: "1" (cs), "2" (ct), "3" (count)
13762306a36Sopenharmony_ci		: "memory");
13862306a36Sopenharmony_ci	return res;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ciEXPORT_SYMBOL(strncmp);
14162306a36Sopenharmony_ci#endif
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRCHR
14462306a36Sopenharmony_cichar *strchr(const char *s, int c)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	int d0;
14762306a36Sopenharmony_ci	char *res;
14862306a36Sopenharmony_ci	asm volatile("movb %%al,%%ah\n"
14962306a36Sopenharmony_ci		"1:\tlodsb\n\t"
15062306a36Sopenharmony_ci		"cmpb %%ah,%%al\n\t"
15162306a36Sopenharmony_ci		"je 2f\n\t"
15262306a36Sopenharmony_ci		"testb %%al,%%al\n\t"
15362306a36Sopenharmony_ci		"jne 1b\n\t"
15462306a36Sopenharmony_ci		"movl $1,%1\n"
15562306a36Sopenharmony_ci		"2:\tmovl %1,%0\n\t"
15662306a36Sopenharmony_ci		"decl %0"
15762306a36Sopenharmony_ci		: "=a" (res), "=&S" (d0)
15862306a36Sopenharmony_ci		: "1" (s), "0" (c)
15962306a36Sopenharmony_ci		: "memory");
16062306a36Sopenharmony_ci	return res;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ciEXPORT_SYMBOL(strchr);
16362306a36Sopenharmony_ci#endif
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRLEN
16662306a36Sopenharmony_cisize_t strlen(const char *s)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	int d0;
16962306a36Sopenharmony_ci	size_t res;
17062306a36Sopenharmony_ci	asm volatile("repne\n\t"
17162306a36Sopenharmony_ci		"scasb"
17262306a36Sopenharmony_ci		: "=c" (res), "=&D" (d0)
17362306a36Sopenharmony_ci		: "1" (s), "a" (0), "0" (0xffffffffu)
17462306a36Sopenharmony_ci		: "memory");
17562306a36Sopenharmony_ci	return ~res - 1;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ciEXPORT_SYMBOL(strlen);
17862306a36Sopenharmony_ci#endif
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#ifdef __HAVE_ARCH_MEMCHR
18162306a36Sopenharmony_civoid *memchr(const void *cs, int c, size_t count)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	int d0;
18462306a36Sopenharmony_ci	void *res;
18562306a36Sopenharmony_ci	if (!count)
18662306a36Sopenharmony_ci		return NULL;
18762306a36Sopenharmony_ci	asm volatile("repne\n\t"
18862306a36Sopenharmony_ci		"scasb\n\t"
18962306a36Sopenharmony_ci		"je 1f\n\t"
19062306a36Sopenharmony_ci		"movl $1,%0\n"
19162306a36Sopenharmony_ci		"1:\tdecl %0"
19262306a36Sopenharmony_ci		: "=D" (res), "=&c" (d0)
19362306a36Sopenharmony_ci		: "a" (c), "0" (cs), "1" (count)
19462306a36Sopenharmony_ci		: "memory");
19562306a36Sopenharmony_ci	return res;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ciEXPORT_SYMBOL(memchr);
19862306a36Sopenharmony_ci#endif
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#ifdef __HAVE_ARCH_MEMSCAN
20162306a36Sopenharmony_civoid *memscan(void *addr, int c, size_t size)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	if (!size)
20462306a36Sopenharmony_ci		return addr;
20562306a36Sopenharmony_ci	asm volatile("repnz; scasb\n\t"
20662306a36Sopenharmony_ci	    "jnz 1f\n\t"
20762306a36Sopenharmony_ci	    "dec %%edi\n"
20862306a36Sopenharmony_ci	    "1:"
20962306a36Sopenharmony_ci	    : "=D" (addr), "=c" (size)
21062306a36Sopenharmony_ci	    : "0" (addr), "1" (size), "a" (c)
21162306a36Sopenharmony_ci	    : "memory");
21262306a36Sopenharmony_ci	return addr;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ciEXPORT_SYMBOL(memscan);
21562306a36Sopenharmony_ci#endif
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci#ifdef __HAVE_ARCH_STRNLEN
21862306a36Sopenharmony_cisize_t strnlen(const char *s, size_t count)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	int d0;
22162306a36Sopenharmony_ci	int res;
22262306a36Sopenharmony_ci	asm volatile("movl %2,%0\n\t"
22362306a36Sopenharmony_ci		"jmp 2f\n"
22462306a36Sopenharmony_ci		"1:\tcmpb $0,(%0)\n\t"
22562306a36Sopenharmony_ci		"je 3f\n\t"
22662306a36Sopenharmony_ci		"incl %0\n"
22762306a36Sopenharmony_ci		"2:\tdecl %1\n\t"
22862306a36Sopenharmony_ci		"cmpl $-1,%1\n\t"
22962306a36Sopenharmony_ci		"jne 1b\n"
23062306a36Sopenharmony_ci		"3:\tsubl %2,%0"
23162306a36Sopenharmony_ci		: "=a" (res), "=&d" (d0)
23262306a36Sopenharmony_ci		: "c" (s), "1" (count)
23362306a36Sopenharmony_ci		: "memory");
23462306a36Sopenharmony_ci	return res;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ciEXPORT_SYMBOL(strnlen);
23762306a36Sopenharmony_ci#endif
238