Функция выводит собачий бред

Тема в разделе "WASM.BEGINNERS", создана пользователем Win32Api, 26 ноя 2023.

  1. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Доброго времени суток!

    Пытаюсь перевести простенькую функцию сравнивающую 2 строки с паскаля на ассемблер.

    Функция проверяет чтоб обе строки не были пустыми, сравнивает первые символы строк, проверяет чтобы строки были одинаковой длины, если все условия выполняются, сравнивает строки целиком.

    Код (Text):
    1.  
    2. function StrCompare(s1, s2: string): bool;
    3. begin
    4.   Result := false;
    5.   if (s1 <> '') and (s2 <> '') then
    6.   begin
    7.     if s1[1] = s2[1] then
    8.     begin
    9.       if Length(s1) = Length(s2) then
    10.       begin
    11.         if s1 = s2 then
    12.         begin
    13.           Result := true;
    14.         end;
    15.       end;
    16.     end;
    17.   end;
    18. end; //StrCompare
    19.  
    Чат гпт подсказал такое решение:

    Код (Text):
    1.  
    2. function StrCompare(S1, S2: string): bool; assembler;
    3. asm
    4.   // Сохраняем регистры
    5.   push ebx
    6.   push edi
    7.   push esi
    8.   // Сравниваем первые символы
    9.   movzx ebx, byte ptr [eax]
    10.   movzx ecx, byte ptr [eax+1]
    11.   cmp bl, byte ptr [edx]
    12.   jne @NotEqual
    13.   // Сравниваем длины строк
    14.   mov edx, ecx
    15.   add edx, eax
    16.   sub edx, 1
    17.   cmp edx, Length(S2)
    18.   jne @NotEqual
    19.   // Сравниваем сами строки
    20.   mov edi, eax
    21.   mov esi, edx
    22.   mov edx, S2
    23.   add esi, edx
    24.   add edi, edx
    25.   sub esi, 1
    26.   sub edi, 1
    27.   mov ecx, esi
    28.   sub ecx, edx
    29.   jz @Equal
    30.   sub ecx, edi
    31.   jz @Equal
    32. @NotEqual:
    33.   // Возвращаем false
    34.   xor eax, eax
    35.   jmp @Exit
    36. @Equal:
    37.   // Возвращаем true
    38.   mov eax, 1
    39. @Exit:
    40.   // Восстанавливаем регистры
    41.   pop esi
    42.   pop edi
    43.   pop ebx
    44. end;
    45.  
    Как сделать чтобы функция на ассемблере работала аналогично моей?

    Есть примеры корректно работающих инлайн функций на ассемблере:

    Код (Text):
    1. function CompareStr(const S1, S2: string): Integer; assembler;
    2. asm
    3.         PUSH    ESI
    4.         PUSH    EDI
    5.         MOV     ESI,EAX
    6.         MOV     EDI,EDX
    7.         OR      EAX,EAX
    8.         JE      @@1
    9.         MOV     EAX,[EAX-4]
    10. @@1:    OR      EDX,EDX
    11.         JE      @@2
    12.         MOV     EDX,[EDX-4]
    13. @@2:    MOV     ECX,EAX
    14.         CMP     ECX,EDX
    15.         JBE     @@3
    16.         MOV     ECX,EDX
    17. @@3:    CMP     ECX,ECX
    18.         REPE    CMPSB
    19.         JE      @@4
    20.         MOVZX   EAX,BYTE PTR [ESI-1]
    21.         MOVZX   EDX,BYTE PTR [EDI-1]
    22. @@4:    SUB     EAX,EDX
    23.         POP     EDI
    24.         POP     ESI
    25. end;
    26.  
    27. function CompareText(const S1, S2: string): Integer; assembler;
    28. asm
    29.         PUSH    ESI
    30.         PUSH    EDI
    31.         PUSH    EBX
    32.         MOV     ESI,EAX
    33.         MOV     EDI,EDX
    34.         OR      EAX,EAX
    35.         JE      @@0
    36.         MOV     EAX,[EAX-4]
    37. @@0:    OR      EDX,EDX
    38.         JE      @@1
    39.         MOV     EDX,[EDX-4]
    40. @@1:    MOV     ECX,EAX
    41.         CMP     ECX,EDX
    42.         JBE     @@2
    43.         MOV     ECX,EDX
    44. @@2:    CMP     ECX,ECX
    45. @@3:    REPE    CMPSB
    46.         JE      @@6
    47.         MOV     BL,BYTE PTR [ESI-1]
    48.         CMP     BL,'a'
    49.         JB      @@4
    50.         CMP     BL,'z'
    51.         JA      @@4
    52.         SUB     BL,20H
    53. @@4:    MOV     BH,BYTE PTR [EDI-1]
    54.         CMP     BH,'a'
    55.         JB      @@5
    56.         CMP     BH,'z'
    57.         JA      @@5
    58.         SUB     BH,20H
    59. @@5:    CMP     BL,BH
    60.         JE      @@3
    61.         MOVZX   EAX,BL
    62.         MOVZX   EDX,BH
    63. @@6:    SUB     EAX,EDX
    64.         POP     EBX
    65.         POP     EDI
    66.         POP     ESI
    67. end;
    68.  
    69. function SameText(const S1, S2: string): Boolean; assembler;
    70. asm
    71.         CMP     EAX,EDX
    72.         JZ      @1
    73.         OR      EAX,EAX
    74.         JZ      @2
    75.         OR      EDX,EDX
    76.         JZ      @3
    77.         MOV     ECX,[EAX-4]
    78.         CMP     ECX,[EDX-4]
    79.         JNE     @3
    80.         CALL    CompareText
    81.         TEST    EAX,EAX
    82.         JNZ     @3
    83. @1:     MOV     AL,1
    84. @2:     RET
    85. @3:     XOR     EAX,EAX
    86. end;
    87.  
     
    Последнее редактирование: 26 ноя 2023
  2. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    rep cmpsb
     
    Win32Api нравится это.
  3. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Можно подробнее?

    Сделал штук 20 запросов к чату гпт, самое похоже на адекватное, решение, который выдал электрический друг:

    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push ebx
    4.   push edi
    5.   push esi
    6.  
    7.   movzx ebx, byte ptr [eax]
    8.   movzx ecx, byte ptr [eax+1]
    9.   cmp bl, byte ptr [edx]
    10.   jne @NotEqual
    11.  
    12.   mov edx, ecx
    13.   add edx, eax
    14.   sub edx, 1
    15.   cmp edx, Length(S2)
    16.   jne @NotEqual
    17.  
    18.   mov edi, eax
    19.   mov esi, edx
    20.   mov edx, S2
    21.   add esi, edx
    22.   add edi, edx
    23.   sub esi, 1
    24.   sub edi, 1
    25.   mov ecx, esi
    26.   sub ecx, edx
    27.   jz @Equal
    28.   sub ecx, edi
    29.   jz @Equal
    30.  
    31. @NotEqual:
    32.   xor eax, eax
    33.   jmp @Exit
    34.  
    35. @Equal:
    36.   mov eax, 1
    37.  
    38. @Exit:
    39.   pop esi
    40.   pop edi
    41.   pop ebx
    42. end;
    Происходит какое-то сравнение, но результат получается забористый
     
  4. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    esi edi rep cmpsb
    --- Сообщение объединено, 26 ноя 2023 ---
    Подробнее:
    Я есть я. Здесь не может быть никакого сравнения.
    Это начинается уже с занятий в школе: сдавать экзамены, раздавать оценки, которые делят людей на группы по их достижениям — какой бред! Что вообще значат такие слова как «важно» или «не важно»? «Важно» иметь хорошую память? Тот, кто имеет плохую — плохой человек? Разве не существует много дебилов с хорошей памятью?
     
    Win32Api нравится это.
  5. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    )
    --- Сообщение объединено, 26 ноя 2023 ---
    Получилось вот так:
    Код (Text):
    1.  
    2. function StrCompare(S1, S2: string): bool; assembler;
    3. asm
    4.   // Сохраняем регистры
    5.   push esi
    6.   push edi
    7.   // Проверяем, что строки не пустые
    8.   mov esi, S1
    9.   mov edi, S2
    10.   cmp byte ptr [esi], 0
    11.   je @Exit
    12.   cmp byte ptr [edi], 0
    13.   je @Exit
    14.   // Сравниваем первые символы строк
    15.   mov al, [esi]
    16.   cmp al, [edi]
    17.   jne @Exit
    18.   // Сравниваем длины строк
    19.   mov ecx, [esi-4]
    20.   cmp ecx, [edi-4]
    21.   jne @Exit
    22.   // Сравниваем строки
    23.   repe cmpsb
    24.   je @Equal
    25. @Exit:
    26.   // Строки не равны
    27.   mov eax, 0
    28.   jmp @Done
    29. @Equal:
    30.   // Строки равны
    31.   mov eax, 1
    32. @Done:
    33.   // Восстанавливаем регистры
    34.   pop edi
    35.   pop esi
    36. end;
    37.  
     
  6. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
  7. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    В паскале длина строк хранится перед первым символом строки. И тут важно понимать какие именно строки в текущем режиме компиляции подразумеваются под string - это может быть ShortString, AnsiString, WideString. Почему важно - потому что в ShortString на длину выделен байт, а у остальный - dword. Поэтому смотрим "корректно работающий пример" и видим там MOV EAX,[EAX-4] - это вот так надо получать длину строки. ЧатГПТ тут херню какую то начал морозить (сужу по первопосту).
    В остальном - ну похоже на правду.
    Правда смысла так делать нет, т.к. уверяю, что штатное s1 <> s2 реализовано ровно так же - сперва сравнит длины, потом тела прерываясь на первом не совпавшем символе.
     
  8. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Сравнил время выполнения s1 <> s2 и function StrCompare(S1, S2: string): bool; assembler;, последнее на 50% быстрее работает

    Как можно эффективнее переделать:
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   // Сохраняем регистры
    4.   push esi
    5.   push edi
    6.   // Проверяем, что строки не пустые
    7.   mov esi, S1
    8.   mov edi, S2
    9.   cmp byte ptr [esi], 0
    10.   je @Exit
    11.   cmp byte ptr [edi], 0
    12.   je @Exit
    13.   // Сравниваем первые символы строк
    14.   mov al, [esi]
    15.   cmp al, [edi]
    16.   jne @Exit
    17.   // Сравниваем длины строк
    18.   mov ecx, [esi-4]
    19.   cmp ecx, [edi-4]
    20.   jne @Exit
    21.   // Сравниваем строки
    22.   repe cmpsb
    23.   je @Equal
    24. @Exit:
    25.   // Строки не равны
    26.   mov eax, 0
    27.   jmp @Done
    28. @Equal:
    29.   // Строки равны
    30.   mov eax, 1
    31. @Done:
    32.   // Восстанавливаем регистры
    33.   pop edi
    34.   pop esi
    35. end;
    С получением длины строки через MOV EAX,[EAX-4]?

    Кажется есть лишние джампы и можно сделать проще
    --- Сообщение объединено, 26 ноя 2023 ---
    По поводу восстановления регистров говорит что все правильно:
     
    Последнее редактирование: 26 ноя 2023
  9. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    Я тут еще не заметил правильно работающую StrCompare чтобы их можно было корректно сравнивать. :)
    Например вот это что приведена тобой под комментарием "проверяем что строки не пустые" сравнивает на ноль первые символы строк в предположении что это ShortString или AnsiString.
    Поэтому какие то странные результаты непонятные - они просто некорректные.
    Юзай просто <> из паскаля, а если нужно сравнивать строки из ассемблера, то просто юзай "проверенные варианты". Остальное лишнее.
     
  10. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Что не правильно в этом решении? Каким образом можно переделать?
    Этот код использует более современные регистры и инструкции, как говорит чат гпт :)
    Код (Text):
    1.  
    2. function StrCompare1(S1, S2: string): Boolean; assembler;
    3. asm
    4.   // Сохраняем регистры
    5.   push ecx
    6.   push edx
    7.   // Проверяем, что строки не пустые
    8.   mov ecx, S1
    9.   cmp byte ptr [ecx], 0
    10.   je @Exit
    11.   mov edx, S2
    12.   cmp byte ptr [edx], 0
    13.   je @Exit
    14.   // Сравниваем символы строк
    15.   mov al, [ecx]
    16.   cmp al, [edx]
    17.   jne @Exit
    18.   // Сравниваем остальные символы
    19.   @@Loop:
    20.     inc ecx
    21.     inc edx
    22.     mov al, [ecx]
    23.     cmp al, [edx]
    24.     jne @Exit
    25.     cmp al, 0
    26.     jne @@Loop
    27.   // Строки равны
    28.   mov eax, 1
    29.   jmp @Done
    30.   // Строки не равны
    31.   @Exit:
    32.     mov eax, 0
    33.   // Восстанавливаем регистры
    34.   @Done:
    35.     pop edx
    36.     pop ecx
    37. end;
    38.  
    --- Сообщение объединено, 26 ноя 2023 ---
    Скажу по секрету, тема была создана чтобы "не юзать <> из паскаля".

    Есть тысяча способов умереть на Диком Западе, и скорее всего есть тысача корректных вариантов, сделать это сравнение на ассемблере.
    --- Сообщение объединено, 26 ноя 2023 ---
    Самый долгий вариант:
    Код (Text):
    1. function StrCompare(S1, S2: string): Boolean; assembler;
    2. asm
    3.   // Проверяем, что строки не пустые
    4.   mov eax, S1
    5.   test eax, eax
    6.   jz @NotEqual
    7.  
    8.   mov edx, S2
    9.   test edx, edx
    10.   jz @NotEqual
    11.  
    12.   // Проверяем длины строк
    13.   mov ecx, [eax-4]
    14.   cmp ecx, [edx-4]
    15.   jne @NotEqual
    16.  
    17.   // Сравниваем строки
    18.   call CompareStr
    19.   test eax, eax
    20.   jnz @NotEqual
    21.  
    22.   // Строки равны
    23.   mov eax, 1
    24.   jmp @Done
    25.  
    26. @NotEqual:
    27.   // Строки не равны
    28.   xor eax, eax
    29.  
    30. @Done:
    31. end;
    32.  
    33. function CompareStr(const S1, S2: string): Integer; assembler;
    34. asm
    35.         PUSH    ESI
    36.         PUSH    EDI
    37.         MOV     ESI,EAX
    38.         MOV     EDI,EDX
    39.         OR      EAX,EAX
    40.         JE      @@1
    41.         MOV     EAX,[EAX-4]
    42. @@1:    OR      EDX,EDX
    43.         JE      @@2
    44.         MOV     EDX,[EDX-4]
    45. @@2:    MOV     ECX,EAX
    46.         CMP     ECX,EDX
    47.         JBE     @@3
    48.         MOV     ECX,EDX
    49. @@3:    CMP     ECX,ECX
    50.         REPE    CMPSB
    51.         JE      @@4
    52.         MOVZX   EAX,BYTE PTR [ESI-1]
    53.         MOVZX   EDX,BYTE PTR [EDI-1]
    54. @@4:    SUB     EAX,EDX
    55.         POP     EDI
    56.         POP     ESI
    57. end;
    58.  
    --- Сообщение объединено, 26 ноя 2023 ---
    Этот быстрее
    Код (Text):
    1. function StrCompare(S1, S2: string): Boolean; assembler;
    2. asm
    3.   // Сохраняем регистры
    4.   push ecx
    5.   push edx
    6.  
    7.   // Проверяем, что строки не пустые
    8.   mov ecx, S1
    9.   cmp byte ptr [ecx], 0
    10.   je @Exit
    11.  
    12.   mov edx, S2
    13.   cmp byte ptr [edx], 0
    14.   je @Exit
    15.  
    16.   // Сравниваем символы строк
    17.   mov al, [ecx]
    18.   cmp al, [edx]
    19.   jne @Exit
    20.  
    21.   // Сравниваем остальные символы
    22.   @@Loop:
    23.     inc ecx
    24.     inc edx
    25.     mov al, [ecx]
    26.     cmp al, [edx]
    27.     jne @Exit
    28.     cmp al, 0
    29.     jne @@Loop
    30.  
    31.   // Строки равны
    32.   mov eax, 1
    33.   jmp @Done
    34.  
    35.   // Строки не равны
    36.   @Exit:
    37.     mov eax, 0
    38.  
    39.   // Восстанавливаем регистры
    40.   @Done:
    41.     pop edx
    42.     pop ecx
    43. end; //StrCompare
    --- Сообщение объединено, 26 ноя 2023 ---
    В первом случае из функции какой-то странный выход:
    Код (Text):
    1. @Done:
    2. end;
    В общем вопрос к спецам, как сделать самое быстрое и сэйфовое сравнение
    --- Сообщение объединено, 26 ноя 2023 ---
    В этом случае -4:
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   // Сохраняем регистры
    4.   push esi
    5.   push edi
    6.   // Проверяем, что строки не пустые
    7.   mov esi, S1
    8.   mov edi, S2
    9.   cmp byte ptr [esi], 0
    10.   je @Exit
    11.   cmp byte ptr [edi], 0
    12.   je @Exit
    13.   // Сравниваем первые символы строк
    14.   mov al, [esi]
    15.   cmp al, [edi]
    16.   jne @Exit
    17.   // Сравниваем длины строк
    18.   mov ecx, [esi-4]
    19.   cmp ecx, [edi-4]
    20.   jne @Exit
    21.   // Сравниваем строки
    22.   repe cmpsb
    23.   je @Equal
    24. @Exit:
    25.   // Строки не равны
    26.   mov eax, 0
    27.   jmp @Done
    28. @Equal:
    29.   // Строки равны
    30.   mov eax, 1
    31. @Done:
    32.   // Восстанавливаем регистры
    33.   pop edi
    34.   pop esi
    35. end;
    36.  
    Есть ли смысл использовать какие-то другие регистры?

    Есть ли смысл заменить это:

    Код (Text):
    1. repe cmpsb
    Вот этим:
    Код (Text):
    1.   @@Loop:
    2.     inc ecx
    3.     inc edx
    4.     mov al, [ecx]
    5.     cmp al, [edx]
    6.     jne @Exit
    7.     cmp al, 0
    8.     jne @@Loop
    Если порядок сравнения:

    1. проверяем что обе строки не пустые,
    2. сравниваем первые символы обеих строк,
    3. проверяем чтобы строки были одинаковой длины,
    4. если все условия выполняются, тогда сравниваем строки целиком.
    --- Сообщение объединено, 26 ноя 2023 ---
    lstrcmp - 34 секунды.
    Код (Text):
    1. function StrCompare(S1, S2: string): bool;
    2. begin
    3.   Result := lstrcmp(PChar(s1), PChar(s2)) = 0;
    4. end;
    Паскалевское сравнение 's1 = s2' - 9 секунд.

    4 секунды:
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   // Сохраняем регистры
    4.   push esi
    5.   push edi
    6.   // Проверяем, что строки не пустые
    7.   mov esi, S1
    8.   mov edi, S2
    9.   cmp byte ptr [esi], 0
    10.   je @Exit
    11.   cmp byte ptr [edi], 0
    12.   je @Exit
    13.   // Сравниваем первые символы строк
    14.   mov al, [esi]
    15.   cmp al, [edi]
    16.   jne @Exit
    17.   // Сравниваем длины строк
    18.   mov ecx, [esi-4]
    19.   cmp ecx, [edi-4]
    20.   jne @Exit
    21.   // Сравниваем строки
    22.   repe cmpsb
    23.   je @Equal
    24. @Exit:
    25.   // Строки не равны
    26.   mov eax, 0
    27.   jmp @Done
    28. @Equal:
    29.   // Строки равны
    30.   mov eax, 1
    31. @Done:
    32.   // Восстанавливаем регистры
    33.   pop edi
    34.   pop esi
    35. end;
    Целый день вместе практиковать дзадзэн — чрезвычайная удача.
    Целый день вместе проводить в публичном доме — чрезвычайная глупость ;)
     
    Последнее редактирование: 26 ноя 2023
  11. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    После
    Код (Text):
    1. @Equal:
    2.   // Строки равны
    3.   mov eax, 1
    Добавил jmp @Done
    Код (Text):
    1. @Equal:
    2.   // Строки равны
    3.   mov eax, 1
    4.   jmp @Done
     
  12. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    Присмотрелся немного к "первообразной функции" и мне не понравилось:
    Код (Text):
    1.  
    2. function StrCompare(s1, s2: string): bool;
    3. begin
    4.   Result := false;
    5.   if (s1 <> '') and (s2 <> '') then
    6.   begin
    7.     if s1[1] = s2[1] then
    8.     begin
    9.       if Length(s1) = Length(s2) then
    10.       begin
    11.         if s1 = s2 then
    12.         begin
    13.           Result := true;
    14.         end;
    15.       end;
    16.     end;
    17.   end;
    18. end; //StrCompare
    19.  
    Если обе строки пустые возвращает false, а должна true.
    Непорядочек.
    Кроме того, если присмотреться к функциям "которые правильные" - они проверяют на 0 сам указатель строки - то есть пустая строка может прийти как nil. Это очень важно проверять, ChatGPT про это походу вообще ничего не знает (как и я, кстати, на начало этой темы, не задумывался, что строки и массивы настолько одинаково работают).
     
    Win32Api нравится это.
  13. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Кстати да. Добавил проверку, если обе строки равны нулю
    Код (Text):
    1.  
    2. function StrCompare(S1, S2: string): bool; assembler;
    3. asm
    4.   // Сохраняем регистры
    5.   push esi
    6.   push edi
    7.  
    8.   mov esi, S1
    9.   mov edi, S2
    10.  
    11.   cmp byte ptr [esi], 0
    12.   je @EmptyStringsCheck1
    13.  
    14.   cmp byte ptr [edi], 0
    15.   je @EmptyStringsCheck2
    16.  
    17.   //Если дошли до сюда значит нет пустых строк.
    18.  
    19.   // Сравниваем первые символы строк
    20.   mov al, [esi]
    21.   cmp al, [edi]
    22.   jne @Exit
    23.  
    24.   // Сравниваем длины строк
    25.   mov ecx, [esi-4]
    26.   cmp ecx, [edi-4]
    27.   jne @Exit
    28.  
    29.   // Сравниваем строки
    30.   repe cmpsb
    31.   je @Equal
    32.  
    33.   jmp @Exit
    34.  
    35.   @Exit:
    36.     // Строки не равны
    37.     mov eax, 0
    38.     jmp @Done
    39.  
    40.   @Equal:
    41.     // Строки равны
    42.     mov eax, 1
    43.     jmp @Done
    44.  
    45.   @EmptyStringsCheck1:
    46.     cmp byte ptr [edi], 0
    47.     je @Equal //Если обе строки пустые.
    48.  
    49.     jmp @Exit
    50.  
    51.   @EmptyStringsCheck2:
    52.     cmp byte ptr [esi], 0
    53.     je @Equal //Если обе строки пустые.
    54.  
    55.     jmp @Exit
    56.  
    57.   @Done:
    58.     // Восстанавливаем регистры
    59.     pop edi
    60.     pop esi
    61. end; //StrCompare
    --- Сообщение объединено, 26 ноя 2023 ---
    Получилось две метки @EmptyStringsCheck1 и @EmptyStringsCheck2, не знаю как можно объединить их в одну

    После
    Код (Text):
    1.  
    2.    cmp byte ptr [esi], 0
    3.     je @Equal //Если обе строки пустые.
    4.  
    5.    jmp @Exit
    6.  
    добавил jmp @Exit, это правильно или нет?
     
    Последнее редактирование: 26 ноя 2023
  14. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    Код (Text):
    1.  
    2.   cmp byte ptr [esi], 0
    3.   je @EmptyStringsCheck1
    4.   cmp byte ptr [edi], 0
    5.   je @EmptyStringsCheck2
    6.  
    Это сравнивает первый символ (байт) в строках (esi и edi это указатели на строки), что вообще то с ходу в карьер делать нельзя.
    Сперва надо проверить не равны ли указатели нулю - если так, то это то же самое, что пустая строка. По нулевому указателю в память обращаться нельзя.

    Я бы сделал алгоритм следующим образом:
    1. определение длины строки 1 и помещение в промежуточный регистр (если указатель строки нулевой - вменить ноль длине)
    2. выделение длины строки 2 и помещение в промежуточный регистр
    3. проверка если обе длины нулевые (это можно сделать наложив их по OR в третий регистр) - вернуть True
    4. проверка если длины различны - вернуть False
    5. и вот тут уже мы знаем, что у нас обе строки есть валидные указатели - ведь мы знаем что на этом месте длины равны, но при этом не равны нулю - значит есть тела с которыми можно работать.
    6. и вот тут уже ты можешь заняться тем что считаешь оптимизацией - предварительное сравнение первым символов на неравенство перед основным циклом rep cmpsb. Правда оно смысла не имеет, но если хочется - никто не запрещает.
     
    Win32Api нравится это.
  15. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Добавил это, не знаю насколько правильно
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push esi
    4.   push edi
    5.  
    6.   mov esi, S1
    7.   mov edi, S2
    8.  
    9.   test esi, esi
    10.   jz @EmptyStringsCheck1
    11.  
    12.   test edi, edi
    13.   jz @EmptyStringsCheck2
    14.  
    15.   cmp byte ptr [esi], 0
    16.   je @EmptyStringsCheck1
    17.   cmp byte ptr [edi], 0
    18.   je @EmptyStringsCheck2
    19.  
    20.   mov al, [esi]
    21.   cmp al, [edi]
    22.   jne @Exit
    23.  
    24.   mov ecx, [esi-4]
    25.   cmp ecx, [edi-4]
    26.   jne @Exit
    27.  
    28.  
    29.   repe cmpsb
    30.   je @Equal
    31.  
    32.   jmp @Exit
    33.  
    34.   @Exit:
    35.     mov eax, 0
    36.     jmp @Done
    37.  
    38.   @Equal:
    39.     mov eax, 1
    40.     jmp @Done
    41.  
    42.   @EmptyStringsCheck1:
    43.     cmp byte ptr [edi], 0
    44.     je @Equal
    45.  
    46.     jmp @Exit
    47.  
    48.   @EmptyStringsCheck2:
    49.     cmp byte ptr [esi], 0
    50.     je @Equal
    51.  
    52.     jmp @Exit
    53.  
    54.   @Done:
    55.  
    56.     pop edi
    57.     pop esi
    58. end;
    --- Сообщение объединено, 26 ноя 2023 ---
    Внутри @EmptyStringsCheck1 и @EmptyStringsCheck2 скорее всего чего-то не хватает после добавления:
    Код (Text):
    1.   test esi, esi
    2.   jz @EmptyStringsCheck1
    3.   test edi, edi
    4.   jz @EmptyStringsCheck2
     
  16. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    Эммм.... Ты продолжаешь что ли в ChatGPT этот код вкидывать? :)
    Ну должно же было быть понимание, что когда исправляешь код, то неверный вариант _исправляется_ а не оставляется на месте. :)
    И в метках @EmptyStringsCheck1 совершается точно такая же ошибка - вместо указателя проверяется на ноль первый байт строки.
    Я бы общую логику переделал на то как описал выше, т.к. не знаю есть ли гарантии, что пустые строки это всегда нулевые указатели. Может ли быть так что указатель ненулевой, но указывает на буфер где указан нулевой размер? Если да, то надо делать как я написал обязательно иначе в твоём коде точно будет баг. Но возможно такие гарантии есть?
     
    Win32Api нравится это.
  17. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    А если перед этим, добавить mov eax, 0
    Код (Text):
    1.   cmp byte ptr [esi], 0
    2.   je @EmptyStringsCheck1
    3.   cmp byte ptr [edi], 0
    4.   je @EmptyStringsCheck2
    Код (Text):
    1.   mov eax, 0
    2.  
    3.   cmp byte ptr [esi], 0
    4.   je @EmptyStringsCheck1
    5.  
    6.   cmp byte ptr [edi], 0
    7.   je @EmptyStringsCheck2
    --- Сообщение объединено, 26 ноя 2023 ---
    По поводу указателей не совсем понятно. Там что-то типа такого?
    Код (Text):
    1.   @EmptyStringsCheck2:
    2.   or eax, ecx
    3.   jz @Equal
    4.  
    5.   cmp eax, ecx
    6.   jne @Exit
    --- Сообщение объединено, 26 ноя 2023 ---
    В функцию всегда передаются строки.
    На данный момент, результат возвращается как от сравнения s1 = s2:
    Код (Text):
    1.   @EmptyStringsCheck1:
    2.     cmp byte ptr [edi], 0
    3.     je @Equal
    Может перестать работать, если будут передаваться данные такого же типа?
    --- Сообщение объединено, 26 ноя 2023 ---
    @EmptyStringsCheck1:
    cmp dword ptr [edi], 0
    je @Equal

    jmp @Exit
    --- Сообщение объединено, 26 ноя 2023 ---
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push esi
    4.   push edi
    5.  
    6.   mov esi, S1
    7.   mov edi, S2
    8.  
    9.   mov eax, 0 //здесь не ясно, целесообразно ли
    10.  
    11.   cmp dword ptr [esi], 0
    12.   //cmp byte ptr [esi], 0
    13.   je @EmptyStringsCheck1
    14.  
    15.   cmp dword ptr [edi], 0
    16.   //cmp byte ptr [edi], 0
    17.   je @EmptyStringsCheck2
    18.  
    19.   mov ecx, [esi-4]
    20.   cmp ecx, [edi-4]
    21.   jne @Exit
    22.  
    23.   mov al, [esi]
    24.   cmp al, [edi]
    25.   jne @Exit
    26.  
    27.   repe cmpsb
    28.   je @Equal
    29.  
    30.   jmp @Exit
    31.  
    32.   @Exit:
    33.     mov eax, 0
    34.     jmp @Done
    35.  
    36.   @Equal:
    37.     mov eax, 1
    38.     jmp @Done
    39.  
    40.   @EmptyStringsCheck1:  
    41.     cmp dword ptr [edi], 0
    42.     //cmp byte ptr [edi], 0
    43.     je @Equal
    44.  
    45.     jmp @Exit
    46.  
    47.   @EmptyStringsCheck2:
    48.     cmp dword ptr [esi], 0
    49.     //cmp byte ptr [esi], 0
    50.     je @Equal
    51.  
    52.     jmp @Exit
    53.  
    54.   @Done:
    55.     pop edi
    56.     pop esi
    57. end;
    --- Сообщение объединено, 26 ноя 2023 ---
    В самом паскале почему-то везде используются конструкции BYTE PTR [...]
    Код (Text):
    1. // Convert Currency to decimal
    2.  
    3. @@CurrToDecimal:
    4.  
    5.         MOV     EAX,[ESI].Integer[0]
    6.         MOV     EDX,[ESI].Integer[4]
    7.         MOV     ECX,EAX
    8.         OR      ECX,EDX
    9.         JE      @@cd20
    10.         OR      EDX,EDX
    11.         JNS     @@cd1
    12.         NEG     EDX
    13.         NEG     EAX
    14.         SBB     EDX,0
    15. @@cd1:  XOR     ECX,ECX
    16.         MOV     EDI,Decimals
    17.         OR      EDI,EDI
    18.         JGE     @@cd2
    19.         XOR     EDI,EDI
    20. @@cd2:  CMP     EDI,4
    21.         JL      @@cd4
    22.         MOV     EDI,4
    23. @@cd3:  INC     ECX
    24.         SUB     EAX,Const1E18Lo
    25.         SBB     EDX,Const1E18Hi
    26.         JNC     @@cd3
    27.         DEC     ECX
    28.         ADD     EAX,Const1E18Lo
    29.         ADC     EDX,Const1E18Hi
    30. @@cd4:  MOV     Temp.Integer[0],EAX
    31.         MOV     Temp.Integer[4],EDX
    32.         FILD    Temp
    33.         MOV     EDX,EDI
    34.         MOV     EAX,4
    35.         SUB     EAX,EDX
    36.         JE      @@cd5
    37.         MOV     EDI,SaveGOT
    38.         FIDIV   @@DecimalTable.Integer[EDI+EAX*4-4]
    39. @@cd5:  FBSTP   BCDValue
    40.         LEA     EDI,[EBX].TFloatRec.Digits
    41.         FWAIT
    42.         OR      ECX,ECX
    43.         JNE     @@cd11
    44.         MOV     ECX,9
    45. @@cd10: MOV     AL,BCDValue[ECX-1].Byte
    46.         MOV     AH,AL
    47.         SHR     AL,4
    48.         JNE     @@cd13
    49.         MOV     AL,AH
    50.         AND     AL,0FH
    51.         JNE     @@cd14
    52.         DEC     ECX
    53.         JNE     @@cd10
    54.         JMP     @@cd20
    55. @@cd11: MOV     AL,CL
    56.         ADD     AL,'0'
    57.         STOSB
    58.         MOV     ECX,9
    59. @@cd12: MOV     AL,BCDValue[ECX-1].Byte
    60.         MOV     AH,AL
    61.         SHR     AL,4
    62. @@cd13: ADD     AL,'0'
    63.         STOSB
    64.         MOV     AL,AH
    65.         AND     AL,0FH
    66. @@cd14: ADD     AL,'0'
    67.         STOSB
    68.         DEC     ECX
    69.         JNE     @@cd12
    70.         MOV     EAX,EDI
    71.         LEA     ECX,[EBX].TFloatRec.Digits[EDX]
    72.         SUB     EAX,ECX
    73. @@cd15: MOV     BYTE PTR [EDI],0
    74.         DEC     EDI
    75.         CMP     BYTE PTR [EDI],'0'
    76.         JE      @@cd15
    77.         MOV     EDX,[ESI].Integer[4]
    78.         SHR     EDX,31
    79.         JMP     @@cd21
    80. @@cd20: XOR     EAX,EAX
    81.         XOR     EDX,EDX
    82.         MOV     [EBX].TFloatRec.Digits.Byte[0],AL
    83. @@cd21: MOV     [EBX].TFloatRec.Exponent,AX
    84.         MOV     [EBX].TFloatRec.Negative,DL
    85.         RET
    86.  
    87. @@Exit:
    88.         POP     EBX
    89.         POP     ESI
    90.         POP     EDI
    91. end;
    --- Сообщение объединено, 26 ноя 2023 ---
    Код (Text):
    1. function CompareStr(const S1, S2: string): Integer; assembler;
    2. asm
    3.         PUSH    ESI
    4.         PUSH    EDI
    5.         MOV     ESI,EAX
    6.         MOV     EDI,EDX
    7.         OR      EAX,EAX
    8.         JE      @@1
    9.         MOV     EAX,[EAX-4]
    10. @@1:    OR      EDX,EDX
    11.         JE      @@2
    12.         MOV     EDX,[EDX-4]
    13. @@2:    MOV     ECX,EAX
    14.         CMP     ECX,EDX
    15.         JBE     @@3
    16.         MOV     ECX,EDX
    17. @@3:    CMP     ECX,ECX
    18.         REPE    CMPSB
    19.         JE      @@4
    20.         MOVZX   EAX,BYTE PTR [ESI-1]
    21.         MOVZX   EDX,BYTE PTR [EDI-1]
    22. @@4:    SUB     EAX,EDX
    23.         POP     EDI
    24.         POP     ESI
    25. end;
    26.  
    27. function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler;
    28. asm
    29.         PUSH    ESI
    30.         PUSH    EDI
    31.         MOV     ESI,P1
    32.         MOV     EDI,P2
    33.         MOV     EDX,ECX
    34.         XOR     EAX,EAX
    35.         AND     EDX,3
    36.         SAR     ECX,2
    37.         JS      @@1     // Negative Length implies identity.
    38.         REPE    CMPSD
    39.         JNE     @@2
    40.         MOV     ECX,EDX
    41.         REPE    CMPSB
    42.         JNE     @@2
    43. @@1:    INC     EAX
    44. @@2:    POP     EDI
    45.         POP     ESI
    46. end;
    47.  
    48. function CompareText(const S1, S2: string): Integer; assembler;
    49. asm
    50.         PUSH    ESI
    51.         PUSH    EDI
    52.         PUSH    EBX
    53.         MOV     ESI,EAX
    54.         MOV     EDI,EDX
    55.         OR      EAX,EAX
    56.         JE      @@0
    57.         MOV     EAX,[EAX-4]
    58. @@0:    OR      EDX,EDX
    59.         JE      @@1
    60.         MOV     EDX,[EDX-4]
    61. @@1:    MOV     ECX,EAX
    62.         CMP     ECX,EDX
    63.         JBE     @@2
    64.         MOV     ECX,EDX
    65. @@2:    CMP     ECX,ECX
    66. @@3:    REPE    CMPSB
    67.         JE      @@6
    68.         MOV     BL,BYTE PTR [ESI-1]
    69.         CMP     BL,'a'
    70.         JB      @@4
    71.         CMP     BL,'z'
    72.         JA      @@4
    73.         SUB     BL,20H
    74. @@4:    MOV     BH,BYTE PTR [EDI-1]
    75.         CMP     BH,'a'
    76.         JB      @@5
    77.         CMP     BH,'z'
    78.         JA      @@5
    79.         SUB     BH,20H
    80. @@5:    CMP     BL,BH
    81.         JE      @@3
    82.         MOVZX   EAX,BL
    83.         MOVZX   EDX,BH
    84. @@6:    SUB     EAX,EDX
    85.         POP     EBX
    86.         POP     EDI
    87.         POP     ESI
    88. end;
    --- Сообщение объединено, 26 ноя 2023 ---
    Еще небольшая порция бреда подъехала, получилось так:
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push esi
    4.   push edi
    5.  
    6.   mov esi, S1
    7.   mov edi, S2
    8.  
    9.   or esi, esi
    10.   je @EmptyStringsCheck1
    11.  
    12.   or edi, edi
    13.   je @EmptyStringsCheck2
    14.  
    15.   mov al, [esi]
    16.   cmp al, [edi]
    17.   jne @Exit
    18.  
    19.   mov ecx, [esi-4]
    20.   cmp ecx, [edi-4]
    21.   jne @Exit
    22.  
    23.   repe cmpsb
    24.   je @Equal
    25.  
    26.   jmp @Exit
    27.  
    28.   @Exit:
    29.     mov eax, 0
    30.     jmp @Done
    31.  
    32.   @Equal:
    33.     mov eax, 1
    34.     jmp @Done
    35.  
    36.   @EmptyStringsCheck1:  
    37.     or edi, edi
    38.     je @Equal
    39.  
    40.     jmp @Exit
    41.  
    42.   @EmptyStringsCheck2:
    43.     or esi, esi
    44.     je @Equal
    45.  
    46.     jmp @Exit
    47.  
    48.   @Done:
    49.     pop edi
    50.     pop esi
    51. end;
    --- Сообщение объединено, 26 ноя 2023 ---
    [​IMG]
     
    Последнее редактирование: 26 ноя 2023
  18. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Меня там не совсем туда понесло. Проблема решена, 42! спасибо за помощь :)
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push esi
    4.   push edi
    5.   mov esi, S1
    6.   mov edi, S2
    7.   or esi, esi
    8.   je @EmptyCheck1
    9.   or edi, edi
    10.   je @EmptyCheck2
    11.   mov al, [esi]
    12.   cmp al, [edi]
    13.   jne @Exit
    14.   mov ecx, [esi-4]
    15.   cmp ecx, [edi-4]
    16.   jne @Exit
    17.   repe cmpsb
    18.   je @Equal
    19.   jmp @Exit
    20.  
    21.   @Equal:
    22.     mov eax, 1
    23.     jmp @Done
    24.  
    25.   //Горшочек, не вари!
    26.   @Exit:
    27.     mov eax, 0
    28.     jmp @Done
    29.  
    30.   @EmptyCheck1:
    31.     or edi, edi
    32.     je @Equal
    33.     jmp @Exit
    34.  
    35.   @EmptyCheck2:
    36.     or esi, esi
    37.     je @Equal
    38.     jmp @Exit
    39.  
    40.   @Done:
    41.     pop edi
    42.     pop esi
    43. end;
     
  19. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
    Да, так выглядит норм (вопрос только про то возможна ли нулевая строка AnsiString такая, что она существует в памяти с нулевой длиной остаётся открытым. я бы на месте создателей языка такое запрещал, т.к. это довольно логично учитывая концепцию паскаля copy on write).
    Но еще можно заметить, что в метке @EmptyCheck2 мы уже точно знаем, что esi не ноль, иначе бы мы ушли в ветку @EmptyCheck1, т.е. там можно сразу прыгать на выход с ложным результатом.
     
  20. Win32Api

    Win32Api Member

    Публикаций:
    0
    Регистрация:
    16 окт 2022
    Сообщения:
    109
    Мне изначально думалось то что объединить метки EmptyCheck1, EmptyCheck2 в одну, трудно решаемая задача

    Глазами смотрят, и не видят; своими ушами слышат, и не разумеют, да не обратятся, и прощены будут им грехи :)
    --- Сообщение объединено, 27 ноя 2023 ---
    aa_dav, нейронка на Фасме, может видел: https://disk.yandex.ru/d/7myOo4JkWqTNOQ
    --- Сообщение объединено, 27 ноя 2023 ---
    Автор до сих пор не знает что существует база данных MNIST,
    и делает изображения для нейросети через веб камеру

    Из за этого такой размер архива :)
    --- Сообщение объединено, 27 ноя 2023 ---
    aa_dav, еще один вопрос по ассемблеру, в чем баг такой реализации:
    Код (Text):
    1. function StrCompare(S1, S2: string): bool; assembler;
    2. asm
    3.   push esi
    4.   push edi
    5.  
    6.   mov esi, S1
    7.   mov edi, S2
    8.  
    9.   mov al, [esi]
    10.   cmp al, [edi]
    11.   jne @Exit
    12.  
    13.   mov ecx, [esi-4]
    14.   cmp ecx, [edi-4]
    15.   jne @Exit
    16.  
    17.   repe cmpsb
    18.   je @Equal
    19.   jmp @Exit
    20.  
    21.   @Equal:
    22.     mov eax, 1
    23.     jmp @Done
    24.  
    25.   @Exit:
    26.     mov eax, 0
    27.     jmp @Done
    28.  
    29.   @Done:
    30.     pop edi
    31.     pop esi
    32. end;
    --- Сообщение объединено, 27 ноя 2023 ---
    С точки зрения:
     
    Последнее редактирование: 27 ноя 2023