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

Особенности персональных ЭВМ типа IBM PC и начальные сведения о языке макроассеблера, его характеристика. Описание структуры и систем команд этих компьютеров. Примеры полных программ и их фрагментов на MASM (версия 4.0) для решения различных задач.

Рубрика Программирование, компьютеры и кибернетика
Вид учебное пособие
Язык русский
Дата добавления 22.11.2009
Размер файла 45,1 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

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

(Справочное пособие)

ГЛАВА 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) .

Числа размером в слово хранятся в памяти в "перевернутом" виде: младiие (правые) 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 числа записываются в нормальном (неперевернутом) виде в системах счисления с основанием 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 (op1: =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.


Подобные документы

  • История создания и эволюция персональных компьютеров. Характеристика современных видов компьютеров, их приспособляемость к различным условиям эксплуатации. Тенденции развития микропроцессорных технологий. Примеры решения задач в среде Mathcad и AutoCAD.

    курсовая работа [1,8 M], добавлен 13.04.2015

  • Исторические предшественники компьютеров. Появление первых персональных компьютеров. Концепция открытой архитектуры ПК. Развитие элементной базы компьютеров. Преимущества многопроцессорных и многомашинных вычислительных систем перед однопроцессорными.

    курсовая работа [1,7 M], добавлен 27.04.2013

  • Характеристика этапов решения задач на электронных вычислительных системах. Разработка алгоритма и основы программирования. Язык Ассемблера, предназначенный для представления в удобочитаемой символической форме программ, записанных на машинном языке.

    контрольная работа [60,5 K], добавлен 06.02.2011

  • Проблема вредоносных программ. Принцип надежности компьютера. Влияние вирусных систем на повседневную работу пользователей персональных компьютеров. Разновидности вредоносных программ, их эволюция и методы зашиты от них. Антивирусы на рабочих станциях.

    контрольная работа [19,6 K], добавлен 04.10.2011

  • Понятие массива и правила описания массивов в программах на языке С. Рассмотрение основных алгоритмов обработки одномерных массивов. Примеры программ на языке С для всех рассмотренных алгоритмов. Примеры решения задач по обработке одномерных массивов.

    учебное пособие [1,1 M], добавлен 22.02.2011

  • Навыки использования теоретического материала и практического опыта для решения задач проектирования и разработки программного обеспечения для систем различного назначения на языке Паскаль. Описание логической структуры, входные и выходные данные.

    курсовая работа [647,0 K], добавлен 23.04.2009

  • Характеристика предприятия ТОО "Com Sales Group". Составление программ на языке программирования. Составление алгоритмов, разработка численных методов решения задач. Методы откладки программ. Анализ технологии машинной обработки экономической информации.

    отчет по практике [1,3 M], добавлен 19.04.2016

  • Выполнение арифметических операций с помощью вспомогательных переменных, которые позволяют вычислить искомую переменную. Использование оператора цикла с предусловием и полной формы условного оператора. Примеры решения задач на работу с двумерным массивом.

    курсовая работа [518,8 K], добавлен 07.03.2014

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

    реферат [2,1 M], добавлен 16.09.2011

  • Этапы развития информатики и вычислительной техники. Аппаратная часть персональных компьютеров. Внешние запоминающие устройства персонального компьютера. Прикладное программное обеспечение персональных компьютеров. Текстовые и графические редакторы.

    контрольная работа [32,8 K], добавлен 28.09.2012

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.