носительно начала структуры. Теперь ссылаться на числа структуры
Вы можете по имени поля точно так, как это делается в Си или Пас-
кале. Например,
сmр MaxMinShort.ShortInteger1,ax
что эквивалентно
cmp [MaxMinShort + 2],ax
В качестве примера, если мы хотим просмотреть весь список чи-
сел в поисках первого числа с плавающей запятой меньше 0, следует
написать:
mov di,MathList ;получить адрес списка
mov cx,ListLength ;длина списка для зацикл-я
mov bx,(TYPE TrueFalse) ;длина структуры
CmpLup: cmp [di].Float1,0 ;число с ПЗ > 0?
jl ExitLup ;если нет, искать
add di,bx ;указатель на др.структуру
loop Cmplup ;просмотреть весь список эл-ов
ExitLup:...
Адресация к данным во множественных структурах
Одной из удобных возможностей использования структур является
то, что Вы можете в любое время переорганизовывать описание
- 1-58 -
структуры или добавлять к нему новые элементы, которые будут ав-
томатически изменяться при ассемблировании. Например, изменим
предыдущую структуру MathList так, чтобы в ней поменялись местами
двоичные числа с плавающей запятой и добавился элемент
LibraryPtr.
MathNumbers STRUC
Float1 DT (0) ;1 10-байтовое слово
Float2 DT (0) ;1 10-байтовое слово
ShortInteger1 DW (0) ;1 слово
ShortInteger2 DW (0) ;1 слово
LongInteger1 DD (0) ;1 двойное слово
LongInteger2 DD (0) ;1 двойное слово
Boolean1 DB (0) ;1 байт
Boolean2 DB (0) ;1 байт
LibraryPtr DD (?) ;1 двойное слово
MathNumbers ENDS
В нашем случае преимущество использования имен структур в том,
что после реассемблирования всей программы и элементов данных но-
вое описание структуры [di].Float1 по-прежнему будет указывать на
первое число с плавающей запятой, хотя мы и реорганизовали дан-
ные. Таким образом, программный код, который ссылается на данные
по именам структур, не требует корректировки. Заметим, однако,
что если данные файла используют старые описания структур, мы
должны перегруппировать существующие данные так, чтобы они отве-
чали новой структуре. Реорганизация структуры не перегруппировы-
вает существующие данные, для них лишь объявляется относительное
местоположение. Мы должны убедиться, что действительные данные
соответствуют объявлению структуры данных.
В отличие от структур языка Си структуры MASM не могут содер-
жать описания других структур (для этого нет особых причин, и,
вероятно, в более старших версиях MASM это ограничение будет сня-
то). Однако нет причины, чтобы структура не могла содержать адрес
другой структуры, вот почему мы включили в структуру элемент
LibraryPtr. Предположим, что у нас есть структура Library, опре-
деленная так:
Library STRUC
FloatLib DD (0) ;указатель на библ. с ПЗ
ShortIntLib DD (0) ;указатель на библ. с коро-
;ткими целыми
LongIntLib DD (0) ;указатель на библ. с длин-
;ными целыми
ВooleanLib DD (0) ;указатель на библ. с бу-
;левыми значениями
Library ENDS
Теперь мы можем определить набор библиотечных программ с адре-
сами, организованными в структуры. Например,
АddLibs Library
Sublibs Library
MultLibs Library
.
.
.
- 1-59 -
Такая комбинация структур может быть использована как показа-
но в следующем программном сегменте:
lds si,MathList[bx] ;адрес конкретной структуры
push ds ;сохранить адрес структуры данных
push si
lds si,LibraryPtr ;адрес адресов библиотеки
call [ds:si].LongIntLib ;переход на выполнение
;операции
Cоответствующие указатели загружаются в структуру или во время
ассемблирования, или во время выполнения программы. Прелесть ис-
пользования адреса структуры для передачи в подпрограммы парамет-
ров и указателей в том, что вызывающий программный код всегда
один и тот же, несмотря на количество изменений структуры, прово-
димых в течение всей жизни программы. Помещая в структуру указа-
тели на другие структуры данных, мы избавляем программный код от
необходимости знания деталей о данных и/или вызываемых операциях.
Такое "сокрытие данных" развито и более часто используется в объ-
ектно ориентированных языках типа С++ или Smalltalk, однако Вы
можете добиться почти того же самого, применяя только структуры.
Применить определенную Вами структуру можно также и к набору дан-
ных, который создан не Вами. Например, получить доступ к первым
22 байтам PSP (префикс программного сегмента), которые MS-DOS по-
мещает в начало выполняемых файлов, можно через следующую струк-
туру:
PSP STRUC
INT32 DB 2 DUP (?) ; 2 байта
MemSize DW (?) ; 1 слово
Reserved DB (?) ; 1 байт
DOSCall DB 5 DUP (?) ; 5 байтов
TermVctr DW 2 DUP (?) ; 2 слова
BreakVctr DW 2 DUP (?) ; 2 слова
ErrorVctr DW 2 DUP (?) ; 2 слова
PSP ENDS
Получить доступ к PSP можно при помощи следующего программного
фрагмента:
mov di,0 ; PSP начинается со смещения 0
push cs ; сегмент PSP в cs
pop ds ; сегмент PSP -> ds
mov si,[di].MemSize ; размер памяти программы ->
; экстра сегмент
Структуры как параметры подпрограмм
Мы ввели структуры, как способ решения задачи по написанию
универсальной процедуры вызова подпрограмм. Разрешите вернуться к
этой проблеме. Наилучший вариант передачи параметров подпрограмме
- через адрес структуры. В качестве примера передадим данные на-
шей подпрограмме в одном из элементов списка чисел, определенного
при рассмотрении структур. Адреса всегда состоят из сегмента и
смещения. Таким образом, макро, вызывающее подпрограмму и переда-
ющее параметры, будет выглядеть так:
- 1-60 -
@FcnCall MACRO Fnctn,StrucAddr ;адрес подпрограммы и
;структуры
push offset StrucAddr
push segment StrucAddr
call Fnctn
Иногда случается, что Вам необходимо ассемблировать команду,
которую ассемблер не поддерживает. Такое необходимо в ранних вер-
сиях MASM, где из-за ошибки не ассемблируется конкретный тип ко-
манды перехода. Подобная проблема может также возникнуть при ра-
боте на новом процессоре, некоторые команды которого MASM еще не
поддерживает. Один из путей решения этой проблемы заключается в
использовании макро, которое ассемблирует данные, как если бы вы-
полнялась команда из Руководства фирмы Intel. Например, следующее
макро имитирует выполнение команды ближнего перехода.
@JmpShort MACRO destin
db 0EBh ;1-ый байт команды перехода
n = destin - * ;вычислить расстояние перехода
IFE (n LE 255) ;в байт поместится?
db n ;расстояние перехода
ELSE
.ERR ;выдать сообщение об ошибке
%OUT Ошибка в макро @JumpShort.
ENDIF ;конец проверки условия
db 90h ;3-ий байт команды
;короткого перехода
ENDM
Такой пример был выбран для простоты. При создании более слож-
ных команд необходимы и более сложные макросы. Чтобы подбодрить
Вас, сообщим, что некоторые программисты создавали полные кросс-
ассемблеры, используя немногим больше, чем описано в данном ме-
тоде.
Заключение
Наше введение в макросы, условное ассемблирование и структуры
MASM завершено. Мы надеемся, что из примеров данной главы Вы по-
чувствовали довольно сложные, но несомненно стоящие возможности
Макро Ассемблера фирмы Майкрософт.
В этой главе по каждой возможности мы представили множество
примеров, начиная с простых и кончая сложными, так что была опре-
делена мера полезности этих возможностей. Используя примеры и вы-
полняя собственные упражнения, Вы можете определить границу между
возможным и невозможным MASM-ассемблера.
Однако Вам не следует забывать причину использования макросов
и условного ассемблирования. Мы утверждаем, что правильное ис-
пользование этих возможностей может помочь Вам в организации
программы, повышая, следовательно, ее читаемость и надежность и
уменьшая время, необходимое на ее отладку. Мы надеемся, что
представленные примеры вместе с дружескими советами, комментария-
ми и некоторыми предупреждениями дали Вам понимание, как исполь-
зовать эти две возможности для развития Ваших программистских на-
выков.
Глава 2. СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ 2: ПРОЕКТИРОВАНИЕ
И РЕАЛИЗАЦИЯ МОДУЛЬНЫХ ПРОГРАММ
Принципы модульного программирования
Реализация модульных программ на языке Ассемблер
Типы кодирования
Интерфейс с языками высокого уровня
Назначение и использование локального ЗУ в памяти
Заключение
В главе 1 обсуждение было сфокусировано на средствах струк-
турного программирования и их применении в среде макроассемблера
MASM. В главе 2 представлены методы структурного программирования
и их применение в среде MS-DOS и микропроцессоров 8086/8088.
Кроме этого, представленный материал содержит еще две отдель-
ные темы. Эти темы связаны с проектированием модульных программ
на языке Ассемблер и реализацией этого проектирования путем ис-
пользования макроассемблера MASM, макроопределений и прочих
средств, относящихся к этим проблемам. Обе темы затрагивают осо-