Реферат: Язык макроассемблера IBM PC - текст реферата. Скачать бесплатно.
Банк рефератов, курсовых и дипломных работ. Много и бесплатно. # | Правила оформления работ | Добавить в избранное
 
 
   
Меню Меню Меню Меню Меню
   
Napishem.com Napishem.com Napishem.com

Реферат

Язык макроассемблера IBM PC

Банк рефератов / Программирование

Рубрики  Рубрики реферат банка

закрыть
Категория: Реферат
Язык реферата: Русский
Дата добавления:   
 
Скачать
Microsoft Word, 563 kb, скачать бесплатно
Заказать
Узнать стоимость написания уникального реферата

Узнайте стоимость написания уникальной работы

ЯЗЫК МАКРО АССЕМБЛЕРА IBM PC (Справочное пособие ) Составитель : В.Н .Пильщиков (МГУ , ВМК ) (январь 1992 г .) В по собии рассматривается язык макроассеблера для персональных ЭВМ типа IBM PC (язык MASM, версия 4.0). Пособие состоит из 4 глав . В главе 1 рассмотрены особенности пер сональных компьютеров тип а IBM PC и приведены начальные сведен ия о языке MASM. В главе 2 описывается система команд этих компьютеров . Глава 3 посвящена посвящена собственно языку MASM. В главе 4 приве дены примеры фрагментов программ и полных программ на MASM для решения р а з ли чных задач. В пособии не рассматриваются вопросы , связанные с обработкой дво ично-десятичных чисе л и работой арифметического сопроцессора 8087 ил и 80287. П од термином "ПК " в пособии понимается перс ональный компьютер типа IBM PC c микропроцессором 8 088/8086, 80186 или 80286. ГЛАВА 1. ОСОБЕННОСТИ ПК . ВВЕДЕНИЕ В MASM. 1.1. ОПЕРАТИВНАЯ ПАМЯТЬ . РЕГИСТРЫ. 1.1.1 Оперативная память Объем оперативной памяти П К - 2^20 байтов (1 Мб ). Байты нумеруются начиная с 0, номер байта называется его адресом. Для ссылок на байты памяти используются 20-разрядные адреса : от 00000 до FFFFF (в 16-рич ной с истеме ). Байт содержит 8 разрядов (битов ), каждый из которых может прини мать значение 1 или 0. Разряды нумеруются справа налево от 0 до 7: ----------------- | | | | | | | | | ----------------- 7 6 5 4 3 2 1 0 Байт - это наименьшая адресуемая ячейка памяти . В ПК используются и более кру пные ячейки - слова и двойные слова . Слово - это два сосед них байта , размер слова - 16 битов (они нумеруются справа налево от 0 до 15). Адресом слова считается адрес его первого байта (с меньшим ад ресом ); этот адрес может быть четным и нечетным . Дво йное слово - это любые четыре соседних бай та (два соседних слова ), размер такой ячейк и - 32 бита ; адресом двойн о го слова считается адрес его первого байта . Б айты используются для хранения небольших цел ых чисел и символов, слова - для хранения целых чисел и адресов , двойные слова - для хране ния "длинных " цел ых чисел и т.н . адресных пар (сегмент :с мещение ). 1.1.2 Регистры Помимо ячеек оперативной п амяти для хранения данных (правда , крат ковреме нного ) можно использовать и регистры - ячейки , входящие в сос тав процессора и доступны е из машинной программы . Доступ к регистр ам осуществляется значительно быстр ее , че м к ячейкам памяти , поэтому ис пользование регистров заметно уменьшает время выполнения программ. Все регистры имеют размер слова (16 бит ов ), за каждым из них зак реплено определен ное имя (AX, SP и т.п .). По назначению и спос обу использования регистры можно разбить на следующие группы : - регистры общего назначения (AX, BX, CX, DX, BP, SI, DI, SP); - сегментные регистры (CS, DS, SS, ES); - счетчик команд (IP); - регистр флагов (Flags). (Расшифровка этих названий : A - accumulator, аккумулято р ; B - base, база ; C - counter, счетчик ; D - data, данные ; BP - base pointer, ука затель базы ; SI - source index, индекс источника ; DI - destination index, индекс приемника ; SP - stack pointer, указатель стека ; CS - code segment, сег мент команд ; DS - data segment, сегмент данных ; SS stack segment, сег мент стека ; ES - extra segment, дополнительный сег мент ; IP - instruction pointer, сч етчик команд .) Регистры общего назначения можно испол ьзовать во всех арифметичес ких и логических командах . В то же время каждый их них имеет опреде ленную специализацию (неко торые команды "работают " только с определен ным и регистрами ). Например , команды умножения и деления требуют , чтобы один из операндов находился в регистре AX или в регистрах AX и DX (в з а висимости от размера о перанда ), а команды управления циклом исполь з уют регистр CX в качестве счетчика цикла . Ре гистры BX и BP очень час то используются как б азовые регистры , а SI и DI - как индексные . Ре г истр SP обычно указывает на вершину стека , а п п аратно поддерживаемого в ПК. Регистры AX, BX, CX и DX конструктивно устроены т ак , что возможен независимый доступ к их старшей и младшей половинам ; можно сказа ть , что каждый из этих регистров состоит из двух байтовых регистров , обо значаемых AH, AL, BH и т.д . (H - high, старший ; L - low, младший ): ----------- ----------- ----------- ----------- AX | AH | AL | BX | BH | BL | CX | CH | CL | DX | DH | DL | ----------- ----------- ----------- ---------- - 15 8 7 0 Таким образом , с каждым из этих регистров можно раб отать как с единым целым , а можно рабо тать и с его "половинками ". Например , можно запи сать слово в AX, а затем считать то лько часть слов а из регистра AH или заменить только часть в регистре AL и т.д . Такое устройство регистров позволяет использо вать их для работы и с числами , и с символами. Все остальные регистры не делятся на "половинки ", поэтому считать или записать их содержимое (16 битов ) можно только целиком. Сегментные регистры CS, DS, SS и ES не могут быть операндами ника ких команд , кроме команд пересылки и стековых команд . Эти регистры ис пользуются только для сегментирования адр есов (см . 1.4). Счетч ик команд IP всегда со держит адрес (сме щение от начала про граммы ) той команды , к оторая должна быть выполнена следующей (начал о программы хранится в регистре CS). Содержимое регистра IP можно изме нить только командами перехода. 1.1.3 Флаги И , наконец , в ПК имеет ся о собый регистр флагов . Флаг - это бит , принимающий значение 1 ("флаг установлен "), если выполнено некоторое условие, и значение 0 ("флаг сброшен ") в противном случае . В ПК ис- пользуется 9 флагов , каждому из них при своено определенное имя (ZF, CF и т. д .). Все они собраны в регистре флагов (каждый ф лаг - это один из разрядов регистра , часть его разрядов не используется ): ------------------------------------------------- Flags | x| x| x| x|OF|DF|IF|TF|SF|ZF| x|AF| x|PF| x|CF| ------------------------------------------------- 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Некото рые флаги принято называть флагами условий ; они автоматичес ки меняются при выполнении команд и фиксируют те или иные свойства их результата (например , равен ли он н улю ). Другие флаги называются фла гами состояний ; они меняются из программы и ока зывают влияние на даль нейшее поведение проце ссора (например , блокируют прерывания ). Флаги условий : CF (carry flag) - флаг переноса . Принимает значение 1, если при сложени и целых чисел появ илась единица переноса , не "влезающая " в ра з рядную сетку , или если при вычитании чис ел без знака первое из них бы ло меньш е второго . В командах сдвига в CF заносится бит , вышедший за разрядную сетку . CF фиксир ует также особенности ком а нды умн ожения. OF (overflow flag) - флаг переполнения . Устанавливается в 1, если при сложении или вычитании целых чисел со знаком получился результат , по модулю превосходящий допустимую величину (пр оизошло переполнение мантиссы и она "залезла " в зна ковый разряд ). ZF (zero flag) - флаг нуля . Устанавливается в 1, ес ли результат команды оказался равным 0. SF (sign flag) - флаг знака . Устанавливается в 1, если в о перации над знаковыми числами получился отриц ательный результат. PF (parity flag) - флаг четности . Равен 1, если результат очеред ной команды содержит четное количество двоич ных единиц . Учитывается обычно только при операциях ввода-вывода. AF (auxiliary carry flag) - флаг дополнительного переноса . Фик си рует особенности выполнения операций над двоично-десятичными числами . Флаг и состояний : DF (direction flag) - флаг направления . Устанавливает направление просмотра строк в строковых командах : при DF=0 строки просматриваются "вперед " (от начала к концу ), при DF=1 - в обратном напр авлении. IF (interrupt flag) - флаг прерываний . При IF=0 процессор переста ет ре агировать на поступающие к нему прерывания , при IF=1 блокировка прерываний снимается. TF (trap flag) - флаг трассировки . При TF=1 после выполнения к аж дой команды процессо р делает прерывани е (с номером 1), чем можно вос пользоваться п ри отладке программы для ее трассировки. 1.2. ПРЕДСТАВЛЕНИЕ ДАННЫХ . АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ Здес ь рассматривается машинное представление целых чисел , строк и адресов . Представление двоич но- десятичных чисел , используемых доста точно редко , не рассматривается . Что касается в ещественных чисел , то в ПК нет команд вещественной арифметики (операции над этими ч ислами реа лизуются программным путем или вып олняются сопроцессором ) и потому нет станд а ртного представления вещественных чи сел . Кроме того , рассматри ваются некоторые ос обенности выполнения арифметических операций . Шест надцатиричные числа записываются с буквой h на конце , двоичные числ а - с буквой b (так принято в MASM). 1.2.1 Представл ение целых чисел. В общем случае под цел ое число можно отвести любое число байтов , однако система команд ПК поддерживает т олько числа размером в байт и слово и частично поддерживает числа размером в д войное слово . Именно эти форматы и будут рассмотр ены. В ПК делается различие между целыми числам и без знака (неотрица тельными ) и со знаком . Это объясняется тем , что в ячейках од ного и то го же размера можно представить больший диапазон беззнаковых чисел , чем неотрицательных знаковых чисел , и если и звестно заранее , что неко торая числовая велич ина является неотрицательной , то выгоднее рас смат ривать ее как беззнаковую , чем как зн аковую. Ц елые числа без знака. Эти числа могут быть представлены в виде байта , слова или двойного слова - в зависимост и от их размера . В ви де байта представляются целые от 0 до 255 (=2^8-1), в виде слова - целые от 0 до 65535 (=2^16-1), в виде двойного слова - целые от 0 до 4 294 967 295 (=2^32-1). Числа за писываются в двоичной системе счисления , занимая все разряды я чейки . Наприме р , число 130 записывается в виде байта 10000010b (82h). Числа размером в слово хранятся в памяти в "перевернутом " виде : младщие (правые ) 8 битов числа размещаются в первом байте слова , а старшие 8 битов - во втором ба йте (в 16-ричн ой системе : две правые цифры - в первом байте , две левые цифры - во втором байте ). Например , число 130 (=0082h) в в иде слова хранится в памяти так : ----------- | 82 | 00 | ----------- (Отметим , однако , что в регист рах чис ла хранятся в нормальном виде : ----------- AX | 00 | 82 | ----------- AH AL ) "Перевернутое " представление используется и при хранении в памяти целых чисел р азмером в двойное слово : в первом его байте размещаются младшие 8 битов числа , во втором байте - предыдущие 8 битов и т.д . На пример , число 12345678h хранится в памяти так : --------------------- | 78 | 56 | 34 | 12 | --------------------- Другими словами , в первом слове д войного сл ова размещаются младшие (правые ) 16 битов числа , а во втором слове - старшие 16 битов , пр ичем в каждом из этих двух слов в свою очередь используется "перевернутое " предст авление. Такое необычное представление чисел объ ясняется тем , что в пе рвых моделях ПК за раз можно было считать из па мяти только один байт и что все арифм етические операции над многозначными числами начинаются с действий над младшими цифрами , поэтому из памяти в первую очередь н адо считывать младшие цифры , если сразу н е льзя считать все цифры . Учитывая это , в первых ПК и стали размещать младшие цифры числа перед старшими цифрамм и , а ради преемственности такое представление чисел сохранили в последующих моделях ПК. Конечно , "перевернутое " представление неудобно для люд е й , однако при использовании языка ас семблера это неудобство не чувствуется : в MASM все числа записываются в нормальном , непер евернутом виде (см . ни же ). Целые числа со знаком. Эти числа также представляются в вид е байта , слова и двойного сло ва . В виде байта записываются числа от -128 до 127, в виде слова числа от -32768 до 32767, а в виде двойного слова - числа от -2147483648 до 2147483647. При этом числа записываются в дополни тель ном коде : неотрицательное число записывается так же, как и беззнаковое число (т.е . в прямом коде ), а отрицательное число -x (x>0) представля ется беззнаковым числом 2^8-x (для б айтов ), 2^16-x (для слов ) или 2^32-x (для двойных слов ). Например , дополнительным кодом числа -6 яв ляет ся байт FAh (=256-6), слово FFFAh или двойное слово FFFFFFFAh. При этом байт 10000000b (=80h) трактуется как -128, а не как +128 (слово 8000h понимается как -32678), п оэтому левый бит дополнительного кода всегда играет роль знакового : для неотрицательных чисел он равен 0 , для отрицательных - 1. Знаковые числа размером в слово и двойное сло во записываются в па мяти в "перевернутом " виде (при этом знаковый бит оказывается в пос леднем байте ячейки ). Но в MASM эти чи сла , как и беззнаковые , записы ваются в нор мальной форм е. Иногда число-байт необходимо расширить до слова , т. е . нужно полу чить такое же по величине число , но размером в слово . Существует два способа такого расширения - без знака и со знаком . В любом случае ис ходное число-байт попадает во второй (до "пер е ворачивания ") байт сло ва , а вот первый бай т заполняется по-разному : при расширении без знака в него записываются нулевые биты (12h -> 0012h), а при расширении со знаком в первый байт записываются нули , если число-байт б ыло неотрица тельным , и записыв а ется восемь двоичных единиц в противном случае (81h -> FF81h). Другими словами , при расширении со з наком в первом байте слова копируется зна ковый разряд числа-байта. Аналогичн о происходит расширение числа-слова до двойно го слова. 1.2.2 Особе нности выпол нения арифметических опреаций В ПК имеются команды сложения и вычитания цел ых чисел размером в слово и байт . Спец иальных команд для сложения и вычитания д войных слов нет , эти операции реализуются через команды сложения и вычитания слов . Сложение и вычи тание беззнаковаых чисел произ водится по модулю 2^8 для бай тов и 2^16 для слов . Это означает , что есл и в результате сложе ния появилась единица переноса , не вмещающаяся в разрядную сетку , то она отбрасывается . Например , при сложе нии байтов 128 и 130 пол учается число 258 = 100000010b, поэтому левая двоичная единица отбрасывается и остается число 2 = 10b, которое и объявляется результатом сложения . Ошибка здесь не фикси руется , но в флаг переноса CF записывается 1 ( ес ли переноса не было , в CF заносится 0). "Поймать " такое искажение сум мы можно только последующим анализом флага CF. Искажение результата происходит и при вычитание из меньшего числа большего . И здесь не фиксируется ошибка , однако первому числу дается "заем единицы " (в случае байтов эт о число увеличивается на 256, д ля слов - на 2^16), после чего и производится вычитание . Напр имер , вычи тание байтов 2 и 3 сводится к вычи танию чисел 256+2=258 и 3, в резуль тате чего получ ается неправильная разность 255 (а не -1). Для т ого чтобы можн о было обнаружить такую ситуацию , в флаг переноса CF зано сится 1 (ес ли заема не было , в CF записывается 0). Сложение и вычитание знаковых целых чисел производится по тем же алгоритмам , что и для беззнаковых чисел (в этом одно из достоинств до полнит ельного код а ): знаковые числа рассматриваются как соответ ствую щие беззнаковые числа , произодится операция над этими беззнаковыми чи слами и получе нный результат интерпретируется как знаковое число . Нап ример , сложение байтовых чисел 1 и -2 происходит т а к : берутся их до п олнительные коды 1 и (256-2)=254, вычисляется сумма эти х величин 1+254=255 и она трактуется как знаково е число -1 (255=256-1). Если при таком сложении возни кла единица переноса , то она , как обычно , отбрасы вается , а флаг CF получае т з начение 1. Однако в данном случае это от се чение не представляет интерес - результат опер ации будет правильным , например : 3+(-2) => 3+254(mod 256) = 257(mod 256) = 1. Зато здесь воз можна иная неприятность : модуль суммы (ее мантисса ) может превзойти допустимую границу и "залезть " в знако вый разряд , испортив его . Напри мер , при сл ожении байтовых чисел 127 и 2 получается величина 129 = = 100001001b, представляющая дополнительный код числа -127 (=256-129). Хотя результат здесь получился и непр авильны м , процессор не фиксирует ошибку , но зато заносит 1 в флаг переполнения OF ( если "переполнения мантиссы " не было , в OF за писывается 0). Анализируя затем этот флаг , можно "поймать " такую ошибку. Таким образом , сложение (вычитание ) знак овых и беззнак овых чисел производится по одному и тому же алгоритму . При этом ПК не "знает ", какие числа (со знак ом или без ) он складывает ; в любом случ ае он скла дывает их как беззнаковые числ а и в любом случае формирует флаги CF и OF. А вот как интерпретироват ь сл агаемые и сумму , на какой из этих флаг ов обращать внимание - это личное дело авт ора программы. Что ка сается умножения и деления знаковых и без знаковых чисел , то они выполняются по раз ным алгоритмам , разными машинными командами . О д нако и у этих оп ераций есть ряд особенностей . При умножении байтов (слов ) первый сомножитель обязан находиться в регис тре AL (AX), ре зультатом же умножения является сло во (двойное слово ), которое зано сится в ре гистр AX (регистры DX и AX). Тем самым при умножен и и сохра няются все цифры произведен ия . При делении байтов (слов ) первый опе ра нд (делимое ) должен быть словом (двойным сл овом ) и обязан находиться в регистре AX (рег истрах DX и AX). Результатом деления являются две величины размером в байт (слово ) - н е полное частное (div) и остаток от деления (mod); неполное частное записывается в регистр AL (AX), а ос таток - в регистр AH (DX). 1.2.3 Предс тавление символов и строк На символ отводится один байт памяти , в который записывается код символа - це лое от 0 до 255. В ПК и спользуется система кодировки ASCII (American Standard Code for Information Interchange). Она , естествен но , не содержит кодов русских бук в , поэтому в нашей стране применяется неко торый вариант этой системы с русскими бук вами (обы ч но это альтер нативная к одировка ГОСТа ). Некоторые особенности этих систем коди ровки : - код проб ела меньше кода любой буквы , цифры и в ообще любого графи- чески пред ставимого символа ; - коды циф р упорядочены по величине цифр и не с одержат пропусков, т .е . из неравенства код ('0')<=код (c)<=код ('9') следует , что c - цифра ; - коды больших латинских букв упорядочены согласно алфавиту и не со- держат про пусков ; аналогично с малыми латинскими буквам и ; - (в альтернативной кодировке ГОСТа ) код ы русских букв (ка к больших , так и малых ) упорядочены согласно алфавиту , но между ними есть коды других символов. Строка (последовательность символов ) размещ ается в соседних байтах памяти (в непереве рнутом виде ): код первого символа строки з аписывает ся в первом байте, код второго символа - во втором байте и т.п . Адре с ом строки считается адрес ее первого байт а. В ПК строкой считается также и последовательность слов (обычно это последова тельность целых чисел ). Элементы таких строк располагаются в последовательных яч ейках памяти , но каждый элемент представлен в "пе ревернутом " виде. 1.2.4 Представление адресов Адрес - это порядковый номе р ячейки памяти , т.е . неотрицательное целое число , поэтому в общем случае адреса пр едставляются так же , как и беззнаковые ч исла . Однако в ПК есть ряд особенн остей в представлении адресов. Дело в том , что в ПК термином "адрес " обозначают разные вещи . Час то под адресом понимается 16-битовое смещение (offset) - адрес ячейки , отсчитанный от начала сегмента (о бласти ) памяти , кот орому принадлежит эта ячейка . В этом случае под адрес отводит ся слово памяти , причем ад рес записывается в "перевернутом " виде (как и числа-слова вообще ). В другом случае под "адресом " понимае тся 20-битовый абсолютный ад рес некоторой ячей ки памяти . В сил у ряда причин в ПК такой адрес зада ется не как 20-битово е число , а как пара "сегмент :смещение ", где "сег мент " (segment) - это первые 16 битов начального адреса сегмента памя ти , которому принадлежит ячейка , а "смещение " - 16-битовый адрес этой ячейки , отсчитанный от начала данного сегмента памяти (величина 16*сегмент +см ещение даетабсолютный адрес ячейки ). Такая пар а записы вается в виде двойного слова , при чем (как и для чисел ) в "переверну том " виде : в первом слове размещается смещение , а во в тором - сегмент , причем каж дое из этих слов в свою очередь предс тавлено в "переверну том " виде . Например , пара 1234h:5678h будет записана так : --------------------- | 78 | 56 | 34 | 12 | --------------------- смещение сегмент 1.2.5 Ди рективы определе ния данных Для того чтобы в прогр амме на MASM зарезервировать ячейки памяти под константы и переменные , необходимо воспользоват ься директивами оп ределения данных - с названи ями DB (описывает данные размером в байт ), DW (р азмером в слово ) и DD (размером в двойн ое слово ). (Директивы , или команды ассемблеру , - это предложения программы , которыми ее авт ор со общает какую-то информацию ассемблеру ил и просит что-то сделать допол нительно , помимо перевода символьных команд на машинный я зык .) В простейшем случае в директиве DB, DW или DD описывается одна константа , которой дается имя для последующих ссылок на н ее . По этой директиве ассемблер формирует машинное представление константы (в час тности , если надо , "переворачивает " ее ) и записы в ает в очередную ячей ку памяти . Адрес этой ячейки становится значением име ни : все вхождения имени в программу ассемб лер будет заменять на этот адрес . Имена , ука занные в директивах DB, DW и DD, называются име нами переменных (в от личие от меток - имен к о манд ). В MASM числа записываются в нормальном ( неперевернутом ) виде в cи стемах счисления с основанием 10, 16, 8 или 2. Десятичные числа запи сывают ся как обычно , за шестнадцатиричным числом ставится буква h (ес ли число начинается с "цифры " A, B, ..., F , то вначале обязателен 0), за восьмиричным числом - буква q или o, за двоичны м числом - буква b. Примеры : A DB 162 ;опи сать константу-байт 162 и дать ей имя A B DB 0A2h ; такая же константа , но с именем B С DW -1 ;константа-слово -1 с им енем С D DW 0FFFFh ;так ая же константа-слово , но с именем D E DD -1 ;-1 как двойное слово Константы-символы описываются в директиве DB двояко : указывается либо код символа (цело е от 0 до 255), либо сам символ в кавычках (оди нарных или двойных ); в последнем случае ассемблер сам заменит символ на его код . Например , следующие директивы эк вивалентны (2A - код звез дочки в ASCII): CH DB 02Ah CH DB '*' CH DB "*" Констан ты-адреса , как правило , задаются именами . Так , по директи ве ADR DW CH будет отведено слово памяти , которому дается имя ADR и в которое запи шется адрес (смещение ), соответствующий имени CH. Если такое же имя описать в директиве DD, то ассем блер автоматически добавит к смещению имени его сегмент и запишет смещение в первую половину двойного слова , а сегмент - во вторую половину. По любой из директив DB, DW и DD можно описать переменную , т.е . отвести ячейку , не дав ей начального значения . В этом случае в правой части директивы указывается воп росительны й знак : F DW ? ;о твести слово и дать ему имя F, ничего в этот байт не ;записывать В од ной директиве можно описать сразу несколько констант и /или пе ременных одного и т ого же размера , для чего их надо переч ислить через запятую . Они размещаются в со седних ячейках памяти . Пример : G DB 200, -5, 10h, ?, 'F' Имя , указанное в директиве , считается именующим первую из констант . Для ссылок на остальные в MASM используются выражения вида <имя >+<це лое >; например , для доступа к б айту с числом -5 надо указать выражение G+1, для доступа к байту с 10h - выражение G+2 и т.д. Если в директиве DB перечислены только символы , например : S DB 'a','+','b' тогда эту директиву можно записать ко роче , заключив все эти символы в одни кавычки : S DB 'a+b' И , наконец , е сли в директиве описывается несколько одинаковых кон стант (переме нных ), то можно воспользоваться конструкцией п овторения k DUP(a,b,...,c) которая эквивалентна повторенной k раз пос ледовательности a,b,...,c. Например , директивы V1 DB 0,0,0,0,0 V2 DW ?,?,?,?,?,?,?,?,?,'a',1,2,1,2,1,2,1,2 можно записать более коротко таким об разом : V1 DB 5 DUP(0) V2 DW 9 DUP(?), 'a', 4 DUP(1,2) 1.3. ПРЕ ДСТАВЛЕНИЕ КОМАНД . МОДИФИКАЦИЯ АДРЕСОВ. 1.3.1 Структура команд . Исполнительные адреса Машинные команды ПК занимают от 1 до 6 байтов. Код операции (КОП ) занимает один или два первых байта команды . В ПК столь много различных операций , что для них не хватает 256 различ ных КОПов , которые можно представить в одном байте . Поэтому некото рые операции объединя ются в группу и им дается один и тот же КОП , во вто ром же байте этот КОП уточняется . Кр оме того , во втором байте указыва ются тип ы и способ адресации операндов . Остальные байты команды указы вают на операнды. Команды могут иметь от 0 до 3 операндо в , у большинства команд один или дв а операнда . Размер операндов - байт или сл ово (редко двойное слово ). Операнд может б ыть указан в самой команде (это т.н . не посредственный операнд ), либо может находиться в одном из регистров ПК и тогда в команде у казывается этот регистр , либо может находиться в ячейке памяти и тогда в команде тем или иным способ ом указывается ад рес этой ячейки . Некоторые команды требуют , чтобы операнд находился в фиксированном месте (например , в регистре AX), тогда операнд явн о не указывает ся в команде . Результат выполнения команды помещается в ре гистр или ячейку памяти , из которого (которой ), как правило , берется первый операнд . Например , большинство команд с двумя операндами реали зуют действие op1 := op1 _ op2 где op1 - регистр или ячейка , а op2 - не посредственный операнд , ре гистр или ячейка. Адрес операнда разрешено модифицировать по одному или двум регист рам . В первом случае в качестве регистра-модификатора разреш ено ис пользовать регистр BX, BP, SI или DI (и ни какой иной ). Во втором слу чае один из модификаторов обязан быть регистром BX или BP, а другой - регис тром SI или DI; одновременная модификация по BX и BP или SI и DI недопустима . Регистры BX и BP обычно используются для хранения базы (началь н ого адреса ) некоторого участка памяти (скажем , массива ) и по тому называются базовыми ре гистрами , а регистры SI и DI часто содержат ин дексы элементов массива и потому называются индексными регистрами . Однако такое распреде ление ролей необязательно , и, например , в SI мо жет находиться база массива , а в BX - индекс элемента массива. В MASM адреса в командах записываются в виде одной из следующих конструкции : A, A[M] или A[M1][M2], где A - адрес , M - регистр BX, BP, SI или DI, M1 - регистр BX ил и BP, а M2 - регистр SI или DI. Во второрм и третьем варианте A может отсут ствовать , в этом случае считается , что A=0. При выполнении команды процессор прежде всего вычисляет т.н . ис полнительный (эффектив ный ) адрес - как сумму адреса , заданного в ко манде , и текущих значений указанны х регистров-модификаторов , причем все эти величи ны рассматриваются как неотрицательные и сум мирование ведется по модулю 2^16 ([r] означает содержимое регистра r): A : Aисп = A A[M] : Aисп = A+[M ] (mod 2^16) A[M1][M2]: Aисп = A+[M1]+[M2] (mod 2^16) По лученный таким образом 16-разрядный адрес опред еляет т.н . смеще ние - адрес , отсчитанный от начала некоторого сегмента (области ) памя ти . П еред обращением к памяти процессор еще до бавляет к сме щению на чальный адрес э того сегмента (он хранится в некотором сег ментном реги стре ), в результате чего получает ся окончательный 20-разрядный ад рес , по которо му и происходит реальное обращение к памя ти (см . 1.4). 1.3.2 Форматы команд В ПК формат ы машинных команд достаточн о разнообразны . Для примера приведем лишь основные форматы команд с двумя операндами. 1) Ф ормат "регистр-регистр " (2байта ): ------------- ---------------- | КОП |d|w| | 11 |reg1|reg2| ------------- ---------------- 7 2 1 0 7 6 5 3 2 0 Команды этого формата описывают обычно действие reg1:=reg1_reg2 или reg2:=reg2_reg1. Поле КОП первого байта указывает на операцию (_), ко торую надо выполнить . Бит w определяет размер операндов , а бит d у ка зывает , в какой из регистров записы вается результат : w = 1 - слова d = 1 - reg1:=reg1_reg2 = 0 - байты = 0 - reg2:=reg2_reg1 Во втором байте два левых бита фи ксированы (для данного формата ), а трехбитовые поля reg1 и reg2 указывают на регистры , уча ствующие в опе рации , согласно следующей табли це : reg w=1 w=0 reg w=1 w=0 ----------------- ---------------- 000 AX AL 100 SP AH 001 CX CL 101 BP CH 010 DX DL 110 SI DH 011 BX BL 111 DI BH 2) Фо рмат "регистр-память " (2-4 байта ): ------------- ------------- ------------------- | КОП |d|w| |mod|reg|mem| |адрес (0-2 байта )| ------------- ------------- ------------------- Эти команды описывают операции reg:=reg_mem или mem:=mem_reg. Бит w первого байта определяет размер оп ерандов (см . выше ), а бит d указыва ет , куда записывается результат : в регистр (d=1) или в ячейку памяти (d=0). Трехбитовое поле reg втор ого байта указывает операнд-регистр (см . выше ), двухбитовое поле mod определяет , сколько байтов в команде занимает операнд-адрес (00 - 0 байтов , 01 - 1 байт , 10 - 2 байта ), а трехбитовое поле mem указыв ает способ модификации этого адреса . В сле дующей таблице указаны правила вычис ления исполнительного адреса в за висимости о т значений полей mod и mem (a8 - адрес размером в байт , a16 - адрес размером в слово ): mem \ mod | 00 01 10 ------------------------------------------------------ 000 | [BX]+[SI] [BX]+[SI]+a8 [BX]+[SI]+a16 001 | [BX]+[DI] [BX]+[DI]+a8 [BX]+[DI]+a16 010 | [BP]+[SI] [BP]+[SI]+a8 [BP]+[SI]+a16 011 | [BP]+[DI] [BP]+[DI]+a8 [BP]+[DI]+a16 100 | [SI] [ SI]+a8 [SI]+a16 101 | [DI] [DI]+a8 [DI]+a16 110 | a16 [BP]+a8 [BP]+a16 111 | [BX] [BX]+a8 [BX]+a16 Замечан ия . Если в команде не задан адрес , то он считается нулевым . Если адрес задан в виде байта (a8), т о он автоматически расширяется со знаком до слова (a16). Случай mod=00 и mem=110 указывает на отсутствие регистров-модиф икаторов , при этом адрес должет иметь разм ер слова (ад ресное выражение [BP] ассемблер транс лирует в mod=01 и mem=110 при a8=0). Сл у чай mod=11 соответствует формату "регистр-регистр ". 3) Формат "регистр-непосредственный операнд " (3-4 байта ): ----------- ------------- -------------------------- | КОП |s|w| |11|КОП "|reg| |непосред.операнд (1-2 б )| ----------- ------------- -------------------------- К оманды этого формата описывают операции reg:=reg_immed (immed - не посредственный операнд ). Бит w указывает н а размер операндов , а поле reg - на регистр-опе ранд (см . выше ). Поле КОП в первом байте определя ет лишь класс операции (на пр имер , класс сложения ), уточняет же опера цию поле КОП " из второго байта . Непосредственны й операнд может зани мать 1 или 2 байта - в зависимости от значения бита w, при этом опе ранд-слово записывается в команде в "перев ернутом " виде . Ради экономии п амяти в ПК предусмотрен случай , когда в опе рации над словами непос редственный операнд м ожет быть задан байтом (на этот случай указывает 1 в бите s при w=1), и тогда перед выполнением операции байт автомати чески расши ряется (со знаком ) до слова. 4) Фор мат "память-непосредственный операнд " (3-6 б айтов ): ----------- -------------- -------------- ------------------ | КОП |s|w| |mod|КОП "|mem| |адрес (0-2б )| |непоср.оп (1-2б )| ----------- -------------- -------------- ------------------ К оманды этог о формата описывают операции типа mem:=mem_immed. Смысл всех полей - тот же , чт о и в предыдущих форматах. Помимо рассмотренных в ПК используются и другие форматы команды с двумя опе рандами ; так , предусмотрен специальный формат для команд , один из операндов которых фиксирован (обычно это регистр AX). Имеют свои форматы и команды с другим числом оп ерандов. 1.3.3 Запись команд в MASM Из сказанного ясно , что одна и та же операция в зависимости от ти пов операдов записывается в виде различных машинных команд : например , в П К имеется 28 команд пересылки байтов и слов . В то же время в MASM все эти "родственные " команды записываются единообразно : например , все команды пересылки имеют одну и ту же символьную форму записи : MOV op1,op2 (op 1:=op2) Анализируя типы операндов , ассемблер сам выбирает подходящую машинную команду. В общем случае команды записываются в MASM сле дующим образом : метка : мнемокод операнды ;комментарий Метка с двоеточием , а также точка с запятой и комментарий м огут отсут с твовать . Метка играет роль имени команды , ее можно использовать в ко мандах перехода на данную команду . Комментарий не влияет на смысл ко манды , а лишь поясняет ее. М немонические названия операций полностью перечис лены в главе 2. Операнды , есл и есть , перечисляются через запятую . Основные правила за писи операндов следующие. Регистры указываются своими именами , нап ример : MOV AX,SI ;оба операнда - регистры Не посредственные операнды задаются константными вы ражениями (их значениями яв ляются констан ты-числа ), например : MOV BH,5 ;5 - непосредственный операнд MOV DI,SIZE X ;SIZE X (число байтов , занимаемых перемен ;ной X) - непосредственный операнд Ад реса описываются адресными выражениями (например , именами пере менных ), которые могут быть модифицированы по одному или двум регист рам ; например , в следующих командах первые операнды задают адреса : MOV X,AH MOV X[BX][DI],5 MOV [BX],CL При записи команд в символьной форме необходимо внимательно сле дить за правильны м указание м типа (размера ) операндов , ч тобы не было ошибок . Тип обычно определяе тся по внешнему виду одного из них , на при мер : MOV AH,5 ;пересылка байта , т.к . AH - байтовый ре гистр MOV AX,5 ;пересылка слова , т.к . AX - 16-битовый рег истр ;(операнд 5 может быть байтом и словом , по нему ;нельзя определить размер пересылаемо й величины ) MOV [BX],300 ;пересылка слова , т.к . число 300 не может быть ;байтом Ес ли по внешнему виду можно однозначно опр еделить тип обоих опе рандов , тогда эти ти пы должны совпадать , ина че ассемблер зафиксирует ошибку . Примеры : MOV DS,AX ;оба операнда имеют размер слова MOV CX,BH ;ошибка : регистры CX и BH имеют разны е размеры MOV DL,300 ;ошибка : DL - байтовый регистр , а число 300 не ;может быть байтом Во зможны ситуации , когда по в нешнему вид у операндов нельзя опреде лить тип ни одн ого из них , как , например , в команде MOV [BX],5 Здесь число 5 может быть и байтом , и словом , а адрес из регистра BX может у казывать и на байт памяти , и на слово . В подобных ситуациях ас семблер фикси рует ошибку . Чтобы избежать ее , надо уточнить тип одного из операндов с пом ощью оператора с названием PTR: MOV BYTE PTR [BX],5 ;пересылка байта MOV WORD PTR [BX],5 ;пересылка слова (Операторы - это разновидность выражений языка MASM, аналогичные фун к циям .) Оператор PTR необходим и в том случае , когда надо изменить тип , предписанный им ени при его описании . Если , например , X описа но как имя переменной размером в слово : X DW 999 и если надо записать в байтовый регистр AH значение только перв ого байта этого слова , тогда воспользоваться командой MOV AH,X нельзя , т.к . ее операнды имеют разный размер . Эту команду следует за писать неско лько иначе : MOV AH,BYTE PTR X Здесь конструкция BYTE PTR X означает адрес X, но уже рассматриваемый не к ак адрес с лова , а как адрес байта . (Напомним , что с одного и того же адреса может начинат ься байт , слово и двойное слово ; оператор PTR уточняет , ячейку какого размера мы име ем в виду .) И еще одно замечание . Если в сим вольной команде , оперирующей со словами , указан непосредственный операнд размером в б айт , как , напри мер , в команде MOV AX,80h то возникает некоторая неоднозначность : ч то будет записано в регистр AX - число 0080h (+128) ил и 0FF80h (-128)? В подобных ситуациях ассем блер формиру ет машинную команду , где операнд-байт ра сширен до слова , причем расширение происходит со знаком , если операнд был записан как отрицательное число , и без знака в остальных случаях . Например : MOV AX,-128 ; => MOV AX,0FF80h (A:=-128) MOV AX,128 ; => MOV AX,0080h (A:=+128) MOV AX,80h ; => MOV AX,0080h (A:=+128) 1.4. СЕГМЕНТИР ОВНИЕ 1.4.1 Сегме нты памяти . Сегментные регистры. Первые модели ПК имели оперативную память объемом 2^16 байтов (64Кб ) и потому использовали 16-бит овые адреса . В последующих моделях память была увеличена до 2^20 байтов (1Мб =1000Кб ), для чего уже необ ходимы 20-битовые адреса . Однако в этих ПК ради сохранения преемствен ности были сохр анены 16-битовые адреса : именно такие адреса хранятся в регистра х и указывают ся в командах , именно такие адреса получа ются в результате модмфикации по базовым и индексным регистрам . Как же удает ся 16-би товыми адресами ссылаться на 1Мб памяти ? Эта пр облема решается с помощью сегментирования адр есов (неявного базиров ания адресов ). В ПК вводится понятие "сегмент памяти ". Так н а зывается любой участок памяти размером до 64Кб и с начальным адресом , кратным 16. Аб солютный (20-битовый ) адрес A любой ячейки памяти можно представить как сумму 20-битового начальног о адреса (базы ) B сегмента , которому принад лежит ячейка , и 16-битового смещения D - адреса этой ячейки , отсчитанного от начала сегмент а : A=B+D. (Неоднозначность выбо ра сегмента не играе т существенной роли , главное - чтобы сумма B и D давала нужный адрес .) А д рес B заносится в некоторый регистр S, а в ко ман де , где должен быть указан адрес A, вместо него записывается пара из регистра S и смещения D (в MASM такая пара , называемая адресно й па рой или указателем , записывается как S:D). Процессор же устроен та к , что при выполнении команды он прежде всего по паре S:D вычисляет абсо лютный адрес A как су мму содержимого регистра S и смещения D и то лько затем обращается к памяти по этому адресу A. Вот так , заменяя в коман дах абс олютные адреса на адресные пары , и удается адресовать всю па мять 16-битовыми адресами (смещениями ). В качес тве регистра S разрешается использовать не люб ой регистр , а только один из 4 регистров , называемых сегментными : CS, DS, SS и ES. В связи с этим одновременно можно работать с 4 сегме нтами памяти : начало одного из них загружается в регистр CS и все ссылки на ячейки этого сегмента указываются в виде пар CS:D, начало другого заносится в DS и в се ссылки на его ячейки задаются в ви де пар DS:D и т.д . Если одновре менно надо работать с большим числом сегментов , тогда нужно своевре менно спасать содержимое сегментных регистров и записывать в них на чальные адреса пятого , шестого и т.д . сегментов. Отметим , что используемые сегменты могут быть расположены в памяти произвольным о бразом : они могут не пересекаться , а могут пересекаться и даже совпадать . Какие сегменты памяти использовать , в каких сег мент ных регистрах хранить их начальные адрес а - все это личное дело автора машинной программы. Как и все регистры ПК , сегментные регистры им еют размер слова . По этому возникает вопрос : как удается разместить в них 20-битовые на чальные адреса сегментов памяти ? Ответ такой . Поскольку все эти адр еса кратны 16 (см . выше ), то в них младшие 4 бита (последняя 16-ричная цифра ) всегда нул евые, а потому эти биты можно н е хранить явно , а лишь подразумевать . Имен но так и делается : в сегментном регистре всегда хранятся только первые 16 битов (пе рвые четыре 16-ричные цифры ) на чального адреса сегмента (эта величина называется номером сегмента или просто сегментом ). При вычислении же абсолютного адреса A по пар е S:D процессор сначала приписывает справа к содержимому регистра S четыре нулевых бита ( другими словами , умножает на 16) и лишь затем прибавляет смещение D, причем суммирование вед етс я по модулю 2^20: Aабс = 16*[S]+D (mod 2^20) Если , нап ример , в регистре CS хранится величина 1234h, тогда адресная пара 1234h:507h определяет абсолютный адрес , равный 16*1234h+507h = 12340h+507h = 12847h. 1.4.2 Сегме нтные регистры по умолчанию Согл асно описанной схе ме сегментирования адресов , замену абсолют ных адресов на адресные пары надо производить во всех командах , имею щих операнд-адрес . Однако разработчики ПК придумали способ , позв оляю щий избежать выписывания таких пар в большинстве кома н д . Суть его в том , что заранее договариваются о том , к акой сегментный регистр на ка- кой сегмен т памяти будет указывать , и что в ком андах задается только смещение : не указанный явно сегментный регистр автоматически восст а навливается согласно этой д оговоренности . И только при необходимости нарушить эту договоренность надо полностью указывать адрес ную пару . Что это за договоренность ? Считается , что регистр CS всегда указывает на начало области памя ти , в которой размещены команд ы программы (эта область называется сег ментом команд или сегментом кодов ), и пото му при ссылках на ячейки этой области регистр CS можно не указывать явно , он по дразумевается по умолчанию . (Отметим попутно , что абсолютный адрес очередной команды , подле жащей выполне н ию , всегда задается парой CS:IP: в счетчике команд IP всегда находится смещение этой команды относительно адреса из реги стра CS.) Аналогично предполагается , что регистр DS указывает на сег мент данных (область памяти с константами , переменными и други м и вели чинами программы ), и потому во всех ссылках на этот сегмент регист р DS можно явно не указывать , т.к . он подр азумевается по умолчанию . Регистр SS, считается , указывает на стек - область памяти , доступ к которой осуществляется по принципу "послед н им записан - первым считан " (см . 1.7), и потому все ссылки на стек , в кот орых явно не указан сегментный регистр , по умолчанию сегментируются по регистру SS. Регист р ES счита ется свободным , он не привязан ни к какому сегменту памяти и его можно использов а ть по своему усмотрени ю ; чаще всего он применяется для дос тупа к данным , которые не поместились или сознательно не были размеще ны в сегменте данных. С учетом такого распределения ролей сегментных регистров машинные программы обычно строятся так : все к оманды программы размещаются в од ном сегменте памяти , начал о которого заносится в регистр CS, а все данные размещаются в другом сегменте , начал о которого заносится в ре гистр DS; если нуж ен стек , то под него отводится третий сегмент памя ти , начало которого записы вается в регистр SS. После этого практически во всех командах можно указывать не по лные адресные пары , а лишь сме щения , т.к . сегментные регистры в этих парах будут восстанавливаться автоматически. Здесь , правда , возникает такой вопрос : как по смещению определить , на какой сегмент памяти оно указывает ? Точный отве т приведен ниже (см . 1.4.3), а в общих чертах он такой : ссылки на сегмент команд мо гут быть только в командах перехода , а ссылки практически во всех других коман дах (кроме стро к овых и стековых ) - это ссылки на сегмент данных . Нап ример , в команде пересылки MOV AX,X имя X воспринимается как ссылка на дан ное , а потому автоматически вос станавливается до адресной пары DS:X. В команде же безусло вного пере хода по адресу , находяще муся в регистре BX, JMP BX абсолютный адрес перехода определяется па рой CS:[BX]. Итак , если в ссылке на какую-то я чейку памяти не указан явно сег ментный р егистр , то этот регистр берется по умолчан ию . Явно же сегмен тные регистры надо указ ывать , только если по каким-то причинам регистр по умолчанию не подходит . Если , например , в команде пересылки нам надо сослаться на стек (скажем , надо записать в регистр AH байт стека , по меченный именем X), тогда нас уже не будет устраивать договор енность о том , чт о по умолчанию операнд команды MOV сегментируется по регистру DS, и потому мы обязаны явно указать ин ой регистр - в нашем случае ре гистр SS, т.к . именно он указывает на стек : MOV AH,SS:X Однако такие случаи встречаются редко и потому в командах , как пр ави ло , указываются только смещения. Отметим , что в MASM сегментный регистр з аписывается в самой коман де непосредственно перед смещением (именем переменной , меткой и т.п .), однако на уровне машинного языка с итуация несколько иная . Имеется 4 специальны е однобайтовые команды , называемые префик сами замены сегмен та (обозначаемые как CS:, DS:, SS: и ES:). Они ставятся перед коман дой , операнд-адрес которой должен быть просегментирован по регистру , отличному от регистра , подразумеваемому по умолчанию . Н апример , приве денная выше символическая команда пересылки - это на самом деле две машинные команды : SS: MOV AH,X 1.4.3 Сегментирование , базирование и индексирование ад ресов Поскольку сегментирование адресов - это разновидность модификации адресов , то в ПК адрес , указываемый в команде , в общем случае модифи цируется по трех регистрам - сегментному , базовому и индексному . В це лом , модификация адреса производится в два этапа . Сначала учитываются только ба зовый и индексный регистры (если о ни , конечно , указаны в ко манде ), причем вычис ление здесь происходит в области 16-битовых адре сов ; полученный в результате 16-битовый адрес называется исполнитель ным (эффективным ) адр есом . Если в команде не предусмотрено обра щение к памяти (например , о на заг ружает адрес в регистр ), то на этом мод ифика ция адреса заканчивается и используется именно исполнительный адрес (он загружается в регистр ). Если же нужен доступ к п амяти , тогда на втором этапе исполнительный адрес рассматривается как смещение и к не му прибавляется (умноженное на 16) сод ержимое сегментного регистра , указанного явно или взятого по умолчанию , в результате чего получается абсолютный (физический ) 20-битовый адрес , по которому реально и проис ходит обращение к памяти. Отметим , что сегментный регистр учитывается тол ько в "последний " момент , непосредственно перед обращением к памяти , а до этого рабо та ведется только с 16-битовыми адресами . Ес ли учесть к тому же , что сег ментные р егистры , как правило , не указываются в ком андах, то можно в общем-то считать , ч то ПК работает с 16-битовыми адресами. Как уже сказано , если в ссылке на ячейку памяти не указан сегмент ный регистр , то он определяется по умолчанию . Это делается по следую щим правилам. 1) В командах перехода адрес пер ехода сегментируется по регистру CS и только по нему , т.к . абсолютный адрес команды , к оторая должна быть выполнена следующей , всегд а определяется парой CS:IP (попытка из менить в таких командах сегментный регистр будет бе зуспешной ). Отмети м , что с егментиорвание по регистру CS ка сается именно адреса переход а , а не адреса той ячейки , где он м ожет находиться . Например , в команде безусловн ого перехода по адресу , находящемуся в яче йке X: JMP X имя X сегментируется по регистру DS, а во т адрес перех ода , взятый из ячейки X, уже сегментируется по регистру CS. 2) Адреса во всех других командах , кроме строковых (STOS, MOVS, SCAS и CMPS), по умолчанию сегмент ируются : - п о регистру DS, если среди указанных регистров-мо дификаторов нет регистра BP; - по регистру SS, если один из модификаторов - регис тр BP. Таким образом , адреса вида A, A[BX], A[SI], A[DI], A[BX][SI] и A[BX][DI] сегментир уются по регистру DS, а адреса A[BP], A[BP][SI] и A[BP][DI] - по регистру SS, т.е . адреса трех последних вид ов использу ются для доступа к ячейка м стека. 3) В строковых командах STOS, MOVS, SCAS и CMPS, имеющих два опе ранда-адреса , на которые указывают индексные регистры SI и DI, один из операндов (на кото рый указывает SI) сегментируется по регистру DS, а другой (на него указывает DI) - по регис тру ES. 1.4.4 Программные сегменты . Директива ASSUME Рассмот рим , как сегментирование проявляется в програ ммах на MASM. Для того чтобы указать , что некоторая группа предложений программы на MASM образуют единый сегмент памяти , они оформляются как программ ный сегмент : перед ними ставится д иректива SEGMENT, после них - дирек тива ENDS, причем в начале обеих этих директив должно быть указано од но и то же имя , играющее ро ль имени сегмента . Программа же в цел о м представляет собой последовательн ость таких программных сегментов , в конце которой указывается директива конца программы END, например : DT1 SEGMENT ;пр ограммный сегмент с именем DT1 A DB 0 B DW ? DT1 ENDS ; DT2 SEGMENT ;прогр аммный сегмент DT2 C DB 'hello' DT2 ENDS ; CODE SEGMENT ;программный сегмент CODE ASSUME CS:CODE, DS:DT1, ES:DT2 BEG: MOV AX,DT2 MOV DS,AX MOV BH,C ... CODE ENDS END BEG ;конец текста программы Предложения программного сегмента ассембле р размещает в одном сег менте памяти (в совокупности они не должны занимать более 64Кб ) начи ная с ближайшего свободного адр еса , кратного 16. Номер (первые 16 би тов начальн ого адреса ) этого сегмента становится значением имени сег мента. В MASM это имя относи тся к константным выражениям , а не адрес- ным , в связи с чем в команде MOV AX,DT2 второй операнд является непосредственным , поэтому в регистр AX будет записано на чало (номер ) сегмента DT2, а не содержимое нач альной ячейки этого сегмента. Имена же переменных (A, B, C) и метки (BEG) от носятся к адресным выражениям , и им стави тся в соответствие адрес их ячейки относи тельно "своего " сегмента : имени A соответствуе т адрес 0, имени B - адрес 1, имени C - адрес 0, а метке BEG - адрес 0. Все ссылки на предложения одного п рограммного сегмента ассемблер сегментирует по умолчанию по одному и тому же сегментн ому регистру . По какому именно - устанавливаетс я специальной директивой ASSUME. В нашем прим ере эта директива определяет , что все ссыл ки на сегмент CODE долж ны , если явно не у казан сегментный регистр , сегментироваться по регис тру CS, все ссылки на DT1 - по регистру DS, а все ссылки на DT2 - по регистру ES. Вс третив в тексте программы сс ылку на какое-либо имя (например , на имя C в команде MOV AX,C), ассемблер определяет , в каком программном сегменте оно описано (у нас - в DT2), затем по информации из директивы ASSUME узнает , какой сегментный регистр поставле н в соответствие этому сегменту (у нас - это ES), и далее образует адресную пару иэ данного регистра и смещения им ени (у нас - ES:0), которую и записывает в ф ор мируемую машинную команду . При этом ассембл ер учитывает используемое в ПК соглашение о сегме н тных регистрах по умол чанию : если в адресной па ре , построенной и м самим или явно заданной в программе , сегментный ре гистр совпадает с регистром по умолчанию , то в машинную команду зано с ится лишь смещение . Если , скажем , в нашем примере встретится кома н да MOV CX,B, тогд а по имени В ассемблер построит пару DS:1, но раз опе ранд-адрес команды MOV по умолчанию сегментируется по регистру DS, то записывать этот регистр в машинную команду излишне и ассемблер записы вает в нее только см ещение 1. Таким обра зом , директива ASSUME избавляе т программистов от необхо димости выписывать полные адресные пары не только тогда , когд а исполь зуются сегментные регистры по умолча нию (как в случае с именем B), но тогда, когда в машинной команде нужно было бы явно указат ь сегментный регистр (как в случае с именем C). В MASM сегментный регистр в ссылке на имя требуется ук азывать лишь тогда , когда имя должно по каким-либо причинам сегментироваться по регистр у , отличному от того , что постав лен в соответствие всему сегмен т у , в кот ором это имя описано. Однако все это справедливо только при соблюдении следующих усло вий . Во-первых , д иректива ASSUME должна быть указана перед первой ко мандой программы . В противном случае асс емблер , просматривающий текст программы сверху вниз , не будет знать , как сегментирова ть имена из ко манд , расположенных до этой директивы , и потому зафиксирует ошибку . В о-вторых , в директиве ASSUME следует каждому сегмен ту ставить в соот ветствие сегментный регистр : если ассемблеру встретится ссыл к а на имя из сегмента , которому не соответствует никакой сегментный регистр , то он зафиксирует ошибку . Правда , в обоих случаях можно избежать ошибки , но для э того в ссылках необходимо явно указывать сегментный регистр. 1.4.5 Начальная загрузка сег мент ных регистров Директива ASSUME сообщает ассмеблер у о том , по каким регистрам он должен сегментировать имена из каких сегментов , и "обещает ", что в этих регистрах будут находиться начальные адреса этих сегментов . Одна ко загрузку этих адресов в регис тры сама директива не осуществляет . С делать такую загрузку - обязанность самой прог раммы , с загрузки сег ментных регистров и должно начинаться выполнение программы . Делается это так. Поскольку в ПК нет команды пересылк и непосредственного операнда в сегментный регистр (а имя , т.е . начало , сегмента - это непосредствен ный операнд ), то такую загрузку приходится делать через какой-то дру гой , несегментный , регистр (например , AX): MOV AX,DT1 ;AX:=начало сегмента DT1 MOV DS,AX ;DS:=AX Аналогич но загружается и регистр ES. Загр ужать регистр CS в начале программы не надо : он , как и счетчик команд IP, загружается операционной системой перед тем , как начина ется выполнение программы (иначе нельзя было бы начать ее выполнение ). Что же каса ется регис тра SS, используемого для работы со стеком , то он мо жет быть загружен так же , как и регистры DS и ES, однако в MASM преду смотрена возможность загрузки этого регистра еще до выполнения прог раммы (см. 1.7). 1.4.6 Ссылки вперед Встречая в символьно й команде ссылку назад - имя , которое описан о в тексте программы до этой команды , ассемблер уже имеет необходимую информацию о б имени и потому может правильно оттранс лировать эту ко манду . Но если в команде встретится ссылка вперед , т.е . имя , котор о е не было описано до команды и которое , наверное , будет описано позже , то ассемблер в большинстве случаев не сможет правильно оттранслировать эту команду . Например , не зная , в каком программном сегменте будет описано это имя , ассемблер не может опр е делить , по каком у сегментному регистру надо сегментировать им я , и потому не может определить , надо или нет размещать перед соответствующей машин ной командой префикс за мены сегмента и , е сли надо , то какой именно. В подобной ситуации ассемблер действует следующим образом : если в команде в стретилась ссылка вперед , то он делает не которое предположе ние относительно этого имени и уже на основе этого предположения фо р мирует машинную команду . Если затем (когда встретится описание имени ) окажется , что да н ное предположение было неверным , тогда ассемблер пы тается исправить сформированн ную им ранее машинную команду . Однако это не всегда удается : если правильная машин ная команда должна занимать больше места , чем машинная команда , построенная на основе п р едположе ния (например , перед ко мандой надо на самом деле вставить префик с за мены сегмента ), тогда ассемблер фиксирует ошибку (как правило , это ошибка номер 6: Phase error between passes.) Какие же предположения делает ассемблер , встречая ссылку в перед ? Во всех командах , кроме команд перехода (о них см . 1.5), ассемблер предполагает , что имя будет о писано в сегменте данных и потому сегмен тируется по регистру DS. Это следует учитывать при составлении прог раммы : если в команд е встречается ссы л ка вперед на имя , которое описа но в сегменте , на нач ало которого указывает сегментный регистр , от лич ный от DS, то перед таким именем автор программы должен написать соот вествующмй преф икс . Пример : code segment assume cs:code x dw ? beg: mov a x,x ;здесь вместо cs:x можно записать просто x mov cs:y,ax ;здесь обязательно надо записать cs:y ... y dw ? code ends 1.5. ПЕ РЕХОДЫ В систему команд ПК вход ит обычный для ЭВМ набор команд перехода : безу словные и условные переходы , пер еходы с возвратами и др . Однако в ПК эти команды имеют некоторые особенности , которые здесь и рассматри ваются. Абсолютный адрес команды , к оторая должна быть выполнена следующей , опред еляется парой CS:IP, поэтому выполнени е перехо да означает измене ние этих регистров , обоих или только одного (IP). Если изменяется толь ко счетчик команд IP, то такой переход назыв ается внутрисегментным или близким (управление остается в том же сегменте команд ), а если ме няются оба регис т ра CS и IP, то это межсегментный или дальний перехо д (начинают выполняться команды из другого сегмента команд ). По способу изменения счет чика команд переходы делятся на абсолютные и относитель ные . Если в команде перехода указан адрес (смещение ) той ко м а нды , ко торой надо передать управление , то это абсолютный переход . Однако в команде может быть указана величина (сдвиг ), которую надо добавить к текущему значению регистра IP, чтобы получился адрес перехода , и тогда это будет относительный переход ; п ри этом сдвиг может быть положитель н ым и отрицательным , так что возможен перех од вперед и назад . По вели чине сдвига относительные переходы делятся на короткие (с двиг задается байтом ) и длинные (сдвиг - сло во ). Абсолютные же переходы делятся на пря мые и косвенные : при прямом перехо де адрес перехода задается в са мой коман де , а при косвенном - в команде указывается регистр или ячей ка памяти , в котором (которой ) находится адрес перехода. 1.5.1 Безу словные переходы. В MASM все команды безусловного п ерехода обозначаются одинаково : JMP op но в зависимости от типа операнда , ассемблер формирует разные машинные команды. 1) Внутрисегментный относительный короткий переход. JMP i8 (IP:=IP+i8) Здесь i8 обозначает непосредственный операнд размеро в в байт , который интерпретирует ся как знаковое целое от -128 до 127. Команда прибавляет это число к текущему значению регистра IP, получая в нем адрес (смеще ние ) той команды , которая должна быть выполнена следующей . Регистр CS при этом не меняется. Не обходимо учитывать следующую особ енность регистра IP. Выполнение любой команды на чинается с того , что в IP заносится адрес следующей за ней команды , и только зате м выполняется собственно команда . Для коман ды относительного перехода это означает , что опе р анд i8 прибавляется не к адр есу этой команды , а к адресу команды , с ледующей за ней , поэто му , к примеру , команд а JMP 0 - это переход на следующую команду про граммы. При написании машинной программы сдвиги для относительных перехо дов приходится вычи с лять вручную , однако MASM избавляет от э того не приятного занятия : в MASM в командах относительного перехода всегда указывается метка той команды , на которую надо передать управление , и ассемблер сам вычисляет сдвиг , который он и записывает в машин н ую ко манду . Отсюда следует , что в MASM команда перехода по метке восприни мается не как абсолютный переход , а как относительн ый. По кор откому переходу можно передать управление то лько на ближай шие команды программы - отстоящ ие от команды , следующей за командой перехода , до 128 байтов назад или до 127 байт ов вперед . Для перехода на более дальние команды используется 2) Внутрисе гментный относительный длинный переход. JMP i16 (IP:=IP+i16) Здесь i16 обозначает непосредственный операнд размер ом в слово , кото рый рассматривае тся как знаковое целое от -32768 до 32767. Этот пере ход аналогичен короткому переходу. Отметим , что , встретив команду перехода с меткой , которой была по мечена одна из предыдущих (по тексту ) команд программы , а ссемблер вы числяет разность между адресом этой метки и адресом команды перехода и по этому сдвигу определяет , какую маш инную команду относительного пе рехода - короткую или длинную - надо сформировать . Но если метка еще не вс тречалась в тексте программы , т.е . делает ся переход вперед , тогда ассемблер , не зна я еще адреса метки , не может определить , какую именно машинную команду относительного перехода формировать , поэтому он на всяк ий случай выбирает команду длинного перехода . Однако эта машинная команда зан и мает 3 байта , тогда как команда коротко го перехода - 2 байта , и если автор программ ы на MASM стремится к экономии памяти и знает заранее , что переход вперед будет на близкую метку , то он должен сообщить об этом ассемблеру , чтобы тот сформировал к о манду короткого перехода . Такое указание делается с помощью оператора SHORT: JMP SHORT L Для переходов назад оператор SHORT не нужен : уже з ная адрес метки , ас семблер сам определит вид команды относительного перехода. 3) Внут рисегментный абсолютный к освенный переход. JMP r16 (IP:=[r]) или JMP m16 (IP:=[m16]) Здесь r16 обозначает любой 16-битовый регистр общего назначения , а m16 - адрес слова памяти . В этом регистре (слове памяти ) должен находиться адрес , по которому и будет произ веден переход . Например , по команде JMP BX осушествляетс я переход по адресу , находящемуся в регист ре BX. 4) Межс егментный абсолютный прямой переход. JMP seg:ofs (CS:=seg, IP:=ofs) Здесь seg - начало (первые 16 битов начального адреса ) н екоторого сег мента памяти , а ofs - смещение в этом сегменте . Пара seg:ofs определя ет абсолютный адрес , по которому делается переход . В MASM эта пара всегда задается конструкцией FAR PTR < метка >, которая "говорит ", что надо сделать переход по указанной метке, причем эта метка - "дальняя ", из другого сегмента . Отмети м , что ассемблер сам определяет , какой это сегмент , и сам подставляет в машинную команду его начало , т.е . seg. 5) Межс егментный абсолютный косвенный переход. JMP m32 (CS:=[m32+2], IP:=[ m32]) Здесь под m32 понимается адрес двойного слова памяти , в котором нахо дится пара seg:ofs, задающая абсолютный адрес , по которому данная ко манда должна выполнить переход . Напомним , что в ПК величины размером в двойное слово хранятся в "перевернутом " виде , поэтому смещение ofs на ходится в первом слов е двойного слова m32, а смещение seg - во втором слове (по адресу m32+2). Команд ы межсегментного перехода используются тогда , когда команды программы размещены не в о дном сегменте памяти , а в нескольки х (напри мер , команд столь много , что в совокупности они занимают более 64Кб , т.е . бо лее максимального размера сегмента памяти ). Пр и переходе из од ного такого сегмента в другой необходимо менять не только счетчик ко манд IP, но и содержимое регистра C S, загружая в последний начальный адрес второго сегмента . Такое одновременное измене ние обоих этих ре гистров и делают команд ы межсегментного перехода. При записи в MASM команд перехода следует учитывать , что они могут восприниматься неоднозначно . Скаж ем , как воспринимать команду JMP A - как переход по метке A или как переход по адресу , хранящемуся в ячейке с именем A? Кроме того , какой это переход - внутрисегментный или межсегментный ? Ответ зави сит от того , как описано имя A, и от то го , к огда описано имя A - до или после команды перехода. Пусть A описано до команды перехода ("с сылка назад "). Если именем A помечена некоторая команда текущего сегмента команда (т.е . A - м ет ка ), тогда ассемблер формирует машинную ком анду внутрисегментного от носительного перехода . Если же A - имя переменной , тогда ассембле р формирует машинную команду косвенного пере хода - внутрисегментного , если A описано в дирек тиве DW, или межсегментного , если A описано в директиве DD. В случае же , если имя A описан о после команды перехода ("ссылка вперед "), ассемблер всегда формирует машинную команду в нутрисегментно го относительного длинного перехода . С учетом этого имя A обязательно должно метить команду из текущего сегмента команд , иначе будет зафикси р ована ошибка . Если такая трактовка ссылки вперед не удовлетворяет автора программы , тогда он об язан с помощью оператора SHORT или PTR уточнить тип имени A: JMP SHORT A ;внутрисегментный короткий переход по метке JMP WORD PTR A ;внутрисегментный косвенный перехо д JMP DWORD PTE A ;межсегментный косвенный переход Отметим , что переход по метке A из другого сегмента команд всегда должен указ ываться с помощью FAR PTR (независимо от того , о писана мет ка A до или после команды перехо да ): JMP FAR PTR A ;межсегментный переход по м етке 1.5.2 Условные переходы. Практически во всех командах условного перехода проверяется значе ние того или иного флага (например , флага нуля ZF) и , если он имеет определенное значение , выполняется переход по а дресу , указанному в к о манде . Значение флага должно быть установлен о предыдущей командой , на пример , командой срав нения CMP op1,op2 которая вычисляет разность op1-op2, однако резу льтат никуда не записы вает, а только меняет флаги , на которые и буд ет реагиро вать команда условного перехода. В MASM команды условного перехода имеют следующую форму : Jxx op где xx - одна или несколько букв , в со кращенном виде отражающие прове ряемое условие (обычно в предположении , что перед этой командой нахо ди тся команда сравнения ). При меры некоторых мнемоник : JE - переход "по равно " (jump if equal) JL - переход "по меньше " (jump if less) JNL - переход "по неменьше " (jump if not less) Особеностью всех машинных команд условн ого перехода являе тся то , что они реализуют внутрисегментный относительный короткий переход , т.е . добавляют к счетчику команд IP свой операнд , рассматриваемый как знаковое число от -128 до 127. В MASM этот операнд всегда должен запи сываться как метка , которую а ссембл е р заменит на соответствующий сдвиг (см . выше ). Такая особенность команд условного пере хода вызывает неудобство при переходах на "дальние " команды . Например , если надо сделат ь пере ход при A M (обход команды JMP) JMP L ;меньше --> L (длинный переход ) M: ... 1.5.3 Ко манды управление циклом В ПК есть несколько ко манд , упрощающих программирование циклов с за ранее известным числом повторений . Применение этих команд требует , чтобы к началу цик ла в регистр CX было занесено число шагов цикла . Са ми команды размещаются в кон це цикла , они уменьшают значение CX на 1 и , если CX еще не равно 0, передают управление на начало цикла . Напри мер , найти S - сумму элементов массива X из 10 чисел-слов можно так : MOV AX,0 ;начальное значение суммы (накапливается в AX) MOV SI,0 ;начальное значение индексного р егистра MOV CX,10 ;число повторений цикла L: ADD AX,X[SI] ;AX:=AX+X[i] ADD SI,2 ;SI:=SI+2 LOOP L ;CX:=CX-1; if CX<>0 then goto L MOV S,AX ;S:=AX Помимо команды LOOP есть еще две "циклич еские " кома нды - LOOPZ и LOOPNZ (они имеют синоним ичные названия LOOPE и LOOPNE), которых кроме регистра CX проверяют еще и флаг нуля ZF; например , к оманда LOOPZ "вы ходит " из цикла , если CX=0 или ZF=1. Эт у команду можно , например , ис пользовать при поиске в массив е первого нулевого элемента , где должно быть предусмотрено два условия выхода из цикла : либо будет найден ну- левой эле мент (ZF=1, если перед LOOPZ поставить команду сравнен ия оче редного элемента с 0), либо будет исч ерпан весь мсассив (CX=0) Отметим , ч то все эти "циклические " команды реали зуют короткий относительный переход , как и команды условного перехода , поэтому их мож но использовать только для циклов с небол ьшим числом команд. В MASM есть еще две коман ды перехода - CALL (переход с возвратом ) и RET (возврат из подпрограммы ), они рассматри ваются в 1.7. 1.6. СТРОКОВЫ Е ОПЕРАЦИИ В ПК под строкой понимается последовательность сосе дних байтов или слов . В связи с этим все строковые команды имеют две разновид ности для работы со строками из байтов (в мнемонику операций входит буква B) и для работы со строками из слов (в мнемонику входит W). Имеются следующие операции над строкам и : · пересылка элементов строк (в память , из памяти , памят ь-память ); · сравнение двух строк ; · просмотр с троки с целью п оиска элемента , равного заданному. Каждая из этих операций выполняется только над одним элементом строки , однако одновременно происходит автоматическая настройка на следую щий или предыдущий элемент строки . Имеются специальные команды повторения (REP и др .), которые заставляют следующую за ними строков ую команду многократно повторяться (до 2^16 раз ), в связи с чем такая па ра команд по зволяет обработать всю строку , причем намного быстрее , чем запрограммированный цикл. Кроме того , строки можно п росма тривать вперед (от их начала к кон цу ) и назад . Направление просмотра зависит от флага направления DF, значение которого можно менять с помощью команд STD (DF:=1) и CLD (DF:=0). При DF=0 все последующие строковые команды программы п росмат рив а ют строки вперед , а при DF=1 - назад. В строковых командах операнды явно не указываются , а подразумева ются . Если коман да работает с одной строкой , то адрес очередного , об рабатываемого сейчас элемента строк и задается парой регистров DS и SI или парой ES и DI, а если команда работает с д вумя строками , то адрес элемента одной из них определяется парой DS:SI, а адрес элемент а дру гой - парой ES:DI. После выполнения операции значение регистра SI и /или DI увеличивается ( при DF=0) или уменьшается (п р и DF=1) на 1 (для байтовых строк ) или на 2 (для строк из слов ). Начальная установка всех этих регистро в , а также флага DF должна быть выполнена до начала операции над строкой . Если се гментный регистр DS уже имеет нужное значение , тогда загрузить реги стр SI можно с по мощью команды LEA SI,<начальный /конечный адрес строки > Если же надо загрузить сразу оба регистра DS и SI, тогда можно вос пользоваться ком андой LDS SI,m32 которая в регистр SI заносит первое сло во , а в регистр DS - второе сло во из двойного слова , имеющего адре c m32 (таким обр азом , по адресу m32+2 должен храниться сегмент , а по адресу m32 - смещение начального или конечного элемента строки ). Начальную загрузку регистров ES и DI обычно осуществляют одной ко мандой LES DI,m 32 которая действует аналогично команде LDS. Перечислим вкратце строковые команды П К. Команда загрузки элемента строки в аккумулятор (LODSB или LODSW) пересылает в регистр AL и ли AX очередной элемент строки , на который указывает пара DS:SI, после чего увеличивает (при DF=0) или уменьшает (при DF=1) регистр SI на 1 и ли 2. Команда записи аккумулятора в строку (STOSB или STOSW) заносит со держимое регистра AL или AX в тот элемент строки , на который указывает пара ES:DI, после чего изменяет регистр DI на 1 или 2. Команда пересылки строк (MOVSB или MOVSW) считыва ет элемент первой строки , определяемый парой DS:SI, в элемент второй строки , определяе мый парой ES:DI, после чего одновременно меняет регист ры SI и DI. Коман да сравнения строк (CMPSB и ли CMPSW) сравнивает очередные элементы строк , указываемые парами DS:SI и ES:DI, и результат сравне ния (равно , меньше и т.п .) фиксирует в флагах , после чего меняет реги стры SI и DI. Команда сканирования строки (SCASB или SCASW) ср авнивает элемент строки , адрес которого задается парой ES:DI, со значением регистра AL или AX и результат сравнения фиксирует в флагах , после чего меняет со держимое регистра DI. Перед любой строковой командой можно поставить одну из двух ко манд , называемы х "префикс ами повторения ", которая заставит многократно повториться эту строковую команд у . Число повторений (обычно это длина стро ки ) должно быть указано в регистре CX. Префи кс повторения REPZ (синонимы - REPE, REP) сначала заносит 1 в флаг нуля ZF, после че г о , посто янно уменьшая CX на 1, заставляет повторяться сл едующую за ним строковую команду до тех пор , пока в CX не окажется 0 или пока ф лаг ZF не изменит свое значение на 0. Другой префикс повторения REPNZ (сино ним - REPNE) действует а налогично , н о только вначале устанав ливает флаг ZF в 0, а при при изменении е го на 1 прекращает повторение стро ковой команд ы. Пример . Пусть надо переписать 10000 байтов начиная с адреса A в другое место пам яти начиная с адреса B. Если оба этих и мени относятся к сегменту данных , на начало которого указывает регистр DS, тогда э ту пересылку можно сделать так : CLD ;DF:=0 (просмотр строки вперед ) MOV CX,1000 ;CX - число повторений MOV AX,DS MOV ES,AX ;ES:=DS LEA SI,A ;ES:SI - "отк уда " LEA DI,B ;DS:DI - "куда " REP MOVSB ;пересылка CX байтов 1.7. СТЕ К . ПОДПРОГРАММЫ. 1.7.1 Стек В ПК имеются специальные команды работы со стеком , т.е . областью памяти , доступ к элементам которой осуществ ляется по принципу "послед н им записан - первым считан ". Но для того , чтобы можно было воспользо ваться этими командами , необхо димо соблюдение ряда условий. Под стек можно отвести область в любом месте памяти . Размер ее мо жет быт ь любым , но не должен превосходить 64Кб , а ее нача льный адрес должен быть кратным 16. Другими словами , эта область должн а быть сег ментом памяти ; он называется се гментом стека . Начало этого сегмента (первые 16 битов начального адреса ) должно обязательно храниться в сегментном регистре SS. Храним ые в стеке элементы могу т иметь любой размер , однако следует учиты вать , что в ПК имеются команды записи в стек и чтения из него только сло в . Поэтому для записи байта в стек ег о надо предварительно расширить до слова , а запись или чтение двойных с л ов осуществляются парой команд. В ПК принято заполнять стек снизу вверх , от больших адресов к меньшим : первый элемент записывается в конец области , отведенной под стек , второй элемент - в предыдущую ячейку области и т.д . Считываетс я всегда элемен т , записанный в стек последним . В связи с этим нижняя грани ца стека всегда фиксирована , а верхняя - ме няется . Слово памяти , в котором находится элемент стека , записанный последним , называется вершиной стека . Адрес вершины , отсчитанный от начала с егмента стека , обязан находиться в указателе стека - регистре SP. Та ким образом , аб солютный адрес вершины стека определяется парой SS:SP. ----- ----- ----- SS:SP | | SS:SP | | SS:SP | | | ----- запись | ----- чт ение | ----- | | | =======> ---->| b | =======> | | | | ----- в стек ----- из стека | ----- ----->| a | | a | ---->| a | ----- ----- ----- Значени е 0 в регистре SP свидетельствует о том , что стек полностью заполне н (его верши на "дошла " до начала области стека ). Поэтом у для контроля за переполнением стека надо перед новой записью в стек прове рять усл овие SP=0 (сам ПК этого не делает ). Для пус того стека значение SP должно равняться размеру стека , т.е . пара SS:SP должна указывать н а байт , следующий за последним байтом обла сти стека . Контроль за чтением из пустого стека , если надо , обязана делать сама программа. Начальная установка регистров SS и SP может быть произведена в са мой программе , одна ко в MASM предусмо трена возможность автомати ческой загрузки этих регистров . Если в дир ективе SEGMENT, начинающей описание сегмента стека , указать параметр STACK, тогда ассемблер (точнее , за грузчик ) перед тем , как передать управление на первую команду машинной программы, загрузит в регистры SS и SP нужные значен ия . Например , если в программе сегмент сте ка описан следующим образом : ST SEGMENT STACK DB 256 DUP(?) ;размер стека - 256 байтов ST ENDS и е сли под этот сегмент была выделена област ь памяти начиная с абсо лютного адреса 12340h, тогда к началу выполнения программы в регистре SS окажется величина 1234h, а в регист ре SP - величина 100h (=256). Отметим , что эти значения соответствуют пустому стеку. 1.7.2 Основные стековые команды При соблюдении у казанн ых требований в программе можно использовать команды , предназначенные для работы со ст еком . Основными из них явля ются следующие. Запись слова в стек : PUSH op Здесь op обозначает любой 16-битовый регистр (в том числе и сегмент ный ) или адрес слова памяти . По этой команде значе ние регистра SP уменьшается на 2 (вычитание прои сходит по модулю 2^16), после чего указанное о перандом слово записывается в cтек по адре су SS:SP. Чтение слова из стека : POP op Слово , считанное из вершины стека , присваивается операнду op (регист ру , в том чи сле сегментному , но не CS, или слову памяти ), после чего значение SP увеличивается на 2. Переход с возвратом : CALL op Эта команда записывает адрес следующей за ней команды в стек и затем дела ет перех од по адресу , определяемому оп ерандом op. Она используется для переходов на подпрограммы с запоминанием в стеке адреса возврата . Имеются следующие разновидности этой команды (они аналогичны вари- антам команды безусловного перехода JMP): - внутрисегментн ый относительный длинный переход (op - непоср едст венный операнд размером в слово , а в MASM - это метка из текущего сег мента команд или имя близкой процедуры (см . ниже )); в этом случае в стек заносится только текущее значение счетчика команд IP, т.е . с меще ние следующей команды ; - внутрисегментный абсолютный косвенный переход (op - адрес слова памяти , в которой находится адрес (смещение ) той команды , на которую и будет сдела н переход ); и здесь в стек записывается только смещение ад реса возврата ; - м ежсегме нтный абсолютный прямой переход (op - непосредственн ый операнд вида seg:ofs, а в MASM - это FAR PTR <метка > или имя дальней процедуры (см . ниже )); здесь в стек заносится текущие значение регист ров CS и IP (первым в стек записывается содер жимо е CS), т.е . абсолют ный адрес возврат а , после чего меняются регистры CS и IP; - межсегментный абсолютный косвенный переход (op - адрес двойного слова , в котором находится пара seg:ofs, задающ ая абсолютный адрес пе рехода ); и здесь в стеке спасается содерж имое регистров CS и IP. Перех од (возврат ) по адресу из стека : RET op Из стека считывается адрес и по н ему производится переход . Если указан операнд (а это должно быть неотрицательное число ), то после чтения ад реса стек еще очи щается на это число байто в (к SP доб авляется это чис ло ). Команда используется для возврата из подпрограммы по адресу , за пи санному в стек по команде CALL при вызове подпрограммы , и одновре менной очистки стека от параметров , которые основная программа з анесла в стек перед обра щением к подпрограмме. Команда RET имеет две разновидности (хотя в MASM они записываются и одинаково ): в одн ом случае из стека считывается только одн о слово смещение адреса возврата , а во втором - из стека считывается пара seg: ofs, указыв ающая абсолют ный адрес возврата . Как ассемблер определяет , какой из этих двух с лучаев имеет место , объяснено ниже. В ПК стек в основном используется для организации подпрограмм и прерываний . Подпрограммы рассматрив аются ниже , а прерывания - в главе 3. Однако , даж е если программе не нужен сте к , она все равно должна от вести под н его место . Дело в том , что стеком будет неявно пользоваться операционная система при обработке прерываний , которые возникают (нап р имер , при нажатии клавиш на клавиатуре ) в то время , когда выполняется прогр амма . Для нужд ОС рекомендуется выделять в стеке 64 байта. 1.7.3 Подпрог раммы Типичная схема огранизации подпрограмм , обычно используемая транс ляторами с языков высокого уровня для реализации процедур и функций (в частности , рекурси вных ), следующая. При обращении к подпрограмме в стек заносятся параметры для нее и адрес возрата , после чего делается переход на ее начало : PUSH param1 ;запись 1-го параметра в стек ... PUSH paramk ;запись последнего (k-го ) параметра в стек CALL subr ;переход в возратом на подпрограмму ( Замечание : если необходимо вычислить параметр или если его размер от личен от слова , тогда для записи параметра в стек нужно , конечно , нес колько команд , а не одна .) Состояние стека после выполнения этих ко манд обращения к подпрограмме показано на рис . a | | |--------------| | | | лок.величины |<-SP | | -2| (m байтов ) | | | |--------------| | | 0| BP стар |<-BP |а дрес возврата |<-SP +2|адрес возврата | | 1-й параметр | +4| 1-й параметр | | ... | | ... | | k-й параметр | | k-й параметр | |//////////////| |//////////////| |//////////////|<-BP |//////////////| рис . а рис . б Первыми командами подпрограммы обычно я вляются следующие : PUSH BP ;спасти в стеке старое значение BP MOV SP,BP ;установить BP на вершину стека SUB SP,m ;отвести в стеке место (m байтов ) под локальные ;в еличины подпрограммы (состояние стека в этот ;момент показано на рис . б ) Поя сним эти "входные " команды . В подпрограмме для обращения к ячейкам стека , занятых па раметрами , используется (как базовый ) регистр BP: если в BP занести адрес вершины стека , то для доступа к этим ячей кам следует использовать адресные выражения вида i[BP] или , что то же самое , [BP+i]. (Отметим , что применять здесь регистры-модификаторы BX, SI и DI нельзя , т.к . формируемые по ним исполнительные адреса будут сегментироваться по умолчанию по регист ру DS, а в да н ном случае нужно сегментирование по SS.) Однако данная подпрограмм а может быть вызвана из другой , также использующей регистр BP, поэтому прежде , чем уст ано вить BP на вершину стека , надо спасти в стеке старое значение этого регистра , чт о и делает пе р вая из "входных " команд . Вторая же команда устанавливает BP на вершину стека . Если предположить , что каждый пара метр и адрес возврата занимают по слову памяти , тогда доступ к первому параметру обеспечивается адресным выражением [BP+4], ко второму - вы р ажением [BP+6] и т. д . (см . рис . б ). Подпрограмме может потребоваться место для ее локальных величин. Такое место обычно отводится в стеке (а для рекурсивных подпрограмм только в стеке ) "на д " ячейкой , занимаемой старым значением BP. Если под эти вел ичины нужно m байтов , т о такой "захват " места можно реали зовать п ростым уменьшением значения регистра SP на m, что и делает 3-я "входная " команда . Доступ к локальным величинам обеспечивается адрес ными выражениями вида [BP-i]. Если подпрограмме не ну жн о место под ло кальные величины , тогда третью из "входных " команд следует опустить . Выход из подпрограммы реализуется следующими коман дами : MOV SP,BP ;очистить стек от локальных величин POP BP ;восстановить старое значение BP RET 2*k ;возврат и з подпрограммы и очистка стека от ;параметров (считаем , что они зан имают 2*k байтов ) Первая из этих "выходных " ко манд заносит в регистр SP адрес той ячейки стека , где хранится старое значение регис тра BP, т.е . происходит очис тка стека от лока льных в еличин (если их не было , то данную команду надо опустить ). Вторая ком анда восстанавливает в BP это старое значе ние , одновременно удаляя его из стека . В этот момент состояние стека будет таким ж е , как и перед входом в подпрограмму (с м . рис а ). Тре т ья команда считы вает из стека адрес возврата (в результате чего SP "опус кается " на 2 байта ), затем добавл яет к SP число , которое должно рав няться чи слу байтов , занимаемых всеми параметрами подп рограммы , и за тем осуществляет переход по адресу возврат а . В этот момент состояние стека будет таким же , каким о но было перед обращением к подпрограмме . Здесь описана универсальная схема организации раб оты подпрограмм. В кокретных же случаях можно использовать более простые схемы . Напри мер , параметры можно передавать не через стек , а через регистры , место под локальные величины можн о отводить не в стеке , а в сегменте данных и т.п. 1.7.4 Процедуры в языке ассемблера При составлении и вызове подпрограмм необходимо следить за тем , что бы команды CALL и RET действовали согласовано - были одновременно близкими или дальними . В MASM эта проблема снимается , если подпрограм му описать как процедуру . Процедуры имеют след ующий вид : имя _процедуры PROC [NEAR или FAR] ... имя _процедуры ENDP Хотя в дире ктиве PROC после имени процедуры не ставится двоеточие , это имя относится к меткам и его можно указыва ть в командах перехода , в частности в команде CALL, когда надо вызвать процедуру . Это же имя должно быть повторено в директи ве ENDP, заканчивающей оп и сание проце дур ы . Предложения между этими двумя директивами образуют тело процеду ры (подпрограмму ). Имя процедуры является фактически меткой первой из команд тела , поэтому данную команду не надо специально метить. Если в директиве PROC указан параметр NEAR или он вообще не ука зан , то т акая процедура считается "близкой " и обращатьс я к ней можно только из того сегмента команд , где она описана . Дело в том , что ас семблер будет заменять все команды CALL, где указано имя данной проце дуры , на машинные команды близкого перехода с возвратом , а все команды RET внутри процеду ры - на близкие возвраты . Если же в дир ективе PROC указан параметр FAR, то это "дальняя " процедура : все обращения к ней и все к оманды RET внутри нее рассматриваются ассемблером как д а льние пе реходы . Обращаться к этой процедуре можно из любых сегмен тов команд . Таким образом , достаточно лишь указать тип процедуры (близкая она или да льняя ), всю же остальную работу возьмет на себя ассемблер : переходы на нее и воз враты из нее будут ав т оматически согласованы с этим типом . В этом глав ное (и единственное ) достоинство описания подп рограмм в ви де процедур . (Отметим , что мет ки и имена , описанные в процедуре , не локализуются в ней .) Например , вычисление ax:=sign(ax) можно описать в виде процедуры следующим образом : sing proc far ;дальняя процедура cmp ax,0 je sgn1 ;ax=0 - перейти к sgn1 mov ax,1 ;ax:=1 (флаги не изменились !) jg sgn1 ;ax>0 - перейти к sgn1 mov ax,-1 ;ax:=-1 sgn1: ret ;дальний возврат sign endp ... Возможны й пример обращения к этой процедуре : ;cx:=sign(var) mov ax,var call sign ; дальний вызов mov cx,ax
1Архитектура и строительство
2Астрономия, авиация, космонавтика
 
3Безопасность жизнедеятельности
4Биология
 
5Военная кафедра, гражданская оборона
 
6География, экономическая география
7Геология и геодезия
8Государственное регулирование и налоги
 
9Естествознание
 
10Журналистика
 
11Законодательство и право
12Адвокатура
13Административное право
14Арбитражное процессуальное право
15Банковское право
16Государство и право
17Гражданское право и процесс
18Жилищное право
19Законодательство зарубежных стран
20Земельное право
21Конституционное право
22Конституционное право зарубежных стран
23Международное право
24Муниципальное право
25Налоговое право
26Римское право
27Семейное право
28Таможенное право
29Трудовое право
30Уголовное право и процесс
31Финансовое право
32Хозяйственное право
33Экологическое право
34Юриспруденция
 
35Иностранные языки
36Информатика, информационные технологии
37Базы данных
38Компьютерные сети
39Программирование
40Искусство и культура
41Краеведение
42Культурология
43Музыка
44История
45Биографии
46Историческая личность
47Литература
 
48Маркетинг и реклама
49Математика
50Медицина и здоровье
51Менеджмент
52Антикризисное управление
53Делопроизводство и документооборот
54Логистика
 
55Педагогика
56Политология
57Правоохранительные органы
58Криминалистика и криминология
59Прочее
60Психология
61Юридическая психология
 
62Радиоэлектроника
63Религия
 
64Сельское хозяйство и землепользование
65Социология
66Страхование
 
67Технологии
68Материаловедение
69Машиностроение
70Металлургия
71Транспорт
72Туризм
 
73Физика
74Физкультура и спорт
75Философия
 
76Химия
 
77Экология, охрана природы
78Экономика и финансы
79Анализ хозяйственной деятельности
80Банковское дело и кредитование
81Биржевое дело
82Бухгалтерский учет и аудит
83История экономических учений
84Международные отношения
85Предпринимательство, бизнес, микроэкономика
86Финансы
87Ценные бумаги и фондовый рынок
88Экономика предприятия
89Экономико-математическое моделирование
90Экономическая теория

 Анекдоты - это почти как рефераты, только короткие и смешные Следующий
Вчера в Ухрюпинске был дерзко ограблен магазин "Всё для рыбалки".
Судя по украденному, злоумышленники идут на леща.
Anekdot.ru

Узнайте стоимость курсовой, диплома, реферата на заказ.

Обратите внимание, реферат по программированию "Язык макроассемблера IBM PC", также как и все другие рефераты, курсовые, дипломные и другие работы вы можете скачать бесплатно.

Смотрите также:


Банк рефератов - РефератБанк.ру
© РефератБанк, 2002 - 2017
Рейтинг@Mail.ru