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

Практикум_СП

.pdf
Скачиваний:
39
Добавлен:
15.02.2015
Размер:
1.01 Mб
Скачать

Початок

введення

паролю

Не

правильно

перевірка

паролю

Правильно

виконання

програми

Кінець

Рисунок 6.2 Алгоритм функціонування програми з паролем.

Текст програми для виведення рядка Hitman, захищеної паролем:

model small stack 256 dataseg

password db 'H2'

сегмент даних для

pass_len = $-password

string db 80 dup(?)

програми пароля

promt db 13,10,'vvedite parol:$'

 

ok db 13,10,'parol prinyat$'

 

H2 db 13,10,'Hitman','$' ;сегмент

даних для програми ;виведення

рядка

 

 

codeseg

mov ax,@data

 

start:

 

mov ds,ax

 

begin:

mov ah,09h

 

mov dx,offset promt

 

int 21h

 

mov bx,0

 

pass:

mov ah,08h

 

int 21h cmp al,13 je compare

mov [string+bx],al

61

mov ah,02

сегмент коду для

mov dl,'*'

int 21h

програми пароля

inc bx

 

jmp pass

 

compare: push ds

 

pop es

 

mov si,offset string

mov di,offset password

cld

 

mov cx,pass_len

repe cmpsb

 

jne error

 

mov ah,09h

 

mov dx,offset ok

int 21h

 

mov ah,9h

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

mov dx,offset H2

 

int 21h

 

exit:mov ax,4C00h int 21h

error: jmp begin ;перехід на перевірку пароля при введенні ;неправильного паролю

end start

Рисунок 6.3 Компіляція і запуск програми.

62

Рисунок 6.4 Дія програми при введенні невірного паролю.

Рисунок 6.5 Дія програми при введенні вірного паролю.

63

Практична робота № 7

Тема: Організація підпрограм. Способи передачі параметрів. Макроси.

Мета роботи: Вивчення способів організації процедур і передачі параметрів в програмах на мові асемблера х86.

Теоретичні відомості

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

name

PROC type

 

 

-

;Оператори процедури

 

-

RET

-

;Оператор повернення в модуль, що викликав

 

name ENDP

 

Команди виклику процедури

CALL

name

 

забезпечують автоматичне збереження в стеку адреси наступної команди, щоб потім командою повернення з підпрограми можна було передати сюди управління і продовжити далі виконання програми, що викликала процедуру. При роботі з процедурами необхідно забезпечити баланс стека, тобто на момент виходу у вершині стека повинна знаходитися адреса повернення, інакше можлива передача управління на випадкові елементи пам'яті. Залежно від типу type процедури в стек заноситься або тільки зсув (type = NEAR, тобто внутрішньосегментний виклик) або повна логічна адреса Seg: Offset (type = FAR, тобто міжсегментний виклик). Від цього описувача залежить і код команди повернення RET. Якщо процедура визначена з атрибутом NEAR (він приймається за умовчанням), то команда RET заносить одне слово з верхівки стека в IP і тим самим забезпечує повернення в межах того сегменту, в якому знаходиться і сама процедура, виклики її з інших сегментів здійснювати неможливо. Якщо ж процедура визначена як дальня (має атрибут FAR), то команда повернення RET вибирає із стека два слова: перше (Offset) поміщається на IP, а друге (Seg) поміщається на CS, що дає можливість

64

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

CALL

[NEAR PTR]

name ;внутрішньосегментний

прямий

виклик по зсуву щодо імені name

 

 

 

CALL

[NEAR PTR]

opr ;внутрішньосегментний

непрямий

виклик opr – регістр або слово в пам'яті, де міститься адреса процедури

CALL

[FAR PTR]name ;міжсегментний прямий виклик процедури

за адресою (Seg:Offset) імені name

 

 

 

CALL

[FAR PTR]opr

;міжсегментний

непрямий

виклик

процедури за адресою (Seg:Offset), записаною в пам'яті

на яку указує операнд

opr

 

 

 

 

Операнд opr в командах непрямого переходу являє собою ім'я регістра, в якому міститься адреса переходу (тільки для внутрішніх переходів), або ім'я змінної, де записана адреса переходу (одне слово для внутрішньосегментного переходу або два слова для міжсегментного переходу), чи ж адресний вираз, яким визначається адреса пам'яті, де зберігається адреса переходу. Слід особливо підкреслити, що у разі внутрішньосегментного прямого виклику в команді CALL зберігається не адреса переходу (Offset), а зсув (Displacement) в байтах від сдедующей після CALL, команди до точки входу в процедуру. Під час виконання команди CALL воно складається з поточним вмістом IP, внаслідок чого його вміст стає рівним цільовій адресі (Offset) входу в процедуру. Це дозволяє переміщати кодовий сегмент в пам'яті без корекції інформації про переходи. У разі прямих міжсегментних викликів в команді CALL зберігається повна логічна адреса точки входу в процедуру (Seg: Offset) і, отже, він повинен коректуватися при переміщеннях сегменту, в якому знаходиться точка переходу.

;Приклади викликів процедур

;Модулі mod1 і mod2 асемблюються окремо

NAME mod1 Dseg SEGMENT

Addr_PN

DW

Go_Proc

; адреса процедури Offset

Addr_PF

DD

Start_Pr

; адреса процедури Seg:0ffset

Tabl_PN

DW

Fadd,Fsub,Fmul,Fdiv ;табл. адр. процедур Offset

Tabl_PF

DD

Dadd,Dsub,Dmul,Ddiv

;те ж, але у вигляді Seg: Offset

SwitchDW

?

 

; перемикач: 0, 1, 2 або 3

Dseg

ENDS

 

 

 

 

Cseg1 SEGMENT 'CODE'

 

 

 

EXTRN Begin: FAR

 

 

Start

PROC FAR

 

 

 

 

PUSH DS

 

; підготуватися

65

 

SUB

AX,AX

 

; до повернення

 

PUSH AX

 

; у DOS

; Приклади внутрішньосегментних викликів процедур

Go_Proc

PROC

 

 

 

MOV

SI,Switch

 

 

 

SHL

SI, 1

 

; підготувати покажчик в таблиці

 

CALL Tabl_PN[SI]

 

; непрямий виклик в сегменті

 

...

 

 

 

Go_Proc

ENDP

 

 

 

...

 

 

 

Start_Pr

PROC FAR

 

 

 

 

-

 

 

 

 

-

 

 

 

RET

-

 

 

 

 

 

 

Start_Pr

ENDP

 

 

 

...

 

 

 

 

CALL Tabl_PN + 4

 

;непрямий виклик Fmul

 

...

 

 

 

 

MOV

BX,Tabl_PN[SI]

;ВХ = адреса з таблиці

 

CALL ВХ

 

;непрямий виклик (адреса в BX)

 

...

 

 

 

 

LEA

ВХ,Tabl_PN

 

;ВХ = база таблиці

 

CALL NEAR PTR [BX]

;непрямий виклик Fadd

 

...

 

 

 

 

CALL NEAR PTR [BX][SI] ;непрямий виклик процедури, її адреса визначається

;перемикачем SI в таблиці, початкова адреса якої ;міститься у ВХ

 

CALL Go_Proc

 

;прямий виклик в сегменті типу NEAR

; Приклади міжсегментних викликів процедур

 

...

 

 

 

 

CALL Begin

;прямий міжсегментний по зовнішньому імені

 

...

 

 

 

 

CALL Dsub

 

;прямий міжсегментний по мітці типу FAR

 

...

 

 

 

 

CALL Tabl_PF + 8

;непрямий міжсегментний на Dmul

 

...

 

 

 

 

MOV

SI,Switch

 

;перемикач адр. дальнього переходу

 

SHL

SI,1

 

 

 

SHL

SI,1

 

;4*SI = 0, 4, 8 або 12

 

CALL Tabl_PF[SI]

;непрямий міжсегментний по таблиці

 

...

 

 

 

 

LEA

BX,Tabl_PF

;ВХ = база таблиці

 

CALL FAR PTR [BX]

;непрямий міжсегментний на Da

 

...

 

 

 

 

CALL FAR PTR [BX][SI]

;непрямий між сегментний по

;адресі з таблиці Tabl_JF, який визначається перемикачем в SI

 

...

 

 

 

 

RET

 

 

; повернення в DOS

Csegl

ENDS

 

 

 

Cseg2

SEGMENT 'CODE'

 

 

66

FADD PROC DSUB PROC FAR

--

--

-RET

RET DSUB ENDP

Fadd ENDP ;

;Dmul PROC FAR

Fsub PROC -

--

-RET

-Dmul ENDP RET ;

Fsub

ENDP Ddiv

PROC FAR

;

 

 

-

Fmul

PROC -

 

 

-

RET

 

 

-

Ddiv

ENDP

-...

 

RET CALL

Addr_PF

;непряма.

Fmul

ENDP ...

 

;межсегм. за адресою

;

Cseg2 ENDS

 

 

Fdiv

PROC END

Start

 

-Name mod2

-Cseg3 DEGMENT 'CODE'

-PUBLIC Begin

RET -

Fdiv ENDP -

;Begin PROC FAR

Dadd PROC FAR -

--

-Begin ENDP

--

RET -

Dadd ENDP Cseg3 ENDS

;END

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

67

визначивши їх в викликаємому модулі для зовнішнього використання директивою PUBLIC.

Прогресивнішим є спосіб взаємозв'язку з даним через динамічні параметри, і реалізується він звичайно шляхом передачі адрес параметрів. Це можна зробити через регістри, через таблицю адресу йти через стек. Вочевидь, що не у всіх випадках доцільно передавати адреси, окремі параметри можуть передаватися підпрограмі своїм значенням. Слід зазначити, що при передачі параметрів через стек зручно організовувати вікно в стеку, покажчиком в якому встановлюється регістр ВР, структуру вікна доцільно визначати директивою опису структури STRUC. При передачі параметрів через стек часто виникає необхідність перед поверненням управління в зухвалий модуль звільнити стек від непотрібних надалі параметрів. В цьому випадку корисною є команда повернення з операндом (RET expr), значення якого визначає, скільки байтів повинно бути пропущено в стеку після вибірки адреси повернення. Приведені нижче фрагменти програмних модулів ілюструють основні прийоми передачі параметрів процедурі.

; Передача параметрів через зовнішні посилання

 

NAMEmod1

 

 

CSeg_P

SEGMENT 'CODE'

 

 

EXTRN

S_Arr: WORD,Average:WORD,Counter:WORD

 

PUBLIC

Avrg

 

 

ASSUME

CS:CSeg_P

 

Avrg

PROG FAR

 

 

 

PUSH AX

 

; зберегти

 

PUSH DX

 

; робочі

 

PUSH CX

 

; регістри

 

PUSH SI

 

 

 

MOV

CX,Counter

; узяти лічильник

 

SUB

AX,AX

; обнулити

 

MOV

DX,AX

; суму

 

MOV

SI,AX

 

; і індекс

Next

ADD

AX,S.Arr[SI]

; накопичувати

 

ADC

DX,0

 

; суму в DX,АХ

 

ADD

SI,2

 

 

 

LOOP Next

 

 

 

DIV

Counter

; обчислити

 

MOV

Average,AX

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

 

POP

SI

 

; відновити

 

POP

CX

 

; вміст

 

POP

DX

 

; регістрів

 

POP

AX

 

; із стека

CSeg_P

ENDS

 

 

 

END

 

 

 

; Цей модуль розробляється окремо від модуля mod1

 

NAMEmod2

 

 

SSeg

SEGMENT

STACK

 

 

DW

100 DUP (?)

 

68

St_TopLABEL

WORD

 

SSeg

ENDS

 

 

 

 

DSeg

SEGMENT

'DATA'

 

 

PUBLIС

S_Arr,Average,Counter

D_Arr DW

100 DUP (?) ; початковий масив цілих чисел

Average

DW

?

 

; середнє арифметичне

Counter

DW

?

 

; лічильник кількості елементів

DSeg

ENDS

 

 

 

 

CSeg_M

SEGMENT

'CODE'

 

 

EXTRN

Avrg:FAR

 

 

ASSUME

CS:CSeg_M,DS:DSeg,SS:SSeg

Main

PROC FAR

 

 

; стартова точка програми

 

MOV

AX,SSeg

 

; підготувати

 

MOV

SS,AX

 

; сегментний регістр

 

MOV

SP,OFFSET SS:St_Top

; і покажчик стека

 

PUSH

DS

 

 

; підготувати

 

SUB

AX,AX

 

; покажчик на PSP

 

PUSH

AX

 

 

; для повернення в DOS

 

MOV

AX,DSeg

 

; підготувати

 

MOV

DS,AX

 

; сегментний регістр даних

 

...

 

 

 

 

 

MOV

S_Arr[SI],AX

; тут формуються елементи

 

INC

CX

 

 

; і лічильник масиву

 

ADD

SI,2

 

 

 

 

MOV

Counter,CX

; записати кількість елементів

 

CALL

Avrg

 

 

; і викликати процедуру обробки

 

MOV

DX,Average

; узяти результат

 

...

 

 

 

 

 

RET

 

 

 

; повернення в DOS

Main

ENDP

 

 

 

 

CSeg_M

ENDS

 

 

 

 

END

Main

 

 

 

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

DSeg SEGMENT

COMMON

; початковий масив цілих чисел

S_Arr

DW

100 DUP (?)

Average

DW

?

;

середнє арифметичне

елементів

Counter

DW

?

;

лічильник кількості

DSeg ENDS

 

 

 

 

 

В цьому випадку директиви PUBLIC і EXTRN для параметрів не потрібні, оскільки зв'язок за даними здійснюється через загальну для зухвалої програми і процедури область пам'яті. Необхідно тільки в модулі процедури в директиві ASSUME додати вказівку про сегментний регістр даних DS:DSeg. Слід зазначити, що імена параметрів в сегментах даних викликаючого модуля і модуля процедури можуть бути різними, важливо тільки, щоб була збережена їх структура.

69

; Приклад передачі параметрів через стек

NAMEmod1

 

SSeg

SEGMENT

STACK

 

DW 100 DUP (?)

St_TopLABEL

WORD

SSeg

ENDS

 

DSef

SEGMENT 'DATA'

S_Arr DW 100 DUP (?)

; початковий масив цілих чисел

Average

DW

?

; середнє арифметичне

Counter

DW

?

; лічильник кількості елементів

DSeg

ENDS

 

 

 

CSeg_M

SEGMENT 'CODE'

 

 

EXTRN

Avrg:FAR

 

 

ASSUME

CS:CSeg_M,DS:DSeg,SS:SSeg

Main

PROC FAR

 

; точка запуску програми

 

MOV

AX,SSeg

; підготувати

 

MOV

SS,AX

 

; сегментний регістр

 

MOV

SP,OFFSET SS:St_Top

; і покажчик стека

 

PUSH

DS

 

; підготувати

 

SUD

AX,AX

; покажчик на PSP

 

PUSH

AX

 

; для повернення в DOS

 

MOV

AX,DSeg

; підготувати

 

MOV

DS,AX

; сегментний регістр даних

 

...

 

 

 

 

MOV

S_Arr[SI],AX

; тут формуються елементи

 

INC

CX

 

; і лічильник масиву

 

ADD

SI,2

 

 

 

...

 

 

 

 

MOV

AX,OFFSET Average

; занести в стек

 

PUSH

AX

; адреса результату

 

 

MOV

AX,OFFSET S_Arr

 

 

PUSH

AX

 

; адреса масиву

 

PUSH

CX

 

; і кількість елементів

 

CALL

Avrg

 

; викликати процедуру обробки

 

POP

DX

 

; узяти результат

 

...

 

 

 

 

RET

 

 

; повернення в DOS

Main

ENDP

 

 

 

CSeg_M

ENDS

 

 

 

END

Main

 

 

; mod2 розробляється окремо

 

 

NAMEmod2

 

 

CSeg_P

SEGMENT 'CODE'

 

 

PUBLIC

Avrg

 

 

ASSUME

CS CSeg_P

 

Avrg

PROC FAR

 

 

 

PUSH BP

 

; зберегти BP

 

MOV

BP,SP

 

; BP - покажчик вікна в стеку

 

PUSH

AX

 

; зберегти

 

PUSH

DX

 

; робочі

70