Глава 16. Интерфейс с компоновщиком
Модульные программы обычно состоят из нескольких независимых
частей кода, называемых модулями. Компилятор обрабатывает каждый
из этих модулей независимо, а компоновщик (TLINK) объединяет по-
лученные части вместе для создания выполняемого файла. О том, как
использовать TLINK, рассказывается в документации по компилятору,
но важно также знать, как определить и включить все файлы и биб-
лиотеки, которые могут понадобиться при компоновке. В данной Гла-
ве рассказывается о том, как это сделать.
Описание внешних идентификаторов
Может оказаться так, что вам потребуется использовать неко-
торые переменные или процедуры во всех модулях вашей программы.
Турбо Ассемблер обеспечивает несколько директив, которые позволя-
ют вам определить идентификаторы и библиотеки таким образом, что
вы сможете использовать их глобально, а также использовать общие
переменные (для которых выделяет память компоновщик). Вам потре-
буется также соблюдать аккуратность при назначении имен идентифи-
каторов, поскольку различные языки имеют здесь конкретные требо-
вания. В следующий нескольких разделах мы обсудим эти директивы и
соглашения по наименованию.
Соглашения для конкретного языка
Когда вы назначаете имена идентификаторам, которые планиру-
ется использовать глобально, нужно помнить об использовании спе-
цификатора языка. К именам переменных предъявляются следующие
требования:
- в Паскале имена указываются символами в верхнем регистре;
- в Си/С++ имен должны начинаться с символа подчеркивания
(_). Остальная часть имени записывается символами в нижнем
регистре.
Параметр /m (описанный в Главе 2) сообщает Турбо Ассемблеру,
что во всех именах идентификаторов нужно различать регистр. Пара-
метр /mx (также описанный в Главе 2) указывает, что различать ре-
гистр символов нужно только во внешних и общедоступных идентифи-
каторах, и что все другие идентификаторы в исходном файле записа-
ны в верхнем регистре. Когда вы используете эти два параметра
вместе, для идентификаторов, описанных в Паскале, они имеют спе-
циальное значение: они приводят к тому, что рассматриваемые иден-
тификаторы будут доступны компоновщику, как идентификаторы в
верхнем регистре.
Описание общедоступных идентификаторов
При описании общедоступного идентификатора вы предполагаете,
что он должен быть доступен из других модулей. Общедоступными мо-
гут быть следующие типы идентификаторов:
- имена переменных;
- метки программы;
- числовые константы, определенные с помощь EQU.
Для определения общедоступных идентификаторов можно исполь-
зовать директиву PUBLIC, которая имеет следующий синтаксис:
PUBLIC [язык] идентификатор [,[язык] идентификатор] .
где "язык" представляет собой C, CPP, PASCAL, BASIC, FORTRAN,
PROLOG или NOLANGUAGE и определяет соглашения конкретного языка,
применяемые к имени переменной. Использование спецификатора языка
в директиве PUBLIC временно переопределяет временно переопределя-
ет текущую установку языка (по умолчанию NOLANGUAGE, если другой
язык не задан в директиве .MODEL).
Турбо Ассемблер описывает идентификатор в объектном модуле
таким образом, что он будет доступен всем другим модулям. Если вы
не сделаете идентификатор общедоступным, то сможете обращаться к
нему только из текущего модуля, например:
PUBLIC XYPROC ; процедура общедоступна
XYPROC PROC NEAR
Описание идентификаторов библиотеки
Вы можете использовать идентификаторы, как динамические точ-
ки входа для динамически компонуемых библиотек (DLL). Для описа-
ния идентификаторов, которые будут доступны таким образом, ис-
пользуйте директиву PUBLICDDL. Она имеет следующий синтаксис:
PUBLICDLL [язык] идентификатор [,[язык] идентификатор] .
Турбо Ассемблер описывает идентификатор в объектном файле,
как динамически компонуемую точку входа, благодаря чему они могут
быть доступны в других программах. Спецификатор "язык" приводит к
применению специфических для языка соглашений к конкретному имени
идентификатора. Допустимыми спецификаторами языка являются специ-
фикаторы C, CPP, PASCAL, BASIC, FORTRAN, PROLOG и NOLANGUAGE.
Приведем пример кода с использованием PUBLICDLL:
PUBLICDLL XYPROC ; процедура XYPROC доступна как
XYPOROXC PROC NEAR ; динамически компонуемая точка
; входа
Определение внешних идентификаторов
Внешние идентификаторы - это идентификаторы, которые опреде-
лены вне модуля и которые вы можете использовать внутри модуля.
Эти идентификаторы должны быть описаны с помощью директивы
PUBLIC. Директива EXTRN имеет следующий синтаксис:
EXTRN определение [,определение] .
где "определение" описывает идентификатор и имеет следующий фор-
мат:
[язык] имя [[счетчик_1]] :сложный_тип [:счетчик_2]
Описание глобальных идентификаторов
Глобальные идентификаторы действуют также, как общедоступ-
ные, при этом вам не нужно определять PUBLIC или EXTRN. Если пе-
ременная определена в модуле, она действует как общедоступная.
Если нет, она действует как внешняя. Для определения глобальных
идентификаторов вы можете использовать директиву GLOBAL. Директи-
ва GLOBAL имеет тот же синтаксис, что директивы PUBLIC и EXTRN
(их синтаксис описан в предыдущих разделах).
Директива GLOBAL позволяет вам иметь включаемый файл, кото-
рый будет включаться во все исходные модули. Включаемый файл со-
держит все совместно используемые данные, определенные как гло-
бальные идентификаторы. Когда вы в каждом модуле ссылаетесь на
эти элементы данных, директива GLOBAL действует как директива
EXTRN, описывая для другого модуля, как определены данные.
Перед тем, как использовать его где-либо в исходном коде, вы
должны описать идентификатор как GLOBAL. Кроме того заметим, что
при задании аргументов директивы GLOBAL используется тот же син-
таксис, что и в директиве EXTRN.
Приведем пример:
GLOBAL X:WORD, Y:BYTE
X DW 0 ; идентификатор стал доступен в
; других модулях
mov al, Y ; описан как внешний
Определение общих переменных
Общие переменные действуют как внешние переменные, но здесь
есть одно существенное различие: общие переменные распределяются
компоновщиком. Общие переменные переменные на самом деле аналоги-
чны глобальным переменным, но вы не можете присвоить им начальные
значения. На эти неинициализированные переменные можно ссылаться
из нескольких модулей.
Для определения общей переменной вы можете использовать ди-
рективу COMM. Она имеет следующий синтаксис:
COMM определение [,определение].
Каждое "определение" описывает идентификатор и имеет следую-
щий формат:
[расстояние] [язык] имя_идентификатора[[счетчик_1]]:
сложный_тип [счетчик_2]
где поле "расстояние" не является обязательным и может быть FAR
или NEAR. Если вы не зададите "расстояние", по умолчанию оно бу-
дет соответствовать используемой модели памяти. Если вы не ис-
пользуете упрощенные директивы сегментации, то по умолчанию ис-
пользуется NEAR. В крошечной, малой и средней моделях по
умолчанию также используется NEAR, а во всех других - FAR.
Поле "язык" задает язык: C, PASCAL, BASIC, FORTRAN, PROLOG
или NOLANGUAGE. Использование в директиве COMM спецификатора язы-
ка временно переопределяет текущую установку языка (по умолчанию
или заданную с помощью директивы .MODEL). Заметим, что для того,
чтобы действовало данное средство, вам не обязательно использо-
вать директиву .MODEL.
Поле "имя_идентификатора" задает имя идентификатора, который
должен быть общим, и память для которого должна выделяться на
этапе компоновки. В этом поле можно также задавать коэффициент
размера элемента массива "счетчик_1", который должен учитываться
в вычисляемом объеме общей памяти. Если в качестве расстояния за-
дано FAR, то компоновщик, использует значение "счетчика_2", чтобы
указать, сколько имеется элементов с размером, равным произведе-
нию основного размера элемента (который определяется его типом)
на "счетчик_1". По умолчанию значение поля "счетчик_1" равно 1.
"Сложный_тип" - это тип данных аргумента. Он может быть либо
простым типом, либо сложным выражением с указателем. Более под-
робно о синтаксисе сложного типа рассказывается в Главе 5.
Необязательное значение "счетчик_2" определяет, сколько эле-
ментов определяет эта общая переменная. Если вы не задаете это
поле, то подразумевается значение 1. Полный объем памяти, выделя-
емой для общей переменной, равен произведению значения "счет-
чик_2" на длину, заданную полем "тип", и на значение "счетчик_1".
В режиме MASM, предполагается, что общие идентификаторы,
описанные вне любого сегмента, должны быть доступны с помощью ре-
гистра DS, что не всегда может допустимым предположением. Убеди-
тесь, что вы либо поместили в DS корректное значение сегмента,
либо при ссылке на эти переменные используете переопределение
сегмента. В режиме Ideal Турбо Ассемблер корректно проверяет, яв-
ляются ли общие переменные адресуемыми, используя любой из теку-
щих сегментных регистров, описанный в директиве ASSUME.
Приведем пример использования директивы COMM:
COMM buffer:BYTE:512 ; во время компоновки выделяет-
; ся 512 байт
COMM abc[41]:WORD:10 ; на этапе компоновки выделяет-
; ся память 820 байт (10 эле-
; ментов из 41 слова каждый)
COMM FAR abc[41]:WORD:10 ; на этапе компоновки выделяет-
; ся 10 элементов из 82 байт
; (2 байта * 41 элемент)
Включение библиотеки
В том случае, когда вы знаете, что ваш исходный файл будет
всегда использовать подпрограммы заданной библиотеки, можно ис-
пользовать директиву INCLUDELIB. Директива INCLUDELIB сообщает
компоновщику, что нужно включить указанную библиотеку. В режиме
Ideal эта директива имеет следующий синтаксис:
INCLUDELIB "имя_файла" ; обратите внимание на кавычки!
а в режиме MASM:
INCLUDELIB имя_файла
где "имя_файла" - это имя библиотеки, которую вы хотите включать
с помощью компоновщика на этапе компоновки. Если вы не укажете в
заданном имени файла расширение, то компоновщик подразумевает
расширение .LIB.
Приведем пример:
INCLUDELIB "diskio" ; включает DISKIO.LIB
Назад | Содержание | Вперед