Процедуры в программах для DOS16
Лекция №12. Процедуры в программах на ассемблере. CRC-код
В языке ассемблера для формирования процедур как отдельных объектов существуют специальные директивы PROC/ENDP и машинная команда ret. Возможные варианты размещения процедур:
– в начале программы (до первой исполняемой команды);
– в конце (после команды, возвращающей управление операционной системе);
– промежуточный вариант, когда тело процедуры располагается внутри другой процедуры или основной программы. В этом случае необходимо предусмотреть обход процедуры с помощью команды безусловного перехода jmp;
– в другом модуле.
С помощью специального механизма вызова процедуры появляется возможность сохранения информации о контексте (контекст – информация о состоянии программы в точке вызова процедуры) программы в точке вызова процедуры.
Есть две команды, осуществляющие работу с контекстом программы. Это команды call и ret:
– call[модификатор] имя_процедуры – вызов процедуры. Команда call, подобно jmp передаёт управление по адресу с символическим именем имя_процедуры, но при этом в стеке сохраняется адрес возврата. Адрес возврата – это адрес команды, следующей после команды call;
|
|
– ret [число] – возвратить управление вызывающей программе. Команда ret считывает адрес возврата из стека и загружает его в регистр cs и eip/ip тем самым возвращая управление на команду следующую в программе за командой call. [число] – необязательный параметр, обозначающий количество элементов, удаляемых из стека при возврате из процедуры.
Вызов процедуры командой call может быть:
– внутрисегментным (имеет тип near) и в качестве возврата команда call сохраняет в стек только содержимое регистра eip/ip;
– межсегментным (имеет тип far) и для осуществления возврата команда call заносит в стек содержимое регистров cs и eip/ip. Очерёдность такова: сначала в стек помещается регистр cs, а потом eip/ip.
При работе с процедурами, которые описаны в другом модуле, программа должна использовать две директивы TASM: extrn и public.
Директива extrn предназначена для объявления некоторого имени внешним по отношению к данному модулю.
Имя, которое будет использоваться в другом модуле, должно быть объявлено в директиве public.
Синтаксис этих директив следующий:
Extrn имя:тип, …, имя:тип
Public имя, …, имя
Здесь имя – идентификатор, определённый в другом модуле. В качестве идентификатора могут выступать:
– имена переменных, определённых директивами типа db, dw и т.п.;
– имена процедур;
– имена констант, определённых операторами = и equ
Возможные значения типов:
1) если имя – это имя переменной, то тип может принимать значения byte, word, dword, pword, fword, qword и tbyte;
|
|
2) если имя – это имя процедуры, то для DOS тип может принимать значения near, far. В данном случае тип характеризует возможность обращения к процедуре из другого сегмента кода. По умолчанию тип принимает значение near (для DOS).
3) если имя – это имя константы, то тип должен быть abs.