Оглавление
Введение
|
5
|
1. Архитектура процессора 8086
|
5
|
1.1. Регистры
|
8
|
1.2. Сегменты, принцип сегментации
|
10
|
1.3. Стек
|
11
|
1.4. Прерывания
|
12
|
1.5. Режимы адресации
|
13
|
2. Загрузка и выполнение программ в DOS
|
14
|
2.1. EXE- и COM-программы
|
16
|
2.2. Выход из программы
|
18
|
3. Ассемблер, макроассемблер, редактор связей
|
18
|
4. Язык Ассемблера. Начальные сведения
|
20
|
4.1. Идентификаторы, переменные, метки, имена, ключевые слова
|
20
|
4.2. Типы данных
|
21
|
4.3. Предложения
|
22
|
4.4. Выражения
|
23
|
4.5. Приоритеты операций
|
25
|
4.6. Ссылки вперед
|
25
|
4.7. Директивы определения данных
|
26
|
4.7.1. Скалярные данные
|
26
|
4.7.2. Записи
|
27
|
4.7.3. Структуры
|
29
|
4.8. Директива эквивалентности
|
29
|
4.9. Структура программы на языке Ассемблера
|
29
|
4.9.1. Директива ASSUME
|
31
|
4.9.2. Директива INCLUDE
|
32
|
4.9.3. Структура EXE- и COM- программы
|
33
|
4.10. Модификация адресов
|
34
|
4.11. Сегментные регистры по умолчанию
|
35
|
5. Команды пересылки
|
35
|
5.1. Команда MOV
|
35
|
5.2. Команда обмена данных XCHG
|
36
|
5.3. Команды загрузки полного указателя LDS и LES
|
37
|
5.4. Команда перекодировки XLAT
|
37
|
5.5. Команды работы со стеком
|
37
|
5.6. Команды ввода-вывода
|
38
|
6. Арифметические команды
|
39
|
6.1. Команды арифметического сложения ADD и ADC
|
39
|
6.2. Команды арифметического вычитания SUB и SBB
|
40
|
6.3. Команда смены знака NEG
|
41
|
6.4. Команды инкремента INC и декремента DEC
|
41
|
6.5. Команды умножения MUL и IMUL
|
41
|
6.6. Команды деления DIV и IDIV
|
42
|
7. Команды побитовой обработки
|
44
|
7.1. Команды, выполняющие логические операции
|
44
|
7.2. Команды, выполняющие операции сдвигов
|
44
|
8. Команды сравнения и передачи управления
|
47
|
9. Подпрограммы и прерывания
|
49
|
10. Команды работы со строками
|
52
|
11. Команды управления процессором
|
54
|
Приложение 1 Система команд МП Intel 8086
|
55
|
|
|
Введение
Не смотря на то, что язык программирования Ассемблера, в чистом виде, относительно редко используется на практике, его изучение является необходимой частью подготовки профессиональных программистов, поскольку позволяет шире понять принципы работы ЭВМ, операционных систем и трансляторов с языков высокого уровня.
Настоящее учебное пособие содержит описание архитектуры и системы команд процессора Intel 8086, что является базой для изучения программирования других, более современных, процессоров Intel. Кроме того, в учебном пособии уделено внимание интеграции языков высокого уровня и языка Ассемблера, что в настоящее время наиболее актуально.
В качестве дополнения учебное пособие включает курс практических работ, изучение которых позволит получить навык в программировании на языке Ассемблера.
1. Архитектура процессора 8086
Системный блок персонального компьютера содержит: блок питания; системную (материнскую) плату; адаптеры внешних устройств; накопители на жестких магнитных (НЖМД) и гибких (НГМД) дисках, а также ряд других устройств. Для нас наибольший интерес представляет системная плата, на которой размещаются постоянное запоминающее устройство ПЗУ (ROM - read only memory), оперативное запоминающее устройство ОЗУ (RAM - random access memory), процессор и логика управления, связанные между собой шинами.
Физически и ОЗУ и ПЗУ выполнены в виде микросхем. Характерным для персонального компьютера является тот факт, что при выключении электропитания содержимое ОЗУ утрачивается (энергозависимая память), а ПЗУ – нет (энергонезависимая память).
Одна из основных задач ПЗУ обеспечить процедуру старта персонального компьютера. В ПЗУ хранятся базовая система ввода/вывода BIOS, а также некоторые служебные программы и таблицы, например, начальный загрузчик, программа тестирования POST и т.п.
Оперативная память ОЗУ предназначена для временного хранения программ и данных, которыми они манипулируют. Логически оперативную память можно представить в виде последовательности ячеек, каждая из которых имеет свой номер, называемый адресом.
Центральный процессор (ЦП) в современных персональных компьютерах выполнен в виде одной сверхбольшой интегральной микросхемы (СБИС). ЦП выполняет машинные команды, выбирая их в заданной последовательности из оперативной памяти. Работа всех электронных устройств компьютера координируется сигналами управления, вырабатываемыми ЦП и некоторыми другими СБИС, сигналами тактового генератора, с помощью которых синхронизируются действия всех сигналов.
Возможности компьютера в большей степени зависят от типа установленного процессора и его тактовой частоты. Семейство процессоров 80х86 корпорации Intel включает в себя микросхемы: 8086, 80186, 80286, 80386, 80486, Pentium, Pentium II, Pentium III и т.д. Совместимые с 80х86 микросхемы выпускают также фирны AMD, IBM, Cyrix. Особенностью этих процессоров является преемственность на уровне машинных команд: программы, написанные для младших моделей процессоров, без каких-либо изменений могут быть выполнены на более старших моделях. При этом базой является система команд процессора 8086, знание которой является необходимой предпосылкой для изучения остальных процессоров.
Структуру центрального процессора Intel 8086 можно разделить на два логических блока (рис.1.1):
блок исполнения (EU:Execution Unit);
блок интерфейса шин (BIU:Bus Interface Unit).
(Интерфейс (interface) - это совокупность средств, обеспечивающих сопряжение устройств и программных модулей как на физическом, так и на логическом уровнях).
В состав EU входят: арифметическо-логическое устройство ALU, устройство управления CU и десять регистров. Устройства блока EU обеспечивают обработку команд, выполнение арифметических и логических операций.
Три части блока BIU - устройство управления шинами, блок очереди команд и регистры сегментов – предназначены для выполнения следующих функций:
управление обменом данными с EU, памятью и внешними устройствами ввода/вывода;
адресация памяти;
выборка команд (осуществляется с помощью блока очереди команд Queue, который позволяет выбирать команды с упреждением).
С точки зрения программиста, процессор 8086 состоит из 8 регистров общего назначения, 4 сегментных регистров, регистра адреса команд (счетчика команд) и регистра флагов. Процессор выставляет на шину адреса адрес выбираемых из памяти команд (или данных), которые поступают в шестибайтный буфер (очередь команд), а затем исполняются.
Адресную шину можно представить в виде 20 проводников, в каждом из которых может либо протекать напряжение заданного уровня (сигнал 1), либо отсутствовать (сигнал 0). Таким образом, микропроцессор оперирует с двоичной системой счисления (двоичной системой представления данных). Символьная информация кодируется в соответствии с кодом ASCII (Американский стандартный код для обмена информацией). Числовые данные кодируются в соответствии с двоичной арифметикой. Отрицательные числа представляются в дополнительном коде.
Минимальная единица информации, соответствующая двоичному разряду, называется бит (Bit). Группа из восьми битов называется байтом (Byte) и представляет собой наименьшую адресуемую единицу – ячейку памяти. Биты в байте нумеруют справа налево цифрами 0...7.
BYTE
Двухбайтовое поле образует шестнадцатиразрядное машинное слово (Word), биты в котором нумеруются от 0 до 15 справа налево. Байт с меньшим адресом считается младшим.
WORD
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Четырехбайтовое поле образует двойное слово (Double Word), а шестнадцатибайтовое – параграф (Paragraph).
Таким образом, с помощью 16-разрядной шины данных можно передавать числа от 0 (во всех проводниках сигнал 0) до 65535 (во всех проводниках сигнал 1). Несмотря на то, что двоичная система обладает высокой наглядностью, она имеет существенный недостаток – числа, записанные в двоичной системе, слишком громоздки. С другой стороны, привычная для нас десятичная система слишком сложна для перевода чисел в двоичную систему счисления и обратно. Поэтому наибольшее распространение в практике программирования получила шестнадцатеричная система счисления.
При написании программ принято двоичные числа сопровождать латинской буквой B или b, (например, 101B), а шестнадцатеричные – буквой H или h на конце. Если число начинается с буквы, то обязательной является постановка нуля впереди, например, 0BA8H.
1.1. Регистры
Процессор 8086 имеет 14 шестнадцатиразрядных регистров, которые используются для управления исполнением команд, адресации и выполнения арифметических операций. Регистр, содержащий одно слово, адресуется по имени.
Регистры общего назначения. К ним относятся 16-разрядные регистры АХ, ВХ, СХ, DX, каждый из которых разделен на 2 части по 8 разрядов:
АХ состоит из АН (старшая часть) и AL (младшая часть);
ВХ состоит из ВH и BL;
СХ состоит из СН и CL;
DX состоит из DH и DL;
В общем случае функция, выполняемая тем или иным регистром, определяется командами, в которых он используется. При этом с каждым регистром связано некоторое стандартное его значение. Ниже перечисляются наиболее характерные функции каждого регистра:
регистр АХ служит для временного хранения данных (регистр аккумулятор); часто используется при выполнении операций сложения, вычитания, сравнения и других арифметических и логических операции;
регистр ВХ служит для хранения адреса некоторой области памяти (базовый регистр), а также используется как вычислительный регистр;
регистр СХ иногда используется для временного хранения данных, но в основном служит счетчиком; в нем хранится число повторений одной команды или фрагмента программы;
регистр DX используется главным образом для временного хранения данных; часто служит средством пересылки данных между разными программными системами, в качестве расширителя аккумулятора для вычислений повышенной точности, а также при умножении и делении.
Регистры для адресации. В микропроцессоре существуют четыре 16-битовых (2 байта или 1 слово) регистра, которые могут принимать участие в адресации операндов. Один из них одновременно является и регистром общего назначения — это регистр ВХ, или базовый регистр. Три другие регистра — это указатель базы ВР, индекс источника SI и индекс результата DI. Отдельные байты этих трех регистров недоступны.
Любой из названных выше 4 регистров может использоваться для хранения адреса памяти, а команды, работающие с данными из памяти, могут обращаться за ними к этим регистрам. При адресации памяти базовые и индексные регистры могут быть использованы в различных комбинациях. Разнообразные способы сочетания в командах этих регистров и других величин называются способами или режимами адресации.
Регистры сегментов. Имеются четыре регистра сегментов, с помощью которых память можно организовать в виде совокупности четырех различных сегментов. Этими регистрами являются:
CS — регистр программного сегмента (сегмента кода) определяет местоположение части памяти, содержащей программу, т. е. выполняемые процессором команды;
DS — регистр информационного сегмента (сегмента данных) идентифицирует часть памяти, предназначенной для хранения данных;
SS — регистр стекового сегмента (сегмента стека) определяет часть памяти, используемой как системный стек;
ES — регистр расширенного сегмента (дополнительного сегмента) указывает дополнительную область памяти, используемую для хранения данных.
Эти 4 различные области памяти могут располагаться практически в любом месте физической машинной памяти. Поскольку местоположение каждого сегмента определяется только содержимым соответствующего регистра сегмента, для реорганизации памяти достаточно всего лишь, изменить это содержимое.
Регистр указателя стека. Указатель стека SP – это 16-битовый регистр, который определяет смещение текущей вершины стека. Указатель стека SP вместе с сегментным регистром стека SS используются микропроцессором для формирования физического адреса стека. Стек всегда растет в направлении меньших адресов памяти, т.е. когда слово помещается в стек, содержимое SP уменьшается на 2, когда слово извлекается из стека, микропроцессор увеличивает содержимое регистра SP на 2.
Регистр указателя команд IP. Регистр указателя команд IP, иначе называемый регистром счетчика команд, имеет размер 16 бит и хранит адрес некоторой ячейки памяти – начало следующей команды. Микропроцессор использует регистр IP совместно с регистром CS для формирования 20-битового физического адреса очередной выполняемой команды, при этом регистр CS задает сегмент выполняемой программы, а IР – смещение от начала сегмента. По мере того, как микропроцессор загружает команду из памяти и выполняет ее, регистр IP увеличивается на число байт в команде. Для непосредственного изменения содержимого регистра IP служат команды перехода.
Регистр флагов. Флаги – это отдельные биты, принимающие значение 0 или 1. Регистр флагов (признаков) содержит девять активных битов (из 16). Каждый бит данного регистра имеет особое значение, некоторые из этих бит содержат код условия, установленный последней выполненной командой. Другие биты показывают текущее состояние микропроцессора.
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
X
|
X
|
X
|
X
|
OF
|
DF
|
IF
|
TF
|
SF
|
ZF
|
X
|
AF
|
X
|
PF
|
X
|
CF
|
Биты регистра флагов имеют следующее назначение:
OF (признак переполнения) – равен 1, если возникает арифметическое переполнение, то есть когда объем результата превышает размер ячейки назначения;
DF (признак направления) – устанавливается в 1 для автоматического декремента в командах обработки строк, и в 0 – для инкремента;
IF (признак разрешения прерывания) – прерывания разрешены, если IF=1. Если IF=0, то распознаются лишь немаскированные прерывания;
TF (признаков трассировки) - если TF=1, то процессор переходит в состояние прерывания INT 3 после выполнения каждой команды;
SF (признак знака) – SF=1, когда старший бит результата равен 1. Иными словами, SF=0 для положительных чисел, и SF=1 для отрицательных чисел;
ZF (признак нулевого результата) – ZF=1, если результат равен нулю;
AF (признак дополнительного переноса) – этот флаг устанавливается в 1 во время выполнения команд десятичного сложения и вычитания при возникновении переноса или заема между полубайтами;
PF (признак четности) – этот признак устанавливается в 1, если результат имеет четное число единиц;
CF (признак переноса) – этот флаг устанавливается в 1, если имеет место перенос или заем из старшего бита результата; он полезен для произведения операций над числами длиной в несколько слов, которые сопряжены с переносами и заемами из слова в слово;
X – зарезервированные биты.
Легко заметить, что все флаги младшего байта регистра флагов устанавливаются арифметическими или логическими операциями процессора. За исключением флага переполнения, все флаги старшего байта отражают состояние микропроцессора и влияют на характер выполнения программы. Флаги старшего байта устанавливаются и сбрасываются специально предназначенными для этого командами. Флаги младшего байта являются кодами условного перехода для изменения порядка выполнения программы.
1.2. Сегменты, принцип сегментации
Числа, устанавливаемые процессором на адресной шине, являются адресами, то есть номерами ячеек оперативной памяти (ОП). Размер ячейки ОП составляет 8 разрядов, т.е. 1 байт. Поскольку для адресации памяти процессор использует 16-разрядные адресные регистры, то это обеспечивает ему доступ к 65536 (FFFFh) байт или 64К (1К = 1024 байт = 210 байт) основной памяти. Такой блок непосредственно адресуемой памяти называется сегментом. Любой адрес формируется из адреса сегмента (всегда кратен 16, т.е. начинается с границы параграфа) и адреса ячейки внутри сегмента (этот адрес называется смещением). Для адресации большего объема памяти в процессоре 8086 используется специальная процедура пересчета адресов, называемая вычислением абсолютного (эффективного) адреса.
Когда процессор выбирает очередную команду на исполнение, в качестве ее адреса используется содержимое, регистра IP. Этот адрес называется исполнительным. Поскольку регистр IP шестнадцатиразрядный, исполнительный адрес тоже содержит 16 двоичных разрядов. Однако адресная шина, соединяющая процессор и память имеет 20 линий связи.
Чтобы получить 20-битовый адрес, дополнительные 4 бита адресной информации извлекаются из сегментных регистров. Сами сегментные регистры имеют размер в 16 разрядов, а содержащиеся в этих регистрах (CS, DS, SS или ES) 16-битовые значения называются базовым адресом сегмента. Микропроцессор объединяет 16-битовый исполнительный адрес и 16-битовый базовый адрес следующим образом: он расширяет содержимое сегментного регистра (базовый адрес) 4 нулевыми битами (в младших разрядах), делая его 20-битовым (полный адрес сегмента) и прибавляет смещение (исполнительный адрес). При этом 20-битовый результат является физическим или абсолютным адресом ячейки памяти (рис. 1.2).
Существуют три основных типа сегментов:
сегмент кода – содержит машинные команды, Адресуется регистром CS;
сегмент данных – содержит данные, то есть константы и рабочие области, необходимые программе. Адресуется регистром DS;
сегмент стека – содержит адреса возврата в точку вызова подпрограмм. Адресуется регистром SS.
При записи команд на языке Ассемблера принято указывать адреса с помощью следующей конструкции:
<�адрес сегмента>:<�смещение>
или
<�сегментный регистр>:<�адресное выражение>
1.3. Стек
Во многих случаях программе требуется временно запомнить некоторую информацию. Эта проблема в персональном компьютере решена посредством реализации стека LIFO ("последний пришел - первый ушел"), называемого также стеком включения/извлечения (stack). Стек – это область памяти для временного хранения данных, в которую по специальным командам можно записывать отдельные слова (но не байты); при этом для запоминания данных достаточно выполнить лишь одну команду и не нужно беспокоиться о выборе соответствующего адреса: процессор автоматически выделяет для них свободное место в области временного хранения. Наиболее важное использование стека связано с подпрограммами, в этом случае стек содержит адрес возврата из подпрограммы, а иногда и передаваемые в/из подпрограмму данные. Стек обычно рассчитан на косвенную адресацию через регистр указатель стека. При включении элементов в стек производится автоматический декремент указателя стека, а при извлечении – инкремент, то есть стек всегда «растет» в сторону меньших адресов памяти. Адрес последнего включенного в стек элемента называется вершиной стека (TOS), а адрес сегмента стека – базой стека.
1.4. Прерывания
Часто возникают ситуации, когда необходимо выполнить одну из набора специальных процедур, если в системе или в программе возникают определенные условия, например, нажата клавиша на клавиатуре или произошло деление на ноль. Действие, стимулирующее выполнение одной из таких процедур, называется прерыванием, поскольку основной процесс при этом приостанавливается на время выполнения этой процедуры. Существует два общих класса прерываний: внутренние и внешние. Первые инициируются состоянием ЦП или командой, а вторые – сигналом, подаваемым от других компонентов системы. Типичные внутренние прерывания: деление на нуль, переполнение и т.п., а типичные внешние – это запрос на обслуживание со стороны какого-либо устройства ввода/вывода.
Переход к процедуре прерывания осуществляется из любой программы, а после выполнения процедуры прерывания обязательно происходит возврат в прерванную программу. Перед обращением к процедуре прерывания должно быть сохранено состояние всех регистров и флагов, используемых процедурой прерывания, после окончания прерывания эти регистры должны быть восстановлены.
Некоторыми видами прерываний управляют флаги IF и TF, которые для восприятия прерываний должны быть правильно установлены. Если условия для прерывания удовлетворяются и необходимые флаги установлены, то микропроцессор завершает текущую команду, а затем реализует последовательность прерывания:
текущее значение регистра флагов включается в стек;
текущее значение кодового сегмента включается в стек;
текущее значение счетчика команд включается в стек;
сбрасываются флаги IF и TF.
Новое содержимое счетчика команд и сегмента кода определяют начальный адрес первой команды процедуры прерывания (обслуживания прерывания). Возврат в прерванную программу осуществляется командой, которая извлекает из стека содержимое для:
указателя стека;
сегмента кода;
регистра флагов.
Двойное слово, в котором находится новое содержимое счетчика команд и сегмента кода, называется указателем прерывания, или вектором прерывания. Каждому типу прерывания назначено число из диапазона 0...255, и адрес вектора прерывания находится путем умножения номера типа на четыре (размер вектора прерывания). Таким образом, все вектора прерываний образуют таблицу векторов прерываний, которая содержится в памяти по адресу 0000h:0000h и инициализируется при загрузке компьютера.
1.5. Режимы адресации
В зависимости от спецификаций и местоположения источников образования полного (абсолютного) адреса в языке ассемблера различают следующие способы адресации операндов:
регистровая;
прямая;
непосредственная;
косвенная;
базовая;
индексная;
базово-индексная.
Регистровая адресация подразумевает использование в качестве операнда регистра процессора, например:
PUSH DS
MOV BP,SP
При прямой адресации один операнд представляет собой адрес памяти, второй – регистр:
MOV Data,AX
Непосредственная адресация применяется, когда операнд, длинной в байт или слово находится в ассемблерной команде:
MOV AH,4CH
При использовании косвенной адресации абсолютный адрес формируется исходя из сегментного адреса в одном из сегментных регистров и смещения в регистрах BX, BP, SI или DI:
MOV AL,[BX] ;База – в DS, смещение – в BX
MOV AX,[BP] ;База – в SS, смещение – в BP
MOV AX,ES:[SI] ;База – в ES, смещение – в SI
В случае применения базовой адресации исполнительный адрес является суммой значения смещения и содержимого регистра BP или BX, например:
MOV AX,[BP+6] ;База – SS, смещение – BP+6
MOV DX,8[BX] ;База – DS, смещение – BX+8
При индексной адресации исполнительный адрес определяется как сумма значения указанного смещения и содержимого регистра SI или DI так же, как и при базовой адресации, например:
MOV DX,[SI+5] ;База – DS, смещение – SI+5
Базово-индексная адресация подразумевает использование для вычисления исполнительного адреса суммы содержимого базового регистра и индексного регистра, а также смещения, находящегося в операторе, например:
MOV BX,[BP][SI] ;База – SS, смещение – BP+SI
MOV ES:[BX+DI],AX ;База – ES, смещение – BX+DI
MOV AX,[BP+6+DI] ;База – SS, смещение - BP+6+DI
2. Загрузка и выполнение программ в DOS
При загрузке программ в оперативную память DOS (дисковая операционная система) инициализирует как минимум три сегментных регистра: CS, DS и SS. При этом совокупности байтов, представляющих команды процессора (код программы), и данные помещаются из файла на диске в оперативную память, а адреса этих сегментов записываются в CS и DS соответственно. Сегмент стека либо выделяется в области, указанной в программе, либо совпадает (если он явно в программе не описан) с самым первым сегментом программы. Адрес сегмента стека помещается в регистр SS. Программа может иметь несколько кодовых сегментов и сегментов данных и в процессе выполнения специальными командами выполнять переключения между ними.
Для того чтобы адресовать одновременно два сегмента данных, например, при выполнении операции пересылки из одной области памяти в другую, можно использовать регистр дополнительного сегмента ES. Кодовый сегмент и сегмент стека всегда определяются содержимым своих регистров (CS и SS), и поэтому в каждый момент выполнения программы всегда используется какой-то один кодовый сегмент и один сегмент стека. Причем если переключение кодового сегмента – довольно простая операция, то переключать сегмент стека можно только при условии четкого представления логики работы программы со стеком, иначе это может привести к зависанию системы.
Все сегменты могут использовать различные области памяти, а могут частично или полностью перекрываться (Рис. 2.1).
Кодовый сегмент должен обязательно описываться в программе, все остальные сегменты могут отсутствовать. В этом случае DOS при загрузке программы в оперативную память инициирует регистры DS и ES значением адреса префикса программного сегмента PSP (Program Segment Prefics) – специальной области оперативной памяти размером 256 (100h) байт. PSP может использоваться в программе для определения имен файлов и параметров из командной строки, введенной при запуске программы на выполнение, объема доступной памяти, переменных окружения системы и т.д. Регистр SS при этом инициализируется значением сегмента, находящегося сразу за PSP, т.е. первого сегмента программы. При этом необходимо учитывать, что стек «растет вниз» (при помещении в стек содержимое регистра SP, указывающего на вершину стека, уменьшается, а при считывании из стека – увеличивается). Таким образом, при помещении в стек каких-либо значений они могут затереть PSP и программы, находящиеся в младших адресах памяти, что может привести к непредсказуемым последствиям. Поэтому рекомендуется всегда явно описывать сегмент стека в тексте программы, задавая ему размер, достаточный для нормальной работы.
Рассмотрим распределение памяти на примере простейшей программы.
;Данные программы
DATA SEGMENT
MSG DB ‘Текст$’
DATA ENDS
;Код программы
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AH,09H ;Вывод сообщения
MOV DX,OFFSET MSG
INT 21H
MOV AH,4CH ;Завершение работы
INT 21H
CODE ENDS
END START
В этой программе явно описаны два сегмента – кода с именем CODE и данных с именем DATA. Директива ASSUME связывает имена этих сегментов, которые в общем случае могут быть произвольными, с сегментными регистрами CS и DS соответственно. Распределение памяти при загрузке программы на исполнение показано на рис. 2.2.
Как видно из рисунка, сегмент стека в данном случае установлен на PSP, что при его интенсивном использовании может привести к неожиданным результатам. После инициализации в регистре IP находится смещение первой команды программы относительно начала кодового сегмента, адрес которого помещен в регистр CS. Процессор, считывая эту команду, начинает выполнение программы, постоянно изменяя содержимое регистра IP и при необходимости CS для получения кодов очередных команд до тех пор, пока не встретит команду завершения программы. DS после загрузки программы установлен на начало PSP, поэтому для его использования в первых двух командах программы выполняется загрузка DS значением сегмента данных.
|