Сборка - струны

Мы уже использовали строки переменной длины в наших предыдущих примерах. Строки переменной длины могут содержать сколько угодно символов. Обычно мы указываем длину строки одним из двух способов:

  • Явное сохранение длины строки
  • Использование дозорного персонажа

Мы можем сохранить длину строки явно, используя символ счетчика $ location, который представляет текущее значение счетчика местоположения. В следующем примере -

msg  db  'Hello, world!',0xa ;our dear string
len  equ  $ - msg            ;length of our dear string

$ указывает на байт после последнего символа строковой переменной msg . Следовательно,$-msgдает длину строки. Мы также можем написать

msg db 'Hello, world!',0xa ;our dear string
len equ 13                 ;length of our dear string

В качестве альтернативы вы можете хранить строки с конечным сигнальным символом для разделения строки вместо того, чтобы явно сохранять длину строки. Сторожевой символ должен быть специальным символом, который не появляется в строке.

Например -

message DB 'I am loving it!', 0

Строковые инструкции

Для каждой строковой инструкции может потребоваться операнд-источник, операнд-адресат или и то, и другое. Для 32-битных сегментов строковые инструкции используют регистры ESI и EDI для указания операндов источника и назначения соответственно.

Однако для 16-битных сегментов регистры SI и DI используются для указания источника и назначения соответственно.

Есть пять основных инструкций по обработке строк. Они -

  • MOVS - Эта инструкция перемещает 1 байт, слово или двойное слово данных из ячейки памяти в другую.

  • LODS- Эта инструкция загружается из памяти. Если операнд состоит из одного байта, он загружается в регистр AL, если операнд представляет собой одно слово, оно загружается в регистр AX, а двойное слово загружается в регистр EAX.

  • STOS - Эта инструкция сохраняет данные из регистра (AL, AX или EAX) в памяти.

  • CMPS- Эта инструкция сравнивает два элемента данных в памяти. Данные могут иметь размер байта, слово или двойное слово.

  • SCAS - Эта инструкция сравнивает содержимое регистра (AL, AX или EAX) с содержимым элемента в памяти.

Каждая из приведенных выше инструкций имеет версию в байтах, словах и двойных словах, а строковые инструкции можно повторять с помощью префикса повторения.

Эти инструкции используют пару регистров ES: DI и DS: SI, где регистры DI и SI содержат действительные адреса смещения, которые относятся к байтам, хранящимся в памяти. SI обычно связан с DS (сегментом данных), а DI всегда связан с ES (дополнительным сегментом).

Регистры DS: SI (или ESI) и ES: DI (или EDI) указывают на исходный и целевой операнды соответственно. Предполагается, что исходный операнд находится в DS: SI (или ESI), а целевой операнд - в ES: DI (или EDI) в памяти.

Для 16-битных адресов используются регистры SI и DI, а для 32-битных адресов используются регистры ESI и EDI.

В следующей таблице представлены различные версии строковых инструкций и предполагаемое пространство операндов.

Базовая инструкция Операнды в Байт Операция Слово Операция Двойное слово Операция
MOVS ES: DI, DS: SI МОВСБ MOVSW МОВСД
LODS AX, DS: SI ЛОДСБ LODSW LODSD
STOS ES: DI, AX СТОСБ STOSW STOSD
CMPS DS: SI, ES: DI CMPSB CMPSW CMPSD
SCAS ES: DI, AX SCASB SCASW SCASD

Префиксы повторения

Префикс REP, установленный перед строковой инструкцией, например REP MOVSB, вызывает повторение инструкции на основе счетчика, помещенного в регистр CX. REP выполняет инструкцию, уменьшает CX на 1 и проверяет, равен ли CX нулю. Обработка инструкции повторяется до тех пор, пока CX не станет нулевым.

Флаг направления (DF) определяет направление операции.

  • Используйте CLD (Clear Direction Flag, DF = 0), чтобы выполнить операцию слева направо.
  • Используйте STD (установить флаг направления, DF = 1), чтобы выполнить операцию справа налево.

Префикс REP также имеет следующие варианты:

  • РЭП: Это безусловный повтор. Операция повторяется до тех пор, пока CX не станет равным нулю.

  • REPE или REPZ: условный повтор. Операция повторяется, пока нулевой флаг указывает на равенство / ноль. Он останавливается, когда ZF указывает не равно / нулю или когда CX равен нулю.

  • REPNE или REPNZ: это также условный повтор. Операция повторяется, пока нулевой флаг указывает не равно / нулю. Он останавливается, когда ZF указывает равный / ноль или когда CX уменьшается до нуля.