assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 73
Текст из файла (страница 73)
Любые непредусмотренные действия пользователя должны приводить к генерации ошибочной ситуацииили к предупреждению о возможности возникновения такой ситуации.Из этих положений видно, какое большое значение придается организацииуправляющих и информационных связей между структурными единицами программы (модулями), совместно решающими одну или несколько больших задач. Применительно к языку ассемблера можно рассматривать несколько форм организации управляющих связей.Si Макроподстановки позволяют изменять исходный текст программы в соответствии с некоторыми предварительно описанными параметризованнымиобъектами.
Эти объекты имеют формальные аргументы, замещаемые в процессе макрогенерации их фактическими аргументами. Такая форма образованияструктурных элементов носит некоторый предварительный характер из-за того,что процессы замены происходят на этапе компиляции и есть смысл рассматривать их только как настройку на определенные условия функционированияпрограммы.Процедуры в языке ассемблера327ii Объединение в одну программу подпрограмм, написанных на ассемблере.В языке ассемблера такие подпрограммы называют процедурами. В отличие отмакрокоманд, взаимодействие процедур осуществляется на этапе выполненияпрограммы.ii Объединение в единый модуль на этапе компоновки подпрограмм, написанных на разных языках программирования.
Эта возможность реализуется благодаря унифицированному формату объектного модуля, однозначным соглашениям о передаче аргументов и единым схемам организации памяти на этапевыполнения.*» Динамический (на этапе выполнения) вызов исполняемых модулей и динамическое подключение библиотек (DLL-файлов) для операционной системы Windows.В качестве основных информационных связей можно выделить следующие:ii общие области памяти и общие программно-аппаратные ресурсы процессорадля связи модулей;ш унифицированная передача аргументов при вызове модуля (эту унификациюможно представлять двояко: на уровне пользователя и на уровне конкретногокомпилятора);ii унифицированная передача аргументов при возвращении управления из модуля.Чуть позже мы подробно рассмотрим процессы, происходящие при передачеаргументов.
Сейчас в качестве некоторого итога приведенных ранее общих рассуждений перечислим средства языка ассемблера по осуществлению функциональной декомпозиции программы:Ii макросредства;il процедуры;II средства компилятора ассемблера в форме директив организации оперативнойпамяти и ее сегментации.Макросредства подробно рассмотрены в главе 14. Предварительное обсуждение процедур проведено при обсуждении команд передачи управления в главе 10.Но процедуры — это не просто механизм тривиальной передачи управления изодной точки программы в другую. В частности, этот механизм тесно связан со средствами компилятора, поддерживающими организацию памяти и сегментацию.Поэтому дальнейшее обсуждение будет посвящено более глубокому изучениюфункциональной декомпозиции программ с использованием процедур и связанных с ними средств компилятора.Процедуры в языке ассемблераВ Ассемблере для оформления процедур как отдельных объектов существуют специальные директивы PROC/ENDP и машинная команда RET (см.
главу 10). Если сравнивать процедуры и макрокоманды, то можно сказать следующее. Процедуры, также как и макрокоманды, могут быть активизированы в любом месте программы.328Глава 15. Модульное программированиеПроцедурам, так же как и макрокомандам, могут быть переданы некоторые аргументы. Это позволяет, имея одну копию кода в памяти, изменять ее для каждогоконкретного случая использования, хотя по гибкости процедуры уступают макрокомандам.В главе 10 нами были рассмотрены возможные варианты размещения процедурв программе:в начале программы (до первой исполняемой команды);в конце программы (после команды, возвращающей управление операционнойсистеме);промежуточный вариант — тело процедуры располагается внутри другой процедуры или основной программы (в этом случае необходимо предусмотретьобход процедуры с помощью команды безусловного перехода JMP);* в другом модуле.Главная цель таких вариантов размещения — не допустить несанкционированной передачи управления коду процедуры.
Три первых варианта относятся к случаю, когда процедуры находятся в одном сегменте кода. Мы их достаточно подробнообсудили. Что же касается последнего варианта, то он предполагает, что процедуры находятся в разных модулях. А это дает нам возможность говорить уже не ободном модуле, а о нескольких. Для реализации одной общей задачи эти модулидолжны быть связаны между собой по управлению и по данным. Если мы разберемся с тем, как организовать такую связь, то фактически сможем выполнить функциональную декомпозицию любой большой программы на нужное количествоболее мелких. В первой части главы мы рассмотрим, как организуется связь поуправлению и по данным между модулями на ассемблере, а во второй части — между модулями на ассемблере и на языках высокого уровня (Pascal и C/C++).Сначала необходимо отметить один общий для всех этих трех языков момент.Так как отдельный модуль в соответствии с концепцией модульного программирования — это функционально автономный объект, то он ничего не должен знатьо внутреннем устройстве других модулей, и наоборот, другим модулям также ничего не должно быть известно о внутреннем устройстве данного модуля.
Однакодолжны быть какие-то средства, с помощью которых можно связать модули. В качестве аналогии можно привести организацию связи (интерфейс) телевизора и видеомагнитофона через разъем типа «скарт». Связь унифицирована, то есть известно, что один контакт предназначен для видеосигнала, другой — для передачи звукаи т. д.
Телевизор и видеомагнитофон могут быть разными, но связь между нимиодинакова. Та же идея лежит и в организации связи модулей. Внутреннее устройство модулей может совершенствоваться, они вообще могут в следующих версияхписаться на другом языке, но в процессе их объединения в единый исполняемыймодуль этих особенностей не должно быть заметно.
Таким образом, каждый модуль должен иметь такие средства, с помощью которых он извещал бы трансляторо том, что некоторый объект (процедура, переменная) видимым вне этого модуля.И наоборот, нужно объяснить транслятору, что некоторый объект находится внеданного модуля. Это позволит транслятору правильно сформировать машинныекоманды, оставив некоторые их поля не заполненными. Позднее, на этапе компо-Процедуры в языке ассемблера329новки, программа TLINK (TASM) или программа компоновки языка высокогоуровня произведут настройку модулей и разрешат все внешние ссылки в объединяемых модулях.Для того чтобы объявить о подобного рода объектах, видимых извне, программа должна использовать две директивы TASM: EXTRN и PUBLIC. Директива EXTRNпредназначена для объявления некоторого имени внешним по отношению к данному модулю.
Это имя в другом модуле должно быть объявлено в директиве PUBLIC.Директива PUBLIC предназначена для объявления некоторого имени, определенного в этом модуле и видимого в других модулях. Синтаксис этих директив следующий:e x t r n имя:типимя:типpublic и м я , . . . , и м яЗдесь имя — идентификатор, определенный в другом модуле. В качестве идентификатора могут выступать:li имена переменных, определенных директивами типа DB, DW и т. д.;ж имена процедур;ж имена констант, определенных операторами = и EQU.Аргумент тип определяет тип идентификатора.
Указание типа необходимо длятого, чтобы транслятор правильно сформировал соответствующую машинную команду. Действительные адреса вычисляются на этапе редактирования, когда будут разрешаться внешние ссылки. Возможные значения типа определяются допустимыми типами объектов для этих директив:в если имя — это имя переменной, то тип может принимать значения BYTE, WORD,DWORD, PWORD, FWORD, QWORD и TBYTE;в если имя — это имя процедуры, то тип может принимать значения near или far;li если имя — это имя константы, то тип должен быть abs.Покажем принцип использования директив EXTRN и PUBLIC на схеме связи модулей 1 и 2 (листинги 15.1 и 15.2).Листинг 15.1. Модуль 1;Модуль 1masm.model small.stack 256.data.codemy_proc_lprocmy_proc_lmy_proc_2endpprocmy_proc_2endp;объявляем процедуру my_proc_l видимой извнеpublic my_proc_lstart:mov a x , @ d a t aend s t a r t330Глава 15.
Модульное программированиеЛистинг 15.2. Модуль 2;Модуль 2masm.modelsmall. s t a c k 256.data. codeextrnmy_proc_lstart:mov a x , @ d a t acall my_proc_lend start;объявляем процедуру roy_proc_l внешней;вызов my_proc_l из модуля 1Рассмотренная нами схема связи — это, фактически, связь по управлению. Ноне менее важно организовать информационный обмен между модулями.
Рассмотрим основные способы организации такой связи.Информационный обмен между модулями (процедурами) предполагает обменданными. В этой связи важно понимать значение терминов аргумент, переменная,константа.Аргумент — это ссылка на некоторые данные, которые требуются для выполнения возложенных на модуль функций и размещенных вне этого модуля. По аналогии с макрокомандами выделяют формальные и фактические аргументы.
Исходя из этого, формальный аргумент можно рассматривать не как непосредственныеданные или их адрес, а как «тару» для действительных данных, которые будут положены в нее с помощью фактического аргумента. Формальный аргумент можнорассматривать как элемент интерфейса модуля (конкретный вывод «скарта»),а фактический аргумент — это то, что фактически передается на место формального аргумента.Переменная — это нечто, размещенное в регистре или ячейке памяти, что может в дальнейшем подвергаться изменению.Константа — информационный объект простого типа, значение которого никогда не изменяется.Таким образом, если некоторые данные в модуле могут подвергаться изменению, то это переменные.