Сравнение строк

Последнее обновление: 16.10.2023

Для сравнения строк из различных типов чисел в ассемблере NASM применяются инструкции

  • cmpsb: сравнивает строку байтов

  • cmpsw: сравнивает строку из слов

  • cmpsd: сравнивает строку из двойных слов

  • cmpsq: сравнивает строку из четверных слов

Процессор сравнивает значение, на которое ссылается регистр RDI, со значением, на которое указывает регистр RSI. RCX содержит количество элементов в исходной строке (не путать с количеством обрабатываемых байтов).

Вместе с этой инструкцией можно использовать ряд префиксов:

  • Префикс repe указывает повторять операцию до тех пор, пока сравнение равно, или до количества раз, указанного RCX (в основном применяется для сравнений символьных строк).

  • Префикс repne повторяет операцию, пока сравнение не равно, или до количества раз, указанного RCX

Без применения этих префиксов инструкции cmps вычитают значение в RDI из значения в RSI и обновляет флаги в соответствии с результатом. После сравнения двух чисел cmps увеличивает или уменьшает регистры RSI и RDI на 1, 2, 4 или 8 (для cmpsb, cmpsw, cmpsd и cmpsq соответственно). cmps увеличивает регистры RSI и RDI, если флаг направления сброшен, и уменьшает их, если флаг установлен. Например, сравненим равные по длине массивы:

global _start

section .data
nums1 dw 10, 11, 12, 13, 14, 15, 16, 17
nums2 dw 10, 11, 12, 13, 14, 15, 16, 17

section .text
_start:
    mov rsi, nums1
    mov rdi, nums2
    mov rcx, 8      ; 8 слов
    repe cmpsw      ; сравниваем слова
    jz equal        ; если строки равны, переход к метке equal
    mov rdi, 2      ; если строки не равны, RDI = 2
    jmp exit
equal:
    mov rdi, 4      ; если строки равны, RDI = 4
exit:
    mov rax, 60
    syscall 

Здесь сравниваем два массива чисел. Если они равны, помещаем в RDI число 4, если не равны - число 2.

Если строки имеют или могут иметь разную длину, то задача немного усложняется. Две строки равны, когда их длины равны и элементы в соответствующих позициях равны. Если одна из строк меньше другой, но все ее элементы равны соответствующим символам второй строки (то есть первая строка является подстрокой второй строки), то мы можем считать что первая строка меньше второй.

В этом случае в регистр RCX помещается длина наименьшей строки. Далее обе строки сравниваются как и вобщем случае. И если они равны, сравниваются их длины.

Пример сравнения двух строк:

global _start

section .data
str1 db "Hello World"
str1_len equ $-str1         ; длина первой строки 
str2 db "Hello World"
str2_len equ $-str2         ; длина второй строки

section .text
_start:
    mov rsi, str1
    mov rdi, str2
    mov rcx, str1_len
    cmp rcx, str2_len       ; сравниваем длины строк
    jbe compare             ; если длина str1 равна или меньше

    mov rcx, str2_len       ; если длина str2 меньше

compare:
    repe cmpsb      ; сравниваем байты
    jnz notequal    ; если не равны

    mov rcx, str1_len
    cmp rcx, str2_len   ; если равны, сравниваем длины строк
    jnz notequal
    mov rdi, 16          ; если строки равны
    jmp exit
notequal:
    mov rdi, 8           ; если строки не равны
exit:
    mov rax, 60
    syscall 

Строки символов обычно сравниваются в алфавитном порядке. Поскольку символы фактически представлены их числовами кодами, то сравнение символов выливается в сравнение их числовых кодов (в данном случае для простоты считаем, что символы в разных регистрах - это разные символы).

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850