Advertisement
RickCHodgin

Custom assembly stricmp() algorithm, uses lookup table

Jun 24th, 2017
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // This is the third algorithm, a hand-coded assembly algorithm:
  2.  
  3.     __declspec(naked)
  4.     int rick_stricmp3(void)
  5.     {
  6.         _asm {
  7.             mov     edx,leftptr             // parameter 1, left data
  8.             mov     edi,rightptr            // parameter 2, right data
  9.             xor     ecx,ecx                 // iterator
  10.  
  11.         top_loop:
  12.             // Try a case-insensitive compare
  13.             movzx   eax,byte ptr [edx+ecx]  // Load left
  14.             movzx   ebx,byte ptr [edi+ecx]  // Load right
  15.  
  16.             cmp     eax,0                   // Is left char null?
  17.             jz      done1                   // Yes if branch
  18.             mov     al,byte ptr lower[eax]  // Make lower-case
  19.  
  20.             cmp     ebx,0                   // Is right char null?
  21.             jz      done2                   // Yes if branch
  22.             mov     bl,byte ptr lower[ebx]  // Make lower-case
  23.  
  24.             cmp     al,bl                   // Relationship?
  25.             jb      left_less_than_right    // If branch, left <
  26.             ja      left_greater_than_right // If branch, left >
  27.             // If we get here, we know they are both still equal
  28.  
  29.             inc     ecx                     // ++iterator
  30.             jmp     top_loop                // Loop again
  31.  
  32.         left_greater_than_right:
  33.             mov     eax,1                   // Return left >
  34.             ret
  35.  
  36.         left_less_than_right:
  37.             mov     eax,-1                  // Return left <
  38.             ret
  39.  
  40.         done1:
  41.             // When we get here, we know left is null
  42.             xor     ebx,ebx
  43.             add     bl,byte ptr [edi+ecx]
  44.  
  45.             // If we branch, they are both null, which means they are equal
  46.             jz      equal
  47.             // If we get here, we know left is null, and right is not null
  48.             mov     eax,-1                  // Return left <
  49.             ret
  50.  
  51.         done2:
  52.             // Still data in _left, but _right is exhausted
  53.             mov     eax,1                   // Return left >
  54.             ret
  55.  
  56.         equal:
  57.             xor     eax,eax                 // Return equal
  58.             ret
  59.         }
  60.     }
  61.  
  62.     // Required global variables (to remove stack-based parameters):
  63.     char *leftptr;
  64.     char *rightptr;
  65.     char lower[256];
  66.  
  67.     // Populate lower-case translation lookup table
  68.     for (int i = 0; i <= 255; i++)
  69.         lower[i] = tolower(i);
  70.  
  71.     // Call for each comparison
  72.     for (int count = 0; count < 50000000; count++)
  73.     {
  74.         for (int i = 0; i < 5; i++)
  75.         {
  76.             leftptr  = left[i];
  77.             rightptr = right[i];
  78.             rick_stricmp3();
  79.         }
  80.     }
  81.  
  82. And if your compiler uses variables for those loops, then you will
  83. need to write the loop in assembly so you are not required to
  84. push and pop the registers:
  85.  
  86.     #define rick_stricmp3_asm(a, b) \
  87.         { \
  88.             leftptr  = a; \
  89.             rightptr = b; \
  90.             rick_stricmp3()); \
  91.         }
  92.  
  93.     _asm
  94.     {
  95.         mov     ecx,50000000
  96.  
  97.     top_loop:
  98.         push    ecx
  99.     }
  100.  
  101.         rick_stricmp4_asm(left[0], right[0]);
  102.         rick_stricmp4_asm(left[1], right[1]);
  103.         rick_stricmp4_asm(left[2], right[2]);
  104.         rick_stricmp4_asm(left[3], right[3]);
  105.         rick_stricmp4_asm(left[4], right[4]);
  106.  
  107.     _asm
  108.     {
  109.         pop     ecx
  110.         loop    alternate_loop  // Loop is out of range for near jmp
  111.         jmp     done
  112.  
  113.     alternate_loop:
  114.         jmp     top_loop        // Hard jump on opposite condition
  115.  
  116.     done:
  117.     }
  118.  
  119. UPDATE:  6:36PM Jun.24.2017 -- Some additional minor optimizations which
  120.                                improved the score (from 105 to 102).
  121.  
  122.     __declspec(naked)
  123.     int rick_stricmp3(void)
  124.     {
  125.         _asm {
  126.             mov     edx,leftptr             // parameter 1, left data
  127.             mov     edi,rightptr            // parameter 2, right data
  128.             xor     ecx,ecx                 // iterator
  129.  
  130.         top_loop:
  131.             // Try a case-insensitive compare
  132.             movzx   eax,byte ptr [edx+ecx]  // Load left
  133.             movzx   ebx,byte ptr [edi+ecx]  // Load right
  134.  
  135.             cmp     eax,0                   // Is left char null?
  136.             jz      done1                   // Yes if branch
  137.             mov     al,byte ptr lower[eax]  // Make lower-case
  138.  
  139.             cmp     ebx,0                   // Is right char null?
  140.             jz      left_greater_than_right // Yes if branch
  141.             mov     bl,byte ptr lower[ebx]  // Make lower-case
  142.  
  143.             cmp     al,bl                   // Relationship?
  144.             jb      left_less_than_right    // If branch, left <
  145.             ja      left_greater_than_right // If branch, left >
  146.             // If we get here, we know they are both still equal
  147.  
  148.             inc     ecx                     // ++iterator
  149.             jmp     top_loop                // Loop again
  150.  
  151.         left_greater_than_right:
  152.             mov     eax,1                   // Return left >
  153.             ret
  154.  
  155.         left_less_than_right:
  156.             mov     eax,-1                  // Return left <
  157.             ret
  158.  
  159.         done1:
  160.             // When we get here, we know left is null
  161.             add     al,byte ptr [edi+ecx]
  162.  
  163.             // If we branch, they are both null, which means they are equal
  164.             jz      equal
  165.             // If we get here, we know left is null, and right is not null
  166.             mov     eax,-1                  // Return left <
  167.             ret
  168.  
  169.         equal:
  170.             xor     eax,eax                 // Return equal
  171.             ret
  172.         }
  173.     }
  174.  
  175.  
  176. UPDATE:  8:54AM Jun.28.2017 -- Some additional minor optimizations which
  177.                                improved the score (from 102 to 85).
  178. NOTE:  These adjustments were taken from an example by Rod Pemberton, which
  179.        introduced the added test to test if they match before conversion to
  180.        lower-case, plus the 32-bit code generated by DJGPP for DOS, which was
  181.        actually a very efficient implementation.  His raw code was able to
  182.        get an 86 without any changes.  The only reason mine is faster is
  183.        because I do not use the stack for parameters, and I use ecx for the
  184.        incrementer, rather than updating both esi and edi in his example,
  185.        which would be edx and edi in this example.
  186.  
  187.     __declspec(naked)
  188.     int rick_stricmp3(void)
  189.     {
  190.         _asm {
  191.             mov     edx,leftptr             // parameter 1, left data
  192.             mov     edi,rightptr            // parameter 2, right data
  193.             xor     ecx,ecx                 // iterator
  194.             xor     esi,esi                 // placeholder for 0
  195.  
  196.         top_loop:
  197.             // Try a case-insensitive compare
  198.             movzx   eax,byte ptr [edx+ecx]  // Load left
  199.             movzx   ebx,byte ptr [edi+ecx]  // Load right
  200.             inc     ecx                     // ++iterator
  201.  
  202.             cmp     eax,esi                 // Is left char null?
  203.             jz      done                    // Yes if branch
  204.             cmp     ebx,esi                 // Is right char null?
  205.             jz      done                    // Yes if branch
  206.  
  207.             // Do they match exactly?
  208.             cmp     al,bl
  209.             jz      top_loop
  210.  
  211.             // Try lower-case
  212.             mov     al,byte ptr lower[eax]  // Make lower-case
  213.             mov     bl,byte ptr lower[ebx]  // Make lower-case
  214.  
  215.             cmp     al,bl                   // Relationship?
  216.             jz      top_loop
  217.  
  218.         done:
  219.             sub     eax,ebx
  220.             ret
  221.         }
  222.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement