Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Most of the string-functions are rather heavily hand-optimized,
0004  * see especially strsep,strstr,str[c]spn. They should work, but are not
0005  * very easy to understand. Everything is done entirely within the register
0006  * set, making the functions fast and clean. String instructions have been
0007  * used through-out, making for "slightly" unclear code :-)
0008  *
0009  * AK: On P4 and K7 using non string instruction implementations might be faster
0010  * for large memory blocks. But most of them are unlikely to be used on large
0011  * strings.
0012  */
0013 
0014 #define __NO_FORTIFY
0015 #include <linux/string.h>
0016 #include <linux/export.h>
0017 
0018 #ifdef __HAVE_ARCH_STRCPY
0019 char *strcpy(char *dest, const char *src)
0020 {
0021     int d0, d1, d2;
0022     asm volatile("1:\tlodsb\n\t"
0023         "stosb\n\t"
0024         "testb %%al,%%al\n\t"
0025         "jne 1b"
0026         : "=&S" (d0), "=&D" (d1), "=&a" (d2)
0027         : "0" (src), "1" (dest) : "memory");
0028     return dest;
0029 }
0030 EXPORT_SYMBOL(strcpy);
0031 #endif
0032 
0033 #ifdef __HAVE_ARCH_STRNCPY
0034 char *strncpy(char *dest, const char *src, size_t count)
0035 {
0036     int d0, d1, d2, d3;
0037     asm volatile("1:\tdecl %2\n\t"
0038         "js 2f\n\t"
0039         "lodsb\n\t"
0040         "stosb\n\t"
0041         "testb %%al,%%al\n\t"
0042         "jne 1b\n\t"
0043         "rep\n\t"
0044         "stosb\n"
0045         "2:"
0046         : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
0047         : "0" (src), "1" (dest), "2" (count) : "memory");
0048     return dest;
0049 }
0050 EXPORT_SYMBOL(strncpy);
0051 #endif
0052 
0053 #ifdef __HAVE_ARCH_STRCAT
0054 char *strcat(char *dest, const char *src)
0055 {
0056     int d0, d1, d2, d3;
0057     asm volatile("repne\n\t"
0058         "scasb\n\t"
0059         "decl %1\n"
0060         "1:\tlodsb\n\t"
0061         "stosb\n\t"
0062         "testb %%al,%%al\n\t"
0063         "jne 1b"
0064         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
0065         : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu) : "memory");
0066     return dest;
0067 }
0068 EXPORT_SYMBOL(strcat);
0069 #endif
0070 
0071 #ifdef __HAVE_ARCH_STRNCAT
0072 char *strncat(char *dest, const char *src, size_t count)
0073 {
0074     int d0, d1, d2, d3;
0075     asm volatile("repne\n\t"
0076         "scasb\n\t"
0077         "decl %1\n\t"
0078         "movl %8,%3\n"
0079         "1:\tdecl %3\n\t"
0080         "js 2f\n\t"
0081         "lodsb\n\t"
0082         "stosb\n\t"
0083         "testb %%al,%%al\n\t"
0084         "jne 1b\n"
0085         "2:\txorl %2,%2\n\t"
0086         "stosb"
0087         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
0088         : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu), "g" (count)
0089         : "memory");
0090     return dest;
0091 }
0092 EXPORT_SYMBOL(strncat);
0093 #endif
0094 
0095 #ifdef __HAVE_ARCH_STRCMP
0096 int strcmp(const char *cs, const char *ct)
0097 {
0098     int d0, d1;
0099     int res;
0100     asm volatile("1:\tlodsb\n\t"
0101         "scasb\n\t"
0102         "jne 2f\n\t"
0103         "testb %%al,%%al\n\t"
0104         "jne 1b\n\t"
0105         "xorl %%eax,%%eax\n\t"
0106         "jmp 3f\n"
0107         "2:\tsbbl %%eax,%%eax\n\t"
0108         "orb $1,%%al\n"
0109         "3:"
0110         : "=a" (res), "=&S" (d0), "=&D" (d1)
0111         : "1" (cs), "2" (ct)
0112         : "memory");
0113     return res;
0114 }
0115 EXPORT_SYMBOL(strcmp);
0116 #endif
0117 
0118 #ifdef __HAVE_ARCH_STRNCMP
0119 int strncmp(const char *cs, const char *ct, size_t count)
0120 {
0121     int res;
0122     int d0, d1, d2;
0123     asm volatile("1:\tdecl %3\n\t"
0124         "js 2f\n\t"
0125         "lodsb\n\t"
0126         "scasb\n\t"
0127         "jne 3f\n\t"
0128         "testb %%al,%%al\n\t"
0129         "jne 1b\n"
0130         "2:\txorl %%eax,%%eax\n\t"
0131         "jmp 4f\n"
0132         "3:\tsbbl %%eax,%%eax\n\t"
0133         "orb $1,%%al\n"
0134         "4:"
0135         : "=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
0136         : "1" (cs), "2" (ct), "3" (count)
0137         : "memory");
0138     return res;
0139 }
0140 EXPORT_SYMBOL(strncmp);
0141 #endif
0142 
0143 #ifdef __HAVE_ARCH_STRCHR
0144 char *strchr(const char *s, int c)
0145 {
0146     int d0;
0147     char *res;
0148     asm volatile("movb %%al,%%ah\n"
0149         "1:\tlodsb\n\t"
0150         "cmpb %%ah,%%al\n\t"
0151         "je 2f\n\t"
0152         "testb %%al,%%al\n\t"
0153         "jne 1b\n\t"
0154         "movl $1,%1\n"
0155         "2:\tmovl %1,%0\n\t"
0156         "decl %0"
0157         : "=a" (res), "=&S" (d0)
0158         : "1" (s), "0" (c)
0159         : "memory");
0160     return res;
0161 }
0162 EXPORT_SYMBOL(strchr);
0163 #endif
0164 
0165 #ifdef __HAVE_ARCH_STRLEN
0166 size_t strlen(const char *s)
0167 {
0168     int d0;
0169     size_t res;
0170     asm volatile("repne\n\t"
0171         "scasb"
0172         : "=c" (res), "=&D" (d0)
0173         : "1" (s), "a" (0), "0" (0xffffffffu)
0174         : "memory");
0175     return ~res - 1;
0176 }
0177 EXPORT_SYMBOL(strlen);
0178 #endif
0179 
0180 #ifdef __HAVE_ARCH_MEMCHR
0181 void *memchr(const void *cs, int c, size_t count)
0182 {
0183     int d0;
0184     void *res;
0185     if (!count)
0186         return NULL;
0187     asm volatile("repne\n\t"
0188         "scasb\n\t"
0189         "je 1f\n\t"
0190         "movl $1,%0\n"
0191         "1:\tdecl %0"
0192         : "=D" (res), "=&c" (d0)
0193         : "a" (c), "0" (cs), "1" (count)
0194         : "memory");
0195     return res;
0196 }
0197 EXPORT_SYMBOL(memchr);
0198 #endif
0199 
0200 #ifdef __HAVE_ARCH_MEMSCAN
0201 void *memscan(void *addr, int c, size_t size)
0202 {
0203     if (!size)
0204         return addr;
0205     asm volatile("repnz; scasb\n\t"
0206         "jnz 1f\n\t"
0207         "dec %%edi\n"
0208         "1:"
0209         : "=D" (addr), "=c" (size)
0210         : "0" (addr), "1" (size), "a" (c)
0211         : "memory");
0212     return addr;
0213 }
0214 EXPORT_SYMBOL(memscan);
0215 #endif
0216 
0217 #ifdef __HAVE_ARCH_STRNLEN
0218 size_t strnlen(const char *s, size_t count)
0219 {
0220     int d0;
0221     int res;
0222     asm volatile("movl %2,%0\n\t"
0223         "jmp 2f\n"
0224         "1:\tcmpb $0,(%0)\n\t"
0225         "je 3f\n\t"
0226         "incl %0\n"
0227         "2:\tdecl %1\n\t"
0228         "cmpl $-1,%1\n\t"
0229         "jne 1b\n"
0230         "3:\tsubl %2,%0"
0231         : "=a" (res), "=&d" (d0)
0232         : "c" (s), "1" (count)
0233         : "memory");
0234     return res;
0235 }
0236 EXPORT_SYMBOL(strnlen);
0237 #endif