- •Модульное программирование на ассемблере. Связь разноязыковых модулей
- •Введение
- •Модульное программирование на ассемблере
- •Процедура ассемблера. Описание процедуры
- •Связь процедур ассемблера по управлению
- •Организация передачи данных в процедурах на ассемблере
- •Передача параметров через регистры
- •Передача данных путем прямого обращения к памяти
- •Передача параметров в стеке
- •Передача параметров через таблицу адресов
- •Особенности реализации рекурсивных программ в ассемблере
- •Директивы описания процедур
- •Директива заголовка процедуры
- •Директива описания локальных переменных
- •Директива объявления прототипа процедуры
- •Директива вызова процедуры
- •Связь разноязыковых модулей в Windows
- •Основные правила организации связи разноязыковых модулей
- •Конвенции о связи модулей. Правила передачи параметров
- •Правила формирования внутренних имен подпрограмм и глобальных данных
- •Сохранение регистров и модель памяти
- •Основные принципы взаимодействия Delphi Pascal и ассемблера
- •Соглашения о передаче управления между модулями
- •Соответствие форматов данных
- •Передача параметров по значению и ссылке. Возврат результатов функций
- •Компоновка модулей
- •Примеры
- •Inc ecx ; адрес начала исходной строки
- •Основные принципы
- •Передача параметров и возвращение результатов функции
- •Определение глобальных и внешних имен
- •Компоновка модулей
- •Примеры
- •Правила формирования внутренних имен
- •Компоновка модулей
- •Примеры
Передача параметров через таблицу адресов
В этом случае в памяти вызывающей программы создается специальная таблица адресов параметров. В таблицу перед вызовом процедуры записывают адреса передаваемых данных. Затем адрес самой таблицы заносится в один из регистров (например, EBX) и управление передается вызываемой процедуре. Вызываемая процедура сохраняет в стеке содержимое всех регистров, которые собирается использовать, после чего выбирает адреса переданных данных из таблицы, выполняет требуемые действия и заносит результат по адресу, переданному в той же таблице.
Пример 1.4. Написать программу, подсчитывающую сумму элементов одномерного массива. Массив и его размер определяются в основной программе, суммирование элементов выполняет процедура. Результат сложения возвращается в основную программу. Данные передаем через таблицу адресов (см. рисунок 1.4).
; Template for console application
.586
.MODEL flat, stdcall
OPTION CASEMAP:NONE
Include kernel32.inc
Include masm32.inc
IncludeLib kernel32.lib
IncludeLib masm32.lib
.CONST
MsgExit DB "Press Enter to Exit",0AH,0DH,0
.DATA
ary SWORD 5,6,1,7,3,4 ; массив
count DWORD 6 ; размер массива
.DATA?
inbuf DB 100 DUP (?)
sum SWORD ? ; сумма элементов
tabl DWORD 3 dup(?) ; таблица адресов параметров
EXTERN masculc:near
.CODE
Start:
;
Рисунок 1.4
– Таблица
адресов параметров
mov tabl,offset ary
mov tabl+4,offset count
mov tabl+8,offset sum
mov EBX,offset tabl
call masculc
XOR EAX,EAX
Invoke StdOut,ADDR MsgExit
Invoke StdIn,ADDR inbuf,LengthOf inbuf
Invoke ExitProcess,0
End Start
Текст процедуры:
; Template for console application
.586
.MODEL flat, stdcall
OPTION CASEMAP:NONE
.CODE
masculc proc c
push AX ; сохранение регистров
push ECX
push EDI
push ESI
; использование таблицы адресов параметров
mov ESI,[EBX]
mov EDI,[EBX+4]
mov ECX,[EDI]
mov EDI,[EBX+8]
xor AX,AX
; суммирование элементов массива
cycl: add AX,[ESI]
add ESI,2
loop cycl
; формирование результатов
mov [EDI],AX
pop ESI ; восстановление регистров
pop EDI
pop ECX
pop AX
ret
masculc endp
END
Передача параметров в стеке
Наиболее распространенным способом передачи данных в практике программирования принято считать передачу параметров в стеке. Именно этот способ используют языки высокого уровня. Параметры помещают в стек командой PUSH, после чего управление передается вызываемой процедуре. Доступ к параметрам в стеке из вызываемой процедуры осуществляют через регистр EBP, в который помещают адрес вершины стека, хранящийся в регистре указателя стека ESP. Для обеспечения корректного возврата в вызывающую процедуру старое значение регистра EBP помещают в стек первой командой процедуры. Параметры в стеке, адрес возврата и старое значение EBP вместе называют фреймом активации процедуры. Вызываемая процедура, зная структуру стека, извлекает параметры в соответствующие регистры, выполняет над ними операции и записывает результат, используя адрес, переданный в стеке.
Примечание – Следует помнить, что в стек можно поместить 2 или 4 байта. Если в стек надо поместить параметр размером 1 байт, то помещают 2 байта, но байт со старшим адресом не используется.
Пример 1.5. Программа суммирования элементов массива. Программа использует 3 параметра: два исходных и результат. Для первого параметра – массива в стек помещается адрес начала массива, второй параметр – адрес счетчика, содержащего количество элементов. В качестве третьего параметра в стек помещается адрес результата, куда процедура поместит полученное значение (см. рисунок 1.5).
; Template for console application
.586
.MODEL flat, stdcall
OPTION CASEMAP:NONE
Include kernel32.inc
Include masm32.inc
IncludeLib kernel32.lib
IncludeLib masm32.lib
.CONST
MsgExit DB "Press Enter to Exit",0AH,0DH,0
.DATA
ary SWORD 5,6,1,7,3,4 ; элементы массива
count DWORD 6 ; размер массива
.DATA?
inbuf DB 100 DUP (?)
sum SWORD ? ; сумма элементов
EXTERN masculc:near
.CODE
S
tart:
; запись параметров в стек
push offset ary
push offset count
push offset sum
; вызов процедуры
Рисунок 1.5 – Состояние
стека во время работы процедуры masculc
XOR EAX,EAX
Invoke StdOut, ADDR MsgExit
Invoke StdIn,ADDR inbuf,LengthOf inbuf
Invoke ExitProcess,0
End Start
Модуль вычисления суммы элементов массива:
.586
.MODEL flat, stdcall
OPTION CASEMAP:NONE
.CODE
masculc proc c
push EBP ; сохранение регистра ebp
mov EBP,ESP ; запись в ebp адреса вершины стека
push AX
push ECX
push EDI
push ESI
; Извлечение параметров из стека
mov ESI,[EBP+16] ; адрес массива
mov EDI,[EBP+12] ; адрес количества элементов
mov ECX,[EDI] ; количество элементов
mov EDI,[EBP+8] ; адрес результата
xor AX,AX ; очистка регистра AX
cycl: add AX,[ESI]
add ESI,2
loop cycl
mov [EDI],AX ; сохранение результата
pop ESI
pop EDI
pop ECX
pop AX
pop EBP ; восстановление регистра еbp
ret 12 ; удаление параметров из стека
masculc ENDP
END
При передаче параметров через стек возникает два вопроса:
– в каком порядке записывать параметры в стек;
– кто – вызывающая или вызываемая процедура – должен удалять параметры из стека.
В обоих вариантах есть свои плюсы и минусы. Например, если стек освобождает вызываемая процедура по команде RET <Число байт>, то код программы получается более коротким. Если за освобождение стека отвечает вызывающая программа, то становится возможным вызов нескольких процедур с одними и теми же значениями параметров просто последовательными командами CALL. Первый способ более строгий, он используется в языке Pascal. Второй, дающий больше возможностей для оптимизации, – в языках C и C++. Вопрос о порядке записи параметров в стек для ассемблера не столь важен, так как и записывают и извлекают параметры подпрограммы на ассемблере. Главное – чтобы этот вопрос был между ними согласован. А вот при взаимодействии ассемблера с языками высокого уровня, следует знать особенности передачи параметров этих языков.
