zoukankan      html  css  js  c++  java
  • 为了效率,我们可以用的招数 之 strchr

    如果要写一个从字符串中查找一个字符的函数,相信你不难想到如下代码:

     1 char* __cdecl strchr_1(
     2   char const* _Str,
     3   int         _Val
     4 ) {
     5 
     6   while (*_Str && *_Str != _Val)
     7     _Str++;
     8   
     9   if (*_Str == _Val)
    10     return(_Str);
    11 
    12   return NULL;
    13 }

     strlen 的效率之旅一样,我们先做好测试脚手架:

     1 typedef char* (__cdecl* p_strchr)(
     2   char const* _Str,
     3   int         _Val
     4 );
     5 
     6 // 测试正确性
     7 void test_function(
     8     char* funName,
     9     p_strchr function,
    10     char* str,
    11     char ch,
    12     int expectIndex) {
    13   int got = function(str, ch) - (int)str;
    14   printf(
    15       "func [%s] test value [%s] find char [%c],"
    16       " expect [%d], got [%d], %s
    ",
    17       funName,
    18       str,
    19       ch,
    20       got,
    21       expectIndex,
    22       got == expectIndex
    23           ? "true"
    24           : "false"
    25   );
    26 }
    27 
    28 // 正确性测试用例
    29 void test_functions(char* funName, p_strchr function) {
    30   struct  test_item {
    31 
    32     char* str;
    33     char val;
    34     int expect_index;
    35   } items[] = {
    36     // return NULL, expect nagtive address of "a"
    37     { "a", 'b',  -(int)"a" }, 
    38     // last is '', returns 1
    39     { "a", '', 1 },         
    40     { "ab", 'a', 0 },
    41     { "ab", 'b', 1 },
    42     {"abc", 'b', 1 }
    43   };
    44 
    45   int size = sizeof(items) / sizeof(struct test_item);
    46 
    47   for (int i = 0; i < size; i++) {
    48     test_function(
    49         funName,
    50         function,
    51         items[i].str,
    52         items[i].val,
    53         items[i].expect_index);
    54   }
    55 }

    放入main函数执行,执行结果如下:

    可以看到,我们获取到了我们想要的效果,那么接下来再来一个效率对比,我们的测试脚手架如下:

     1 #define BUFF_SIZE 100000000
     2 char buff[BUFF_SIZE + 1]; // 100M + 1BYTE
     3 void test_function_prof(
     4     char* funName,
     5     p_strchr function,
     6     char* str,
     7     char ch) {
     8   ULONGLONG start = 0;
     9   ULONGLONG end = 0;
    10 
    11   start = GetTickCount64();
    12   function(str, ch);
    13   end = GetTickCount64();
    14 
    15   printf(
    16       "test func [%s] start [%lld], end [%lld], cost: [%lld]
    ",
    17       funName,
    18       start,
    19       end,
    20       end - start
    21   );
    22 }
    23 
    24 void test_profs() {
    25   // init
    26   int size = BUFF_SIZE;
    27   for (int i = 0; i < size; i++) {
    28     buff[i] = 'a';
    29   }
    30   buff[BUFF_SIZE - 1] = 'b';
    31   buff[BUFF_SIZE] = '';
    32 
    33   test_function_prof("strchar_1", strchr_1, buff, 'b');
    34 }

    在主函数中调用 test_profs 函数,得到结果如下:

     一个100M长的字符串,查找到结尾需要 156ms,那么系统自带的 strchr 函数表现如何呢?向 test_profs 函数添加如下代码:

    1 test_function_prof("strchar",   strchr,   buff, 'b');

    得到结果如下:

     哇,差距挺大的,居然差了8.75(140/16)倍,那么效率何来?我们到源码中找答案,找到系统 strchr 函数的实现,我们获取到如下代码:

      1         page    ,132
      2         title   strchr - search string for given character
      3 ;***
      4 ;strchr.asm - search a string for a given character
      5 ;
      6 ;       Copyright (c) Microsoft Corporation. All rights reserved.
      7 ;
      8 ;Purpose:
      9 ;       defines strchr() - search a string for a character
     10 ;
     11 ;*******************************************************************************
     12 
     13         .xlist
     14         include vcruntime.inc
     15         .list
     16 
     17 page
     18 ;***
     19 ;char *strchr(string, chr) - search a string for a character
     20 ;
     21 ;Purpose:
     22 ;       Searches a string for a given character, which may be the
     23 ;       null character ''.
     24 ;
     25 ;       Algorithm:
     26 ;       char *
     27 ;       strchr (string, chr)
     28 ;       char *string, chr;
     29 ;       {
     30 ;         while (*string && *string != chr)
     31 ;             string++;
     32 ;         if (*string == chr)
     33 ;             return(string);
     34 ;         return((char *)0);
     35 ;       }
     36 ;
     37 ;Entry:
     38 ;       char *string - string to search in
     39 ;       char chr     - character to search for
     40 ;
     41 ;Exit:
     42 ;       returns pointer to the first occurence of c in string
     43 ;       returns NULL if chr does not occur in string
     44 ;
     45 ;Uses:
     46 ;
     47 ;Exceptions:
     48 ;
     49 ;*******************************************************************************
     50 
     51         CODESEG
     52 
     53         align   16
     54         public  strchr, __from_strstr_to_strchr
     55 strchr  proc 
     56         string:ptr byte, 
     57         chr:byte
     58 
     59         OPTION PROLOGUE:NONE, EPILOGUE:NONE
     60 
     61         .FPO    ( 0, 2, 0, 0, 0, 0 )
     62 
     63 ; Include SSE2 code path for platforms that support it.
     64         include strchr_sse.inc
     65 
     66         xor     eax,eax
     67         mov     al,[esp + 8]        ; al = chr (search char)
     68 
     69 __from_strstr_to_strchr label proc
     70 
     71         push    ebx                 ; PRESERVE EBX
     72         mov     ebx,eax             ; ebx = 0/0/0/chr
     73         shl     eax,8               ; eax = 0/0/chr/0
     74         mov     edx,[esp + 8]       ; edx = buffer
     75         test    edx,3               ; test if string is aligned on 32 bits
     76         jz      short main_loop_start
     77 
     78 str_misaligned:                     ; simple byte loop until string is aligned
     79         mov     cl,[edx]
     80         add     edx,1
     81         cmp     cl,bl
     82         je      short found_bx
     83         test    cl,cl
     84         jz      short retnull_bx
     85         test    edx,3               ; now aligned ?
     86         jne     short str_misaligned
     87 
     88 main_loop_start:                    ; set all 4 bytes of ebx to [chr]
     89         or      ebx,eax             ; ebx = 0/0/chr/chr
     90         push    edi                 ; PRESERVE EDI
     91         mov     eax,ebx             ; eax = 0/0/chr/chr
     92         shl     ebx,10h             ; ebx = chr/chr/0/0
     93         push    esi                 ; PRESERVE ESI
     94         or      ebx,eax             ; ebx = all 4 bytes = [chr]
     95 
     96 ; in the main loop (below), we are looking for chr or for EOS (end of string)
     97 
     98 main_loop:
     99         mov     ecx,[edx]           ; read  dword (4 bytes)
    100         mov     edi,7efefeffh       ; work with edi & ecx for looking for chr
    101 
    102         mov     eax,ecx             ; eax = dword
    103         mov     esi,edi             ; work with esi & eax for looking for EOS
    104 
    105         xor     ecx,ebx             ; eax = dword xor chr/chr/chr/chr
    106         add     esi,eax
    107 
    108         add     edi,ecx
    109         xor     ecx,-1
    110 
    111         xor     eax,-1
    112         xor     ecx,edi
    113 
    114         xor     eax,esi
    115         add     edx,4
    116 
    117         and     ecx,81010100h       ; test for chr
    118         jnz     short chr_is_found  ; chr probably has been found
    119 
    120         ; chr was not found, check for EOS
    121 
    122         and     eax,81010100h       ; is any flag set ??
    123         jz      short main_loop     ; EOS was not found, go get another dword
    124 
    125         and     eax,01010100h       ; is it in high byte?
    126         jnz     short retnull       ; no, definitely found EOS, return failure
    127 
    128         and     esi,80000000h       ; check was high byte 0 or 80h
    129         jnz     short main_loop     ; it just was 80h in high byte, go get
    130                                     ; another dword
    131 retnull:
    132         pop     esi
    133         pop     edi
    134 retnull_bx:
    135         pop     ebx
    136         xor     eax,eax
    137         ret                         ; _cdecl return
    138 
    139 found_bx:
    140         lea     eax,[edx - 1]
    141         pop     ebx                 ; restore ebx
    142         ret                         ; _cdecl return
    143 
    144 chr_is_found:
    145         mov     eax,[edx - 4]       ; let's look one more time on this dword
    146         cmp     al,bl               ; is chr in byte 0?
    147         je      short byte_0
    148         test    al,al               ; test if low byte is 0
    149         je      retnull
    150         cmp     ah,bl               ; is it byte 1
    151         je      short byte_1
    152         test    ah,ah               ; found EOS ?
    153         je      retnull
    154         shr     eax,10h             ; is it byte 2
    155         cmp     al,bl
    156         je      short byte_2
    157         test    al,al               ; if in al some bits were set, bl!=bh
    158         je      retnull
    159         cmp     ah,bl
    160         je      short byte_3
    161         test    ah,ah
    162         jz      retnull
    163         jmp     short main_loop     ; neither chr nor EOS found, go get
    164                                     ; another dword
    165 byte_3:
    166         pop     esi
    167         pop     edi
    168         lea     eax,[edx - 1]
    169         pop     ebx                 ; restore ebx
    170         ret                         ; _cdecl return
    171 
    172 byte_2:
    173         lea     eax,[edx - 2]
    174         pop     esi
    175         pop     edi
    176         pop     ebx
    177         ret                         ; _cdecl return
    178 
    179 byte_1:
    180         lea     eax,[edx - 3]
    181         pop     esi
    182         pop     edi
    183         pop     ebx
    184         ret                         ; _cdecl return
    185 
    186 byte_0:
    187         lea     eax,[edx - 4]
    188         pop     esi                 ; restore esi
    189         pop     edi                 ; restore edi
    190         pop     ebx                 ; restore ebx
    191         ret                         ; _cdecl return
    192 
    193 strchr  endp
    194         end

    其中,

    78-86行进行地址32位对齐(硬件访问32位对齐地址更快);

    88-94行我们将ebx(32位4字节)中的四个字节均设置为要查找的字符;

    98-129行是对字符串的迭代查找目标字符;

    在循环中,我们看到了几个特殊的值,分别列出值以及其二进制位如下:

    我们先看下对 ecx 寄存器的操作:

    1. 读取查询字符串的四个字节(这里因为是 ASCII 字符,所以是四个字符);
    2. 与 ebx(chr/chr/chr/chr) 异或;
    3. 按位取反(xor ecx, -1);
    4. edi = 0x7efefeff + ecx;
    5. 异或edi;
    6. 按位与 0x81010100;
    7. 跳转到依次判断各个字节是否位目标字符的逻辑;

    从以上的逻辑,我们可以看到,117行判断决定了是否有可能找到了目标字符。那么是怎么做到的呢?

    首先,我们假设 ecx 所有字节均不是目标值,则执行 xor     ecx,ebx 之后,所有字节均不为0;

    第二步,按位取反,则 ecx 所有字节均不为 0;

    第三步,edi = 0x7efefeff + ecx,这一步参考 strlen 的效率之旅 中对 '' 的判断;

    第四步,判断 ecx & 81010100 的值,如果结果不为0,则可能找到了对应字符,跳转到字节判断逻辑(chr_is_found);

    第五步,如果走到了122行,则说明肯定没有找到目标,这里判断是否到了查找字符串结尾,逻辑和 strlen 的效率之旅 中判断字符串结尾逻辑相同,每次读取并处理了四个字节。

    那么就不难理解,效率肯定比之前单字节匹配的速度更快,但......为什么是 8 倍而不是 4 倍呢?

    仔细看代码之后,发现有这么一句:

    1 ; Include SSE2 code path for platforms that support it.
    2         include strchr_sse.inc

    由于没有找到对应源代码,所以这里我们通过反汇编的方式,获取到strchr函数真正执行的代码来看,反汇编结果如下:

      1 cmp         dword ptr ds:[7BEB92DCh],1        ; 7BEA42E0  
      2 jb          7BEA4348                          ; 7BEA42E7  
      3 movzx       eax,byte ptr [esp+8]              ; 7BEA42E9  
      4 mov         edx,eax                           ; 7BEA42EE  
      5 shl         eax,8                             ; 7BEA42F0  
      6 or          edx,eax                           ; 7BEA42F3  
      7 movd        xmm3,edx                          ; 7BEA42F5  
      8 pshuflw     xmm3,xmm3,0                       ; 7BEA42F9  
      9 movlhps     xmm3,xmm3                         ; 7BEA42FE  
     10 mov         edx,dword ptr [esp+4]             ; 7BEA4301  
     11 mov         ecx,0Fh                           ; 7BEA4305  
     12 or          eax,0FFFFFFFFh                    ; 7BEA430A  
     13 and         ecx,edx                           ; 7BEA430D  
     14 shl         eax,cl                            ; 7BEA430F  
     15 sub         edx,ecx                           ; 7BEA4311  
     16 movdqu      xmm1,xmmword ptr [edx]            ; 7BEA4313  
     17 pxor        xmm2,xmm2                         ; 7BEA4317  
     18 pcmpeqb     xmm2,xmm1                         ; 7BEA431B  
     19 pcmpeqb     xmm1,xmm3                         ; 7BEA431F  
     20 por         xmm2,xmm1                         ; 7BEA4323  
     21 pmovmskb    ecx,xmm2                          ; 7BEA4327  
     22 and         ecx,eax                           ; 7BEA432B  
     23 jne         7BEA4337                          ; 7BEA432D  
     24 or          eax,0FFFFFFFFh                    ; 7BEA432F  
     25 add         edx,10h                           ; 7BEA4332  
     26 jmp         7BEA4313                          ; 7BEA4335  
     27 bsf         eax,ecx                           ; 7BEA4337  
     28 add         eax,edx                           ; 7BEA433A  
     29 movd        edx,xmm3                          ; 7BEA433C  
     30 xor         ecx,ecx                           ; 7BEA4340  
     31 cmp         dl,byte ptr [eax]                 ; 7BEA4342  
     32 cmovne      eax,ecx                           ; 7BEA4344  
     33 ret                                           ; 7BEA4347  
     34 xor         eax,eax                           ; 7BEA4348  
     35 mov         al,byte ptr [esp+8]               ; 7BEA434A  
     36 push        ebx                               ; 7BEA434E  
     37 mov         ebx,eax                           ; 7BEA434F  
     38 shl         eax,8                             ; 7BEA4351  
     39 mov         edx,dword ptr [esp+8]             ; 7BEA4354  
     40 test        edx,3                             ; 7BEA4358  
     41 je          7BEA4375                          ; 7BEA435E  
     42 mov         cl,byte ptr [edx]                 ; 7BEA4360  
     43 add         edx,1                             ; 7BEA4362  
     44 cmp         cl,bl                             ; 7BEA4365  
     45 je          7BEA43C2                          ; 7BEA4367  
     46 test        cl,cl                             ; 7BEA4369  
     47 je          7BEA43BE                          ; 7BEA436B  
     48 test        edx,3                             ; 7BEA436D  
     49 jne         7BEA4360                          ; 7BEA4373  
     50 or          ebx,eax                           ; 7BEA4375  
     51 push        edi                               ; 7BEA4377  
     52 mov         eax,ebx                           ; 7BEA4378  
     53 shl         ebx,10h                           ; 7BEA437A  
     54 push        esi                               ; 7BEA437D  
     55 or          ebx,eax                           ; 7BEA437E  
     56 mov         ecx,dword ptr [edx]               ; 7BEA4380  
     57 mov         edi,7EFEFEFFh                     ; 7BEA4382  
     58 mov         eax,ecx                           ; 7BEA4387  
     59 mov         esi,edi                           ; 7BEA4389  
     60 xor         ecx,ebx                           ; 7BEA438B  
     61 add         esi,eax                           ; 7BEA438D  
     62 add         edi,ecx                           ; 7BEA438F  
     63 xor         ecx,0FFFFFFFFh                    ; 7BEA4391  
     64 xor         eax,0FFFFFFFFh                    ; 7BEA4394  
     65 xor         ecx,edi                           ; 7BEA4397  
     66 xor         eax,esi                           ; 7BEA4399  
     67 add         edx,4                             ; 7BEA439B  
     68 and         ecx,81010100h                     ; 7BEA439E  
     69 jne         7BEA43C7                          ; 7BEA43A4  
     70 and         eax,81010100h                     ; 7BEA43A6  
     71 je          7BEA4380                          ; 7BEA43AB  
     72 and         eax,1010100h                      ; 7BEA43AD  
     73 jne         7BEA43BC                          ; 7BEA43B2  
     74 and         esi,80000000h                     ; 7BEA43B4  
     75 jne         7BEA4380                          ; 7BEA43BA  
     76 pop         esi                               ; 7BEA43BC  
     77 pop         edi                               ; 7BEA43BD  
     78 pop         ebx                               ; 7BEA43BE  
     79 xor         eax,eax                           ; 7BEA43BF  
     80 ret                                           ; 7BEA43C1  
     81 lea         eax,[edx-1]                       ; 7BEA43C2  
     82 pop         ebx                               ; 7BEA43C5  
     83 ret                                           ; 7BEA43C6  
     84 mov         eax,dword ptr [edx-4]             ; 7BEA43C7  
     85 cmp         al,bl                             ; 7BEA43CA  
     86 je          7BEA4404                          ; 7BEA43CC  
     87 test        al,al                             ; 7BEA43CE  
     88 je          7BEA43BC                          ; 7BEA43D0  
     89 cmp         ah,bl                             ; 7BEA43D2  
     90 je          7BEA43FD                          ; 7BEA43D4  
     91 test        ah,ah                             ; 7BEA43D6  
     92 je          7BEA43BC                          ; 7BEA43D8  
     93 shr         eax,10h                           ; 7BEA43DA  
     94 cmp         al,bl                             ; 7BEA43DD  
     95 je          7BEA43F6                          ; 7BEA43DF  
     96 test        al,al                             ; 7BEA43E1  
     97 je          7BEA43BC                          ; 7BEA43E3  
     98 cmp         ah,bl                             ; 7BEA43E5  
     99 je          7BEA43EF                          ; 7BEA43E7  
    100 test        ah,ah                             ; 7BEA43E9  
    101 je          7BEA43BC                          ; 7BEA43EB  
    102 jmp         7BEA4380                          ; 7BEA43ED  
    103 pop         esi                               ; 7BEA43EF  
    104 pop         edi                               ; 7BEA43F0  
    105 lea         eax,[edx-1]                       ; 7BEA43F1  
    106 pop         ebx                               ; 7BEA43F4  
    107 ret                                           ; 7BEA43F5  
    108 lea         eax,[edx-2]                       ; 7BEA43F6  
    109 pop         esi                               ; 7BEA43F9  
    110 pop         edi                               ; 7BEA43FA  
    111 pop         ebx                               ; 7BEA43FB  
    112 ret                                           ; 7BEA43FC  
    113 lea         eax,[edx-3]                       ; 7BEA43FD  
    114 pop         esi                               ; 7BEA4400  
    115 pop         edi                               ; 7BEA4401  
    116 pop         ebx                               ; 7BEA4402  
    117 ret                                           ; 7BEA4403  
    118 lea         eax,[edx-4]                       ; 7BEA4404  
    119 pop         esi                               ; 7BEA4407  
    120 pop         edi                               ; 7BEA4408  
    121 pop         ebx                               ; 7BEA4409  
    122 ret                                           ; 7BEA440A 
    View Code

    由于这里是反汇编,是加载到内存中的,没有标号,跳转的时候指定的是跳转目标地址,这里将地址放到语句之后。

    这里可以看到,反汇编代码和我们之前看到的明显不同,应该就是之前包含进来的代码了。那么,它都做了些什么呢?

    在这里,我们从intel文档中查看几个命令:

    pshuflw:

     movlhps:

     movdqu:

    pxor:

     pcmpeqb:

     pmovmskb:

     cmovne:

     bsf:

     第一行和第二行,是一个判断,我们看到,如果 ds:[7BEB92DCh] 处的值大于或等于1,则跳转到第 34 行(7BEA4348),为什么会有这个跳转呢?我们看看34行代码,并和之前看到的汇编代码作比较:

    我们发现,后面的代码和之前我们看到的汇编源代码一模一样。所以,这里我们可以认为是在判断是否支持SSE,至于为什么如此判断,暂时还没有调查清楚,如果有清楚的,麻烦在评论区回复下,不胜感激。

    在了解到执行代码后面部分一致的情况下,我们此时就可以将重点放在前半部分了,为了方便,我们这里再次引用反汇编得到的代码前面部分,并忽略第一句,如下:

     1 movzx       eax,byte ptr [esp+8]              ; 7BEA42E9  
     2 mov         edx,eax                           ; 7BEA42EE  
     3 shl         eax,8                             ; 7BEA42F0  
     4 or          edx,eax                           ; 7BEA42F3  
     5 movd        xmm3,edx                          ; 7BEA42F5  
     6 pshuflw     xmm3,xmm3,0                       ; 7BEA42F9  
     7 movlhps     xmm3,xmm3                         ; 7BEA42FE  
     8 mov         edx,dword ptr [esp+4]             ; 7BEA4301  
     9 mov         ecx,0Fh                           ; 7BEA4305  
    10 or          eax,0FFFFFFFFh                    ; 7BEA430A  
    11 and         ecx,edx                           ; 7BEA430D  
    12 shl         eax,cl                            ; 7BEA430F  
    13 sub         edx,ecx                           ; 7BEA4311  
    14 movdqu      xmm1,xmmword ptr [edx]            ; 7BEA4313  
    15 pxor        xmm2,xmm2                         ; 7BEA4317  
    16 pcmpeqb     xmm2,xmm1                         ; 7BEA431B  
    17 pcmpeqb     xmm1,xmm3                         ; 7BEA431F  
    18 por         xmm2,xmm1                         ; 7BEA4323  
    19 pmovmskb    ecx,xmm2                          ; 7BEA4327  
    20 and         ecx,eax                           ; 7BEA432B  
    21 jne         7BEA4337                          ; 7BEA432D  
    22 or          eax,0FFFFFFFFh                    ; 7BEA432F  
    23 add         edx,10h                           ; 7BEA4332  
    24 jmp         7BEA4313                          ; 7BEA4335  
    25 bsf         eax,ecx                           ; 7BEA4337  
    26 add         eax,edx                           ; 7BEA433A  
    27 movd        edx,xmm3                          ; 7BEA433C  
    28 xor         ecx,ecx                           ; 7BEA4340  
    29 cmp         dl,byte ptr [eax]                 ; 7BEA4342  
    30 cmovne      eax,ecx                           ; 7BEA4344  
    31 ret                                           ; 7BEA4347

    1 - 4行:原理和之前类似,[esp+8] 处为要查找的目标字符值,到第四行,将edx寄存器的0-7位,和8-15位均设置为查找目标字符。

    5 - 7行:将 xmm3 寄存器的每字节均设置为目标字符值,如果我们查找 'x' 字符,则 xmm3 的值为 "xxxxxxxxxxxxxxxx"。

    8 - 13行:将查询的源字符串的地址进行16位对齐,并指向源字符串地址之前。并将 eax 值左移目标字符串地址的低四位值(意味着将eax作为之后取值的mask);

    14 - 31 行:是查询的主要逻辑,下面我们详细讨论。

    第14行,将edx指针指向内存开始的16字节复制到 xmm1寄存器中;

    第15行,将xmm2寄存器所有字节设置为0;

    第16行,将xmm1中所有的字节与xmm2字节做比较,比较结果放到xmm2中(如果xmm1中字节和xmm2中字节相等,则xmm2对应字节将被设置为0xff,否则将被设置为0x00);

    第17行,将xmm3(每个字节值均为目标字符值)和xmm1中的字节做比较,结果放置到xmm1中,如果是第一次做比较,则xmm1中可能存有查找字符串之前的内容,而且有可能包含查找的目标字符,这种情况将在第20行进行处理;

    第18行,将xmm1中(源字符串中16个字符或者字符串n个字节内容+字符串前n个字符和要查找的目标字符的比对结果,即前n个字符的擦护照结果)和xmm2中内容执行字节或运算。并将结果放到 xmm2 中。

    第19行,按照xmm2中字节内容,生成一个 mask值,并将其放到 ecx 寄存器;

    第20行,将ecx和eax(如果第一次,有效位被第12行设置为1,无效位被置为0)执行 and 运算;

    第21行,如果20行执行结果不为0(说明找到了目标值),跳转到第25行;

    第22行,eax 所有位均置为1;

    第23行,将源字符串指针前移16(10h)个字节;

    第24行,跳转到循环初始位置,开始新的一轮循环;

    第25行,查找ecx中为1的位的编号,并将编号放置到eax;

    第26行,将源字符串指针前移eax个字节,这就是目标字符所在位置了;

    第27行,从xmm3(每个字节均为查找目标字符)中读取4个字节,并将值放置到edx中;

    第28行,置ecx为0,以备返回(目标字符未找到);

    第29行,比较dl(edx最低字节)和eax指向的字符;

    第30行,如果29行比较结果不相等,说明没有找到目标字符,就置eax为0,否则eax不变;

    第31行,返回;

    这里可以看到,因为使用了 xmm 寄存器,我们每次都处理了16个字节,那为什么效率提升不是16倍呢?只能归结为xmm寄存器增加了电路复杂性,使得处理周期增加了一倍吧。

  • 相关阅读:
    10_14 drf接口框架。
    10_11 vue路由跳转
    10_10,vue项目环境搭建
    10_9vue循环指令与组件
    10_8 vue的导入
    9_25中间键与登录认证
    块级元素居中问题
    2019牛客多校第五场 F maximum clique 1 状压dp+最大独立集
    2019牛客多校第五场C generator 2 hash,bsgs模板
    2019牛客多校第五场B generator 十进制快速幂
  • 原文地址:https://www.cnblogs.com/lee2014/p/14616582.html
Copyright © 2011-2022 走看看