Для сравнения строк из различных типов чисел в ассемблере GAS применяются инструкции
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, если флаг направления сброшен, и уменьшает их, если флаг установлен. Например, сравненим равные по длине массивы:
.globl _start .data nums1: .word 10, 11, 12, 13, 14, 15, 16, 17 nums2: .word 10, 11, 12, 13, 14, 15, 16, 17 .text _start: movq $nums1, %rsi movq $nums2, %rdi movq $8, %rcx # 8 слов repe cmpsw # сравниваем слова jz equal # если строки равны, переход к метке equal movq $2, %rdi # если строки не равны, RDI = 2 jmp exit equal: movq $4, %rdi # если строки равны, RDI = 4 exit: movq $60, %rax syscall
Здесь сравниваем два массива чисел. Если они равны, помещаем в %rdi число 4, если не равны - число 2.
Если строки имеют или могут иметь разную длину, то задача немного усложняется. Две строки равны, когда их длины равны и элементы в соответствующих позициях равны. Если одна из строк меньше другой, но все ее элементы равны соответствующим символам второй строки (то есть первая строка является подстрокой второй строки), то мы можем считать что первая строка меньше второй.
В этом случае в регистр RCX помещается длина наименьшей строки. Далее обе строки сравниваются как и вобщем случае. И если они равны, сравниваются их длины.
Пример сравнения двух строк:
.globl _start .data str1: .ascii "Hello World" str1_len = . - str1 # длина первой строки str2: .ascii "Hello World" str2_len = . - str2 # длина второй строки .text _start: movq $str1, %rsi movq $str2, %rdi movq $str1_len, %rcx cmpq $str2_len, %rcx # сравниваем длины строк jbe compare # если длина str1 равна или меньше movq $str2_len, %rcx # если длина str2 меньше compare: repe cmpsb # сравниваем байты jnz notequal # если не равны movq $str1_len, %rcx cmpq $str2_len, %rcx # если равны, сравниваем длины строк jnz notequal movq $1, %rdi # если строки равны jmp exit notequal: movq $0, %rdi # если строки не равны exit: movq $60, %rax syscall
Строки символов обычно сравниваются в алфавитном порядке. Поскольку символы фактически представлены их числовами кодами, то сравнение символов выливается в сравнение их числовых кодов (в данном случае для простоты считаем, что символы в разных регистрах - это разные символы).