Электронный учебник - Assembler - Ответ 13022916

ГЛАВА 17
СТРОКОВЫЕ КОМАНДЫ
(часть 1/2)

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

символьными строками

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

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

Строковые команды требуются при переходе от одной системы кодирования к другой (от ASCII к EBCDIC или Unicode), строковые команды так же необходимы в системах шифрования и дешифровки.

У строковых команд много общего, поэтому, чтобы не повторяться, сначала подробно рассмотрим одну из них, а затем коротко опишем остальные.

ASCII —

American Standard Code for Information Interchange

— американский стандартный код для обмена информацией. Стандартная схема кодирования знаков, веденная в 1963 и широко используемая во многих машинах.

EBCDIC —

Extended Binary Coded Decimal Interchange Code

— расширенный двоично-десятичный код для обмена информацией. 8-битный код для кодирования знаков, в основном используемый в вычислительных машинах фирмы IBM.

Unicode — Стандарт Unicode был предложен некоммерческой организацией Unicode Consortium, образованной в 1991 г. Для представления каждого символа в этом стандарте используются два байта, что позволяет закодировать очень большое число символов из разных письменностей: в документах Unicode могут соседствовать русские, латинские, греческие буквы, китайские иероглифы и математические символы.

Команды сравнения строк CMPSB/W/D/Q
(Сравнение строк, состоящих из байтов/слов/двойных слов =
"COMPARE Strings Byte/Word/Double/Quadruple word operands")

В строковых командах под строкой понимается не только последовательность байт (символов), но и последовательность слов, а также двойных и четверных слов. Поэтому каждая строковая операция может быть представлена четырьмя командами: одни предназначены для обработки строк из байтов, другие — для обработки строк из слов, третьи — для двойных слов и четвертые — для учетверенных. В языке ассемблера мнемокоды этих команд различаются тем, что в первом случае указывается буква B (byte), в другом — буква W (word), в третьем — D (double word), в четвертом — Q (quadruple word). Например, в командах сравнения строк (CMPS, compare strings) используются следующие мнемокоды:

Синтаксис команд

:

CMPS <операнд1>,< операнд2>

CMPSB

CMPSW

CMPSD

CMPSQ

В целом действия этих команд совпадают, поэтому обычно про них говорят как про одну команду CMPS, и только если надо, уточняют, какой вариант ее имелся в виду

Семантика команды

: сравнение двух последовательностей (цепочек) элементов в памяти.

Алгоритм работы

:

выполнить вычитание элементов (<операнд2> -<операнд1>), адреса элементов предварительно должны быть загружены:

адрес операнда1 — в пару регистров DS:ESI/SI;
адрес операнда2 — в пару регистров ES:EDI/DI;

в зависимости от состояния флага DF изменить значение регистров ESI/SI и EDI/DI:

если DF=0, то увеличить содержимое этих регистров на длину элемента последовательности;
если DF=1, то уменьшить содержимое этих регистров на длину элемента последовательности;

в зависимости от результата вычитания установить флаги:

если очередные элементы цепочек не равны, то CF=1, ZF=0;
если очередные элементы цепочек или цепочки в целом равны, то CF=0, ZF=1;

при наличии префикса выполнить определяемые им действия (см. команды REPE/REPNE).

Применение

: у команды два операнда, но их местоположение заранее известно, поэтому они явно не указываются. Команда без префиксов осуществляет простое сравнение двух элементов в памяти. Размеры сравниваемых элементов зависят от применяемой команды. Команда CMPS может работать с элементами размером в байт, слово, двойное слово. В качестве операндов в команде указываются идентификаторы последовательностей этих элементов в памяти. Реально эти идентификаторы используются лишь для получения типов элементов последовательностей, а их адреса должны быть предварительно загружены в указанные выше пары регистров. Транслятор, обработав команду CMPS и выяснив тип операндов, генерирует одну из машинных команд CMPSB, CMPSW или CMPSD. Абсолютный адрес операнда1 из первой строки по умолчанию должен задаваться регистрами DS:SI/ESI, а абсолютный адрес операнда2 из второй строки должен задаваться регистрами ES: DI/EDI.

Причем для операнда2 обязательно должен использоваться регистр ES, а для адресации операнда1 можно делать замену сегмента с использованием соответствующего префикса.

Основное действие команды CMPS заключается в сравнении элемента одной строки с элементом другой строки. Это сравнение выполняется так же, как и в команде CMP, то есть путем вычитания операндов без записи куда-либо полученной разности, команда CMPS так же меняет значения регистров SI/ESI и DI/EDI и меняет их так, чтобы в них оказались адреса соседних элементов строк. В зависимости от текущего значения флага направления DF: при DF=0 значения регистров увеличиваются — происходит переход вперед к следующим элементам, а при DF=1 значения регистров уменьшаются — происходит переход назад к предыдущим элементам.

Сам по себе флаг DF не меняется, его должен менять автор программы командами CLD (очистка флага DF) и STD (установка флага DF). По команде CLD флаг направления сбрасывается (DF=0), а по команде STD — устанавливается (DF=1).

Для того чтобы эти команды можно было использовать для сравнения последовательности элементов, имеющих размерность байт, слово, двойное слово, необходимо использовать один из префиксов REPE или REPNE. Префикс REPE заставляет циклически выполняться команды сравнения до тех пор, пока содержимое регистра ECX/CX не станет равным нулю или пока не совпадут очередные сравниваемые элементы цепочек (флаг ZF=1). Префикс REPNE заставляет циклически производить сравнение до тех пор, пока не будет достигнут конец цепочки (ECX/CX=0) либо не встретятся различающиеся элементы цепочек (флаг ZF=0).

Допустим Вам необходимо сравнить пароль, вводимый с клавиатуры, с паролем находящимся где-то в памяти:

AssemblerВыделить код

1
2
3
4
5
6
7
8
9
10
11

PASSWORD db ‘fyfcnfcbz’,0Dh ;строка символов пароля
;плюс 0Dh код, генерируемый клавиатурой при нажатии 
;на клавишу «Enter»
MOV ECX,10 ;количество символов в пароле
XOR EBX,EBX ;позиционируемся на первый символ
A1: MOV AH,0 ;получение очередного символа
INT 16h ;из буфера клавиатуры в регистр AL
CMP AL,PASSWORD[EBX];сравнение с очередным символом
JNE EXIT ;если не совпал символ — выход из программы
INC EBX ;переход на следующий символ
LOOP A1 ;продолжаем сравнение

При использовании команды CMPS и префикса повторения REPE программа изменится следующим образом:

AssemblerВыделить код

1
2
3
4
5
6
7
8
9
10

PASSWORD DB 'fyfcnfcbz',0Dh ;Строка для сравнения
BUFFER_KLAV DB 50 DUP (?) ;буфер клавиатуры
CLD ;просмотр строки в направлении возрастания адресов
MOV ECX,10 ;длина цепочки
MOV ESI,OFFSET PASSWORD ;в DS:ESI адрес пароля
MOV EDI,BUFFER_KLAV ;в ES:EDI адрес буфера клавиатуры
REPE CMPSB ;сравнивать, пока равны, если не конец
JNZ M1 ; строки, то встретились разные элементы
;действия, если элементы строки совпали
M1: ;действия, если элементы строки не совпали

Команды загрузки строки LODSB/W/D/Q
(Загрузка строки, состоящей из байтов/слов/двойных слов =
"LOAD String Byte/Word/Double/Quadruple word operands")

Синтаксис команд

:

LODS <операнд>

LODSB

LODSW

LODSD

LODSQ

Семантика команды

: загрузка элемента из операнда в регистр-аккумулятор AL/AX/EAX.

Алгоритм работы

:

загрузить элемент из ячейки памяти, адресуемой парой DS:ESI/SI, в регистр AL/AX/EAX. Размер элемента задается неявно (для команды LODS определяется по размерности операнда) или явно в соответствии с применяемой командой (для команд LODSB, LODSW, LODSD);
изменить значение регистра SI/ESI на величину, равную длине элемента цепочки. Знак этой величины зависит от состояния флага DF:

DF=0 — значение положительное, то есть просмотр от начала цепочки к ее концу;
DF=1 — значение отрицательное, то есть просмотр от конца цепочки к ее началу.

Применение

: команды извлекают элемент из ячейки памяти в один из регистров. Перед командой LODS можно указать префикс повторения REP, но в этом нет особого смысла, так как обычно эту команду используют в некотором цикле для просмотра некоторой цепочки с элементами фиксированного размера:

AssemblerВыделить код

1
2
3
4

STR DB · · · ;строка данных STR
CLD ;будем двигаться от начала строки к ее концу
LEA SI,STR ;загружаем в регистр SI адрес строки STR
LODSB ;загрузить первый байт из STR в AL

Команды сохранения строки STOSB/W/D/Q

Синтаксис команд

:

STOS <операнд>

STOSB

STOSW

STOSD

STOSQ

Семантика команды

: сохранение элемента из регистра-аккумулятора AL/AX/EAX в последовательности (цепочке) операндов.

Алгоритм работы

:

записать элемент из регистра AL/AX/EAX в ячейку памяти, адресуемую парой ES: DI/EDI. Размер элемента задается неявно (для команды STOS определяется из размерности операнда) или конкретной применяемой командой (для команд STOSB, STOSW, STOSD);
изменить значение регистра DI на величину, равную длине элемента цепочки. Знак этого изменения зависит от состояния флага DF:

DF=0 — увеличить, что означает просмотр от начала цепочки к ее концу;
DF=1 — уменьшить, что означает просмотр от конца цепочки к ее началу.

Применение

: команды сохраняют элемент из регистров AL/AX/EAX в ячейку памяти. Перед командой STOS можно указать префикс повторения REP, в этом случае появляется возможность работы с блоками памяти, заполняя их значениями в соответствии с содержимым регистра ECX/CX:

AssemblerВыделить код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

;заполнить область памяти STR пробелами
STR db 'Какая-то строка'
LEN_STR=$-STR ;вычисляем длину строки STR
CLD ;двигаемся от начала строки STR
MOV AL,' ' ;поместим в регистр AL символ пробела
LEA DI,STR ;поместим в DI адрес начала STR
MOV CX,LEN_STR ;поместим в CX длину STR
REP STOSB ;заполняем пробелами строку STR
;пример совместной работы STOSB и LODSB: копировать одну
; строку в другую до первого пробела
STR1 db 'Какая-то строка'
LEN_STR1=$-STR
STR2 DB LEN_STR1 DUP (' ')
CLD
MOV CX,LEN_STR1
LEA SI,STR1
LEA DI,STR2
M1: LODSB
CMP AL,' '
JC EXIT ;выход, если пробел
STOSB
LOOP M1
EXIT:

Команды пересылки строк MOVSB/W/D/Q
(Пересылка строк байтов/слов/двойных/учетверенных слов =
“MOVE String Byte/Word/Double/Quadruple word”)

Синтаксис команд

:

MOVS <операнд1>,<операнд2>

MOVSB

MOVSW

MOVSD

MOVSQ

Семантика команды

: пересылка элементов из последовательности (цепочки) операнд1 в последовательность (цепочку) операнд2.

Алгоритм работы

:

выполнить копирование байта, слова, двойного или учетверенного слова из операнда2 в операнд1, при этом адреса элементов предварительно должны быть загружены:

адрес операнда2 — в пару регистров DS:ESI/SI (DS по умолчанию, допускается замена сегмента);
адрес операнда1 — в пару регистров ES:EDI/DI (замена сегмента не допускается);

в зависимости от состояния флага DF изменить значение регистров ESI/SI и EDI/DI:

если DF=0, то увеличить содержимое этих регистров на длину структурного элемента последовательности;
если DF=1, то уменьшить содержимое этих регистров на длину структурного элемента последовательности;

если есть префикс повторения, то выполнить определяемые им действия.

Применение

: команды пересылают элемент из одной ячейки памяти в другую. Размеры пересылаемых элементов зависят от применяемой команды. Команда MOVS может работать с элементами размером в байт, слово, двойное, учетверенное слово. В качестве операндов в команде указываются идентификаторы последовательностей этих элементов в памяти. Реально эти идентификаторы используются лишь для получения типов элементов последовательностей, а их адреса должны быть предварительно загружены в указанные выше пары регистров. Транслятор, обработав команду MOVS и выяснив тип операндов, генерирует одну из машинных команд MOVSB, MOVSW, MOVSD или MOVSQ. Для адресации операнд1 обязательно должен использоваться регистр ES.

Для того чтобы эти команды можно было использовать для пересылки последовательности элементов, имеющих размерность байт, слово, двойное, учетверенное слово, необходимо использовать префикс REP. Префикс REP заставляет циклически выполняться команды пересылки до тех пор, пока содержимое регистра ECX/CX не станет равным нулю:

AssemblerВыделить код

1
2
3
4
5
6
7
8
9
10

STR1 DB 'STR1 копируется в STR2'
LEN_STR1=$-STR1
A_STR1 DD STR1
STR2 DB LEN_STR1 DUP (' ')
A_STR2 DD STR2
MOV CX,LEN_STR1
LDS SI,STR1
LES DI,STR2
CLD
REP MOVSB

Пару команд LODS и STOS можно использовать вместо команды MOVS, если вам требуется примитивное шифрование или дешифровка данных. Наиболее часто используемый фрагмент пригоден как для шифрования, так и для дешифровки.

AssemblerВыделить код

1
2
3
4

V1: LODSD ;грузим в EAX
NOT EAX ;или XOR EAX,0F3D4B90Ah или ROR EAX,3;шифруем
STOSD ;пересылаем в память
LOOP V1

Текст получается зашифрованным от простого просмотра, но его криптостойкость равна нулю, если его захотят дешифровать.

Команды сканирования строк SCASB/W/D/Q
(Сканирование строки байтов/слов/двойных/учетверенных слов =
SCAN String Byte/Word/Double/Quadruple word”)

Синтаксис команд

:

SCAS <операнд>

SCASB

SCASW

SCASD

SCASQ

Семантика команды

: поиск значения в последовательности (цепочке) элементов операнда в памяти.

Алгоритм работы

:

выполнить вычитание (элемент цепочки <операнд>—(EAX/AX/AL)).
Элемент цепочки <операнд> локализуется парой ES:EDI/DI. Замена сегмента ES не допускается;
по результату вычитания установить флаги;
изменить значение регистра EDI/DI на величину, равную длине элемента цепочки. Знак этой величины зависит от состояния флага DF:

DF=0 — величина положительная, то есть просмотр от начала цепочки к ее концу;
DF=1 — величина отрицательная, то есть просмотр от конца цепочки к ее началу.

Применение

: команды сканирования сравнивают значение в регистре EAX/AX/AL с ячейкой памяти, локализуемой парой регистров ES:EDI/DI.

Размер сравниваемого элемента зависит от применяемой команды.

Команда SCAS может работать с элементами размером в байт, слово или двойное слово. В качестве операнда в команде указывается идентификатор последовательности элементов в памяти. Реально этот идентификатор используется лишь для получения типа элементов последовательности, а ее адрес должен быть предварительно загружен в указанную выше пару регистров. Транслятор, обработав команду SCAS и выяснив тип операндов, генерирует одну из машинных команд: SCASB, SCASW или SCASD. Для адресации операнда обязательно должен использоваться регистр ES.

Для того чтобы эту команду можно было использовать для поиска значения в последовательности элементов, имеющих размерность байт, слово или двойное слово, необходимо использовать один из префиксов REPE или REPNE. Эти префиксы не только заставляют циклически выполняться команду поиска, пока

, но и отслеживают состояние флага ZF:

AssemblerВыделить код

1
2
3
4
5
6
7
8
9
10
11
12

STR DB '...' ;сосчитаем число пробелов в строке STR
LEN_STR=$-STR ;вычислим длину строки
LEA DI,STR ;адрес начала строки в DI
MOV CX,LEN_STR ;длину строки — в CX
MOV AL,' ' ;в AL символ, который ищем
MOV BX,0 ;счетчик для подсчета пробелов в строке
CLD ;считаем от начала строки
CYCL: REPE SCASB ;переход на EXIT, если цепочка просмотрена
JCXZ EXIT ;полностью
INC BX ;нашли пробел — увеличим счетчик пробелов
JMP CYCL ;в начало цикла
EXIT:

Вернуться к обсуждению:

Электронный учебник Assembler