Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Labs / 5_String / Lab5

.pdf
Скачиваний:
16
Добавлен:
16.04.2013
Размер:
254.4 Кб
Скачать

1

Лабораторная работа по курсу "Организация ЭВМ и систем"

Использование команд обработки строк в ассемблере IBM PC

Цель работы: познакомиться с командами обработки блоков байтов (слов, двойных слов).

1. Команды обработки строк

Команды обработки строк производят операции пересылки, сравнения, сканирования, загрузки и сохранения над блоками байтов и слов (в 32-битных МП Intel - и двойных слов) памяти длиной до 64 Кбайт (в 32-битных МП - до 4 Гбайт).

Команды обработки строк обрабатывают строку по одному байту, слову или двойному слову за прием. При этом оба операнда находятся в памяти: строка-источник находится в сегменте данных и адресуется при помощи DS:SI, строка-приемник - в дополнительном сегменте данных и адресуется при помощи ES:DI. (В 32-битных МП - при помощи DS:ESI и ES:EDI соответственно.) Команды обработки строк автоматически модифицируют указатели для адресации следующих элементов строки-источника и строки-приемника по завершении выполнения команды.

Флаг направления. Флаг направления DF в регистре флагов FLAGS (EFLAGS) определяет, будут ли значения SI и DI увеличены или уменьшены по завершении выполнения команды обработки строк. Если DF=0, это соответствует прямому направлению (от меньших адресов к бoльшим), значения регистров SI и DI увеличиваются после обработки одного элемента строки; если DF=1, это соответствует обратному направлению, значения SI и DI уменьшаются. Состоянием флага DF можно управлять с помощью двух команд:

CLD (CLear Direction flag)

- сбросить флаг направления в ноль;

STD (SeT Direction flag)

- установить флаг направления в единицу.

Префиксы повторения. Одна команда обработки строк может обработать группу последовательных элементов памяти. Для этого перед ней требуется указать префикс повторения REP (от REPeat), который заставляет процессор выполнить повторения команды CX/ECX раз. Например, последовательность команд

mov

cx, 500

rep movs

dest,source

заставит процессор выполнить команду MOVS 500 раз, уменьшая значение регистра СХ после каждого повторения.

Остальные префиксы повторения используют при принятии решения о продолжении или прекращении повторений флаг нуля ZF. Поэтому они применимы только к командам сравнения строк и поиска значения в строке, которые воздействуют на флаг ZF.

Префикс REPNE (REPeat while Not Equal - повторять, пока не равно), имеющий синоним REPNZ (REPeat while Not Zero - повторять, пока не нуль), дают указание повторять команду, пока флаг ZF равен 0 и значение регистра CX не равно 0. Если приписать префикс REPNE команде сравнения строк CMPS, то операция сравнения будет повторяться до первого совпадения элементов строк или уменьшения значения в регистре CX до нуля. Например, последовательность команд

mov cx,100

dest,source

repne cmps

будет поэлементно сравнивать строки SOURCE и DEST до тех пор, пока не будет просмотрено 100 пар элементов или пока в строке DEST не найдется элемент, совпадающий с соответствующим ему элементом строки SOURCE.

Действие префикса REPE (REPeat while Equal - повторять, пока равно), имеющего синоним REPZ (REPeat while Zero - повторять, пока нуль) обратно действию префикса REPNE (REPNZ). Он дает указание повторять следующую за ним команду, пока флаг ZF равен 1 и значение в регистре CX не равно 0. Последовательность команд

mov cx,100

2

repe

cmps

dest,source

будет поэлементно сравнивать строки SOURCE и DEST до тех пор, пока не будет просмотрено 100 пар элементов или пока в строке DEST не найдется элемент, НЕ совпадающий с соответствующим ему элементом SOURCE. Действие префиксов и флага направления распространяется на все команды обработки строк.

Команды пересылки строк. Команда MOVS копирует байт или слово (а также двойное слово в 32-битных МП) из одной части памяти в другую. Она имеет формат:

movs dest, source

Здесь SOURCE - строка в сегменте данных, а DEST - строка в дополнительном сегменте. Как и в случае команды CMPS, МП использует регистр SI (ESI) для адресации в сегменте данных и регистр DI (EDI) для адресации в дополнительном сегменте. Указание в качестве операндов стро- ки-приемника и строки-источника не освобождает от необходимости инициализировать сегменты ES:DI и DS:SI перед выполнением команды MOVS. По виду операндов определяется только размер копируемых элементов - байты, слова, двойные слова.

Можно заменить сегмент, соответствующий регистру SI, но не регистру DI. Например, можно добиться копирования строки из одной части дополнительного сегмента в другую.

Следующий фрагмент копирует 100 байтов из строки SOURCE, находящейся в сегменте данных, в строку DEST, которая находится в дополнительном сегменте.

 

cld

si,source

; DF=0 для обработки в прямом направлении.

 

lea

;Занести смещение source в SI,

 

lea

di,es:dest

;а смещение dest - в DI

rep

mov

cx,100

;CX - счетчик элементов

movs

dest,source

;Скопировать 100 байтов

При этом в программе должен быть описан сегмент данных со строкой-источником и дополнительный сегмент со строкой-приемником, например:

dest db

100 dup(?)

В данном случае команда MOVS пересылает байты, т.к. указана директива DB - резервирование байтов. Если бы на месте DB стояла директива DW, то команда MOVS пересылала бы слова, а не байты. Для 32-разрядных МП наиболее эффективной является пересылка двойных слов.

На самом деле кодового эквивалента команде MOVS не существует. Она преобразуется либо в команду MOVSB (пересылка байтов), либо в команду MOVSW (пересылка слов), либо MOVSD (пересылка двойных слов, только для 32-битных МП). Аргументы в команде MOVS нужны только для извлечения информация о размере пересылаемых элементов, которая используется транслятором для принятия решения об использовании той или иной формы команды.

Команды MOVSB, MOVSW и MOVSD могут быть применены и в явном виде. Аргументы им в таком случае не требуются. Пример, приведенный выше, можно переписать в виде:

 

cld

si,

source

 

lea

 

lea

di,

es:dest

rep

mov

cx,

100

movsb

 

 

В виде кодов оба примера будут выглядеть идентично. Для большей надежности при написании программ рекомендуется пользоваться именно явными формами команд MOVSB, MOVSW и MOVSD. Остальные строковые команды - SCAS, CMPS, LODS, STOS - тоже имеют явные формы, и все сказанное относительно MOVS справедливо и для них.

Команды сравнения строк. Действие команды CMPS похоже на действие обычной команды CMP. Подобно команде CMP, команда CMPS сравнивает операнды, вычитая их один из другого. Однако CMP вычитает операнд-источник (SOURCE) из операнда-приемника (DEST), а CMPS - наоборот, операнд-приемник (DEST) из операнда-источника (SOURCE). Команда CMPS имеет формат

cmps

dest, source

DEST и SOURCE имеют тот же смысл, что и в описании команды MOVS.

3

Команды сканирования строк. Основная команда группы команд сканирования строк SCAS (SCAn String) имеет формат

scas dest

где DEST идентифицирует строку в дополнительном сегменте, смещение первого элемента которой загружается в регистр DI/EDI. Сканирование заключается в последовательном просмотре элементов строки и сравнении их с шаблоном поиска, который хранится в регистре AL (если это байт), AX (если это слово) или EAX (двойное слово - в 32-битных МП). Следующий фрагмент

 

cld

di, es:s_string

 

 

lea

;Код пробела

 

mov

al, 32

repe

mov

cx, 100

 

scas

s_string

 

 

je

notfound

 

 

...

 

 

notfound:...

просматривает до 100 элементов строки байтов S_STRING в поисках элемента, отличного от пробела. Если такой элемент обнаружен, то сканирование прекращается, даже если строка просмотрена не полностью, в регистре DI остается смещение следующего за найденным элемента, а флаг ZF сбрасывается в 0 (что указывает на несовпадение при сравнении). Последующая команда JE покажет, найден такой элемент (ZF=0 - отсутствие перехода) или не найден (ZF=1 - переход).

Команды загрузки и сохранения элемента строки. Команда LODS (LoaD String) пересыла-

ет элемент операнда-источника, адресованный регистром SI/ESI, из сегмента данных в регистр AL (при пересылке байта), в AX (при пересылке слова) или EAX (при пересылке двойного слова), а затем изменяет SI (ESI) так, чтобы он указывал на следующий элемент строки. Следующий фрагмент программы сравнивает строки DEST и SOURCE длиной 50 байтов каждая в поисках первой пары несовпадающих элементов. Если обнаружено несовпадение, то элемент строки SOURCE загружается в регистр AL.

 

cld

di, es:dest

;DF=0 - прямое направление

 

lea

;Загрузка смещения приемника

 

lea

si, source

;Загрузка смещения источника

repe

mov

cx, 500

;Загрузка счетчика элементов

cmpsb

match

;Искать до несовпадения

 

jcxz

;Несовпадение обнаружено?

 

dec

si

;Да. Подправить регистр SI

 

lods

source

;Считать элемент в регистр AL

 

...

 

 

match: ...

Команда сохранения элемента строки STOS (STOre String) пересылает байт из регистра AL или слово из регистра AX/EAX в элемент операнда DEST, находящийся в дополнительном сегменте и адресуемый регистром DI/EDI, а затем изменяет значение регистра DI/EDI так, чтобы оно указывало на следующий элемент строки. Будучи многократно повторенной, команда STOS удобна для заполнения строки заданным значением. Например, следующий фрагмент программы сканирует строку W_STRING длиной в 200 слов в поисках первого ненулевого элемента. Если такой элемент обнаружен, то он и следующие за ним пять слов обнуляются.

 

cld

di, es:w_string

;Адрес строки

 

lea

 

mov

ax, 0

;Искомое значение

repe

mov

cx, 200

;Счетчик поиска

scasw

w_zero

;Искать

 

jcxz

;Нашли не нуль?

 

sub

di, 2

;Да. Подправить DI,

rep

mov

CX, 6

;и шесть слов

stos

w_string

;заполнить нулями.

w_zero: ...

 

;Нет, Продолжить отсюда.

Команда JCXZ (переход, если CX=0; у 32-битных МП есть команда JECXZ, проверяющая на 0

4

регистр ECX) удобна для контроля достижения конца строк при многократно повторяемых строковых операциях. Так как эта команда не реагирует на состояние флагов, то несовпадение последних элементов строк (или одноэлементных строк) или несоответствие образцу может быть обнаружено уже после выполнения перехода (на метку MATCH - в первом примере, на W_ZERO - во втором), где необходимо предусмотреть дополнительную проверку.

2. Пример

Задание: считать с клавиатуры строку символов, преобразовать все большие латинские буквы в маленькие и вывести результат на экран.

sseg

segment para stack 'stack'

 

 

sseg

db

64 dup

 

 

 

ends

 

 

 

 

data

segment

 

 

 

buffer

db

80,0

 

 

 

string

db

80 dup(0),'$'

 

 

 

prompt

db

'Вариант Х- Считать строку и преобразовать',13,10

 

db

'прописные буквы в строчные ',13,10

 

 

db

'Студент Иванов И.И., группа МП-25',13,10,10

message

db

'Введите строку > $'

 

 

db

13,10,'Результат > '

 

 

res_str

db

80 dup(0)

 

 

 

ending

db

13,10,'Конец',13,10,'$'

 

 

letter

db

13,10,'Символ '

 

 

sym

db

?,'$'

 

 

 

tranx

db

' преобразован в строчный$'

 

 

data

ends

 

 

 

 

main

segment

 

 

 

start:

assume cs:main,ds:data,ss:sseg,es:data

 

mov

ax, data

; ds = адрес сегмента data

 

mov

ds, ax

 

mov

es, ax

; es = адрес сегмента data

 

mov

dx, offset prompt ; приглашение

 

 

 

mov

ah, 9h

 

 

 

 

int

21h

 

 

 

 

mov

dx, offset buffer ; куда считывать

 

 

mov

ah, 0Ah

; считать строку

 

 

int

21h

mov si,offset string

 

lea

si, string

; эквивалентно команде

 

lea

di, es:res_str

; эквивалентно команде

mov si,offset es:string

 

mov

cx, 0

 

; длина считанной строки

next:

mov

cl, byte ptr buffer+1

lodsb

 

; считать очередной символ

 

mov

byte ptr sym, al

 

 

 

push

ax

 

; сообщение

 

mov

dx, offset letter

 

mov

ah, 9h

 

 

 

 

int

21h

 

 

 

 

pop

ax

 

; Буква?

 

 

cmp

al, 'A'

 

 

 

jl

nosym

 

 

 

 

cmp

al, 'Z'

 

 

 

 

jg

nosym

 

 

 

 

push

ax

 

; сообщение

 

mov

dx, offset tranx

 

mov

ah, 09h

 

 

 

 

int

21h

 

 

 

 

pop

ax

 

; да, преобразование

nosym:

xor

al, 00100000B

 

stosb

 

; нет

 

5

 

loop

next

; на следующий

 

mov

al, '$'

; фиксируем конец строки

 

stosb

dx, offset message

 

mov

; результат

 

mov

ah, 9h

 

 

int

21h

; завершающее сообщение

 

mov

dx, offset ending

 

mov

ah, 9h

 

 

int

21h

; Функция 4Ch завершения программы

 

mov

ax,4C00h

main

int

21h

 

ends

start

 

 

end

 

3.Порядок выполнения работы

1.При подготовке к лабораторной работе (дома) занесите в отчет текст программы своего варианта и краткие сведения о командах обработки строк;

2.Выполните программу своего варианта. Результаты покажите преподавателю.

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

4. Варианты заданий.

Программа должна быть написана с использованием команд обработки строк. Размер строк по-

лагать равным 80 байтам. В начале программы вывести ФИО, группу и описание задания.

1, 10, 19. Считать с клавиатуры строку символов, затем каждый пробел в ней заменить символом подчеркивания. Вывести результат на экран.

2, 11, 20. Считать с клавиатуры строку символов, копировать ее в другую строку, исключая пробелы и знаки препинания: точки, запятые, точки с запятой, двоеточия. Вывести результат на экран.

3, 12, 21. Считать с клавиатуры две строки символов, сформировать третью строку, состоящую из совпадающих символов первой и второй строк. Вывести результат на экран.

4, 13, 22. Считать с клавиатуры две строки символов, сформировать третью строку, состоящую из символов первой строки, не совпадающих с соответствующими символами из второй строки. Вывести результат на экран.

5, 14, 23. Считать с клавиатуры строку символов, сформировать другую строку, представляющую собой первую строку в обратном порядке. Подсчитать количество знаков препинания и вывести результат на экран.

6, 15, 24. Моделирование ввода пароля: считать посимвольно с клавиатуры строку символов без эхо-печати. Если вводится пробел, то выдать звуковой сигнал, иначе отпечатать на экране звездочку и сохранить введенный символ в строке. Затем вывести строку на экран.

7, 16, 25. Считать с клавиатуры строку символов, затем запросить еще один символ, подсчитать количество его появлений в строке и вывести на экран.

8, 17, 26. Считать с клавиатуры строку символов. В случае появления среди первых 15 символов символа * вывести на экран его порядковый номер.

9, 18. Сравнить введенную строку со строкой, находящейся в памяти, и вывести на экран позиции несовпадающих символов.

---------------------------------------------------------------------------------------------------

© Лабораторная работа подготовлена А.Я. Пьянзиным.