 |
::
Меню :: |
 |
|
|
 |
::
Друзі :: |
 |
|
|
 |
::
Лічильники :: |
 |
|
|
|
Виклики підпрограм
Практично в будь-якій програмі, незалежно від
її змісту, зустрічаються ділянки, які
потрібно виконувати (можливо, з невеликими
змінами) кілька разів по ходу
програми. Такі ділянки, що
повторюються, доцільно виділити із загальної
програми, оформити у вигляді підпрограм і
звертатися до них кожного разу, коли в
основній програмі виникає
необхідність їх виконання.
Підпрограма, залежно від виконуваних
нею функцій, може вимагати передачі із
зухвалої програми певних даних (званих
аргументами, або параметрами), повертати в
зухвалу програму результати
обчислень або обходитися і без того, і без
іншого.
Підпрограма може бути оформлена у
вигляді процедури, і тоді ім'я цієї процедури
служитиме точкою входу в підпрограму:
drawline proc ;Подпрограмма-процедура
. . . ;Тіло підпрограми
ret ;Команда повернення в зухвалу програму
drawline endp
З таким же успіхом можна обійтися без
процедури, просто помітивши перший рядок
програми деякою міткою:
drawline:
;Подпрограмма, що починається з мітки
. . . ;Тіло підпрограми
ret ;Команда повернення в зухвалу програму
. . . ;Продовження основної програми або
;інші підпрограми
У будь-якому випадку виклик підпрограми
здійснюється командою call. Підпрограма
повинна завершуватися командою ret, службовці
для повернення управління в ту крапку, звідки
підпрограма була викликана. Питання
використання підпрограм, передачі
в них параметрів і повернення результату
будуть розглянуті в наступному розділі.
Тут ми зупинимося тільки на таких принципових
архітектурних питаннях, як механізм
виконання і можливості команд call
і ret. При цьому треба мати на увазі, що синтаксичні
особливості і закономірності
використання команд call і jmp багато
в чому збігаються, і значна частина
пояснень до команд переходу справедлива
і для команд виклику.
Команда виклику підпрограми call може
використовуватися в 4 різновидах. Виклик
може бути:
прямим ближнім (в межах поточного
сегменту команд);
прямим дальнім (у інший сегмент команд);
непрямим ближнім (в межах поточного
сегменту команд через осередок з адресою
переходу);
непрямим дальнім (у інший сегмент команд
через осередок з адресою
переходу).
Розглянемо послідовно перераховані
варіанти. Прямий
ближній виклик. Як і у разі прямого ближнього
переходу, в команді прямого виклику в
явній формі указується адреса (зсув) точки
входу в підпрограму; як ця адреса
можна використовувати як ім'я процедури, так
і ім'я влучні, що характеризує точку
входу в підпрограму. У код команди, окрім
коди операції E8h, входить зсув до підпрограми,
що викликається. У приведеному
нижче прикладі підпрограма оформлена у вигляді
процедури.
code segment
main proc ;Основная програма
.
call sub ;Код Е8 dddd
.
main endp
sub proc near ;Подпрограмма
.
ret ;Код СЗ
sub endp
code ends
Процедура-програма знаходиться в тому ж
сегменті команд, що і зухвала програма.
У коді команди dddd позначає зсув в
сегменті команд до точки входу в
підпрограму. При виконанні команди call
процесор поміщає адреса повернення (вміст
регістра IP) в стек виконуваної програми (мал.
2.16), після чого до поточного вмісту IP
додає dddd. В результаті в IP виявляється
адреса підпрограми. Команда ret, якою
закінчується підпрограма, виконує
зворотну процедуру - витягує із стека
адресу повернення і заносить її в IP.

Мал. 2.16. Участь стека в механізмі виклику
ближньої підпрограми.
Участь стека в механізмі виклику підпрограми і
повернення з неї є вирішальною. Оскільки
в стеку зберігається адреса повернення, підпрограма,
сама використовуючи стек, наприклад, для
зберігання проміжних результатів, зобов'язана
до моменту виконання команди ret
повернути стек в початковий стан. Команда
ret, природно, ніяк не аналізує стан
або вміст стека. Вона просто
знімає із стека верхнє слово, вважаючи його
за адресу повернення, і завантажує це
слово в покажчик команд IP. Якщо до моменту
виконання команди ret покажчик стека
виявиться зміщеним в ту або іншу сторону,
команда ret як і раніше
розглядатиме верхнє слово стека, як
адресу повернення, і передасть по ньому
управління, що неминуче приведе до краху
системи. Прямий
дальній
виклик. Цей виклик дозволяє звернутися до
підпрограми з іншого сегменту. У
код команди, окрім коди операції 9ah, входить
повна адреса (сегмент плюс зсув) підпрограми,
що викликається. Зазвичай в початковому
тексті програми за допомогою описувача
far ptr указується, що виклик є
дальнім, хоча, якщо транслятор налаштований
на трансляцію в два проходи, цей описувач
не обов'язковий. Структура програмного
комплексу, що містить дальній
виклик підпрограми, може виглядати
таким чином:
codel segment
assume Cs:codel
main proc ;Основная програма
call far ptr subr ; Код 9а dddd ssss
.
main endp
codel ends
code2 segment
assume Cs:code2
subr proc far ;Объявляем підпрограму дальньої
.
ret ;Код СВ - дальнє повернення
subr endp
code2 ends
Процедура-підпрограма знаходиться в іншому
сегменті команд тієї ж програми. У коді
команди dddd позначає відносну адресу
точки входу в підпрограму в її сегменті
команд, а ssss - це сегментна адреса. При
виконанні команди call процесор поміщає
в стек спочатку сегментну адресу зухвалої
програми, а потім відносну
адресу повернення (мал. 2.17). Далі
в сегментний регістр CS заноситься 5555 (у нас
це значення code2), а в IP - dddd (у нас це значення
subr). Оскільки процедура-підпрограма атрибутом
far оголошена дальній, команда ret має
код, відмінний від коди аналогічної команди
ближньої процедури і виконується по-іншому: із
стека витягуються два верхні слова і переносяться
в IP і CS, чим і здійснюється повернення
в зухвалу програму, що
знаходиться в іншому сегменті команд. У
мові асемблера існує і явне
мнемонічне позначення команди
дальнього повернення - retf.

Мал. 2.17. Участь стека в механізмі виклику
дальньої підпрограми.
Непрямий ближній виклик. Адреса
підпрограми міститься або в елементі
пам'яті, або в регістрі. Це дозволяє, як і
у разі непрямого ближнього переходу,
модифікувати адресу виклику, а також
здійснювати виклик не за допомогою мітки, а за
відомою абсолютною адресою. Структура
програми з непрямим викликом підпрограми
може виглядати таким чином:
code segment
main proc ;Основная програма
.
call Ds:subadr ;Код FF 16 dddd
main endp
subr proc near ;Подпрограмма
.
ret ;Код СЗ
subr endp
code ends
data segment .
subadr dw subr ;Яейка з адресою підпрограми
data ends
Процедура-програма з атрибутом near
знаходиться в тому ж сегменті, що і
зухвала програма, а її відносна
адреса в осередку subadr в сегменті даних. У коді
команди dddd позначає відносну адресу
слова subadr в сегменті даних. Другий байт
коди команди (16h в даному прикладі) залежить від
способу адресації. Непрямий виклик
дозволяє використовувати різноманітні
способи адресації підпрограми:
call BX ; У ВХ адреса підпрограми
call[BX]; У ВХ адреса осередку з адресою
підпрограми
call[BX][SI];У ВХ адреса таблиці адрес
підпрограм
;у SI індекс в цій таблиці.
tbl[SI];tbl - адреса таблиці адрес підпрограм
;у SI індекс в цій таблиці
Непрямий дальній виклик. Відрізняється від непрямого
ближнього виклику лише тим, що підпрограма
знаходиться в іншому сегменті, а в
елементі пам'яті міститься повна адреса підпрограми,
що включає сегмент і
зсув.
codel segment
main proc ;Основная програма
call dword ptr subadr ;Код FF IE dddd
.
main endp
codel ends
code2 segment
subr proc far ;Подпрограмма
.
ret ;Код СВ
subr endp
code2 ends
data segment . subadr dd subr ;Двухсловная осередок з
;адресою підпрограми
data ends
Процедура-підпрограма з атрибутом far
знаходиться в іншому сегменті команд тієї ж
програми, а її повна двухсловний адреса - в
осередку subadr в сегменті даних. Другий байт
коди команди (IE в даному прикладі) залежить від
способу адресації. Непрямий дальній виклик,
як і непрямий ближній, дозволяє
використовувати різні способи адресації.
-
|
 |
::
Наша кнопка :: |
 |
|
 |
Отримати код:
|
Підтримайте наш сайт і розмістіть нашу
кнопку на своєму ресурсі. |
|
|
 |
::
Популярне :: |
 |
|
|
 |
:: Посилання :: |
 |
|
|
|