Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
л.р.1-12.СПРГ-1(40, укр).doc
Скачиваний:
5
Добавлен:
27.08.2019
Размер:
2.33 Mб
Скачать

4. Приклади виконання деяких типових задач обробки рядків

Приклад 1. Пересилання і копіювання даних.

Для виконання операцій пересилання і копіювання рядків і масивів дуже зручно використовувати команду movs. Ця команда може застосовуватися для пересилання одиночних байтів, слів або подвійних слів, однак із префіксом rер і лічильником байтів у регістрі ЕСХ (СХ) можна виконувати пересилання будь-якого числа символів більш ефективно. При цьому в регістрі EDI (DI) повинний утримуватися відносна адреса області пам'яті, у яку буде поміщений рядок, а адресація джерела виконується через регістр ESI (SI).

Таким чином, перед виконанням команди movs варто ініціалізувати регістри ESI (SI) і EDI (DI) необхідними відносними адресами джерела і приймача. У залежності від стану прапора DF команда movs робить збільшення або зменшення на 1 (для байта), на 2 (для слова) і на 4 (для подвійного слова) умісту регістрів EDI (DI) і ESI (SI).

При використанні команди movs (b, w, d) компілятор асемблера припускає наявність коректного розміру строкових даних і не вимагає кодування операндів у команді. Для команди movs розмір повинний бути закодований в операндах. Наприклад, якщо перемінні STRING_A і STRING_B визначені як байтові за допомогою директиви DB, те наступна команда буде виконувати пересилання байтів, кількість яких визначене в регістрі СХ, з перемінної STRINGB у перемінну STRINGA:

rep movs STRING_A, STRING_B

Цю команду можна записати в альтернативній формі:

rep movs ES: BYTE PTR [DI], DS:[SI]

У будь-якому випадку перед початком операції варто помістити в регістри DI і SI адреси STRING_A і STRING_B.

Приклад виконання.

format pe

start:

cld

; установимо прапор напрямку DF для інкременту

lea esi, [src]

; адреса джерела -> DS: SI

lea edi, [dst]

; адреса приймача -> ES: DI

mov ecx, [len]

; кількість символів, що копіюються -> CX

rep movsb

; копіювання символів

mov edx, dst

; адреса результуючого рядка

ret

; секція визначення даних

src DB “COPIED TESTING STRING” len=$-src

dst DB len DUP (' ') DB '$'

Приклад 2. Порівняння рядків і масивів

Операція порівняння рядків і масивів може виконуватися як за допомогою звичайних команд асемблера, так і з використанням спеціальної ланцюжкової команди cmps. Команда cmps порівнює вміст однієї області пам'яті (яка адресується регістрами DS: SI або ESI) із вмістом іншої області пам'яті (яка адресується регістрами ES: DI або EDI). У залежності від значення прапора DF команда cmps також збільшує або зменшує адреси в регістрах ESI (SI) і EDI (DI) на 1 для байта, на 2 для слова і на 4 для подвійного слова. Команда cmps впливає на прапори AF, CF, OF, PF, SF і ZF. При використанні префікса rep регістр ЕСХ (СХ) повинний містити кількість порівнюваних перемінних, при цьому команда cmps може порівнювати будь-яке число байтів або слів.

При виконанні команди cmps (а також seas) можлива установка прапорів стану так, щоб операція могла завершитися відразу після виявлення необхідної умови.

При рішенні даної задачі необхідно визначити розмір порівнюваних рядків, а тільки потім – робити порівняння.

Приклад. Порівняння рядків по декількох критеріях

format pe

start:

mov esi, str1

; адреса рядка - джерела

mov edx, esi

mov eax, 0

src_again:

cmp al, [esi]

je check_dst

inc esi

jmp src_again

check_dst:

mov edi, str2

; адреса рядка - приймача

mov ebx, edi

dst_again:

cmp al, [edi]

je check_size

inc edi

jmp dst_again

check_size:

mov ecx, ESI

sub ECX, EDX

mov EAX, EDI

sub EAX, EBX

cmp EAX, ECX

je compare

lea EAX, [size_diff]

jmp exit

compare:

cld

mov ESI, EDX

mov EDI, EBX

repe cmpsb

je equal

lea EAX, [s_ne]

jmp exit

equal:

lea EAX, [s_eq]

exit:

ret

s_eq DB “Strings are equal”,0

s_ne DB “Strings are not equal”,0

size_diff DB “Strings have different size!",0

str1 db “1st string”,0

str2 db “1st string”,0

Приклад 3. Сканування рядків і масивів

У процесі обробки текстової інформації може виникнути необхідність маніпулювання елементами рядків або масивів. Найбільше часто виконуються такі операції:

• заміна визначених символів у тексті іншими, наприклад підстановка пробілів замість різних символів, що редагують, (табуляції, повернення каретки і перекладу рядка)

  • ; підрахунок кількості елементів рядків або масивів, що задовольняють якій-небудь умові

  • ; обробка окремого елемента масиву чисел, наприклад обчислення модуля числа, квадратного кореня і т. д.

Мова асемблера має широкі можливості для виконання таких операцій. Ми розглянемо різні способи сканування рядків і масивів і почнемо з використання спеціально призначеної для цього команди seas. Команда seas відрізняється від команди cmps тим, що виконує перегляд рядка або масиву в пошуку визначеного елемента. Команда seas порівнює вміст області пам'яті, яка адресується регістрами ES: DI або EDI, із умістом регістра AL, АХ або ЕАХ.

Операція порівняння здійснюється шляхом вирахування вмісту комірки пам'яті з умісту AL, АХ або ЕАХ, із установленням при цьому відповідних прапорів. У залежності від значення прапора DF команда seas збільшує або зменшує адресу в регістрі DI (EDI) на 1 для байта, на 2 для слова і на 4 для подвійного слова. Команда seas установлює прапори AF, CF, OF, PF, SF і ZF. При використанні префікса rep і розміру рядка в регістрі СХ (ЕСХ) команда seas може сканувати рядки і масиви будь-якого розміру. Ця команда особливо корисна при розробці текстових редакторів, де програма повинна сканувати рядка, виконуючи пошук знаків пунктуації.

Приклад. Пошук і заміна чисел менше заданого в масиві цілих чисел. Даний приклад ілюструє можливості ланцюжкових команд по обробці масивів чисел.

format pe

mov ECX,???

; размер массива -> ECX

mov EDI,???

; адреса першого елемента-> EDI

mov EAX,???

; порівнюване значення

cld

; установити прапор напрямку

; убік збільшення адрес

next:

scasd

; порівнюємо елементи масиву

; із умістом EAX

jg change

; число в EAX більше

; поточного елемента?

loop next

jmp exit

change:

елемент масиву менше

; числа в EAX

mov dword [EDI-4], 0

; замінити вміст осередку

; пам'яті на 0

dec ECX

; декремент лічильника

jmp next

exit:

ret

; тут задаємо масив

Приклад 4. Використання команд lods і stos

Команда lods може завантажити з пам'яті один байт у регістр AL, одне слово в регістр АХ або одне подвійне слово в регістр ЕАХ. Адреса пам'яті визначається або регістрами DS: SI, або регістром ESI. Як і для попередніх ланцюжкових команд, у залежності від значення прапора DF відбувається інкремент або декремент умісту регістра SI або ESI. Ця команда використовується без префікса повторення rep.

Якщо порівнювати команди mov і lods, то при однаковому результаті mov вимагає трьох байтів машинного коду, у той час як lods — тільки одного. Команда lods додатково вимагає ініціалізації регістра SI або ESI. Команда lods зручна в тих випадках, коли потрібно аналізувати кожен байт, слово або подвійне слово і виконувати з ними визначені дії. Команда 1ods підійде, наприклад, при заміні окремих символів рядка, для реверсування рядка, тобто зміни порядку проходження елементів на зворотний, і т. д. Команда lods, як і інші ланцюжкові команди, має модифікації для роботи з байтами (lodsb), зі словами (lodsw) і подвійними словами (lodsd).

Команда stos записує вміст одного з регістрів AL, АХ або ЕАХ у байт, слово або подвійне слово в пам'яті. Адреса пам'яті визначається регістрами ES: DI або регістром EDI. У залежності від значення прапора DF команда stos збільшує або зменшує адресу в регістрі DI на 1 для байта, на 2 для слова і на 4 для подвійного слова. Команда stos, використовувана з префіксом rep, дозволяє ініціалізувати область даних якими-небудь значеннями, наприклад пробілами або нулями. Команда stos, як і інші ланцюжкові команди, має модифікації для роботи з байтами (stosb), зі словами (stosw) і подвійними словами (stosd).

Приклад. Підрахунок числа символів у рядку

format pe

start:

lea esi, [src]

mov ecx, len

cld

xor ebx, ebx

next:

lodsb

cmp al, 's'

sete bl

; див. примітку

add [cnt], ebx

loop next

lea eax, [cnt]

ret

cnt dd 0

src db “this string contains five words”,0

len = $-src-1

Примітка: інструкції, утворені за допомогою додавання умовного мнемоніка) до мнемоніку set привласнюють байтові одиницю, якщо умова щира, і нуль, якщо умова не виконується, див. лабораторну роботу №4 “Команди передачі керування”.

Операндом повинний бути 8-бітний регістр загального призначення або байт у пам'яті.

setne al ; одиницю в al, якщо прапор нуля порожній

seto byte [bx] ; одиницю в байт, якщо є переповнення

Приклад 5. Масиви рядків

У багатьох випадках програмістові приходиться мати справа не з окремими рядками, а з групою, або масивом, рядків. Дуже часто в програмах потрібно, у залежності від результатів якихось проміжних обчислень, відображати відповідну інформацію, що утримується в одній з рядків масиву.

Процедура приймає як параметр номер рядка, рівний 0,1 або 2, і повертає адреса обраної раніше рядка. Як індексатор рядка обраний регістр ЕСХ, у якому отриманий номер рядка збільшується на 4 (адреса рядка представлена подвійним словом). У регістр ESI міститься адреса масиву рядків (він збігається з адресою подвійного слова, що містить адресу нульового рядка). Для доступу до подвійного слова, що містить адресу необхідного рядка, випливає до вмісту ESI додати вміст регістра ЕСХ. Нарешті, у регістр ЕАХ міститься адреса шуканого рядка.

Приклад.

format pe

jmp start

s1 DB “It's a String s1”,0

s2 DB “Here is String s2”,0

s3 DB “String s3 is placed here”,0

label saddr dword

DD s1

DD s2

DD s3

start:

mov ECX,????

; індекс рядка -> ECX

shl ECX, 2

; перетворити в подвійне слово

lea ESI, [saddr]

; адреса масиву рядків saddr –> ESI

add ESI, ECX

; адреса подвійного слова, що містить

; адреса рядка -> ESI

mov EAX, [ESI]

; адреса шуканого рядка -> EAX

ret

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]