Доброго времени суток! Пытаюсь перевести простенькую функцию сравнивающую 2 строки с паскаля на ассемблер. Функция проверяет чтоб обе строки не были пустыми, сравнивает первые символы строк, проверяет чтобы строки были одинаковой длины, если все условия выполняются, сравнивает строки целиком. Code (Text): function StrCompare(s1, s2: string): bool; begin Result := false; if (s1 <> '') and (s2 <> '') then begin if s1[1] = s2[1] then begin if Length(s1) = Length(s2) then begin if s1 = s2 then begin Result := true; end; end; end; end; end; //StrCompare Чат гпт подсказал такое решение: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push ebx push edi push esi // Сравниваем первые символы movzx ebx, byte ptr [eax] movzx ecx, byte ptr [eax+1] cmp bl, byte ptr [edx] jne @NotEqual // Сравниваем длины строк mov edx, ecx add edx, eax sub edx, 1 cmp edx, Length(S2) jne @NotEqual // Сравниваем сами строки mov edi, eax mov esi, edx mov edx, S2 add esi, edx add edi, edx sub esi, 1 sub edi, 1 mov ecx, esi sub ecx, edx jz @Equal sub ecx, edi jz @Equal @NotEqual: // Возвращаем false xor eax, eax jmp @Exit @Equal: // Возвращаем true mov eax, 1 @Exit: // Восстанавливаем регистры pop esi pop edi pop ebx end; Как сделать чтобы функция на ассемблере работала аналогично моей? Есть примеры корректно работающих инлайн функций на ассемблере: Code (Text): function CompareStr(const S1, S2: string): Integer; assembler; asm PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX OR EAX,EAX JE @@1 MOV EAX,[EAX-4] @@1: OR EDX,EDX JE @@2 MOV EDX,[EDX-4] @@2: MOV ECX,EAX CMP ECX,EDX JBE @@3 MOV ECX,EDX @@3: CMP ECX,ECX REPE CMPSB JE @@4 MOVZX EAX,BYTE PTR [ESI-1] MOVZX EDX,BYTE PTR [EDI-1] @@4: SUB EAX,EDX POP EDI POP ESI end; function CompareText(const S1, S2: string): Integer; assembler; asm PUSH ESI PUSH EDI PUSH EBX MOV ESI,EAX MOV EDI,EDX OR EAX,EAX JE @@0 MOV EAX,[EAX-4] @@0: OR EDX,EDX JE @@1 MOV EDX,[EDX-4] @@1: MOV ECX,EAX CMP ECX,EDX JBE @@2 MOV ECX,EDX @@2: CMP ECX,ECX @@3: REPE CMPSB JE @@6 MOV BL,BYTE PTR [ESI-1] CMP BL,'a' JB @@4 CMP BL,'z' JA @@4 SUB BL,20H @@4: MOV BH,BYTE PTR [EDI-1] CMP BH,'a' JB @@5 CMP BH,'z' JA @@5 SUB BH,20H @@5: CMP BL,BH JE @@3 MOVZX EAX,BL MOVZX EDX,BH @@6: SUB EAX,EDX POP EBX POP EDI POP ESI end; function SameText(const S1, S2: string): Boolean; assembler; asm CMP EAX,EDX JZ @1 OR EAX,EAX JZ @2 OR EDX,EDX JZ @3 MOV ECX,[EAX-4] CMP ECX,[EDX-4] JNE @3 CALL CompareText TEST EAX,EAX JNZ @3 @1: MOV AL,1 @2: RET @3: XOR EAX,EAX end;
Можно подробнее? Сделал штук 20 запросов к чату гпт, самое похоже на адекватное, решение, который выдал электрический друг: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push ebx push edi push esi movzx ebx, byte ptr [eax] movzx ecx, byte ptr [eax+1] cmp bl, byte ptr [edx] jne @NotEqual mov edx, ecx add edx, eax sub edx, 1 cmp edx, Length(S2) jne @NotEqual mov edi, eax mov esi, edx mov edx, S2 add esi, edx add edi, edx sub esi, 1 sub edi, 1 mov ecx, esi sub ecx, edx jz @Equal sub ecx, edi jz @Equal @NotEqual: xor eax, eax jmp @Exit @Equal: mov eax, 1 @Exit: pop esi pop edi pop ebx end; Происходит какое-то сравнение, но результат получается забористый
esi edi rep cmpsb --- Сообщение объединено, Nov 26, 2023 --- Подробнее: Я есть я. Здесь не может быть никакого сравнения. Это начинается уже с занятий в школе: сдавать экзамены, раздавать оценки, которые делят людей на группы по их достижениям — какой бред! Что вообще значат такие слова как «важно» или «не важно»? «Важно» иметь хорошую память? Тот, кто имеет плохую — плохой человек? Разве не существует много дебилов с хорошей памятью?
) --- Сообщение объединено, Nov 26, 2023 --- Получилось вот так: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push esi push edi // Проверяем, что строки не пустые mov esi, S1 mov edi, S2 cmp byte ptr [esi], 0 je @Exit cmp byte ptr [edi], 0 je @Exit // Сравниваем первые символы строк mov al, [esi] cmp al, [edi] jne @Exit // Сравниваем длины строк mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit // Сравниваем строки repe cmpsb je @Equal @Exit: // Строки не равны mov eax, 0 jmp @Done @Equal: // Строки равны mov eax, 1 @Done: // Восстанавливаем регистры pop edi pop esi end;
В паскале длина строк хранится перед первым символом строки. И тут важно понимать какие именно строки в текущем режиме компиляции подразумеваются под string - это может быть ShortString, AnsiString, WideString. Почему важно - потому что в ShortString на длину выделен байт, а у остальный - dword. Поэтому смотрим "корректно работающий пример" и видим там MOV EAX,[EAX-4] - это вот так надо получать длину строки. ЧатГПТ тут херню какую то начал морозить (сужу по первопосту). В остальном - ну похоже на правду. Правда смысла так делать нет, т.к. уверяю, что штатное s1 <> s2 реализовано ровно так же - сперва сравнит длины, потом тела прерываясь на первом не совпавшем символе.
Сравнил время выполнения s1 <> s2 и function StrCompare(S1, S2: string): bool; assembler;, последнее на 50% быстрее работает Как можно эффективнее переделать: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push esi push edi // Проверяем, что строки не пустые mov esi, S1 mov edi, S2 cmp byte ptr [esi], 0 je @Exit cmp byte ptr [edi], 0 je @Exit // Сравниваем первые символы строк mov al, [esi] cmp al, [edi] jne @Exit // Сравниваем длины строк mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit // Сравниваем строки repe cmpsb je @Equal @Exit: // Строки не равны mov eax, 0 jmp @Done @Equal: // Строки равны mov eax, 1 @Done: // Восстанавливаем регистры pop edi pop esi end; С получением длины строки через MOV EAX,[EAX-4]? Кажется есть лишние джампы и можно сделать проще --- Сообщение объединено, Nov 26, 2023 --- По поводу восстановления регистров говорит что все правильно:
Я тут еще не заметил правильно работающую StrCompare чтобы их можно было корректно сравнивать. Например вот это что приведена тобой под комментарием "проверяем что строки не пустые" сравнивает на ноль первые символы строк в предположении что это ShortString или AnsiString. Поэтому какие то странные результаты непонятные - они просто некорректные. Юзай просто <> из паскаля, а если нужно сравнивать строки из ассемблера, то просто юзай "проверенные варианты". Остальное лишнее.
Что не правильно в этом решении? Каким образом можно переделать? Этот код использует более современные регистры и инструкции, как говорит чат гпт Code (Text): function StrCompare1(S1, S2: string): Boolean; assembler; asm // Сохраняем регистры push ecx push edx // Проверяем, что строки не пустые mov ecx, S1 cmp byte ptr [ecx], 0 je @Exit mov edx, S2 cmp byte ptr [edx], 0 je @Exit // Сравниваем символы строк mov al, [ecx] cmp al, [edx] jne @Exit // Сравниваем остальные символы @@Loop: inc ecx inc edx mov al, [ecx] cmp al, [edx] jne @Exit cmp al, 0 jne @@Loop // Строки равны mov eax, 1 jmp @Done // Строки не равны @Exit: mov eax, 0 // Восстанавливаем регистры @Done: pop edx pop ecx end; --- Сообщение объединено, Nov 26, 2023 --- Скажу по секрету, тема была создана чтобы "не юзать <> из паскаля". Есть тысяча способов умереть на Диком Западе, и скорее всего есть тысача корректных вариантов, сделать это сравнение на ассемблере. --- Сообщение объединено, Nov 26, 2023 --- Самый долгий вариант: Code (Text): function StrCompare(S1, S2: string): Boolean; assembler; asm // Проверяем, что строки не пустые mov eax, S1 test eax, eax jz @NotEqual mov edx, S2 test edx, edx jz @NotEqual // Проверяем длины строк mov ecx, [eax-4] cmp ecx, [edx-4] jne @NotEqual // Сравниваем строки call CompareStr test eax, eax jnz @NotEqual // Строки равны mov eax, 1 jmp @Done @NotEqual: // Строки не равны xor eax, eax @Done: end; function CompareStr(const S1, S2: string): Integer; assembler; asm PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX OR EAX,EAX JE @@1 MOV EAX,[EAX-4] @@1: OR EDX,EDX JE @@2 MOV EDX,[EDX-4] @@2: MOV ECX,EAX CMP ECX,EDX JBE @@3 MOV ECX,EDX @@3: CMP ECX,ECX REPE CMPSB JE @@4 MOVZX EAX,BYTE PTR [ESI-1] MOVZX EDX,BYTE PTR [EDI-1] @@4: SUB EAX,EDX POP EDI POP ESI end; --- Сообщение объединено, Nov 26, 2023 --- Этот быстрее Code (Text): function StrCompare(S1, S2: string): Boolean; assembler; asm // Сохраняем регистры push ecx push edx // Проверяем, что строки не пустые mov ecx, S1 cmp byte ptr [ecx], 0 je @Exit mov edx, S2 cmp byte ptr [edx], 0 je @Exit // Сравниваем символы строк mov al, [ecx] cmp al, [edx] jne @Exit // Сравниваем остальные символы @@Loop: inc ecx inc edx mov al, [ecx] cmp al, [edx] jne @Exit cmp al, 0 jne @@Loop // Строки равны mov eax, 1 jmp @Done // Строки не равны @Exit: mov eax, 0 // Восстанавливаем регистры @Done: pop edx pop ecx end; //StrCompare --- Сообщение объединено, Nov 26, 2023 --- В первом случае из функции какой-то странный выход: Code (Text): @Done: end; В общем вопрос к спецам, как сделать самое быстрое и сэйфовое сравнение --- Сообщение объединено, Nov 26, 2023 --- В этом случае -4: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push esi push edi // Проверяем, что строки не пустые mov esi, S1 mov edi, S2 cmp byte ptr [esi], 0 je @Exit cmp byte ptr [edi], 0 je @Exit // Сравниваем первые символы строк mov al, [esi] cmp al, [edi] jne @Exit // Сравниваем длины строк mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit // Сравниваем строки repe cmpsb je @Equal @Exit: // Строки не равны mov eax, 0 jmp @Done @Equal: // Строки равны mov eax, 1 @Done: // Восстанавливаем регистры pop edi pop esi end; Есть ли смысл использовать какие-то другие регистры? Есть ли смысл заменить это: Code (Text): repe cmpsb Вот этим: Code (Text): @@Loop: inc ecx inc edx mov al, [ecx] cmp al, [edx] jne @Exit cmp al, 0 jne @@Loop Если порядок сравнения: 1. проверяем что обе строки не пустые, 2. сравниваем первые символы обеих строк, 3. проверяем чтобы строки были одинаковой длины, 4. если все условия выполняются, тогда сравниваем строки целиком. --- Сообщение объединено, Nov 26, 2023 --- lstrcmp - 34 секунды. Code (Text): function StrCompare(S1, S2: string): bool; begin Result := lstrcmp(PChar(s1), PChar(s2)) = 0; end; Паскалевское сравнение 's1 = s2' - 9 секунд. 4 секунды: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push esi push edi // Проверяем, что строки не пустые mov esi, S1 mov edi, S2 cmp byte ptr [esi], 0 je @Exit cmp byte ptr [edi], 0 je @Exit // Сравниваем первые символы строк mov al, [esi] cmp al, [edi] jne @Exit // Сравниваем длины строк mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit // Сравниваем строки repe cmpsb je @Equal @Exit: // Строки не равны mov eax, 0 jmp @Done @Equal: // Строки равны mov eax, 1 @Done: // Восстанавливаем регистры pop edi pop esi end; Целый день вместе практиковать дзадзэн — чрезвычайная удача. Целый день вместе проводить в публичном доме — чрезвычайная глупость
После Code (Text): @Equal: // Строки равны mov eax, 1 Добавил jmp @Done Code (Text): @Equal: // Строки равны mov eax, 1 jmp @Done
Присмотрелся немного к "первообразной функции" и мне не понравилось: Code (Text): function StrCompare(s1, s2: string): bool; begin Result := false; if (s1 <> '') and (s2 <> '') then begin if s1[1] = s2[1] then begin if Length(s1) = Length(s2) then begin if s1 = s2 then begin Result := true; end; end; end; end; end; //StrCompare Если обе строки пустые возвращает false, а должна true. Непорядочек. Кроме того, если присмотреться к функциям "которые правильные" - они проверяют на 0 сам указатель строки - то есть пустая строка может прийти как nil. Это очень важно проверять, ChatGPT про это походу вообще ничего не знает (как и я, кстати, на начало этой темы, не задумывался, что строки и массивы настолько одинаково работают).
Кстати да. Добавил проверку, если обе строки равны нулю Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm // Сохраняем регистры push esi push edi mov esi, S1 mov edi, S2 cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp byte ptr [edi], 0 je @EmptyStringsCheck2 //Если дошли до сюда значит нет пустых строк. // Сравниваем первые символы строк mov al, [esi] cmp al, [edi] jne @Exit // Сравниваем длины строк mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit // Сравниваем строки repe cmpsb je @Equal jmp @Exit @Exit: // Строки не равны mov eax, 0 jmp @Done @Equal: // Строки равны mov eax, 1 jmp @Done @EmptyStringsCheck1: cmp byte ptr [edi], 0 je @Equal //Если обе строки пустые. jmp @Exit @EmptyStringsCheck2: cmp byte ptr [esi], 0 je @Equal //Если обе строки пустые. jmp @Exit @Done: // Восстанавливаем регистры pop edi pop esi end; //StrCompare --- Сообщение объединено, Nov 26, 2023 --- Получилось две метки @EmptyStringsCheck1 и @EmptyStringsCheck2, не знаю как можно объединить их в одну После Code (Text): cmp byte ptr [esi], 0 je @Equal //Если обе строки пустые. jmp @Exit добавил jmp @Exit, это правильно или нет?
Code (Text): cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp byte ptr [edi], 0 je @EmptyStringsCheck2 Это сравнивает первый символ (байт) в строках (esi и edi это указатели на строки), что вообще то с ходу в карьер делать нельзя. Сперва надо проверить не равны ли указатели нулю - если так, то это то же самое, что пустая строка. По нулевому указателю в память обращаться нельзя. Я бы сделал алгоритм следующим образом: 1. определение длины строки 1 и помещение в промежуточный регистр (если указатель строки нулевой - вменить ноль длине) 2. выделение длины строки 2 и помещение в промежуточный регистр 3. проверка если обе длины нулевые (это можно сделать наложив их по OR в третий регистр) - вернуть True 4. проверка если длины различны - вернуть False 5. и вот тут уже мы знаем, что у нас обе строки есть валидные указатели - ведь мы знаем что на этом месте длины равны, но при этом не равны нулю - значит есть тела с которыми можно работать. 6. и вот тут уже ты можешь заняться тем что считаешь оптимизацией - предварительное сравнение первым символов на неравенство перед основным циклом rep cmpsb. Правда оно смысла не имеет, но если хочется - никто не запрещает.
Добавил это, не знаю насколько правильно Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push esi push edi mov esi, S1 mov edi, S2 test esi, esi jz @EmptyStringsCheck1 test edi, edi jz @EmptyStringsCheck2 cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp byte ptr [edi], 0 je @EmptyStringsCheck2 mov al, [esi] cmp al, [edi] jne @Exit mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit repe cmpsb je @Equal jmp @Exit @Exit: mov eax, 0 jmp @Done @Equal: mov eax, 1 jmp @Done @EmptyStringsCheck1: cmp byte ptr [edi], 0 je @Equal jmp @Exit @EmptyStringsCheck2: cmp byte ptr [esi], 0 je @Equal jmp @Exit @Done: pop edi pop esi end; --- Сообщение объединено, Nov 26, 2023 --- Внутри @EmptyStringsCheck1 и @EmptyStringsCheck2 скорее всего чего-то не хватает после добавления: Code (Text): test esi, esi jz @EmptyStringsCheck1 test edi, edi jz @EmptyStringsCheck2
Эммм.... Ты продолжаешь что ли в ChatGPT этот код вкидывать? Ну должно же было быть понимание, что когда исправляешь код, то неверный вариант _исправляется_ а не оставляется на месте. И в метках @EmptyStringsCheck1 совершается точно такая же ошибка - вместо указателя проверяется на ноль первый байт строки. Я бы общую логику переделал на то как описал выше, т.к. не знаю есть ли гарантии, что пустые строки это всегда нулевые указатели. Может ли быть так что указатель ненулевой, но указывает на буфер где указан нулевой размер? Если да, то надо делать как я написал обязательно иначе в твоём коде точно будет баг. Но возможно такие гарантии есть?
А если перед этим, добавить mov eax, 0 Code (Text): cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp byte ptr [edi], 0 je @EmptyStringsCheck2 Code (Text): mov eax, 0 cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp byte ptr [edi], 0 je @EmptyStringsCheck2 --- Сообщение объединено, Nov 26, 2023 --- По поводу указателей не совсем понятно. Там что-то типа такого? Code (Text): @EmptyStringsCheck2: or eax, ecx jz @Equal cmp eax, ecx jne @Exit --- Сообщение объединено, Nov 26, 2023 --- В функцию всегда передаются строки. На данный момент, результат возвращается как от сравнения s1 = s2: Code (Text): @EmptyStringsCheck1: cmp byte ptr [edi], 0 je @Equal Может перестать работать, если будут передаваться данные такого же типа? --- Сообщение объединено, Nov 26, 2023 --- @EmptyStringsCheck1: cmp dword ptr [edi], 0 je @Equal jmp @Exit --- Сообщение объединено, Nov 26, 2023 --- Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push esi push edi mov esi, S1 mov edi, S2 mov eax, 0 //здесь не ясно, целесообразно ли cmp dword ptr [esi], 0 //cmp byte ptr [esi], 0 je @EmptyStringsCheck1 cmp dword ptr [edi], 0 //cmp byte ptr [edi], 0 je @EmptyStringsCheck2 mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit mov al, [esi] cmp al, [edi] jne @Exit repe cmpsb je @Equal jmp @Exit @Exit: mov eax, 0 jmp @Done @Equal: mov eax, 1 jmp @Done @EmptyStringsCheck1: cmp dword ptr [edi], 0 //cmp byte ptr [edi], 0 je @Equal jmp @Exit @EmptyStringsCheck2: cmp dword ptr [esi], 0 //cmp byte ptr [esi], 0 je @Equal jmp @Exit @Done: pop edi pop esi end; --- Сообщение объединено, Nov 26, 2023 --- В самом паскале почему-то везде используются конструкции BYTE PTR [...] Code (Text): // Convert Currency to decimal @@CurrToDecimal: MOV EAX,[ESI].Integer[0] MOV EDX,[ESI].Integer[4] MOV ECX,EAX OR ECX,EDX JE @@cd20 OR EDX,EDX JNS @@cd1 NEG EDX NEG EAX SBB EDX,0 @@cd1: XOR ECX,ECX MOV EDI,Decimals OR EDI,EDI JGE @@cd2 XOR EDI,EDI @@cd2: CMP EDI,4 JL @@cd4 MOV EDI,4 @@cd3: INC ECX SUB EAX,Const1E18Lo SBB EDX,Const1E18Hi JNC @@cd3 DEC ECX ADD EAX,Const1E18Lo ADC EDX,Const1E18Hi @@cd4: MOV Temp.Integer[0],EAX MOV Temp.Integer[4],EDX FILD Temp MOV EDX,EDI MOV EAX,4 SUB EAX,EDX JE @@cd5 MOV EDI,SaveGOT FIDIV @@DecimalTable.Integer[EDI+EAX*4-4] @@cd5: FBSTP BCDValue LEA EDI,[EBX].TFloatRec.Digits FWAIT OR ECX,ECX JNE @@cd11 MOV ECX,9 @@cd10: MOV AL,BCDValue[ECX-1].Byte MOV AH,AL SHR AL,4 JNE @@cd13 MOV AL,AH AND AL,0FH JNE @@cd14 DEC ECX JNE @@cd10 JMP @@cd20 @@cd11: MOV AL,CL ADD AL,'0' STOSB MOV ECX,9 @@cd12: MOV AL,BCDValue[ECX-1].Byte MOV AH,AL SHR AL,4 @@cd13: ADD AL,'0' STOSB MOV AL,AH AND AL,0FH @@cd14: ADD AL,'0' STOSB DEC ECX JNE @@cd12 MOV EAX,EDI LEA ECX,[EBX].TFloatRec.Digits[EDX] SUB EAX,ECX @@cd15: MOV BYTE PTR [EDI],0 DEC EDI CMP BYTE PTR [EDI],'0' JE @@cd15 MOV EDX,[ESI].Integer[4] SHR EDX,31 JMP @@cd21 @@cd20: XOR EAX,EAX XOR EDX,EDX MOV [EBX].TFloatRec.Digits.Byte[0],AL @@cd21: MOV [EBX].TFloatRec.Exponent,AX MOV [EBX].TFloatRec.Negative,DL RET @@Exit: POP EBX POP ESI POP EDI end; --- Сообщение объединено, Nov 26, 2023 --- Code (Text): function CompareStr(const S1, S2: string): Integer; assembler; asm PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX OR EAX,EAX JE @@1 MOV EAX,[EAX-4] @@1: OR EDX,EDX JE @@2 MOV EDX,[EDX-4] @@2: MOV ECX,EAX CMP ECX,EDX JBE @@3 MOV ECX,EDX @@3: CMP ECX,ECX REPE CMPSB JE @@4 MOVZX EAX,BYTE PTR [ESI-1] MOVZX EDX,BYTE PTR [EDI-1] @@4: SUB EAX,EDX POP EDI POP ESI end; function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler; asm PUSH ESI PUSH EDI MOV ESI,P1 MOV EDI,P2 MOV EDX,ECX XOR EAX,EAX AND EDX,3 SAR ECX,2 JS @@1 // Negative Length implies identity. REPE CMPSD JNE @@2 MOV ECX,EDX REPE CMPSB JNE @@2 @@1: INC EAX @@2: POP EDI POP ESI end; function CompareText(const S1, S2: string): Integer; assembler; asm PUSH ESI PUSH EDI PUSH EBX MOV ESI,EAX MOV EDI,EDX OR EAX,EAX JE @@0 MOV EAX,[EAX-4] @@0: OR EDX,EDX JE @@1 MOV EDX,[EDX-4] @@1: MOV ECX,EAX CMP ECX,EDX JBE @@2 MOV ECX,EDX @@2: CMP ECX,ECX @@3: REPE CMPSB JE @@6 MOV BL,BYTE PTR [ESI-1] CMP BL,'a' JB @@4 CMP BL,'z' JA @@4 SUB BL,20H @@4: MOV BH,BYTE PTR [EDI-1] CMP BH,'a' JB @@5 CMP BH,'z' JA @@5 SUB BH,20H @@5: CMP BL,BH JE @@3 MOVZX EAX,BL MOVZX EDX,BH @@6: SUB EAX,EDX POP EBX POP EDI POP ESI end; --- Сообщение объединено, Nov 26, 2023 --- Еще небольшая порция бреда подъехала, получилось так: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push esi push edi mov esi, S1 mov edi, S2 or esi, esi je @EmptyStringsCheck1 or edi, edi je @EmptyStringsCheck2 mov al, [esi] cmp al, [edi] jne @Exit mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit repe cmpsb je @Equal jmp @Exit @Exit: mov eax, 0 jmp @Done @Equal: mov eax, 1 jmp @Done @EmptyStringsCheck1: or edi, edi je @Equal jmp @Exit @EmptyStringsCheck2: or esi, esi je @Equal jmp @Exit @Done: pop edi pop esi end; --- Сообщение объединено, Nov 26, 2023 ---
Меня там не совсем туда понесло. Проблема решена, 42! спасибо за помощь Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push esi push edi mov esi, S1 mov edi, S2 or esi, esi je @EmptyCheck1 or edi, edi je @EmptyCheck2 mov al, [esi] cmp al, [edi] jne @Exit mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit repe cmpsb je @Equal jmp @Exit @Equal: mov eax, 1 jmp @Done //Горшочек, не вари! @Exit: mov eax, 0 jmp @Done @EmptyCheck1: or edi, edi je @Equal jmp @Exit @EmptyCheck2: or esi, esi je @Equal jmp @Exit @Done: pop edi pop esi end;
Да, так выглядит норм (вопрос только про то возможна ли нулевая строка AnsiString такая, что она существует в памяти с нулевой длиной остаётся открытым. я бы на месте создателей языка такое запрещал, т.к. это довольно логично учитывая концепцию паскаля copy on write). Но еще можно заметить, что в метке @EmptyCheck2 мы уже точно знаем, что esi не ноль, иначе бы мы ушли в ветку @EmptyCheck1, т.е. там можно сразу прыгать на выход с ложным результатом.
Мне изначально думалось то что объединить метки EmptyCheck1, EmptyCheck2 в одну, трудно решаемая задача Spoiler: Спойлер Глазами смотрят, и не видят; своими ушами слышат, и не разумеют, да не обратятся, и прощены будут им грехи --- Сообщение объединено, Nov 27, 2023 --- aa_dav, нейронка на Фасме, может видел: https://disk.yandex.ru/d/7myOo4JkWqTNOQ --- Сообщение объединено, Nov 27, 2023 --- Автор до сих пор не знает что существует база данных MNIST, и делает изображения для нейросети через веб камеру Из за этого такой размер архива --- Сообщение объединено, Nov 27, 2023 --- aa_dav, еще один вопрос по ассемблеру, в чем баг такой реализации: Code (Text): function StrCompare(S1, S2: string): bool; assembler; asm push esi push edi mov esi, S1 mov edi, S2 mov al, [esi] cmp al, [edi] jne @Exit mov ecx, [esi-4] cmp ecx, [edi-4] jne @Exit repe cmpsb je @Equal jmp @Exit @Equal: mov eax, 1 jmp @Done @Exit: mov eax, 0 jmp @Done @Done: pop edi pop esi end; --- Сообщение объединено, Nov 27, 2023 --- С точки зрения: