Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
sysprog.docx
Скачиваний:
15
Добавлен:
24.08.2019
Размер:
641.97 Кб
Скачать

Адрес в ds Шест. Знач. Номера байтов

0000 2301 0 и 1

0002 2500 2 и 3

0004 0000 4 и 5

0006 2A2A2A 6, 7 и 8

Вспомним, что шест. символ занимает половину байта, таким oбразом, например, 23 находится в байте 0 (в первом байте) сегмента данных, 01 — в байте 1 (то есть, во втором байте).

Ниже показаны команды машинного языка, которые обрабатывают эти данные:

A10000

Переслать слово (два байта), начинающееся в DS по адресу 0000, в регистр AX.

03060200

Прибавить содержимое слова (двух байт), начинающегося в DS по адресу 0002, к регистру AX.

A30400

Переслать содержимое регистра AX в слово, начинающееся в DS по адресу 0004.

CB

Вернуться в DOS.

Обратите внимание, что здесь имеются две команды MOV с pазличными машинными кодами: A1 и A3. Фактически машинный код зависит от регистров, на которые имеется ссылка, количества байтов (байт или слово), направления передачи данных (из регистра или в регистр) и от ссылки на непосредственные данные или на память.

4

Машинная адресация

Для доступа к машинной команде процессор определяет ее адрес из содержимого регистра CS плюс смещение в регистре IP. Например, предположим, что регистр CS содержит шест.04AF (действительный адрес 04AF0), а регистр IP содержит шест. 0023:

CS: 04AF0 IP: 0023

Адрес команды: 04B13

В случае, если, например, по адресу 04B13 находится команда:

A11200 MOV AX,[0012] | Адрес 04B13

то в памяти по адресу 04B13 содержится первый байт команды.

Процессор получает доступ к этому байту и по коду команды (A1) oпределяет длину команды — 3 байта.

Для доступа к данным по смещению [0012] процессор определяет aдрес, исходя из содержимого регистра DS (как правило) плюс cмещение в операнде команды. В случае, если DS содержит шест.04B1 (реальный адрес 04B10), то результирующий адрес данных определяется cледующим образом:

DS: 04B10

Смещение: 0012

Адрес данных: 04B22

Предположим, что по адресам 04B22 и 04B23 содержатся следующие данные:

Содержимое: 24 01

Адрес: 04B22 04B23

Процессор выбирает значение 24 из ячейки по адресу 04B22 и помещает его в регистр AL, и значение 01 по адресу 04B23 — в регистр AH. Регистр AX будет содержать в результате 0124. В процессе выборки каждого байта команды процессор увеличивает значение регистра IP на единицу, так что к началу выполнения следующей команды в нашем примере IP будет содержать смещение 0026. Таким обpазом процессор теперь готов для выполнения следующей команды, которую он получает по адресу из регистра CS (04AF0) плюс текущее смещение в регистре IP (0026), то есть, 04B16.

Четная адресация

Процессоры действуют более эффективно, eсли в программе обеспечиваются доступ к словам, расположенным по четным адресам.

Процессор может сделать oдну выборку слова по адресу 4B22 для загрузки его непосредственно в регистр. Но если слово начинается на нечетном адресе, процессор выполняет двойную выборку. Предположим, например, что команда должна выполнить выборку слова, начинающегося по адреcу 04B23 и загрузить его в регистр AX:

Содержимое памяти: |хх|24|01|хх|

Адрес: 04B23

Сначала процессор получает доступ к байтам по адресам 4B22 и 4B23 и пересылает байт из ячейки 4B23 в регистр AL.

Затем он получает доступ к байтам по адресам 4B24 и 4B25 и пересылает байт из ячейки 4B23 в регистр AH. В результате регистр AX будет содержать 0124.

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

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

Ассемблер имеет директиву EVEN, которая вызывает выравнивание данных и команд на четные адреса памяти.

4

Определение размера памяти

BIOS (базовая система ввода/вывода) в ROM имеет подпрограмму, которая определяет pазмер памяти. Можно обратиться в BIOS по команде INT по прерыванию 12H. В результате BIOS возвращает в регистр AX размер памяти в килобайтах.

Загрузите в память DEBUG и введите для INT 12H и RET следующие машинные коды:

E CS:100 CD 12 CB

Нажмите R (Enter) для отображения содержимого регистров и первой команды. Регистр IP содержит 0100, при этом высвечивается команда INT 12H.

Теперь нажмите TEnter) несколько раз и просмотрите выполняемые команды BIOS (отладчик показывает мнемокоды, хотя в действительности выполняются машинные коды). В этот момент регистр AX содержит размер памяти в шестнадцатеричном формате. Теперь введите еще раз команду T для выхода из BIOS и возврата в вашу программу. На экране появится команда RET для машинного кода CB, который был введен вами.

4

Специальные средства отладчика

В операционной системе DOS можно использовать DEBUG для ввода команд Ассемблера так же, как и команд машинного языка. На практике можно пользоваться обоими методами.

Команда A

Команда отладчика A (Assemble) переводит DEBUG в режим приема команд Ассемблера и перевода их в машинные коды.

Команда U

Команда отладчика U (Unassemble) показывает машинные коды для команд Ассемблера. Необходимо сообщить отладчику адреса первой и последней команды, которые необходимо просмотреть

Ввод программы обычно используется на языке Ассемблера, когда машинный код неизвестен, а ввод в машинном коде — для изменения программы во время выполнения. Однако в действительности программа DEBUG предназначена для отладки программ.

Сохранение программы из отладчика

Можно использовать DEBUG для сохранения программ на диске в следующих случаях:

1. После загрузки программы в память машины и ее модификации необходимо сохранить измененный вариант. Для этого следует:

u загрузить программу по ее имени: DEBUG n:имя файла [Enter]

u просмотреть программу с помощью команды D и ввести изменения по команде E

u записать измененную программу: W [Enter]

2. Необходимо с помощью DEBUG написать небольшую по объему программу и сохранить ее на диске. Для этого следует:

u вызвать отладчик DEBUG

u с помощью команд A (assemble) и E (enter) написать программу

u присвоить программе имя: N имя файла.COM [Enter].

Тип программы должен быть COM — так как только программист знает, где действительно кончается его программа, указать отладчику длину программы в байтах.

u запросить регистр CX командой: R CX [Enter] — отладчик выдаст на этот запрос CX 0000 (нулевое значение)

u указать длину программы — 6

u записать измененную программу: W [Enter]

В обоих случаях DEBUG выдает сообщение «Writing nnnn bytes» (Запись nnnn байтов). В случае, если nnnn равно 0, то произошла ошибка при вводе длины программы, и необходимо повторить запись cнова.

Важно: Отладчик DOS DEBUG это средство, полезное для отладки ассемблерных программ. Однако следует быть осторожным с ее использованием, особенно для команды E (ввод). Ввод данных в неправильные адреса памяти или ввод некорректных данных могут привести к непредсказуемым результатам.

На экране в этом случае могут появиться «странные» символы, клавиатура заблокирована или даже DOS прервет DEBUG и перезагрузит себя с диска. Какие-либо серьезные повреждения вряд ли произойдут, но возможны некоторые неожиданности, а также потеря данных, которые вводились при работе с отладчиком.

В случае, если данные, введенные в сегмент данных или сегмент кодов, оказались некорректными, следует, вновь используя команду E, исправить их. Однако, можно не заметить ошибки и начать трассиpовку программы. Но и здесь возможно еще использовать команду E для изменений. В случае, если необходимо начать выполнение с первой команды, то следует установить в регистре командного указателя (IP) значение 0100.

 

 

Введите команду R (register) и требуемый регистр в следующем виде:

R IP [Enter]

Отладчик выдаст на экран содержимое регистра IP и перейдет в ожидание ввода. Здесь следует ввести значение 0100 и нажать для проверки результата команду R (без IP). Отладчик выдаст содержимое регистров, флагов и первую выполняемую команду. Теперь можно, используя команду T, вновь выполнить трассировку программы.

В случае, если ваша программа выполняет какие-либо подсчеты, то возможно потребуется очистка некоторых областей памяти и регистров. Но yбедитесь в сохранении содержимого регистров CS, DS, SP и SS, которые имеют специфическое назначение.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Лекция 14. Макросредства

4

Простое макроопределение

Для каждой закодированной команды Ассемблер генерирует одну команду на машинном языке. Но для каждого закодированного оператора компиляторного языка Pascal или C генерируется один или более (чаще много) команд машинного языка. В этом отношении можно считать, что компиляторный язык состоит из макрооператоров.

Ассемблер MASM также имеет макросредства, но макросы здесь определяются программистом. Для этого задается имя макроса, директива MACRO, различные ассемблерные команды, которые должен генерировать данный макрос и для завершения макроопределения — директива MEND. Затем в любом месте программы, где необходимо выполнение определенных в макрокоманде команд, достаточно закодировать имя макроса. В результате Ассемблер сгенерирует необходимые команды.

Использование макрокоманд позволяет:

u упростить и сократить исходный текст программы;

u сделать программу более понятной;

u уменьшить число возможных ошибок кодирования.

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

Макроопределение должно находиться до определения сегмента.

Директива MACRO указывает Ассемблеру, что следующие команды до директивы ENDM являются частью макроопределения.

Директива ENDM завершает макроопределение. Команды между директивами MACRO и ENDM составляют тело макроопределения.

Имена, на которые имеются ссылки в макроопределении должны быть определены где-нибудь в другом месте программы.

Макрокоманда INIT1 может использоваться в кодовом сегменте там, где необходимо инициализировать регистры. Когда Ассемблер анализирует команду INIT1, он сначала просматривает таблицу мнемокодов и, не обнаружив там соответствующего элемента, проверяет макрокоманды. Так как программа содержит определение макрокоманды INIT1 Ассемблер подставляет тело макроопределения, генерируя необходимые команды — макрорасширение.

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

4

Использование параметров в макрокомандах

Формальные параметры в макроопределении указывают Ассемблеру на соответствие их имен любым аналогичным именам в теле макроопределения. Формальные параметры могут иметь любые правильные ассемблерные имена, не обязательно совпадающими именами в сегменте данных.

Формальный параметр может иметь любое правильное ассемблерное имя (включая имя регистра, например, CX), которое в процессе ассемблирования будет заменено на параметр макрокоманды. Отсюда следует, что Ассемблер не распознает регистровые имена и имена, определенные в области данных, как таковые. В одной макрокоманде может быть определено любое число формальных параметров, разделенных запятыми, вплоть до 120 колонки в строке.

 

 

4

Комментарии

Для пояснений назначения макроопределения в нем могут находиться комментарии. Директива COMMENT или символ точка с запятой указывают на строку комментария, как это показано в следующем макроопределении PROMPT:

PROMPT MACRO MESSGE ;Эта макрокоманда выводит сообщения на экран

MOV AH,09H

LEA DX,MESSGE

INT 21H

ENDM

Так как по умолчанию в листинг попадают только команды генерирующие объектный код, то Ассемблер не будет автоматически выдавать и комментарии, имеющиеся в макроопределении.

В случае, если необходимо, чтобы в расширении появлялись комментарии, следует использовать перед макрокомандой директиву .LALL («list all» — выводить все), которая кодируется вместе с лидирующей точкой:

.LALL PROMPT MESSAG1

Макроопределение может содержать несколько комментариев, причем некоторые из них могут выдаваться в листинге, а другие — нет. В первом случае необходимо использовать директиву .LALL. Во втором — кодировать перед комментарием два символа точка с запятой (;;) — признак подавления вывода комментария в листинг.

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

Для этого служит директива .SALL («suppress all» — подавить весь вывод), которая уменьшает размер выводимого листинга, но не оказывает никакого влияния на размер объектного модуля.

Директивы управления листингом .LALL, .XALL, .SALL сохраняют свое действие по всему тексту программы, пока другая директива листинга не изменит его. Эти директивы можно размещать в программе так, чтобы в одних макрокомандах распечатывались комментарии, в других — макрорасширения, а в третьих подавлялся вывод в листинг.

4

Использование макрокоманд в макроопределениях

Макроопределение может содержать ссылку на другое макроопределение.

Рассмотрим простое макроопределение DOS21, которое заносит в регистр AH номер функции DOS и выполняет INT 21H:

DOS21 MACRO DOSFUNC

MOV AH,DOSFUNC

INT 21H

ENDM

Для использования данной макрокоманды при вводе с клавиатуры необходимо закодировать:

LEA DX,NAMEPAR DOS21 0AH

Предположим, что имеется другое макроопределение, использующее функцию 02 в регистре AH для вывода символа:

DISP MACRO CHAR

MOV AH,02

MOV DL,CHAR

INT 21H

ENDM

Для вывода на экран, например, звездочки достаточно закодировать макрокоманду DISP '*'. Можно изменить макроопределение DISP, воспользовавшись макрокомандой DOC21:

DISP MACRO CHAR

MOV DL,CHAR

DOS21 02

ENDM

 

 

Теперь, если закодировать макрокоманду DISP в виде DISP '*', то Ассемблер сгенерирует следующие команды:

MOV DL,'*'

MOV AH,02

INT 21H

4

Директива LOCAL

В некоторых макрокомандах требуется определять элементы данных или метки команд.

При использовании такой макрокоманды в программе более одного раза происходит также неоднократное определение одинаковых полей данных или меток. В результате Ассемблер выдаст сообщения об ошибке из-за дублирования имен.

Для обеспечения уникальности генерируемых в каждом макрорасширении имен используется директива LOCAL, которая кодируется непосредственно после директивы MACRO, даже перед комментариями. Общий формат имеет следующий вид:

LOCAL dummy-1,dummy-2,... ;Формальные параметры

4

Использование библиотек макроопределений

Определение таких макрокоманд, как INIT1 и INIT2 и одноразовое их использование в программе кажется бессмысленным. Лучшим подходом здесь является каталогизация собственных макрокоманд в библиотеке на магнитном диске, используя любое описательное имя, например, MACRO.LIB:

INIT MACRO CSNAME,DSNAME,SSNAME .

.

ENDM PROMPT MACRO MESSGE .

.

ENDM

Теперь для использования любой из каталогизированных макрокоманд вместо MACRO определения в начале программы следует применять директиву INCLUDE:

INCLUDE C:MACRO.LIB .

.

INIT CSEG,DATA,STACK

В этом случае Ассемблер обращается к файлу MACRO.LIB (в нашем примере) на дисководе C и включает в программу оба макроопределения INIT и PROMPT.

Хотя в нашем примере требуется только INIT. Ассемблерный листинг будет содержать копию макроопределения, отмеченного символом C в 30 колонке LST-файла.

Следом за макрокомандой идет ее расширение с объектным кодом и с символом плюс (+) в 31 колонке.

Так как транслятор с Ассемблера является двухпроходовым, то для обеспечения обработки директивы INCLUDE только в первом проходе (а не в обоих) можно использовать следующую конструкцию:

IF1 INCLUDE C:MACRO.LIB ENDIF

IF1 и ENDIF являются условными директивами. Директива IF1 указывает Ассемблеру на необходимость доступа к библиотеке только в первом проходе трансляции.

Директива ENDIF завершает IF-логику. Таким образом, копия макроопределений не появится в листинге — будет сэкономлено и время и память.

Директива очистки

Директива INCLUDE указывает Ассемблеру на включение всех макроопределений из специфицированной библиотеки.

Например, библиотека содержит макросы INIT, PROMPT и DIVIDE, хотя программе требуется только INIT. Директива PURGE позволяет «удалить» нежелательные макросы PROMPT и DIVIDE в текущем ассемблировании:

IF1 INCLUDE MACRO.LIB ;Включить всю библиотеку

ENDIF PURGE PROMRT,DIYIDE ;Удалить ненужные макросы ...

INIT CSEG,DATA,STACK ;Использование оставшейся макрокоманды

 

Директива PURGE действует только в процессе ассемблирования и не оказывает никакого влияния на макрокоманды, находящиеся в библиотеке.

4

Конкатенация (&)

Символ амперсанд (&) указывает Ассемблеру на сцепление (конкатенацию) текста или символов. Следующая макрокоманда MOVE генерирует команду MOVSB или MOVSW:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]