Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lec_asm_06_3495.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
178.18 Кб
Скачать

7.2.3. Использование глобальных данных

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

Чтобы обеспечить подпрограмме на языке ассемблера доступ к внешним объектам, в ней надо определить сегмент данных и использовать для ссылки на внешние объекты псевдоопе­ратор EXTRN.

Приведем пример, в котором подпрограмма изменяет значение внешнего объекта VAL.

extern “C” void f2(); /* Объявить внешнюю подпрограмму на языке

ассемблера */

int val; /* Определить внешний объект данных */

main ( )

{

f2 ( );

printf ("val = %d\n", val);

}

DGROUP GROUP DATA

DATA SEGMENT WORD PUBLIC 'DATA'

ASSUME DS: DGROUP

EXTRN _VAL: WORD

DATA ENDS

PGROUP GROUP PROG ; Сегмент команд

PROG SEGMENT BYTE PUBLIC 'PROG'

ASSUME CS: PGROUP

PUBLIC _F2

_F2 PROC NEAR

MOV _VAL, 4

RET

_F2 ENDP

PROG ENDS

END

7.2.4. Использование аргументов функции

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

Пусть а1, а2 и аЗ – целые значения.

Тогда вызов

f3(a1, а2, аЗ);

будет преобразован компилятором языка Си в последовательность команд микроп­роцессора:

PUSH АЗ

PUSH А2

PUSH А1

CALL _F3

Заметим, что аргументы помещаются в стек в порядке, обратном тому, в котором они указаны при вызове функции.

Обратим внимание на то, что ячейка с адресом возврата имеет адрес [SP]. (Квадратные скобки означают "содержимое SP".) Копии аргу­ментов имеют адреса [SP] + 2, [SP] + 4 и [SP] + 6.

Микропроцессор 8088 не позволяет использовать регистр указате­ля стека SP в команде MOV для извлечения значений, находящихся по этим адресам. Поэтому следует воспользоваться регистром ВР (регистр указателя базы).

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

Непосредственно перед возвратом в вызывающую функцию следует восстановить исходное зна­чение ВР. Обычно старое содержимое регистра ВР сохраняют в стеке.

Таким обра­зом, общепринятые заголовок и заключительная часть подпрограммы имеют следующий вид:

_F3 РRОС NEAR

PUSH ВР ; Сохранить значение ВР при вызове

MOV BP, SP ; Установить новое значение ВР

...........................

POP ВР ; Восстановить исходное значение ВР

RET ; Вернуться в вызывающую функцию

_F3 ENDP

В этом случае на время исполнения подпрограммы стек будет содержать не только аргументы и адрес возврата, но еще и сохраненное значение регистра ВР.

Используем тот же вызов функции, что и в предыдущем примере:

f3 (a1, а2. аЗ):

Адреса аргументов можно задать следующим образом:

[ВР]+4 ; Адрес первого аргумента

[ВР]+6 ; Адрес второго аргумента

[ВР]+8 ; Адрес третьего аргумента

Следующим примером является подпрограмма, которая получает три целых ар­гумента, суммирует их, а затем возвращает полученный результат через внешнюю переменную VAL.

extern “C” void sum();

int val;

main ()

{

int x = 10;

sum(x, 20, 20+5);

printf( "val = %d\n", val );

}

..............................

_SUM PROC NEAR

PUSH BP ; Сохранить значение BP при вызове

MOV BP, SP ; Установить новое значение BP

MOV АХ, [ВР]+4 ; Первый аргумент находится в стеке

; над сохраненными значениями BP и

; адреса возврата

ADD АХ, [ВР]+6 ; Добавить значение второго аргумента ADD АХ, [BP]+8 ; Добавить значение третьего аргумента MOV _VAL, AX ; Поместить результат в VAL

POP BP ; Восстановить исходное значение BP

RET

_SUM ENDP

В подпрограмме на языке ассемблера первый аргумент загружается в регистр АХ, а значения остальных аргументов до­бавляются к этому регистру с помощью команды сложения ADD. Затем результат (находящийся в регистре АХ) поме­щается во внешний объект VAL.

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

1) объекты типов char, short и int занимают в стеке по одному слову;

2) объекты типа long занимают по два слова;

3) объекты типов float и double передаются в формате объектов типа double и требуют в стеке по четыре слова;

4) если компилятор обеспечивает передачу структур по значению, то в стеке требуется столько байтов, чтобы в них поместились все элементы структуры. При этом обычно число выделяемых байтов округляется до целого, кратного размеру слова;

5) для указателя требуется одно или два слова в зависимости от используемой модели распределения памяти.

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

Наряду с возвращением значений через глобальные объекты подпрограмма на языке ассемблера может возвращать их через аргументы вызова или как значение подпрограммы. Рассмотрим соглашения о реализации этих способов возвращения значений.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]