Turbo Assembler 3.0. Руководство пользователя

         

Командная строка компоновщика


Простейший способ скомпоновать модули 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

Таким образом вы можете использовать длинный список стандар- тных файлов и параметров, благодаря чему можно легко изменять по- ведение Ассемблера при каждом ассемблировании.

Вы можете либо поместить все имена и параметры файлов в одну строку командного файла, либо разбить их на несколько строк, как это необходимо.



Labels can't start with numeric characters


(Метки не могут начинаться с цифровых символов)

Обнаружено имя, которое не является ни допустимым числом, ни допустимым именем идентификатора. Например: 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, как он определен выше.

б). Если она не является первым символом в строке, или если результирующее имя идентификатора будет предс- тавлять собой определенное имя идентификатора, тогда точка присоединяется к началу следующего за ней иден- тификатора.



Line too long - truncated


(Строка слишком длинная - производится усечение)

Текущая строка исходного файла содержит более 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).

Назад | Содержание | Вперед



Location counter overflow


(Переполнение счетчика адреса)

Текущий сегмент заполнен, последующий код или данные затрут начало сегмента. Например:

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


В 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 (где каждая буква интерпретируется как имя идентификатора.



Макрокоманды, состоящие из нескольких строк


Макрокоманды, состояние из нескольких строк, позволяют вам определить в их теле инструкции, директивы или другие макрокоман- ды, которые будут включаться в исходный код при вызове макроко- манды. Вы можете указать аргументы макрокоманды, которые Турбо Ассемблер будет подставлять в тело макрокоманды при ее включении в модуле.

Существует насколько типов макрокоманд, состоящих из нес- кольких строк. Одна версия подставляет каждый элемент строки (один за другим), который является аргументом макрокоманды. Дру- гая версия повторяет определенное число раз тело макрокоманды. Наконец, в одном месте вы можете определить еще одну версию, ко- торая будет много раз вызываться. Все эти версии имеют общее оп- ределение тела макрокоманды.



Method call requires object name


(В вызове метода необходимо имя объекта)

Оператор CALL.METHOD не может получить тип объекта из эк- земпляра указателя. Вы должны указать имя объекта.



Missing argument list


(Отсутствует список аргументов)

В директиве IRP или IRPC, определяющей блок повторения, не указан список аргументов для формального параметра. Например:

IRP X ; нет списка аргументов DB X ENDM

В директивах IRP и IRPC обязательно должен быть указан фор- мальный параметр и список аргументов.



Missing argument or <


(Отсутствует аргумент, либо не указана угловая скобка <)

Не указаны угловые скобки, либо вообще отсутствует выражение в угловых скобках там, где оно необходимо. Например:

if b ; должно быть указано выражение в угловых ; скобках



Missing argument size variable


(Отсутствует переменная для размера блока параметров)

В директиве ARG или LOCAL не указано имя идентификатора пос- ле знака равенства в конце оператора. Например:

ARG A:WORD,B:DWORD= ; ошибка, нет имени после знака= LOCAL X:TBYTE= ; та же ошибка

В директивах ARG и LOCAL после знака равенства, если он ука- зан, обязательно должно быть указано имя переменной для размера блока параметров.



Missing COMM ID


(Отсутствует идентификатор в директиве COMM)

В директиве COMM не указано имя идентификатора перед специ- фикатором типа. Например:

COMM NEAR ; ошибка: отсутствует ; имя идентификатора перед "NEAR"

В директиве СОММ обязательно должно быть указано имя иденти- фикатора. Имя идентификатора и спецификатор типа должны быть раз- делены двоеточием (:).



Missing dummy argument


(Отсутствует формальный параметр)

В директиве IRP или IRPC, определяющей блок повтора, отсутс- твует формальный параметр. Например:

IRP DB X ; нет формального параметра ENDM

В директивах IRP и IRPC обязательно должны быть указаны фор- мальный параметр и список аргументов.



Missing end quote


(Отсутствует закрывающая кавычка)

В конце строковой константы нет закрывающей кавычки. Напри- мер:

DB "abc ; отсутствует кавычка в конце ABC mov al,'X ; отсутствует кавычка после Х

Строковая константа должна оканчиваться той же кавычкой, ко- торой она начинается.



Missing macro ID


(Отсутствует идентификатор макрокоманды)

В директиве MACRO, определяющей макрокоманду, отсутствует имя. Например:

MACRO ; ошибка: не указано имя макрокоманды DB A ENDM

Имя в определении макрокоманды указывать обязательно.



Missing module name


(Отсутствует имя модуля)

В директиве NAME не указано имя модуля. Напомним, что дирек- тива NAME действует только в режиме Ideal.



Missing or illegal language ID


(Отсутствует или неверно указан идентификатор языка)

В директиве .MODEL неверно указан идентификатор языка. Под- робное описание директивы MODEL см. в Главе 7 настоящего руко- водства.



Missing or illegal type specifier


(Отсутствует или неверно указан спецификатор типа)

В операторе отсутствует или неверно указан обязательный па- раметр - идентификатор типа (BYTE, WORD и т.д.) Например:

RED LABEL XXX ; ошибка: "ХХХ" не является ; идентификатором типа



Missing table member ID


(Пропущен идентификатор элемента таблицы)

В операторе CALL.METHOD после ключевого слова METHOD пропущено имя объекта.



Missing term in list


(Отсутствует член в списке параметров)

В режиме Ideal в директиве, допускающей указание нескольких параметров (такой как EXTRN, PUBLIC и т.д.), отсутствует параметр после одной из запятых, отделяющих параметры друг от друга. Нап- ример:

EXTRN XXX:BYTE,,YYY:WORD

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



Missing text macro


(Отсутствует текстовая макрокоманда)

В директиве не указан обязательный параметр - текстовая мак- рокоманда. Например:

NEWSTR SUBSTR ; для SUBSTR должны быть ; указаны параметры



Множества


Множества, как и строки, обычно никогда не заносятся непос- редственно в стек. Вместо этого в стек заносится указатель на множество. Первый бит младшего байта множества всегда соответс- твует элементу базового типа (или порождающего типа) с порядковым значением 0.

Единственное исключение из этого правила - это случай, когда подпрограмма в перекрываемом (оверлейном) модуле A передает как параметр-значение константу-множество подпрограмме в оверлейном модуле B. В этом контексте перекрываемый модуль означает любой модуль, компилированный с директивой {$O+} (допускаются оверлеи). В этом случае перед тем, как будет сделан вызов и адрес стека бу- дет передан программе в модуле B, в стеке для множества-константы резервируется временная память.



Model must be specified first


(Сначала должна быть указана модель памяти)

Использована одна из упрощенных сегментных директив без предварительной спецификации модели памяти. Например:

.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. Выведется сообщение:


Это время после полудня? (ДА/НЕТ) - [Y/N]

Курсор будет мерцать у последнего символа в ожидании ввода ответа. Нажмите Y. Программа ответит:

Здравствуйте!

Таким образом HELLO.ASM стала теперь интерактивной програм- мой с принятием решений.

В ходе ассемблирования вы, конечно, получите различные сооб- щения об ошибках из-за неправильного набора программы и ошибках в синтаксисе. Турбо Ассемблер перехватывает такие ошибки, сообщая о них. Выводимые сообщения об ошибках разбиваются на две категории: предупреждения и ошибки. Если Турбо Ассемблер обнаруживает что-то подозрительное, но необязательно неверное, он выводит предупреж- дающее сообщение. Иногда предупреждающие сообщения можно игнори- ровать, но всегда лучше их проверить и убедиться в том, что вы понимаете суть проблемы. При обнаружении чего-либо явно непра- вильного в вашей программе, что делает невозможным завершение ас- семблирования и формирование объектного файла, Турбо Ассемблер выводит сообщение об ошибке.

Другими словами, предупреждающие сообщения не свидетельству- ют о критических ошибках, в то время как ошибки, о которых гово- риться в сообщениях об ошибках, должны быть исправлены перед за- пуском программы. В Приложении E содержится перечень сообщений об ошибках и предупреждающих сообщений.

Как и любой язык программирования, Турбо Ассемблер не может распознавать ошибки в логике программы. Турбо Ассемблер только сообщает вам, может ли ваш ассемблируемый код быть выполнен в том виде, как он введен, но он не может сделать вывод о том, будет ли программа работать так, как вы этого хотите. Об этом можете су- дить только вы сами.

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


Module is pass-dependant - compatibility pass was done


(Модуль зависит от прохода. Выполнен проход, обеспечивающий совместимость с MASM)

Это предупреждающее сообщение выдается, если обнаружена конструкция, зависящая от прохода, и в командной строке указан параметр /m. В этом случае выполняется проход, обеспечивающий совместимость с MASM.



Name must come first


(Имя должно быть указано первым)

Имя идентификатора указано после названия директивы, тогда когда оно должно находиться перед названием директивы. Например:

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;}

// Две функции, которые будут фактически написаны на // Ассемблере:


void increment(void); void add(int what_to_add=-1); // Отметим, что умолчание влияет только // на вызовы add; оно не влияет на код add }

extern "C" { // Для создания уникальных и осмысленных имен // ассемблерных подпрограмм прибавим имя класса к // имени ассемблерной подпрограммы. В отличие от прочих // ассемблеров, Турбо Ассемблер не имеет проблем с // длиной имен. void count_add_increment(int *count); // Мы передадим // указатель на // переменную count. // Ассемблер выполнит // увеличение. void count_add_add(int *count,int what_to_add); }

void count_add::increment(void) { count_add_increment(&count); }

void count_add(int what_to_add) { count_add(&count, int what_to_add); }

Ваш ассемблерный модуль, определяющий подпрограммы count_add _increment и count_add_add, должен иметь вид (COUNTADD.ASM):

.MODEL small ; выбор модели small (ближние код и данные) .CODE PUBLIC _count_add_increment _count_add_increment PROC ARG count_offset:word ; Адрес переменной-элемента push bp ; Сохранение записи активации ; вызывающей программы mov bp,sp ; Установка собственной записи ; активации mov bx,[count_offset] ; Загрузка указателя inc word ptr [bx] ; Увеличение переменной-элемента pop bp ; Восстановление записи активации ; вызывающей программы _count_add_increment ENDP

PUBLIC _count_add_add _count_add_add PROC ARG count_offset:word,what_to_add:word push bp mov bp,sp mov bx,[count_offset] ; Загрузка указателя mov ax,[what_to_add] add [bx],ax pop bp ret _count_add_add ENDP

end

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


Near jump or call to different CS


(Адресат ближнего перехода или вызова находится в другом ко- довом сегменте)

Это сообщение об ошибке выдается при попытке осуществить ближний вызов или переход по адресу, определенному в области, где регистр CS указывает на другой сегмент.



Need address or register


(Требуется указать адрес или регистр)

Не указан второй операнд команды, т.е. операнд указываемый после запятой. Например:

mov ax, ; нет второго операнда



Need angle brackets for structure fill


(Значения для структуры должны указываться в угловых скоб- ках)

В операторе выделения памяти под структуру не указан список начальных значений. Например:

STR1 STRUC M1 DW ? M2 DD ? ENDS STR1 ; нет списка начальных значений



Need colon


(Требуется двоеточие)

В директиве EXTRN, GLOBAL, ARG и LOCAL отсутствует двоеточие перед спецификатором типа (BYTE, WORD и т.д.) Например:

EXTRN X BYTE,Y:WORD ; после Х нет двоеточия



Need expression


(Требуется указать выражение)

Выражение содержит операцию, для которой не указан операнд. Например:

Х = 4 + * 6



Need file name after INCLUDE


(В директиве INCLUDE должно быть указано имя файла)

В директиве INCLUDE не указано имя файла. Например:

INCLUDE ; не указано, какой файл должен быть включен

В режиме Ideal имя файла должно быть заключено в кавычки.



Need left parenthesis


(Отсутствует левая круглая скобка)

Опущена левая круглая скобка там, где это не допускается синтаксисом выражения. Например:

DB 4 DUP 7

Выражение в операции DUP обязательно должно быть заключено в круглые скобки.



Need method name


(Требуется имя метода)

Оператор CALL.METHOD требует после ключевого слова METHOD имени метода.



Need pointer expression


(Требуется выражение-указатель)

Эта ошибка возникает только в режиме Ideal и указывает, что выражение в квадратных скобках ([]) не является указателем на па- мять. Например:

mov ax,[word ptr]

В режиме Ideal в квадратных скобках допускается указывать только адресные выражения.



Need quoted string


(Требуется указать строку в кавычках)

Ошибка при вводе параметра директивы, который должен предс- тавлять собой строку, заключенную в кавычки. В режиме Ideal для ряда директив в качестве параметра указывается строка в кавычках. Например:

Ideal DISPLAY "Все сделано"



Need register in expression


(В выражении требуется указать имя регистра)

В выражении не указано имя регистра там, где это является обязательным.