Реферат: Язык макроассемблера 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 - 2016
Рейтинг@Mail.ru