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

гос / sp-lect (1)

.pdf
Скачиваний:
18
Добавлен:
16.02.2016
Размер:
2.59 Mб
Скачать

xor esi,esi mov ax,[ebx] mov edi,esi

mov ecx, lengthof x dec ecx

inc esi

@@: cmp word ptr [ebx+esi*2],ax cmovg ax,word ptr [ebx+esi*2] cmovg edi,esi

inc esi loop @B ret

end start

4.2Багатовимірні масиви

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

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

Елементи в рядку адресуються за зміщенням від значення адреси початку рядка в базовому регістрі. Значення зміщення зберігається в індексному регістрі і змінюється у внутрішньому циклі. При використанні масштабних коефіцієнтів (1,2,4,8 в залежності від розміру елементу) значення в індексному регістрі змінюється у внутрішньому циклі від 0 до С-1, де С кількість елементів рядка (стовпчиків матриці). Така адресація дозволяє оперувати вже

не адресами елементів рядка, а логічними індексами 0,1,2,..., що відповідає нашим інтуїтивним уявленням і використовується мовами програмування високого рівня.

Приклад 4.5 Визначення суми елементів кожного рядка матриці. Результати зберігаються в одновимірному масиві result. Перший елемент масиву result – сума елементів першого рядка матриці, другий елемент масиву result – сума елементів другого рядка матриці, і.т.д.

.386

 

 

 

 

.model flat, stdcall

 

 

 

.data

 

 

 

 

matrix

dw 1,5,3,2,7

 

 

cols

=($-matrix)/type matrix

; кількість стовпчиків

 

dw 2,5,7,8,9

 

 

 

dw 4,9,3,2,6

 

 

rows

= ($-matrix)/(cols*type matrix)

; кількість рядків

.data?

 

 

 

 

result

dd rows dup (?)

 

; масив результатів

.code

 

 

 

 

start:

 

 

 

 

lea edi,result

; в edi –

адреса результату внутрішнього циклу

lea ebx,matrix

; в ebx –

адреса першого рядка

mov ecx,rows

; кількість рядків лічильник зовнішнього циклу

rows_cycle:

 

 

 

push ecx

; зберегти лічильник зовнішнього циклу

xor eax,eax

; в dx:ax буде накопичуватися сума елементів

xor edx,edx

; у внутрішньому циклі

xor esi,esi

; починаючи з першого (зміщення від бази 0)

mov ecx,cols

; для всіх елементів рядка

cols_cycle:

add ax,word ptr [ebx+esi*type matrix] ; додати елемент до суми

adc dx,0 ; з врахуванням можливого переносу

inc esi

; і перейти до наступного

loop cols_cycle

 

shl edx,16

; скласти з пари dx:ax єдине 32-х бітне

or eax,edx

; в регістрі eax

mov dword ptr [edi],eax; і зберегти результат

add edi,type result ; перерахувати адресу наступного результату add ebx, cols*type matrix ; перерахувати адресу наступного рядка pop ecx ; й перейти до його обробки

loop rows_cycle ; якщо він не останній

ret end start

Обробка матриці за стовпчикам не значно відрізняється від обробки матриці за рядкам. Змінюється лише порядок вкладення циклів і перерахунок складових адрес. При обробці елементів матриці за стовбцями кількість повторень зовнішнього циклу визначається кількістю стовбців матриці (кількістю елементів у рядку), і стовбці адресуються за допомогою базового регістра, початкове значення якого встановлюється рівним адресі початку першого рядка матриці і збільшується на розмір елемента на кожній ітерації зовнішнього циклу. Кількість повторень внутрішнього циклу визначається кількістю рядків матриці, і рядки адресуються за допомогою індексного регістра шляхом його збільшення на загальний розмір елементів рядка від нуля на кожній ітерації внутрішнього циклу.

Приклад 4.6 Визначення суми елементів кожного стовпчика матриці. Результати роботи зберігаються в одновимірному масиві result. Перший елемент масиву result – сума елементів першого стовпчика матриці, другий елемент масиву result – сума елементів другого стовпчика матриці, і.т.д.

.386

.model flat, stdcall

.data

 

matrix

dw 1,5,3,2,7

cols

=($-matrix)/type matrix

 

dw 2,5,7,8,9

 

dw 4,9,3,2,6

rows

= ($-matrix)/(cols*type matrix)

.data?

 

result

dd cols dup (?)

.code

 

start:

 

lea edi,result lea ebx,matrix mov ecx,cols

cols_cycle: push ecx

xor eax,eax xor edx,edx xor esi,esi mov ecx,rows

rows_cycle:

add ax,word ptr [ebx+esi] adc dx,0

add esi,cols*type matrix loop rows_cycle

shl edx,16 or eax,edx

mov dword ptr [edi],eax add edi,type result

add ebx,type matrix pop ecx

loop cols_cycle ret

end start

4.3 Рядки символів

Рядки символів являють собою звичайні одновимірні масиви, однак у звязку з деякими особливостями подання, їх виділяють в окрему категорію. Рядки символів розглядають як ланцюги байт або слів довільної довжини. Ознакою кінця ланцюга байт виступає нульовий байт (не символ «0» з ASCII- кодом 30h, а двійковий 0), а ознакою кінця ланцюга слів нульове слово (два нульових байта). Однобайтові рядки містять коди символів у певному кодуванні, а рядки слів використовують двобайтове кодування Unicode з різним порядком зберігання байтів у слові.

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

Приклад 4.7 Цей приклад демонструє виконання декількох операцій з обробки ASCII-рядків:

1.Визначає довжину рядка.

2.Визначає кількість слів в рядку (словом вважається група символів розділених пробілом з кодом 20h)

3.Визначає позицію входження під рядка в рядок.

4.Прибирає пробіли в рядку.

5.Перетворює строкові літери рядка на прописні.

6.Шифрує рядок.

Зробимо попередні зауваження щодо реалізації перетворень символів букв із строкових в прописні та шифрування. Проаналізувавши ASCII таблицю кодувань символів, можна зазначити, що:

а) символи строкових і символи прописних букв займають в ній окремі неперервні діапазони;

б) в межах кожного діапазону символи впорядковано в алфавітному порядку так, що старшій за алфавітом букві відповідає більше значення ASCII-коду;

в) значення ASCII-кодів строкових букв відрізняються від ASCII-кодів відповідних їм прописних букв на фіксоване значення.

На прикладі ASCII-кодів букв «a» та «A» в двійковій системі не важко побачити, що відрізняються ці коди лише значенням одного біта.

«A» – 41h = 0010 0001b

«a» – 61h = 0 110 0001b

Таким чином, перетворення символу зі строкового на прописний виконується скиданням шостого біту байта ASCII-коду, і навпаки, перетворення символу із прописного на строковий виконується встановленням шостого біту байта ASCII-коду.

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

Таке перетворення може виконуватися з використанням суперпозиції будь-яких арифметичних та/або логічних операцій, але це перетворення повинно бути зворотнім, тобто передбачати можливість однозначного поновлення шифрованого тексту.

Властивістю зворотності володіє елементарна логічна функція XOR для якої в системі команд процесора передбачена однойменна команда. Наприклад,

0010 0001b XOR 0000 0111b = 0010 0110b – шифрування 0010 0110b XOR 0000 0111b = 0010 0001b – дешифрування

0010 0001b = 41h – «A»

0000 0111b маска (ключ шифру)

0010 0110b = 46h – «F»

0000 0111b маска (ключ шифру)

0010 0001b = 41h – «A»

.386

.model flat, stdcall

.data

str1

db "uiop",0

str2

db "qwertyuiopasdfghjkl",0

str3

db "qw erty uio pasd fgh jkl",0

.code

 

start:

 

; Знайти довжину рядка str3

lea edi,str3

 

mov ecx,-1

 

xor al,al

 

repnz scasb

 

neg ecx

 

dec ecx

; в ECX – довжина рядка str3

; Підрахувати кількість слів в str3

lea edi,str3 xor ebx,ebx mov al,20h

@@: repnz scasb jecxz @F

inc ebx ; в EВX – кількість слів

jmp @B

; Знайти входження рядка str1 в str2

@@: mov ecx,lengthof str2-lengthof str1+1

lea ebx,str2

@@: push ecx

mov edi,ebx lea esi,str1

mov ecx,lengthof str1

repe cmpsb

 

jecxz @F

 

inc ebx

 

pop ecx

 

loop @B

 

jmp NotFound

 

@@: pop ecx

; в EВX – адреса початку підрядка str1 в рядку str2

lea eax,str2

sub ebx,eax ; в EВX – позиція (з нуля) підрядка str1 в рядку str2

NotFound:

; Прибрати пробіли в str3

lea esi,str3 mov edi,esi

@@: lodsb or al,al jz @F

cmp al,20h je @B stosb

jmp @B @@: stosb

; Перетворити строкові літери в str3 на прописні

lea esi,str3 lea edi,esi

@@: lodsb or al,al jz @F

cmp al,"a" jb @B cmp al,"z" ja @B

or al, 01000000b stosb

jmp @B @@: stosb

; Зашифрувати str3

lea esi,str3

lea edi,esi

@@: lodsb

or al,al

jz @F

xor al,01010101b

stosb

jmp @B

@@: stosb

ret

end start

4.4 Записи

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

Ім’я запису RECORD Ім’я поля:довжина[=значення] [,...]

Імена полів запису повинні бути унікальними, довжина полів зазначається у бітах, за необхідності бітовому полю можна призначити не обовязкове початкове значення ініціалізації за замовченням. Загальна довжина усіх бітових полів запису не може перевищувати 8/16/32/64 біта.

Наприклад,

DATE

RECORD

Year:12, Month:4, Day:5

DATE

RECORD

Year:12=2011, Month:4, Day:5

DATE

RECORD

Year:12=2011, Month:4=01, Day:5=01

Опис типу запису це тільки інформація для транслятора і память під його розміщення не виділяється, тому опис типу запису виконується до першої директиви визначення секцій даних і констант.

Після опису типу запису на його основі можна визначати одну або декілька змінних у вигляді:

Ім’я змінної Ім’я запису <[значення[,значення]…]> Ім’я змінної Ім’я запису {[значення[,значення]…]}

Ім’я змінної Ім’я запису кількість DUP (<[значення[,значення]…]>) Ім’я змінної Ім’я запису кількість DUP ({[значення[,значення]…]})

Ініціалізація бітових полів запису припустима для секції .data, для секції констант .const її можна вважати обовязковою, а для секції не ініціалізованих даних .data? вона не припустима (ігнорується з повідомленням транслятора). Змінні з типом запису у секції не ініціалізованих даних .data? визначаються на основі опису типу без попередньої ініціалізації полів і виглядають наступним чином:

.data?

 

Date1

DATE <>

Date2

DATE {}

Date3

DATE 5 DUP ({})

Date4

DATE 5 DUP (<>)

Змінні з типом запису у секції ініціалізованих даних .data можуть визначатися як на основі опису типу з попередньою ініціалізацією полів, так і без неї. При визначенні змінної надається можливість прийняти значення попередньої ініціалізації, перевизначити та/або ініціалізувати будь яке одне або усі поля запису. Символом роздільником полів запису виступає кома. Якщо ініціалізації підлягають лише деякі бітові поля, то для зазначення їх місце розташування зберігають порядок роздільників. Наприклад:

Date1

DATE 5 dup (<2011,04,24>)

Date2

DATE {2011,,24}

Date3

DATE <2011,04,>

Date4

DATE <2011,04>

Date5

DATE {,,25}

Date6

DATE {}

Під змінні з типом запису виділяється память. Розмір наданої для розміщення змінної памяті складає 8/16/32/64 біта і визначається загальною довжиною усіх бітових полів запису обирається найменший розмір достатній для розміщення усіх полів запису. При цьому якщо загальна довжина усіх бітових полів запису не дорівнює 8/16/32/64 бітам, то ліві (старші) біти байта, слова, подвійного або зчетвереного слова не використовуються.

Соседние файлы в папке гос