Программы пользователя выполняются на компьютере под управлением системного программного обеспечения, реализованного в виде операционной системы (ОС). ОС выполняет достаточно много функций, из которых наиболее важными для системного программиста являются:
1) управление файлами. ОС поддерживает структуру файлов и папок (файловая система) на дисках компьютера. Это физический уровень хранения информации. Прикладные программы создают, изменяют информацию в файлах, но ОС управляет их размещением в дисковой памяти;
2) ввод/вывод информации. Прикладные программы запрашивают ввод исходных данных у системы и предоставляют результаты обработки системе с помощью прерываний. Низкоуровневые операции ввода/вывода (канальные программы) ОС выполняет без вмешательства программиста;
3) загрузка программ. Когда пользователь или прикладная программа запрашивают выполнение другой программы, загрузчик (ОС) выполняет последовательность шагов, описываемую ниже, для получения доступа к программе на диске, размещения ее в оперативной памяти и начала выполнения;
4) управление памятью. Когда загрузчик размещает программу в оперативной памяти, он выделяет достаточный объем памяти для кода программы и ее данных. Программы могут обрабатывать данные в первоначально зарезервированной области, могут освобождать ненужную память или запрашивать дополнительную память. Конкретные физические адреса оперативной памяти определяются ОС без вмешательства программиста;
5) обработка прерываний. ОС позволяет прикладным программам получать доступ к внешним устройствам посредством прерываний – специальных команд, включаемых в прикладную программу.
Теперь подробнее о загрузке программ. Включение питания компьютера приводит к переходу процессора в состояние запуска, очистке памяти (записи нулей в ячейки ОЗУ), проверки четности памяти (фактически минимальная адресуемая единица памяти – байт – содержит не 8, а 9 битов; дополнительный бит является битом четности и принимает такое состояние, чтобы в 9 битах было четное количество двоичных единиц). Кроме того процессор загружает в регистр CS значение FFFF[0]H, и смещение 0 в регистр IP, настраивая компьютер на выполнение программы BIOS, находящейся в ПЗУ по адресу FFFF0H. Эта часть BIOS содержит набор процедур, которые проверяют разные части компьютера , чтобы опознать и инициализировать устройства, присоединенные к нему. После этого BIOS создает 2 области данных:
1) таблицу векторов прерываний, начинающуюся с 0 абсолютного адреса ОЗУ и содержащую 256 4-байтовых адреса программ обработки прерываний (более подробно этот вопрос рассматривается в теме “команды прерывания”);
2) область данных BIOS, начинающуюся с адреса 40[0]Н. В этой области отображается состояние присоединенных к компьютеру устройств.
После создания областей данных, BIOS определяет, доступен ли диск, на котором содержится ОС, и вызывает начальный загрузчик с диска. Начальный загрузчик загружает и передает управление системным файлам. Системные файлы содержат драйвера устройств и другие коды для работы с аппаратурой. При их выполнении инициализируются внутренние системные таблицы и системная часть векторов прерываний.
При выполнении команды прерывания в прикладной программе возможны 2 основных сценария реализации прерывания:
1) прикладная программа обращается к ОС, которая после анализа команды обращается к BIOS, а уже BIOS непосредственно работает с аппаратурой;
2) прикладная программа обращается в BIOS напрямую (например, при работе с дисплеем или клавиатурой).
Существует конечно и вариант прямого обращения прикладной программы к устройству. Но для его реализации нужен опыт как программирования, так и работы с аппаратурой.
Отработав, системные файлы приводят компьютер в состояние ожидания запросов пользователя. Одним из таких запросов является выполнение прикладной программы. Существуют 2 типа исполняемых файлов – СОМ и ЕХЕ. Программы типа СОМ состоят из единственного сегмента, содержащего код, данные и стек. Такие программы создаются для утилит или резидентных программ (программ, остающихся в оперативной памяти при выполнении других программ). На таких программах мы останавливаться не будем. Прикладные программы пользователя, как правило, хранятся в виде ЕХЕ-файлов. Они состоят из отдельных сегментов кода, данных и стека. При вызове на выполнение ЕХЕ-программы загрузчик выполняет следующие шаги:
1) находит программу на диске;
2) создает 256-байтовый (100Н) префикс сегмента программы (PSP) в доступной оперативной памяти на границе параграфа ( с начального адреса, кратного 16);
3) загружает программу в память, непосредственно после PSP;
4) загружает адрес PSP в регистры DS и ES;
5) загружает адрес сегмента кода в регистр CS и устанавливает регистр IP в 0 (это состояние соответствует первой инструкции программы, подлежащей выполнению);
6) загружает адрес стека в регистр SS и записывает в регистр SP значение, равное размеру стека;
7) передает управление исполняемой программе, конкретно по адресу CS:IP (адрес записан в виде сегмент:смещение).
Из вышеописанного следует, что загрузчик инициализирует сегментные регистры стека и кода автоматически. Но заметьте, что адрес PSP загрузчик сохраняет в регистрах DS и ES, однако для выполнения программы требуется наличие в этих регистрах адреса данных. В теме “режимы адресации” подробно описываются команды принудительной загрузки сегментного регистра данных.
Поясним вопросы адресации инструкций (команд программы) и данных на примерах.
Пусть программа на ассемблере содержит нижеприведенные команды, причем команды эти записаны в самом начале программы.
Смещение команды
Команда
Комментарий
PUSH DS
поместить в стек номер блока адреса возврата
MOV AX,0
обнулить регистр АХ
PUSH AX
поместить в стек значение адреса возврата=0
MOV AX,DSEG
инициировать адрес сегмента данных
MOV DS,AX
Пусть после загрузки регистр кода CS инициализирован значением 05ВЕ[0]Н.
Пусть сегмент данных содержит нижеприведенные переменные, первая из которых записана в самом начале сегмента.
Смещение переменной
Идентификатор (имя) переменной
Описание переменной
Комментарий
CHAR
DB ?
Неинициализированный байт
SOURCE
DB 10,20,30
Вектор десятичных значений
DEST
DW 3 DUP(?)
Зарезервированные слова
000А
MESS
DB ‘Name? ,$’
Текст запроса
REZ
DD ?
Зарезервированное двойное слово
Если Вы будете просматривать дамп памяти с такой информацией, то увидите примерно такую картину:
0000 00 0А 14 1Е 00 00 00 00 ________
0008 00 00 4Е 61 4D 45 3F 20 __Name?
0010 00 00 00 00 ____
(Цветное выделение сделано мною для пояснений!)
Здесь голубым цветом выделены поля значений смещения, розовым цветом – поля значений переменных и зарезервированных слов или байтов в шестнадцатеричном виде, зеленым цветом – те же поля переменных, но в символьном виде (Числовые значения, такие как 20 десятичное, равное 14 шестнадцатеричному, в символьном виде либо отображаются нечисловыми и небуквенными символами, либо не отображаются вовсе. Я эти символы заменила в примере подчеркиванием _).
Из приведенного примера очевидно, что память для переменных выделяется в соответствии с их описанием в сегменте данных: в том порядке, как они описываются, и столько байтов, каков размер переменных. В машинных командах программы ассемблер будет заменять имена переменных их смещениями относительно начала сегмента кодов, так, в команде
LEA DX,MESS имя переменной MESS будет заменено значением 000А.
Если регистр данных DS инициализирован значением 0СС2[0], то физический адрес переменной MESS будет равен: 0СС20+0000А=0СС2А.
Вопросы для самопроверки
1. Укажите длину следующих элементов данных: а) параграфа, б) слова, в) сегмента, г) байта, д) двойного слова, е) килобайта.
2. Какова самая малая единица памяти компьютера и какие значения она может принимать?
3. Поясните следующие термины: сегмент, смещение, граница адреса сегмента.
4. Определите абсолютные адреса, формируемые следующими значениями: SS=2AB4, CS=2BC3, IP=3F, SP=24. Все значения адресов указаны в шестнадцатеричной системе счисления.
5. Опишите сегмент данных и в нем переменные для трех целочисленных сторон треугольника. Предусмотрите текст запроса для ввода сторон с клавиатуры, а также сообщение о том, что введенные стороны не могут быть сторонами треугольника.
6. Укажите различия между компилятором и ассемблером.
7. Что такое зарезервированное слово в Ассемблере? Приведите примеры.
8. Какие два типа идентификаторов есть в ассемблере?
9. Из приведенных идентификаторов переменных, определенных в сегменте данных, найдите неверные и поясните характер ошибки: а)$50, б)AT&T, в)@$_A, г)23АС, д)DX, е)MOV.
10. Формат директива SEGMENT таков:
имя SEGMENT выравнивание совмещение ‘класс’.
Объясните назначение параметров а) выравнивание, б)совмещение, в)‘класс’.
11. Какие предложения относятся к концу а)процедуры, б)сегмента, в)программы?
12. Укажите предложение ASSUME, если имена сегментов стека, данных и кода соответственно – STKSEG, DATSEG, CODSEG?
13. Укажите длины в байтах для переменных, описанных в сегменте кода директивами а)DD, б)DW, в)DB.
14. Опишите символьную строку с именем IS и текстом “Internet service”.
15. Определите следующие числовые значения в элементах данных ITEM1, ITEM2,…ITEM5:
16. Покажите, какой шестнадцатеричный объектный код соответствует а)DB 82, б) DB ‘82’, в)DB 4DUP(‘5’).
17. Определите шестнадцатеричный объектный код, сохраняемый ассемблером для а)DB 72, б)DW 2ABE, в)DD 1EB6C3. . Все значения переменных указаны в шестнадцатеричной системе счисления.