Небольшая программа на языке ассемблера
Переходя от теории к практике, рассмотрим короткую программу на языке ассемблера и вывод ее текста в интерпретаторе. На рис. В.1, а представлена программа на языке ассемблера 8088. Числа, следующие за восклицательными знаками, обозначают номера строк; они введены с единственной целью — упростить построчный анализ программы. Текст этой программы также размещен на сопроводительном компакт-диске (файл HlloWrld.s) в папке examples. Расширение этой программы (s), как и всех других, к которым мы будем обращаться, указывает на то, что она написана на языке ассемблера и не преобразована в двоичную форму. В окне трассера, показанном на рис. В.1, б, располагаются семь дочерних окон. В каждом из них указываются те или иные сведения о состоянии исполняемой двоичной программы.
Рис. В.1. Исходный текст программы на языке ассемблера (а); окно трассера с информацией о ходе выполнения программы (б)
Теперь вкратце рассмотрим содержимое семи дочерних окон, изображенных на рис. В.1, б. В верхнем ряду расположены три окна — два больших и одно поменьше. В верхнем левом окне показано содержимое процессора, а именно — текущие значения сегментных (CS, DS, SS и ES), арифметических (АН, AL, АХ) и других регистров.
В среднем окне в верхнем ряду указывается содержимое стека — области памяти, предназначенной для хранения временных значений.
В верхнем правом окне выводится фрагмент программы на языке ассемблера; стрелка указывает на команду, которая выполняется в данный момент. По мере выполнения программы эта стрелка, естественно, перемещается от одной команды к другой. Интерпретатор может работать в таком режиме, при котором однократное нажатие клавиши Enter приводит к выполнению одной команды и соответствующему обновлению всех окон. Таким образом, программу, написанную на языке ассемблера, в среде симулятора можно выполнять с той скоростью, которая позволяет разобраться в происходящем.
Окно, находящееся под верхним левым окном, определяет содержимое стека вызова подпрограмм, который в данном случае пуст. Ниже размещаются собственные команды трассера. Окно, расположенное справа от этих двух окон, предназначено для входных и выходных сообщений, а также сообщений об ошибках. В самом нижнем окне выводится содержимое части памяти.
Подробно обо всех этих окнах мы поговорим позже, а на данный момент важно получить общее представление о том, какие сведения трассер позволяет увидеть пользователю: исходный текст программы, содержимое регистров машины, информацию о состоянии исполняемой программы. При запуске каждой последующей команды содержимое окна интерпретатора обновляется, поэтому программист может разобраться в процессе настолько подробно, насколько он захочет.
Процессор 8088
Любой процессор, в том числе и у 8088, обладает своим внутреннем состоянием, под которым понимается та или иная критически важная информация. Для хранения и обработки этой информации в процессоре предусмотрен особый набор регистров. Наиболее важным из них является регистр PC (Program Counter — счетчик команд). В нем указывается ячейка памяти (адрес), в которой хранится следующая в порядке выполнения команда. Другое обозначение этого регистра — IP (Instruction Pointer — указатель команд). Та часть основной памяти, в которой хранится следующая команда в порядке выполнения, называется кодовым сегментом. Допустимая емкость основной памяти, которую поддерживает процессор 8088, составляет чуть более 1 Мбайт, однако размер кодового сегмента ограничен значением 64 Кбайт. Начало этого сегмента в рамках памяти емкостью 1 Мбайт определяется в регистре CS (см. рис. В.1). Чтобы активировать новый кодовый сегмент, достаточно изменить значение регистра CS. Помимо кодового сегмента, существует сегмент данных, также занимающий 64 Кбайт и определяющий начало данных. На рис. В.1 начало данных определяется регистром DS, содержание которого можно при необходимости изменить и тем самым получить доступ к данным, находящимся за пределами текущего сегмента. Потребность в регистрах CS и DS обусловлена тем, что разрядность регистров 8088 составляет 16 бит, а, значит, хранить в них 20-разрядные адреса, необходимые для обращения к памяти емкостью 1 Мбайт, невозможно. Вот почему появились кодовый сегмент и сегмент данных.