Вывод на экран символов
Назад | Оглавление | Дальше Новая версия документа | Форум

Знакомство с прерываниями
Выход из программы
Ввод программы
Команда MOV
Запись программы на диск
Вывод на экран строки символов
Редактирование строк

Как уже отмечалось ранее, микропроцессор оперирует двоичными числами. Но на экране компьютера мы видим привычные символы: цифры, буквы и знаки. Данная тема раскроет секреты вывода на экран отдельных символов и строк.


Знакомство с прерываниями

Множество полезных операции на ассемблере выполняется с помощью инструкции INT (Interrupt - прерывание). Печать символов и строк выполняется прерыванием "INT 21h". Например, требуется вывести на экран символ "A":

  1. В регистр AH занесите функцию 02h (вывод символа): AX = 0200h
  2. В регистр DL занесите ASCII код символа "A": DX = 0041h
  3. Коды [CDh, 21h] инструкции INT 21h занесите в память по адресам: 100h и 101h
  4. Установите регистр IP = 100h
  5. Просмотрите регистры и убедитесь, что инструкция записана верно: "INT 21h"

Прерывание INT 21h выполняет функцию, заданную в регистре AH. Подпрограмма функции содержит значительное количество инструкций, поэтому трассировка прерывания может завести нас очень далеко. Для выполнения прерывания используем команду "G" (Go), которая выполняет все инструкции подряд. Адрес остановки (т.е. адрес инструкции, следующей за INT 21h) мы укажем непосредственно в команде G:

-g 102
A
AX=0241  BX=0000  CX=0000  DX=0041  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0ABD  ES=0ABD  SS=0ABD  CS=0ABD  IP=0102   NV UP EI PL NZ NA PO NC
0ABD:0102 96            XCHG    SI,AX

Операционная система вывела букву "A" и передала управление Debug. По причинам рассмотренным ранее, последняя строка вашего листинга будет выглядеть иначе.

Используя инструкцию INT 21h, выведите следующие символы на экран:

Z, F, Я, Ю, @, *, #, 9, ^.Таблица ASCII кодов

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


Выход из программы

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

Введите коды [CDh, 20h] по адресам 100h и 101h. Проверьте наличие инструкции INT 20h командой "R", и выполните прерывание командой "G":

-g
Program terminated normally

Прерывание INT 20h сообщает об успешном выполнении программы, и передает управление Debug. Кроме того, INT 20h восстанавливает содержимое всех регистров к виду, в котором они были до запуска программы. То есть, после выполнения INT 20h регистр IP вернется в исходное состояние: IP = 100h.

Инструкцию INT 20h логично добавлять в конец каждой программы. Например, объединим INT 21h и INT 20h в одну программу, которая будет печатать заданный символ на экран:

  1. По адресам 100h и 101h введите коды инструкции INT 21h [CDh, 21h].
  2. По адресам 102h и 103h введите коды инструкции INT 20h [CDh, 20h].

Ранее, выполняемую инструкцию мы просматривали в листинге регистров. Для просмотра сразу двух инструкций мы используем команду "U" (Unassemble) - дизассемблирование:

-u 100
0ABD:0100 CD21          INT     21
0ABD:0102 CD20          INT     20
0ABD:0104 42            INC     DX
0ABD:0105 007538        ADD     [DI+38],DH
0ABD:0108 8E062850      MOV     ES,[5028]
0ABD:010C 26            ES:
0ABD:010D 8B1E7200      MOV     BX,[0072]
0ABD:0111 1E            PUSH    DS
0ABD:0112 FFB7FE05      PUSH    [BX+05FE]
0ABD:0116 8D840B01      LEA     AX,[SI+010B]
0ABD:011A 1E            PUSH    DS
0ABD:011B 50            PUSH    AX
0ABD:011C 3400          XOR     AL,00
0ABD:011E AC            LODSB
0ABD:011F 0A29          OR      CH,[BX+DI]

Курсивом помечены инструкции, оставшиеся от программ или данных, отработавших до запуска Debug. С увеличением сложности примеров, размер дизассемблированного листинга также будет увеличиваться.

Занесите в регистр AH функцию 02h, а в регистр DL код символа "#". Запустите программу:
-g
#
Program terminated normally
Проверьте работу программы с другими символами. Таблица ASCII кодов


Ввод программы

До сих пор мы вводили коды инструкций, например: [CDh, 21h]. Но это очень неудобно. В Debug имеется команда "A" (Assemble), позволяющая вводить мнемокоды инструкций:

-a 100
0ABD:0100	INT 21
0ABD:0102	INT 20
0ABD:0104	<Enter>

Параметр 100 означает, что ввод инструкций начнется с адреса 100h.


Команда MOV

Команда "R" позволяет изменять значения регистров до и после запуска программы. В ходе программы, число в регистр можно загрузить командой MOV. Например, загрузим функцию печати числа в регистр AH следующим образом:

-a 100
0ABD:0100	MOV AH,02
0ABD:0102	<Enter>
Проверьте наличие команды в листинге регистров:
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0ABD  ES=0ABD  SS=0ABD  CS=0ABD  IP=0100   NV UP EI PL NZ NA PO NC
0ABD:0100 B402          MOV     AH,02

В исходном состоянии AX = 0000. Выполните трассировку, и вновь просмотрите регистры. Теперь AX = 0200 (AH = 02h).

Команда MOV позволяет копировать числа из регистра в регистр. Например, скопируем число из регистра BX в регистр AX:

-a 100
0ABD:0100	MOV AX,BX
0ABD:0102	<Enter>

Загрузите в регистры числа: AX = FF00, BX = 00EE. Выполните трассировку команды. После просмотра регистров вы увидите, что AX = 00EE. Содержимое регистра BX не изменилось.

Следующая программа демонстрирует возможности команды MOV:
-a 100
0ABD:0100	MOV AX,FEFE
0ABD:0102	MOV BX,AX
0ABD:0104	MOV CX,BX
0ABD:0106	MOV DX,CX
Выполните трассировку, анализируя каждый шаг программы.

Команда MOV имеет два ограничения:
  • нельзя загружать в байтовые регистры слово: MOV AH,FE4B
  • нельзя передавать числа между регистрами разного типа: MOV DL,BX

Используем команду MOV, для модернизации программы вывода символа на экран:

-a 100
0ABD:0100	MOV AH,02
0ABD:0102	MOV DL,2A
0ABD:0104	INT 21
0ABD:0106	INT 20

Программа будет печатать символ "*" (ASCII код 2Ah). Используйте команду "U 100" для проверки введенных инструкций. Убедитесь, что регистр IP = 100h. Выполните программу:

-g
*
Program terminated normally

Запись программы на диск

В предыдущем разделе была рассмотрена программа вывода на экран символа "*". Чтобы записать эту программу на диск, следует выполнить три действия:

  1. присвоить программе имя;
  2. указать длину программы;
  3. выполнить запись.

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

Используя команду "N" (Name), присвойте будущему файлу имя:
-n star.com

Программа состоит из четырех двухбайтных инструкций, значит ее длина - 8 байт. Размер программы Debug хранит в регистровой паре [BX:CX]. Регистровая пара позволяет хранить числа размером до FFFFFFFFh. В нашем случае значение длины умещается в одном регистре, поэтому старший регистр пары мы просто обнулим: BX = 0, CX = 8.

Для записи программы на диск используйте команду "W" (Write):
-w
Writing 00008 bytes

Если вы используете FAR, то программа будет записана на диск в текущий каталог. Покиньте Debug и запустите программу Star.com. В приложении FAR, результат выполнения Star.com будет скрыт панелями. Включить/выключить панели FAR можно комбинацией: [Ctrl] + [O].


Вывод на экран строки символов

Как отмечалось ранее, прерывание INT 21h может выполнять несколько различных функций. Мы рассмотрели функцию 02h, которая выводит на экран отдельные символы. Для вывода на экран строк, используется функция 09h. Например, требуется вывести на экран строку:

We are the champions!
Список ASCII кодов для этой строки следующий:
57 65 20 61 72 65 20 74 68 65 20 63 68 61 6D 70 69 6F 6E 73 21 24

В конец строки добавляется символ "$" (ASCII код 24h) - это признак конца строки. Получив этот код, прерывание прекращает чтение строки из памяти.

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

-e 109
0ABD:0109  03.57<пробел> 1F.65<пробел> и т.д.
Проверьте введенные коды командой "D" (Dump - дампирование памяти):
-d 109
0ABD:0100                             57 65 20 61 72 65 20            We are
0ABD:0110  74 68 65 20 63 68 61 6D-70 69 6F 6E 73 21 24 0A   the champions!$.
0ABD:0120  75 12 80 3E 07 96 00 BA-DD 89 75 03 E9 17 01 C6   u..>......u.....
0ABD:0130  06 13 99 01 B8 00 6C BE-FC 97 BB 21 00 33 C9 BA   ......l....!.3..
0ABD:0140  01 01 80 3E 13 99 00 75-03 BA 12 01 CD 21 73 11   ...>...u.....!s.
0ABD:0150  E8 2D DE C7 06 E0 97 FC-97 C6 06 B6 89 01 E9 E5   .-..............
0ABD:0160  00 A3 53 98 C6 06 11 96-01 8B D8 B8 00 44 CD 21   ..S..........D.!
0ABD:0170  88 16 55 98 F6 C2 80 74-33 A0 0D 96 24 0C 75 09   ..U....t3...$.u.
0ABD:0180  A0 18 99 0A 06 14 99 74-19                        .......t.

Фактически, дамп - это листинг памяти, в основной области которого печатаются коды, а с правой стороны выводятся соответствующие им символы. Для наглядности, коды введенной строки выделены жирным шрифтом.

Начиная с адреса 100h, введите в память программу:
-a 100
0ABD:0100 B409          MOV     AH,09
0ABD:0102 BA0901        MOV     DX,0109
0ABD:0105 CD21          INT     21
0ABD:0107 CD20          INT     20
В регистр DX заносится адрес первого символа строки (указатель на строку).

Дизассемблируйте коды программы:
-u 100 11E
0ABD:0100 B409          MOV     AH,09
0ABD:0102 BA0901        MOV     DX,0109
0ABD:0105 CD21          INT     21
0ABD:0107 CD20          INT     20
0ABD:0109 57            PUSH    DI
0ABD:010A 65            DB      65
0ABD:010B 206172        AND     [BX+DI+72],AH
0ABD:010E 65            DB      65
0ABD:010F 207468        AND     [SI+68],DH
0ABD:0112 65            DB      65
0ABD:0113 206368        AND     [BP+DI+68],AH
0ABD:0116 61            DB      61
0ABD:0117 6D            DB      6D
0ABD:0118 7069          JO      0183
0ABD:011A 6F            DB      6F
0ABD:011B 6E            DB      6E
0ABD:011C 7321          JNB     013F
0ABD:011E 240A          AND     AL,0A

По адресам 100h...108h находятся коды программы. Начиная с адреса 109h, идут коды строки. Коду 57h ставится в соответствие инструкция PUSH DI - это интерпретация дизассемблера. В регистре DX хранится указатель на строку символов. Используя указатель, прерывание читает все байты, начиная с адреса 109h до кода 24h, как строку символов.

Установите регистр IP = 100h, и запустите программу:
-g
We are the champions!
Program terminated normally
Программа готова к записи на диск. Присвойте программе имя:
-n champion.com

Определим размер программы. Первый код находится по адресу 100h, а последний (24h) по адресу 11Eh. Значит длина программы равна: 11Eh - 100h + 1h = 1Fh байт. Занесите размер программы в регистровую пару [BX:CX]: BX = 0, CX = 1F. Запишите программу на диск:

-w
Writing 0001F bytes

Покиньте Debug, и проверьте работу программы Champion.com.

Напишите программы, которые выводят на экран следующие строки:
  1. Люк в сеть открыт...
  2. Virus attack!
  3. Работа выполнена,
    пора отдыхать!
В третьем задании для перевода строки используйте коды 0Ah, 0Dh. Таблица ASCII кодов


Редактирование строк

Использовать команду "E", для ввода или редактирования строки, очень неудобно. Быстро отредактировать строку в COM-файле позволяет текстовый редактор, поддерживающий DOS кодировку. Например, в FAR: ставим курсор на файл Champion.com и жмём клавишу [F4]. В результате откроется окно редактора с символьным представлением кодов программы:

┤	║	☺═!═ We are the champions!$

Измените строку "We are the champions!" на любую другую, и сохраните изменения [F2]. При редактировании помните: символы слева от строки являются кодами программы, а знак $ является признаком конца строки. Все остальное можно менять без последствий.


Назад | Оглавление | Дальше Новая версия документа | Форум