Процедуры в языке ассемблера

В Ассемблере для оформления процедур как отдельных объектов с у шествуют специальные директивы PROC/ENDP и машинная команда RET. Если сравнивать процедуры и макрокоманды, то можно сказать следующее [7-8]:

· процедуры, так же как и макрокоманды, могут быть активизированы в любом месте программы.

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

Возможные варианты размещения процедур в программе:

· в начале программы (до первой исполняемой команды);

· в конце программы (после команды, возвращающей управление операционной системе);

· промежуточный вариант – тело процедуры располагается внутри другой процедуры или основной программы (в этом случае необходимо предусмотреть обход процедуры с помощью команды безусловного перехода JMP);

· в другом модуле.

Главная цель таких вариантов размещения – не допустить несанкционированной передачи управления коду процедуры. Три первых варианта относятся к случаю, когда процедуры находятся в одном сегменте кода. Что же касается последнего варианта, то он предполагает, что процедуры находятся в разных модулях. А это дает нам возможность говорить уже не об одном модуле, а о нескольких. Для реализации одной общей задачи эти модули должны быть связаны между собой по управлению и по данным.

Так как отдельный модуль в соответствии с концепцией модульного программирования — это функционально автономный объект, то он ничего не должен знать о внутреннем устройстве других модулей, и наоборот, другим модулям также ничего не должно быть известно о внутреннем устройстве данного модуля. Однако должны быть какие-то средства, с помощью которых можно связать модули. В качестве аналогии можно привести организацию связи (интерфейс) монитора и видеокарты через стандартный интерфейс. Связь унифицирована, то есть известно через какой контакт какой сигнал передается. Та же идея лежит и в организации связи модулей. Внутреннее устройство модулей может совершенствоваться, они вообще могут в следующих версиях писаться на другом языке, но в процессе их объединения в единый исполняемый модуль этих особенностей не должно быть заметно. Таким образом, каждый модуль должен иметь такие средства, с помощью которых он извещал бы транслятор о том, что некоторый объект (процедура, переменная) видимы вне этого модуля. И наоборот, нужно объяснить транслятору, что некоторый объект находится вне данного модуля. Это позволит транслятору правильно сформировать машинные команды, оставив некоторые их поля не заполненными. Позднее, на этапе компоновки, программа TLINK (TASM) или программа компоновки языка высокого уровня произведут настройку модулей и разрешат все внешние ссылки в присоединяемых модулях.

Для того, чтобы объявить о подобного рода объектах, видимых извне, программа должна использовать две директивы TASM: EXTERN и PUBLIC. Директива EXTERN предназначена для объявления некоторого имени, внешнего по отношению к данному модулю. Это имя в другом модуле должно быть объявлено в директиве PUBLIC. Директива PUBLIC предназначена для объявления некоторого имени, определенного в этом модуле, видимым в других модулях. Синтаксис этих директив следующий:

EXTERN имя:тип,..., имя:тип

PUBLIC имя,..., имя

Здесь имя — идентификатор, определенный в другом модуле. В качестве идентификатора могут выступать:

· имена переменных, определенных директивами типа DB, DW и т. д.;

· имена процедур;

· имена констант, определенных операторами = и EQU.

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

· если имя – это имя переменной, то тип может принимать значения BYTE, WORD, DWORD, PWORD, FWORD, QWORD и TBYTE;

· если имя – это имя процедуры, то тип может принимать значения near или far;

· если имя – это имя константы, то тип должен быть abs.

Покажем принцип использования директив EXTRN и PUBLIC на схеме связи модулей 1 и 2.

.model small

.stack 256

.data

.code

my_proc_l proc

my_proc_1 endp

my_proc__2 proc

my_proc__2 endp

; объявляем процедуру my_proc_l видимой извне

public my_proc_1

start:

mov ax,@data

end start

/Модуль 2

.model small

.stack 256

.data

.code

extrn my_proc_l;объявляем процедуру my_proc_1 внешней

start:

mov ax,@data

call my_proc_l; вызов процедуры my_proc_l из модуля 1

end start

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

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

Аргумент – это ссылка на некоторые данные, которые требуются для выполнения возложенных на модуль функций и размещенных вне этого модуля. По аналогии с макрокомандами выделяют формальные и фактические аргументы. Исходя из этого, формальный аргумент можно рассматривать не как непосредственные данные или их адрес, а как «тару» для действительных данных, которые будут положены в нее с помощью фактического аргумента. Формальный аргумент можно рассматривать как элемент интерфейса модуля, а фактический аргумент - это то, что фактически передается на место формального аргумента.

Переменная – это нечто, размещенное в регистре или ячейке памяти, что может в дальнейшем подвергаться изменению.

Константа – информационный объект простого типа, значение которого никогда не изменяется.

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

Если входные данные для модуля (аргументы) – переменные, то один и тот же модуль можно использовать многократно для разных наборов значений этих переменных. Но как организовать передачу значений переменных в модуль (процедуру)? При программировании на языке высокого уровня программист ограничен в выборе способов передачи аргументов теми рамками, которые для него оставляет компилятор. В языке ассемблера практически нет никаких ограничений на этот счет, и, фактически, решение проблемы передачи аргументов предоставлено программисту.

На практике используются следующие варианты передачи аргументов в модуль (процедуру):

· через регистры;

· через общую область памяти;

· через стек (используется при вызове API-функций в программах для Windows);

· с помощью директив EXTERN и PUBLIC.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: