sScas адреса_приймача
casd
(SCAning
String Double Word)
- сканувати
ланцюжок
подвійних
слів.
Команда scas
Команда має один операнд, що позначає місцезнаходження ланцюжка в додатковому сегменті (адреса ланцюжка має бути заздалегідь сформована у es:edi/di). Транслятор аналізує тип ідентифікатора адреса_приймача, який позначає ланцюжок в сегменті даних, і формує одну з трьох машинних команд scasb, scasw або scasd. Умова пошуку для кожної з цих трьох команд знаходиться в строго визначеному місці. Так, якщо ланцюжок описаний за допомогою директиви db, то шуканий елемент повинен бути байтом і перебувати в al, а сканування ланцюжка здійснюється командою scasb; якщо ланцюжок описаний за допомогою директиви dw, то це - слово в ax, і пошук ведеться командою scasw; якщо ланцюжок описаний за допомогою директиви dd, то це - подвійне слово в eax, і пошук ведеться командою scasd. Принцип пошуку той же, що і в команді порівняння cmps, тобто послідовне виконання віднімання (вміст_регістра_аккумулятора мінус вміст_чергового_елемента_ланцюжка). Залежно від результатів віднімання проводиться встановлення прапорів, при цьому самі операнди не змінюються. Так само, як і у випадку команди cmps, з командою scas зручно використовувати префікси repe/repz або repne/repnz:
• repe або repz - якщо потрібно організувати пошук до тих пір, поки не буде виконано одну з двох умов:
• досягнуто кінець ланцюжка (вміст ecx/cx = 0);
• в ланцюжку зустрівся елемент, відмінний від елемента в регістрі al/ax/eax;
• repne або repnz - якщо потрібно організувати пошук до тих пір, поки не буде виконано одну з двох умов:
• досягнуто кінець ланцюжка (вміст ecx/cx = 0);
• в ланцюжку зустрівся елемент, що співпадає з елементом в регістрі al/ax/eax.
Таким чином, команда scas з префіксом repe/repz дозволяє знайти елемент ланцюжка, що відрізняється за значенням від заданого в акумуляторі. Команда scas з префіксом repne/repnz дозволяє знайти елемент ланцюжка, що збігається за значенням з елементом в акумуляторі.
В якості прикладу розглянемо лістинг 3, який здійснює пошук символу в рядку.
У програмі використовується команда-примітив scas. Символ задається явно (рядок 20). Префікс повторення — repne.
Лістинг 3. Пошук символу в рядку командою scas <1> ;prg_13_3.asm <2> MASM <3> MODEL small <4> STACK 256 <5> .data <6> ;тексти повідомлень <7> fnd db 0ah,0dh, 'Символ знайдений! ','$' <8> nochar db 0ah,0dh,'Символ не знайдений.','$' <9> ;рядок пошуку <10> string db 'Пошук символу в цьому рядку.',0ah,0dh,'$' <11> .code <12> ASSUME ds:@data,es:@data <13> main: <14> mov ax,@data <15> mov ds,ax <16> mov es,ax ;налаштування ES на DS <17> mov ah,09h <18> lea dx,string <19> int 21h ; виведення повідомлення string <20> mov al,'а' ; символ для пошуку - 'а'(кирилиця) <21> cld ; скидання прапора df <22> lea di,string ; завантаження в es:di зміщення рядка <23> mov cx,29 ; для префікса repne - довжина рядка <24> ; пошук в рядку (поки шуканий символ і символ в рядку не співпадуть) <25> ; вихід при першому збігу <26> repne scas string <27> je found ; якщо рівні - перехід на обробку, <28> failed: ; інакше виконуємо деякі дії <29> ; виведення повідомлення про те, що символ не знайдено <30> mov ah,09h <31> lea dx,nochar <32> int 21h ; виведення повідомлення nochar <33> jmp exit ; на вихід <34> found: ; збіглися <35> mov ah,09h <36> lea dx,fnd <37> int 21h ; виведення повідомлення fnd <38> ; тепер, щоб дізнатися про місце, де збігся елемент у рядку, необхідно <39> ; зменшити значення в регістрі di і вставити потрібний обробник <40> dec di <41> ;... вставте обробник <42> exit: ; вихід <43> mov ax,4c00h <44> int 21h <45> end main |
5. Завантаження елемента ланцюжка в акумулятор
Ця операція-примітив дозволяє витягти елемент ланцюжка і помістити його в регістр-акумулятор al, ax або eax. Цю операцію зручно використовувати разом з пошуком (скануванням) для того, щоб, знайшовши потрібний елемент, витягнути його (наприклад, для зміни). Можливий розмір витягуваного елемента визначається застосовуваної командою.
Програміст може використовувати чотири команди завантаження елемента ланцюжка в акумулятор, що працюють з елементами різного розміру:
lods адреса_джерела (LOaD String) - завантажити елемент з ланцюжка в регістр-акумулятор al/ax/eax;
lodsb (LOaD String Byte) - завантажити байт з ланцюжка в регістр al;
lodsw (LOaD String Word) - завантажити слово з ланцюжка в регістр ax;
lodsd (LOaD String Double Word) - завантажити подвійне слово з ланцюжка в регістр eax.
Розглянемо роботу цих команд на прикладі lods.
К
lods
адреса_джерела
Команда має один операнд, що позначає рядок в основному сегменті даних. Робота команди полягає в тому, щоб витягти елемент з ланцюжка за адресою, що відповідає вмісту пари регістрів ds:esi/si, і помістити його в регістр eax/ax/al. При цьому вміст esi/si піддається інкрементe або декрементe (в залежності від стану прапора df) на значення, що дорівнює розміру елемента. Цю команду зручно використовувати після команди scas, що локалізує місце розташування шуканого елементу в ланцюжку. Префікс повторення в цій команді може і не знадобитися - все залежить від логіки програми.
В якості прикладу розглянемо лістинг 4. Програма порівнює командою cmps два ланцюжки байтів в пам'яті string1 і string2 і поміщає перший байт, що не збігся зі string2 в регістр al. Для завантаження цього байту в регістр-акумулятор al використовується команда lods. Префікса повторення в команді lods немає, тому що він просто не потрібний.
Лістинг 4. Використання lods для завантаження байту в регістр al <1> ;prg_13_4.asm <2> MASM <3> MODEL small <4> STACK 256 <5> .data <6> ; рядки для порівняння <7> string1 db 'Пошук символу в цьому рядку.', 0ah, 0dh, '$' <8> string2 db 'Пошук символу не в цьому рядку.', 0ah, 0dh, '$' <9> mes_eq db 'Рядки збігаються.', 0ah, 0dh, '$' <10> fnd db 'Елемент, що не збігся, в регістрі al', 0ah, 0dh, '$' <11> .code <12> ; прив'язка ds і es до сегмента даних <13> assume ds:@data,es:@data <14> main: <15> mov ax,@data ; завантаження сегментних регістрів <16> mov ds,ax <17> mov es,ax ; налаштування es на ds <18> mov ah,09h <19> lea dx,string1 <20> int 21h ; виведення string1 <21> lea dx,string2 <22> int 21h ; виведення string2 <23> cld ; скидання прапора df <24> lea di,string1 ; завантаження в es:di зміщення рядка string1 <25> lea si,string2 ; завантаження в ds:si зміщення рядка string2 <26> mov cx,29 ; для префікса repe - довжина рядка <27> ; пошук в рядку (поки потрібний символ і символ в рядку не рівні) <28> ; вихід - при першому, що не збігся <29> repe cmps string1,string2 <30> jcxz eql ; якщо рівні - перехід на eql <31> jmp no_eq ; якщо не рівні - перехід на no_eq <32> eql: ; виводимо повідомлення про збіг рядків <33> mov ah,09h <34> lea dx,mes_eq <35> int 21h ; виведення повідомлення mes_eq <36> jmp exit ; на вихід <37> no_eq: ; обробка неспівпадання елементів <38> mov ah,09h <39> lea dx,fnd <40> int 21h ; виведення повідомлення fnd <41> ; тепер, щоб витягти елемент, що не збігся, з рядка в регістр-акумулятор, <42> ;зменшуємо значення регістра si і тим самим переміщаємося до дійсної позиції елемента в рядку <43> dec si ; команда lods використовує ds:si-адресацію <44> ; тепер ds:si вказує на позицію в string2 <45> lods string2 ; завантажимо елемент з рядка в AL <46 > ;Неважко здогадатися, що в нашому прикладі це символ "н" <47> exit: ;вихід <48> mov ax,4c00h <49> int 21h <50> end main
|
6. Перенесення елемента з акумулятора в ланцюжок
Ця операція-примітив дозволяє провести дію, зворотну команді lods, тобто зберегти значення з регістра-акумулятора в елементі ланцюжка. Цю операцію зручно використовувати разом з операцією пошуку (сканування) scans і завантаження lods, з тим, щоб, знайшовши потрібний елемент, витягти його в регістр і записати на його місце нове значення. Команди, що підтримують цю операцію-примітив, можуть працювати з елементами розміром 8, 16 або 32 біт. TASM надає програмісту чотири команди збереження елемента ланцюжка з регістра-акумулятора, що працюють з елементами різного розміру:
stos адреса_приймача (STOre String) - зберегти елемент з регістра-аккум. al/ax/eax в ланцюжку;
stosb (STOre String Byte) - зберегти байт з регістра al в ланцюжку;
stosw (STOre String Word) - зберегти слово з регістра ax в ланцюжку;