Простейший способ скомпоновать модули Borland C++ с модулями Турбо Ассемблера состоит в том, чтобы ввести одну командную стро- ку Borland C++, после чего он выполнит всю остальную работу. При задании нужной командной строки Borland C++ выполнит компиляцию исходного кода Си, вызовет Турбо Ассемблер для ассемблирования, а затем вызовет утилиту TLINK для компоновки объектных файлов в вы- полняемый файл. Предположим, например, что у вас есть программа, состоящая из файлов на языке Си MAIN.CPP и STAT.CPP и файлов Ас- семблера SUMM.ASM и DISPLAY.ASM. Командная строка:
bcc main.cpp stat.cpp summ.asm display.asm
выполняет компиляцию файлов MAIN.CPP и STAT.CPP, ассемблирование файлов SUMM.ASM и DISPLAY.ASM и компоновку всех четырех объектных файлов, а также кода инициализации С++ и необходимых библиотечных функций в выполняемый файл MAIN.EXE. При вводе имен файлов Ас- семблера нужно только помнить о расширениях .ASM.
Если вы используете утилиту TLINK в автономном режиме, то генерируемые Турбо Ассемблером объектные файлы представляют собой стандартные объектные модули и обрабатываются также, как объек- тные модули С++. Описание TLINK в автономном режиме см. в Прило- жении С.
Комментировать код Ассемблера можно несколькими способами. Один из методов состоит в добавлении комментария в конец строки, используя точку с запятой, например:
mov [bx],a1 ; записать измененный символ
Другой способ комментирования исходного кода заключается в использовании в качестве символа комментария символа продолжения строки (\). (См. ниже раздел "Продолжение строки").
Комментирование исходного кода позволяет вам (или тому, кто будет эти программы в последующем поддерживать) быстро разбирать- ся в его работе. Использование комментариев считается хорошей практикой программирования на любом языке. Они позволяют описать семантику (смысл), а не только синтаксис кода. Мы рекомендуем вам широко использовать комментарии в исходном коде Ассемблера, и в данном разделе описывается, как это можно сделать.
Важной концепцией С++ является безопасная с точки зрения стыковки типов компоновка. Компилятор и компоновщик должны рабо- тать согласованно, чтобы гарантировать правильность типов переда- ваемых между функциями аргументов. Процесс, называемый "корректи- ровкой имен" (name-mangling), обеспечивает необходимую информацию о типах аргументов. "Корректировка имени" модифицирует имя функ- ции таким образом, чтобы оно несло информацию о принимаемых функ- цией аргументах.
Когда программа пишется целиком на С++, корректировка имен происходит автоматически и прозрачно для программы. Однако, когда вы пишете ассемблерный модуль для последующей его компоновки с программой на С++, вы сами обязаны обеспечить корректировку имен в модуле. Это легко сделать, написав пустую функцию на С+ и ском- пилировав ее с ассемблерным модулем. Генерируемый при этом Borland С++ файл .ASM будет содержать исправленные имена. Затем вы можете их использовать при написании реального ассемблерного модуля.
Например, следующий фрагмент кода определяет четыре различ- ные версии функции с именем test:
void test() { }
void test( int ) { }
void test( int, int ) { }
void test( float, double ) { }
Если этот код компилируется с параметром -S, то компилятор создает на выходе файл на языке Ассемблера (.ASM). Вот как он выглядит (несущественные детали убраны):
; void test() @testSqv proc near push bp mov bp,sp popo bp ret @testSqv endp
; void test( int ) @testSqi proc near push bp mov bp,sp popo bp ret @testSqi endp
; void test( int, int ) @testSqii proc near push bp mov bp,sp popo bp ret @testSqii endp
; void test( float, double ) @testSqfd proc near push bp mov bp,sp popo bp ret @testSqfd endp
После ассемблирования файла HELLO.ASM вы продвинулись только на один шаг в процессе создания программы. Теперь, если вы ском- понуете только что полученный объектный код в выполняемый вид, вы сможете запустить программу.
Для компоновки программы используется программа TLINK, представляющая собой поставляемый вместе с Турбо Ассемблером ком- поновщик. Введите командную строку:
TLINK HELLO
Здесь опять не требуется вводить расширение имени файла. Компоновщик TLINK по умолчанию предполагает, что этим расширением является расширение .OBJ. Когда компоновка завершится (самое большее через несколько секунд), компоновщик автоматически прис- воит файлу с расширением .EXE имя, совпадающее с именем вашего объектного файла (если вы не определили другое имя). При успешной компоновке на экране появляется сообщение:
Turbo Linker Version 3.0 Copyright (c) 1988, 1991 by Borland International Inc.
В процессе компоновки могут возникнуть ошибки (в данной программе это маловероятно). Если вы получили сообщения об ошиб- ках компоновки (они выводятся на экран), измените исходный код программы так, чтобы он в точности соответствовал тексту програм- мы в приведенном выше примере, а затем снова выполните ассембли- рование и компоновку.
Хорошим правилом является вызов библиотечных функций Borland C++ только из Ассемблера в программах, которые компонуются с мо- дулем инициализации С++ (используя его в качестве первого компо- нуемого модуля). Этот "надежный" класс включает в себя все прог- раммы, которые компонуются с помощью командной строки TC.EXE или TCC.EXE, и программы, в качестве первого компонуемого файла кото- рых используется файл C0T, C0S, C0C, C0M, C0L или C0H.
В общем случае вам не следует вызывать библиотечные функции Borland C++ из программ, которые не компонуются с модулем инициа- лизации Borland C++, так как некоторые библиотечные функции Borland C++ не будут правильно работать, если не выполнялась ком- поновка с кодом инициализации. Если вы действительно хотите вызы- вать библиотечные функции Borland C++ из таких программ, мы пред- лагаем вам взглянуть на код инициализации (файл C0.ASM на дистри- бутивных дисках Borland C++) и приобрести у фирмы Borland исход- ный код библиотеки языка С++, после чего вы сможете обеспечить правильную инициализацию для нужных библиотечных функций.
Вызов определяемых пользователем функций С++, которые в свою очередь вызывают библиотечные функции языка С++, попадают в ту же категорию, что и непосредственный вызов библиотечных функ- ций С++. Отсутствие кода инициализации С++ может вызывать ошибки в любой программе Ассемблера, которая прямо или косвенно обраща- ется к библиотечным функциям С++.
Константы представляют собой числа или строки, которые Турбо Ассемблер интерпретирует, как фиксированное числовое значение. Вы можете использовать различные типы числовых форматов, включая десятичные, шестнадцатиричные, двоичные и восьмеричные.
В качестве операндов в выражениях вы можете использовать константы, например:
mov ax,5 ; "5" - это операнд-константа
В любой момент, когда вы вводите командную строку, Турбо Ас- семблер позволяет вам задавать косвенный командный файл, с по- мощью указания перед его именем символа @. Например:
TASM /DTESTMODE @MYPROJ.TA
Эта команда приводит к тому, что содержимое файла MYPROJ.TA становится частью командной строки (как если бы вы ввели ее со- держимое непосредственно).
Это полезное средство позволяет вам поместить наиболее часто используемые командные строки и списки файлов в отдельный файл. При этом нет необходимости помещать всю командную строку в один косвенный файл, поскольку в одной командной строке допускается использовать несколько исходных файлов с обычными аргументами, например:
TASM @MYFILES @IOLIBS /DBUF=1024
Таким образом вы можете использовать длинный список стандар- тных файлов и параметров, благодаря чему можно легко изменять по- ведение Ассемблера при каждом ассемблировании.
Вы можете либо поместить все имена и параметры файлов в одну строку командного файла, либо разбить их на несколько строк, как это необходимо.
(Метки не могут начинаться с цифровых символов)
Обнаружено имя, которое не является ни допустимым числом, ни допустимым именем идентификатора. Например: 123XYZ.
допустимая_строка ::= пропуск допустимая_строка знак_пунктуации допустимая_строка числовая_строка допустимая_строка идентификатор_строки допустимая_строка нуль
пропуск ::= символ_пробела пропуск символ_пробела
символ_пробела ::= все управляющие символы, символы > 128, ' '
идентификатор_строки ::= идентификатор_символа идентификатор_строки_2
идентификатор_строки_2 ::= идентификатор_символа_2 идентификатор_строки_2 нуль
идентификатор_символа ::= $,%,_,?,символы алфавита
идентификатор_символа_2 ::= идентификатор_символов плюс цифры
числовая_строка ::= числ_строка стр_строка
числ_строка ::= цифры буквенно_цифровые_символы цифры'.'цифры показатель_степени цифры показатель_степени ; Только в режиме MASM в директи- ; вах DD, DQ и DT
цифры ::= цифра цифры цифра
цифра ::= от 0 до 9
алфавитно-цифровые_символы ::= цифра буквенно_цифровые_символы буква буквенно_цифровые_символы нуль
буква ::= буквы алфавита
показатель_степени ::= Е+цифры Е-цифры Ецифры нуль
стр_строка ::= строка в двойных кавычках; кавычка, вводимая двумя кавычками
знак_пунктуации ::= любой символ, отличный от следующих: символ_пробела,идентификатор_символ,'"',"'" или цифры
Символ точки (.) трактуется различным образом в режиме MASM и в режиме Ideal. Этот символ не требуется указывать в числах с плавающей запятой в режиме MASM. Точка не может входить в состав символического имени в режиме Ideal. В режиме MASM с этого симво- ла иногда начинаются символические имена, кроме того, знак пунк- туации используется иногда в качестве селектора поля структуры.
Правила интерпретации точки (.):
1. В режиме Ideal точка всегда интерпретируется как знак пунктуации.
2. В режиме MASM точка трактуется как первый символ иденти- фикатора в следующих случаях:
а). Когда она является первым символом в строке и в ряде некоторых других специальных случаев, например, в составе внешних (EXTRN) и общих (PUBLIC) символичес- ких имен, она присоединяется к следующему за ней сим- волическому имени, если следующий за ней символ представляет собой идентификатор_символа_2, как он определен выше.
б). Если она не является первым символом в строке, или если результирующее имя идентификатора будет предс- тавлять собой определенное имя идентификатора, тогда точка присоединяется к началу следующего за ней иден- тификатора.
(Строка слишком длинная - производится усечение)
Текущая строка исходного файла содержит более 255 символов. Лишние символы игнорируются.
Используйте угловые скобки для выделения литеральной строки, содержащей символы-разделители. Следует использовать следующий синтаксис:
<текст>
где "текст" интерпретируется как одиночный строковый параметр, даже если он содержит запятые, пробелы или символы табуляции, ко- торые обычно разделяют параметры. Используйте данную операцию, когда вы хотите передать аргумент, содержащий один из таких сим- волов.
Вы можете также использовать эту операцию, чтобы Турбо Ас- семблер интерпретировал символ литерально, не придавая ему специ- альное значение. Например, если вы хотите передать в качестве па- раметра макровызова точку с запятой (;), то чтобы предотвратить ее интерпретацию как комментария, вы можете заключить ее в угло- вые скобки (<;>). При преобразовании заключенной в скобки строки в текстовый аргумент Турбо Ассемблер убирает только один уровень угловых скобок. Это позволяет вызывать макрокоманду, требующую наличия угловых скобок, из другой макрокоманды.
Многие ведущие издательства издают по продуктам фирмы Borland превосходные книги, предназначенные для любого круга чи- тателей - от начинающих пользователей до тех, кто имеет достаточ- ный опыт работы. Приведем несколько названий книг, в которых можно найти дополнительную информацию о Турбо Ассемблере, Турбо отладчике и Турбо Профайлере:
Ackerman, Charles. Turbo Debugger and Tools: A Self-Teaching Guide, John Wiley and Sons (New York: 1990).
Swan, Tom. Mastering Turbo Assembler. Indianapolis: Hayden Books, 1989.
Swan, Tom. Mastering Turbo Debugger and Tools. Howard W. Sams and Co. (Carnel, IN: 1990).
Syck, Gary. The Waite Group's Turbo Assembler Bible, Howard W. Sams and Co. (Carmel, IN: 1990).
Назад | Содержание | Вперед
(Переполнение счетчика адреса)
Текущий сегмент заполнен, последующий код или данные затрут начало сегмента. Например:
ORG 0FFF0h ARRAY DW 20 DUP (0) ; переполнение
Логические арифметические операции позволяют вам выполнять операции булевской алгебры. Каждая из этих операций выполняется поразрядно, то есть, логическая операция выполняется по одному биту. Логические операции приведены в следующей таблице.
Логические арифметические операции Таблица 5.16 ------------------------------T---------------------------------¬ ¦ Выражение ¦ Значение ¦ +-----------------------------+---------------------------------+ ¦ NOT выражение ¦ Поразрядное дополнение выраже- ¦ ¦ ¦ ния. ¦ ¦ ¦ ¦ ¦ выражение_1 AND выражение_2 ¦ Поразрядная операция "И". ¦ ¦ ¦ ¦ ¦ выражение_1 OR выражение_2 ¦ Поразрядная операция "ИЛИ". ¦ ¦ ¦ ¦ ¦ выражение_1 XOR выражение_2 ¦ Поразрядная операция "исключа- ¦ ¦ ¦ ющее ИЛИ". ¦ L-----------------------------+----------------------------------
В начале тела макрокоманды вы всегда можете включить одну или более директив LOCAL. Директива LOCAL описывает специальные формальные аргументы, которым при каждом расширении макрокоманды будет присваиваться уникальное символьное имя.
Синтаксис директивы LOCAL в теле макрокоманды выглядит сле- дующим образом:
LOCAL формальный_аргумент_1 [,формальный_аргумент_2].
Если имя "формальный_аргумент", указанное в директиве LOCAL, не содержит префикс локального идентификатора, то присваиваемое ему уникальное имя идентификатора будет иметь вид ??xxxx, где xxxx представляет шестнадцатиричное число. В противном случае уникальное символьное имя будет иметь вид <локальный_пре- фикс>xxxx.
Примечание: Подробности о разрешении локальных иденти- фикаторов и задании локального префикса можно узнать в Гла- ве 11.
Вы можете использовать формальные аргументы LOCAL для зада- ния в теле макрокоманды меток, например:
LOCAL @agn, @zero XOR dx,dx MOV cx,exp MOV ax,1 JCXZ @zero MOV bx,factor @agn: MUL bx LOOP @agn @zero:
В MASM 5.1 и 5.2 предусмотрены специальные идентификаторы, которые вы можете использовать для управления областью действия ближних меток в небольшом диапазоне строк. Это идентификаторы @@, @F и @B.
Когда вы описываете @@, как ближнюю метку, используя двоето- чие (:), то определяете уникальный идентификатор вида @@xxxx (где xxxx - это шестнадцатиричное число). @B ссылается на последний определенный таким образом идентификатор. @F ссылается на следую- щий идентификатор с определением такого вида. Например:
version m510 @@: jmp @B ; перейти на предыдущий идентификатор @@ jmp @F ; перейти на следующий идентификатор @@ @@: jmp @B ; перейти на предыдущий идентификатор @@ jmp @F ; ошибка: нет следующего @@
Назад | Содержание | Вперед
Для повторения тела макрокоманды для каждого элемента в списке или каждого символа в строке вы можете использовать макро- директивы повторения IRP и IRPC. Каждая из этих директив требует от вас задания одного формального аргумента. Приведем синтаксис директивы IRP:
IRP формальный_аргумент, список_аргументов тело_макрокоманды ENDM
Директива IRPC имеет следующий синтаксис:
IRP формальный_аргумент, строка тело_макрокоманды ENDM
в обоих случаях "формальный_аргумент" - это аргумент, используе- мый в теле макрокоманды. Конец тела макрокоманды отмечает ENDM.
В синтаксисе директивы IRP "список_аргументов" состоит из спискам аргументов, разделенных запятыми. Аргументами может быть любой текст (идентификаторы, строки, числа и т.д.). Форма каждого аргумента в списке аналогична той, которая описана выше для вызо- ва общей макрокоманды, состоящей из нескольких строк. Список ар- гументов всегда нужно заключать в угловые скобки (<>).
В синтаксисе директива IRPC аргумент состоит из одной стро- ки. Строка может содержать столько символов, сколько вы хотите.
Для каждого аргумента или символа в строке Турбо Ассемблер будет включать в модуль тело макрокоманды, подставляя вместо фор- мального аргумента аргумент или символ (когда он его находит). Например:
IRP reg <ax,bx,cx,dx> PUSH reg ENDM
дает следующее:
PUSH ax PUSH bx PUSH cx PUSH dx
а директива IRPC:
IRPC LUCKY,1379 DB LUCKY ENDM
дает следующее:
DB 1 DB 2 DB 3 DB 4
Используйте директива IRPC аккуратно, поскольку Турбо Ас- семблер помещает каждый символ в строке в макрорасширение "как есть", поэтому макрокоманда строкового повторения:
IRPC CHAR,HELLO DB CHAR ENDM
может дать не DB 'H','E'','L','L','O', а DB H,E,L,L,O (где каждая буква интерпретируется как имя идентификатора.
Макрокоманды, состояние из нескольких строк, позволяют вам определить в их теле инструкции, директивы или другие макрокоман- ды, которые будут включаться в исходный код при вызове макроко- манды. Вы можете указать аргументы макрокоманды, которые Турбо Ассемблер будет подставлять в тело макрокоманды при ее включении в модуле.
Существует насколько типов макрокоманд, состоящих из нес- кольких строк. Одна версия подставляет каждый элемент строки (один за другим), который является аргументом макрокоманды. Дру- гая версия повторяет определенное число раз тело макрокоманды. Наконец, в одном месте вы можете определить еще одну версию, ко- торая будет много раз вызываться. Все эти версии имеют общее оп- ределение тела макрокоманды.
(В вызове метода необходимо имя объекта)
Оператор CALL.METHOD не может получить тип объекта из эк- земпляра указателя. Вы должны указать имя объекта.
(Отсутствует список аргументов)
В директиве IRP или IRPC, определяющей блок повторения, не указан список аргументов для формального параметра. Например:
IRP X ; нет списка аргументов DB X ENDM
В директивах IRP и IRPC обязательно должен быть указан фор- мальный параметр и список аргументов.
(Отсутствует аргумент, либо не указана угловая скобка <)
Не указаны угловые скобки, либо вообще отсутствует выражение в угловых скобках там, где оно необходимо. Например:
if b ; должно быть указано выражение в угловых ; скобках
(Отсутствует переменная для размера блока параметров)
В директиве ARG или LOCAL не указано имя идентификатора пос- ле знака равенства в конце оператора. Например:
ARG A:WORD,B:DWORD= ; ошибка, нет имени после знака= LOCAL X:TBYTE= ; та же ошибка
В директивах ARG и LOCAL после знака равенства, если он ука- зан, обязательно должно быть указано имя переменной для размера блока параметров.
(Отсутствует идентификатор в директиве COMM)
В директиве COMM не указано имя идентификатора перед специ- фикатором типа. Например:
COMM NEAR ; ошибка: отсутствует ; имя идентификатора перед "NEAR"
В директиве СОММ обязательно должно быть указано имя иденти- фикатора. Имя идентификатора и спецификатор типа должны быть раз- делены двоеточием (:).
(Отсутствует формальный параметр)
В директиве IRP или IRPC, определяющей блок повтора, отсутс- твует формальный параметр. Например:
IRP DB X ; нет формального параметра ENDM
В директивах IRP и IRPC обязательно должны быть указаны фор- мальный параметр и список аргументов.
(Отсутствует закрывающая кавычка)
В конце строковой константы нет закрывающей кавычки. Напри- мер:
DB "abc ; отсутствует кавычка в конце ABC mov al,'X ; отсутствует кавычка после Х
Строковая константа должна оканчиваться той же кавычкой, ко- торой она начинается.
(Отсутствует идентификатор макрокоманды)
В директиве MACRO, определяющей макрокоманду, отсутствует имя. Например:
MACRO ; ошибка: не указано имя макрокоманды DB A ENDM
Имя в определении макрокоманды указывать обязательно.
(Отсутствует имя модуля)
В директиве NAME не указано имя модуля. Напомним, что дирек- тива NAME действует только в режиме Ideal.
(Отсутствует или неверно указан идентификатор языка)
В директиве .MODEL неверно указан идентификатор языка. Под- робное описание директивы MODEL см. в Главе 7 настоящего руко- водства.
(Отсутствует или неверно указан спецификатор типа)
В операторе отсутствует или неверно указан обязательный па- раметр - идентификатор типа (BYTE, WORD и т.д.) Например:
RED LABEL XXX ; ошибка: "ХХХ" не является ; идентификатором типа
(Пропущен идентификатор элемента таблицы)
В операторе CALL.METHOD после ключевого слова METHOD пропущено имя объекта.
(Отсутствует член в списке параметров)
В режиме Ideal в директиве, допускающей указание нескольких параметров (такой как EXTRN, PUBLIC и т.д.), отсутствует параметр после одной из запятых, отделяющих параметры друг от друга. Нап- ример:
EXTRN XXX:BYTE,,YYY:WORD
В режиме Ideal параметры в любом списке всегда разделяются только одной запятой, в конце списка запятой быть не должно.
(Отсутствует текстовая макрокоманда)
В директиве не указан обязательный параметр - текстовая мак- рокоманда. Например:
NEWSTR SUBSTR ; для SUBSTR должны быть ; указаны параметры
Множества, как и строки, обычно никогда не заносятся непос- редственно в стек. Вместо этого в стек заносится указатель на множество. Первый бит младшего байта множества всегда соответс- твует элементу базового типа (или порождающего типа) с порядковым значением 0.
Единственное исключение из этого правила - это случай, когда подпрограмма в перекрываемом (оверлейном) модуле A передает как параметр-значение константу-множество подпрограмме в оверлейном модуле B. В этом контексте перекрываемый модуль означает любой модуль, компилированный с директивой {$O+} (допускаются оверлеи). В этом случае перед тем, как будет сделан вызов и адрес стека бу- дет передан программе в модуле B, в стеке для множества-константы резервируется временная память.
(Сначала должна быть указана модель памяти)
Использована одна из упрощенных сегментных директив без предварительной спецификации модели памяти. Например:
.CODE ; ошибка: сначала нужно указать директиву ; .MODEL
Перед использованием упрощенных сегментных директив должна быть указана с помощью директивы .MODEL модель памяти.
Чтобы данная функция Ассемблера могла могла вызываться из С++, она должна использовать ту же модель памяти, что и программа на языке С++, а также совместимый с С++ сегмент кода. Аналогично, чтобы данные, определенные в модуле Ассемблера, были доступны в программе на языке С++ (или данные С++ были доступны в программе Ассемблера), в программе на Ассемблере должны соблюдаться согла- шения языка С++ по наименованию сегмента данных.
Модели памяти и обработку сегментов на Ассемблере может ока- заться реализовать довольно сложно. К счастью, Турбо Ассемблер сам выполняет почти всю работу по реализации моделей памяти и сегментов, совместимых с Borland C++, при использовании упрощен- ных директив определения сегментов.
Теперь снова войдем в редактор и модифицируем программу та- ким образом, чтобы она могла воспринимать какие-то данные из внешней среды (этой "внешней средой" будете вы, а вводимые данные будут набираться на клавиатуре). Измените программу следующим об- разом:
.MODEL SMALL .STACK 100h .DATA TimePrompt DB 'Это время после полудня? (ДА/НЕТ) - [Y/N]$' GoodMorningMessage LABEL BYTE DB 13,10,'Доброе утро!',13,10,'$' GoodAfternoonMessage LABEL BYTE DB 13,10,'Здравствуйте!',13.10,'$' .CODE mov ax,@Data mov ds,ax ; установить регистр DS таким ; образом, чтобы он указывал ; на сегмент данных mov dx,OFFSET TimePrompt ; ссылка на сообщение-запрос mov ah,9 ; функция DOS вывода строки int 21h ; получить ответ из одного ; символа cmp al,'Y' ; указано время после полудня ; (прописная буква Y) jz IsAfternoon ; да, время указано после ; полудня cmp al,'y' ; указано время после полудня ; (строчная буква y) jnz IsMorning ; нет, время указано до ; полудня IsAfternoon: mov dx,OFFSET GoodAfternoonMessage ; указывает на ; приветствие "Здравствуйте" jmp DisplayGreeting IsMorning: mov dx,OFFSET GoodMorningMessage ; указывает на ; приветствие "Доброе утро" DisplayGreeting: mov ah,9 ; функция DOS вывода сообщения int 21h ; вывести соответствующее ; сообщение mov ah,4ch ; функция DOS завершения ; программы int 21h ; завершить программу END
Таким образом вы добавили в программу два очень важных новых средства: возможность ввода и принятие решений. Эта программа запрашивает у вас, является ли вводимое время временем после по- лудня, воспринимая ответ (один символ) с клавиатуры. Если таким ответом будет буква Y в верхнем или нижнем регистре (что означает ответ ДА), то программа выводит сообщение "Здравствуйте!", в про- тивном случае выводится сообщение "Доброе утро!". В данной прог- рамме имеются все основные элементы полезной программы: ввод из информации внешней среды, обработка данных и принятие решения.
Сохраните эту модифицированную программу на диске. После этого заново ассемблируйте и скомпонуйте программу, как в преды- дущем примере. Запустите ее снова, введя hello в ответ на подс- казку DOS. Выведется сообщение:
(Модуль зависит от прохода. Выполнен проход, обеспечивающий совместимость с MASM)
Это предупреждающее сообщение выдается, если обнаружена конструкция, зависящая от прохода, и в командной строке указан параметр /m. В этом случае выполняется проход, обеспечивающий совместимость с MASM.
(Имя должно быть указано первым)
Имя идентификатора указано после названия директивы, тогда когда оно должно находиться перед названием директивы. Например:
STRUC ABC ; ошибка: "ABC" должно стоять перед ; ключевым словом STRUC
В режиме Ideal имя идентификатора указывается после названия директивы, поэтому эта ошибка часто возникает при попытках ас- семблирования в режиме MASM программ, предназначенных для работы в режиме Ideal.
Хотя можно написать функцию-элемент класса С++ целиком на языке Ассемблера, это далеко не просто. Например, все функ- ции-элементы классов С++ имеют "откорректированные" имена, что обеспечивает безопасную по согласованности типов компоновку функ- ций и делает возможным переопределение функций, а ваша ассемблер- ная функция должна знать в точности, какое имя С++ ожидает для данной функции-элемента. Для доступа к переменным-элементам вы должны подготовить в ассемблерном коде определение STRUC, опреде- ляющее все переменные-элементы с точно совпадающими размерами и расположением. Если ваш класс является производным, то могут су- ществовать и другие переменные-элементы, производные от базового класса. Даже если класс не является производным (порожденным), то расположение переменных-элементов в памяти изменяется в случае, если класс этот включает в себя какие-либо виртуальные функции.
Если вы пишете функцию на встроенном Ассемблере, Borland С++ может взять на себя эти вопросы. Однако если вы работаете на язы- ке Ассемблера отдельно (например, переделываете уже имеющийся код), то существуют некоторые методы, позволяющие упростить эту работу.
Создайте определение фиктивной функции С++ для ассемблерной функции. Это определение удовлетворит компоновщик, так как будет содержать откорректированное имя функции-элемента. Эта фиктивная функция будет вызывать ассемблерную функцию и передавать ей пере- менные-элементы и прочие параметры. Так как ассемблерный код бу- дет иметь все нужные ему параметры посредством аргументов, вы мо- жете не заботиться об изменениях в определении класса. Ваша ассемблерная функция может быть описана в коде С++ как extern "C", что показано в примерах. Например (countadd.cpp):
class count_add { // Частные переменные-элементы (private) int access_count; // число обращений int count; // текущий счетчик public: count_add(void) { access_count=0; count=0; } int get_count (void) {return Count;}
// Две функции, которые будут фактически написаны на // Ассемблере:
(Адресат ближнего перехода или вызова находится в другом ко- довом сегменте)
Это сообщение об ошибке выдается при попытке осуществить ближний вызов или переход по адресу, определенному в области, где регистр CS указывает на другой сегмент.
(Требуется указать адрес или регистр)
Не указан второй операнд команды, т.е. операнд указываемый после запятой. Например:
mov ax, ; нет второго операнда
(Значения для структуры должны указываться в угловых скоб- ках)
В операторе выделения памяти под структуру не указан список начальных значений. Например:
STR1 STRUC M1 DW ? M2 DD ? ENDS STR1 ; нет списка начальных значений
(Требуется двоеточие)
В директиве EXTRN, GLOBAL, ARG и LOCAL отсутствует двоеточие перед спецификатором типа (BYTE, WORD и т.д.) Например:
EXTRN X BYTE,Y:WORD ; после Х нет двоеточия
(Требуется указать выражение)
Выражение содержит операцию, для которой не указан операнд. Например:
Х = 4 + * 6
(В директиве INCLUDE должно быть указано имя файла)
В директиве INCLUDE не указано имя файла. Например:
INCLUDE ; не указано, какой файл должен быть включен
В режиме Ideal имя файла должно быть заключено в кавычки.
(Отсутствует левая круглая скобка)
Опущена левая круглая скобка там, где это не допускается синтаксисом выражения. Например:
DB 4 DUP 7
Выражение в операции DUP обязательно должно быть заключено в круглые скобки.
(Требуется имя метода)
Оператор CALL.METHOD требует после ключевого слова METHOD имени метода.
(Требуется выражение-указатель)
Эта ошибка возникает только в режиме Ideal и указывает, что выражение в квадратных скобках ([]) не является указателем на па- мять. Например:
mov ax,[word ptr]
В режиме Ideal в квадратных скобках допускается указывать только адресные выражения.
(Требуется указать строку в кавычках)
Ошибка при вводе параметра директивы, который должен предс- тавлять собой строку, заключенную в кавычки. В режиме Ideal для ряда директив в качестве параметра указывается строка в кавычках. Например:
Ideal DISPLAY "Все сделано"
(В выражении требуется указать имя регистра)
В выражении не указано имя регистра там, где это является обязательным.