Для поиска определенного элемента в строке применяется следующий набор инструкций:
scasb: поиск в строке байтов
scasw: поиск в строке слов
scasd: поиск в строке двойных слов
scasq: поиск в строке четверных слов
Данные инструкции принимают только один операнд - строку, в которую помещается результат поиска и адрес которой загружается в регистр RDI.
Строка для поиска загружается в регистре AL (scasb
), AX (scasw
), EAX (scasd
) или RAX (scasq
).
Инструкции scas
сравнивают значение в аккумуляторе (AL, AX, EAX или RAX) со значением, на которое указывает RDI, а затем увеличивает (или уменьшает) значение
RDI на 1, 2, 4 или 8. В соответствии с результатом сравнения процессор устанавливает флаги. Так, если символ найден, то устанавливается флаг нуля, а регистр RDI указывает на символ, следующий за найденным.
При применении префикса repe инструкции scas
просматривают строку в поисках элемента, не соответствующего значению в аккумуляторе.
При использовании префикса repne scas сканирует строку в поисках первого элемента, равного значению в аккумуляторе.
Регистр RCX в этом случае хранит количество элементов, а не байтов, которые необходимо обработать при сканировании.
Например, найдем индекс символа в строке:
.data text byte "Hello", 0 len = $ - text ; длина первой строки char byte 'l' ; символ для поиска .code main proc lea rdi, text ; загружаем адрес переменной text mov rsi, rdi ; копируем адрес в RSI для последующего поиска индекса mov al, char ; в AL символ для поиска mov rcx, len ; в RCX количество символов строки repne scasb ; ищем байт jz found ; если символ найден, устанавливается флаг нуля ZF mov rax, -1 ; если символ не найден, в RAX число -1 jmp exit found: sub rdi, rsi ; если символ найден, получаем индекс следующего символа после найденного dec rdi ; отнимает 1 байт - получем индекс найденного символа mov rax, rdi ; в RAX индекс exit: ret main endp end
Здесь в строке "Hello" ищем символ "l". Для этого строку для поиска загружаем в RDI, а в AL - символ (байт), который будем искать.
Если при выполнении инструкции scas
элемент был найден, то устанавливается флаг нуля. И мы можем это проверить и выполнить определенные действия. В данном случае,
если символ найден, от значения в RDI (адрес следующего символа за найденным) отнимаем начальный адрес строки text (адрес первого символа строки text), который для удобства
сохранили в регистр RSI и таким образом получаем расстояние в байтах между первым символом и следующим за найденным символом. Поскольку все элементы строки - байты, то это расстояние будет
представлять индекс следующего символа за найденным. Соответственно, чтобы получить индекс найденного символа (а не следующего за ним), надо от этого расстояния отнять 1 (размер одного элемента в байтах).
Например, при поиске символа "l" в строке "Hello" мы получим 2 - это индекс третьего символа.
Если символ не найден, то в регистр RAX помещаем -1.