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

Учебное пособие 903

.pdf
Скачиваний:
2
Добавлен:
30.04.2022
Размер:
645.9 Кб
Скачать

Любая подпрограмма кроме задания последовательности действий может содержать описание некоторой совокупности локальных объектов – констант, типов, переменных и так далее. Эти объекты предназначены только для внутреннего использования в подпрограмме, внутри которой они объявлены.

Подпрограмма может быть предназначена для работы с различными данными. Гибкость и универсальность подпрограммного механизма обеспечивают с помощью понятия параметров, которые используются в объявление подпрограммы.

Часто в программах, особенно больших, приходится несколько раз решать одну и ту же подзадачу. Чтобы избежать повторного выписывания одной и той же й группы команд, ее обычно записывают один раз и оформляют соответствующим образом, а затем в нужных местах программы просто передают управление на эти команды, которые, проработав, возвращают управление обратно. В языке ассемблера есть несколько средств, решающих проблему дублирования фрагментов программного кода. К ним относятся:

-процедуры;

-макроподстановки (макроассемблер);

-генерация и обработка программных прерываний. Подпрограмма представляет собой совокупность

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

имя-процедурыPROC [far или

near]

<команды тела процедуры>

RET [n]; обязательная команда возврата

имя-процедурыENDP

9

Директива PROC указывает начало процедуры. Имя процедуры должно обязательно присутствовать. Параметр у директивы PROC может быть near(близкий) и far (дальний). К близкой процедуре можно обращаться только из того сегмента команд, где она описана, и нельзя обращаться из других сегментов, а к дальней процедуре можно обращаться из любых сегментов команд. Имена и метки, описанные в процедуре, не локализуются внутри нее. Конец описания процедуры указывает директива ENDP.

Обычно подпрограммы размещают либо в конце сегмента команд, либо в самом начале этого сегмента - перед той командой, с которой должно начинаться выполнение основной программы. Если имеется несколько подпрограмм, то их обычно размещают последовательно. В больших программах подпрограммы часто размещают в отдельном сегменте.

Подпрограмма может выполняться лишь тогда, когда ее вызовут (к ней обратятся).

Пример оформления модульной программы в одном сегменте кода.

A_codeSEGMENTpara

Assume cs:a_code, ss:a_stack, ds:a_data

; описание подпрограммы 1

P1 procnear

Команды алгоритма подпрограммы 1

Ret

P1 endp

; описание подпрограммы 2

P2 procnear

Команды алгоритма подпрограммы 2

Ret

10

P2 endp

; начало команд главной программы

Begin:mov

ax,

a_data

mov ds, ax

Команды алгоритма главной программы

;Вызов подпрограммы 1

Call P1

Команды главной программы

;Вызов подпрограммы 2

Call P2

Команды главной программы

……..

Mov ah, 4ch

Int 21h

A_code ends

Endbegin

Выполнение главной программы начинается командой с меткой begin. Вызов процедур осуществляется с помощью команды управленияCall. При этом существуют несколько видов обращения к процедуре:

1.Явное указание имени процедуры: Call имя

процедуры.

Пример: Call P1.

2.С помощью косвенной адресации:

Call [регистр индекса или базы]

Call [Имя переменной из сегмента данных] Пример: Call [BX].

11

Механизм исполнения команды Call в общем виде состоит из двух этапов:

Содержимое регистра IP помещается в стек, то есть, на вершине стека сохраняется адрес команды, следующей после команды Call - адрес возврата.

В регистр IP заносится адрес вызываемой процедуры, и начинает выполняться процедура, выполнение главной программы приостанавливается в это время.

Команда RET осуществляет возврат из процедуры в вызывающий модуль. Содержимое вершины стека (адрес возврата) пересылается в регистр IP, таким образом, управление возвращается в вызывающий модуль. Если была передача параметров через стек, то команда возврата RET должна быть с параметром N. В данном случае возврат сопровождается «выталкиванием» из стека загруженных фактических параметров, занимавших N байтов в стеке. Если главная программа оформлена в виде процедуры, то в директиве END пишется имя главной процедуры: END имя

главной процедуры.

Пример:

A_CODE SEGMENT PARA

P_MAIN PROC FAR

ASSUME ……..

………

RET

P_MAIN ENDP

A_CODE ENDS

Endp_main

12

В

начало

главной

процедуры

добавляются

три

дополнительных команды

PUSH DS

;сохранение текущего адреса сегмента данных в стеке

XOR AX, AX

PUSH AX

; выполняется инициализация регистра DS

MOV AX, A_ DATA

MOV DS, AX

Процедуры могут быть с параметрами. В этом случае обмен данным между процедурами может быть выполнен либо через регистры общего назначения, либо через стек. Процедуры без параметров обычно получают или возвращают данные через области, доступные как вызывающему, так и вызываемому модулю: общий сегмент данных (глобальные переменные), определённая область оперативной памяти с заданным физическим адресом или через файлы.

Примеры программ с использованием процедур.

Пример 1.

Оформить группу команд для вывода сообщения в виде внутренней процедуры. Адрес начала сообщения передаётся в процедуру через регистр DX. Используется прерывание DOS 21h, функция вывода 9h. Текст сообщения должен завершаться знаком $.

WRITE_MPROCNEAR

;Процедура с одним параметром, вывод сообщения

;DX – адрес начала сообщения($)

13

MOVAh, 09h

Int 21h

RET

WRITE_ MENDP

В вызывающем модуле:

………………………………..

; Регистр DX надо инициализировать«вручную»перед CALL:

LEADX, MES1 ; адрес первого сообщения в DX

CALLWRITE_M ; явный вызов процедуры WRITE _ M

……..

LEADX, MES 2; адрес сообщения MES2 в DX

CALLWRITE_M ; явный вызов процедуры WRITE _ M

……………………….

Пример 2.

Вычислить y = K! + 5!, где n<=10.

Алгоритм вычисления факториала оформим процедурой ближнего типа с одним параметром, передаваемым через регистр AX. Результат возвращается в регистре BX.

A_datasegmentpara

K DW 7

Y DW ?

A_data ends

A_codeSEGMENT para

14

Assume cs:a_code,

ss:a_stack, ds:a_data

 

 

; описание подпрограммы 1

 

 

FAKTPRICNEARr

;Заголовок процедуры

; процедура вычисления N!

 

 

; регистр AX - входной параметр, значение N.

 

; регистр BX - возвращаемое значениеN!.

 

; арифметика для чисел БЕЗ знака

 

 

PushCX

; сохранение в стеке регистра CX

MOV CX, AX

;инициализация счетчика

MOV AX, 1

;инициализация произведения

BODY:

;метка начала цикла

 

MUL CX

;AX*CX ->AX; вычисляем факториал

LOOPBODY

; CX=CX-1; если

CX<>0,

переходим на

BODY

 

 

 

MOVBX, AX

; результат ->BX

 

 

PopCX; восстановление регистра CX

 

 

RET

; возврат:

IP :=

содержимое

вершины стека

 

 

 

FAKT ENDP

; конецпроцедуры

 

 

Main proc far

 

 

 

 

 

 

MOV AX, N

; AX = N

 

 

15

CALL FAKT

 

; Вызов процедуры FAKT, адрес возврата

– в стек

 

 

 

MOV Y, BX

 

; Y = BX

(N!)

MOVAX, 5

 

; AX = 5

CALLFAKT

 

; Вызов процедуры FAKT, адрес возврата

– в стек

 

 

 

ADDY, BX

 

; Y = Y+5!

MOVAX, Y

 

; подготовка к выводу

PRINT_NUMBER

; макрокоманда вывода числа из регистра

AX

 

 

 

 

 

 

MAINENDP

 

 

 

A_code

ends

 

 

Endmain

 

 

 

16

4. ПРИМЕР ПРОГРАММЫ КУРСОВОЙ РАБОТЫ

Заданы два массива X[N] и Y[M], где N<=10, M<=8 . Найти количество четных элементов каждого массива. Программа должна иметь модульную структуру. Алгоритмы ввода и вывода массивов выделить в отдельные процедуры. Вычисление количества четных элементов в массиве оформить

ввиде процедуры. Передача параметров через регистры:

вВХ – смещение массива;

вСХ – число элементов в массиве;

в АХ – результат вычислений (число четных элементов массива).

Блок-схема главного модуля изображена на рис. 2.

17

НАЧАЛО

ABOUT

ввод массива Хvvod_mas

vvod_mas

ввод массива Y

Bx=X CX=10

SCHET

KOLX=AX

Bx=Y CX=12

SCHET

KOLY=AX

Bx=Y CX=12 print_mas

Ax=KOLX

Bx=X CX=10 print_mas

AX=KOLY print

КОНЕЦ

Рис. 2. Блок-схема главного модуля

18