Список литературы
Абель П. Ассемблер. Язык и программирование для IBM PC: пер с англ. – К.: Век+, 2005. – 736 с.
Рудольф М. Ассемблер на примерах. Базовый курс – М.: Наука и техника, 2005. – 240 с.
Пильщиков В. Assembler. Программирование на языке Ассемблера IBM PC – М.: Диалог-МИФИ, 2005. – 288 с.
Финогенов К. Г. Основы языка Ассемблера. – М.: Радио и связь, 2000. – 288 с.
Голубь Н.Г. Искусство программирования на Ассемблере Platinum Edition (3 изд.) –М.: Диасофт-ЮП, 2005. – 832 с.
ПРИЛОЖЕНИЕ 1
Программа DEBUG
DOS-программу DEBUG можно применять для написания совсем небольших программ, для отладки программ, или для просмотра содержимого файла либо памяти. Удобнее всего запустить DEBUG в отдельном окне. Пользуясь командами из системного меню окна, можно копировать фрагменты его содержимого в буфер обмена или вставлять текст из буфера в окно.
Для запуска DEBUG из командной строки наберите DEBUG и нажмите . DEBUG загрузится с диска в память. Когда символ-приглашение появится на экране, DEBUG будет готов воспринимать команды (приглашение представляет собой дефис).
DEBUG можно запускать двумя способами:
1. DEBUG без указания аргументов, чтобы просмотреть содержимое памяти или создать новый файл.
2. DEBUG <�имя файла>, чтобы отладить или модифицировать существующую программу.
Загрузчик программ размещает DEBUG в памяти, и DEBUG выводит дефис (–) в качестве приглашения. Регистры CS, DS, ES и SS инициализированы адресом 256-байтового (100Н) префикса сегмента программы (PSP), а рабочая область в памяти начинается с адреса PSP + 100Н. DEBUG отображает значения флагов следующим образом:
-
|
Перепол-нение
OF
|
Направ-ление
F
|
Прерыва-ние
IF
|
Знак
SF
|
Нуль
ZF
|
Вспомог. перенос
AF
|
Четность
PF
|
Перенос
CF
|
1
0
|
OV
NV
|
DN
UP
|
EI
DI
|
NG
PL
|
ZR
NZ
|
AC
NA
|
PE
PO
|
CY
NC
|
Ссылка на память может задаваться в виде сегмент:смещение, например, DS:120, или в виде только смещения, например, 120. Можно также напрямую обращаться к адресам в памяти, например, 40:17, где 40[0]Н – адрес начала сегмента, а 17Н - смещение. Сегмент данных для программ типа .ЕХЕ начинается с адреса DS:0, а для программ типа .СОМ – с DS:100.
DEBUG воспринимает все вводимые числа как шестнадцатеричные, т.е. вводить завершающую букву Н не нужно. Клавиша F1 воспроизводит последнюю команду по одной букве за нажатие, a F3 – целиком. Кроме того, DEBUG не различает строчные и заглавные буквы.
Далее в алфавитном порядке перечислены команды DEBUG.
A (Assemble)
Транслирует ассемблерные команды в машинный код. Операция используется для написания и тестирования маленьких программ на ассемблере и для изучения небольших фрагментов кода. Адрес начала кода по умолчанию – CS:100H. Формат команды: а [адрес], где адрес по умолчанию – 100Н.
DEBUG поддерживает следующие возможности:
определение элементов данных в программах с помощью DB и DW;
операнд в квадратных скобках, например, [12Е], указывает адрес (смещение) в памяти;
оператор PTR можно использовать для указания байта или слова, например, INC BYTE PTR[12E].
Можно применять все виды косвенной адресации с использованием регистров, например, [BP+DI] или 25[ВХ].
Ниже приведен пример создания маленькой ассемблерной программы из пяти инструкций. Вводить нужно только инструкции; DEBUG указывает адрес сегмента кода (показанный здесь в виде хххх:) и смещения, начиная со 100Н:
А (или А 100) ;Начать ввод с адреса
хххх:0100 MOV CX,[10D] ;Прочитать в СХ значение из DS:10D хххх:0104 ADD CX,1A ;Прибавить к содержимому СХ
;непосредственное значение
хххх:0107 MOV [10D],СХ ;Поместить содержимое СХ в DS:10D хххх:010В JMP 100 ;Вернуться к началу программы xxxx:010D DW 2500 ;Определение элемента данных по
;адресу DS:10D
;Завершение ввода
С учетом размера PSP DEBUG устанавливает IP равным 100Н, и инструкции программы начинаются с этого адреса. Последнее нажатие (два подряд) указывает DEBUG, что ввод программы завершен. Теперь можно при необходимости использовать команды U (Unassemble) для просмотра машинного кода или Т (Trace) для наблюдения за выполнением программы.
Можно заменять любые введенные команды или элементы данных, при условии, что новые инструкции или элементы будут иметь ту же длину. Например, чтобы заменить инструкцию ADD, расположенную по адресу 104Н, на SUB, введите
А 104
хххх:0104 SUB CX,1A
При повторном исполнении программы значение в IP будет продолжать увеличиваться. Для занесения в IP значения 100Н используйте команду R (Register). Для выхода используйте команду Q.
С (Compare)
Сравнивает содержимое двух областей памяти. По умолчанию используется регистр DS. В команде можно указывать длину сравниваемых участков или диапазон адресов:
1. С <�начальный_адрес_1> L<�длина> <�начальный_адрес_2>
Пример команды, сравнивающей 20Н байтов, начиная с адреса DS:050, с байтами, начинающимися с DS:200:
С 050 L20 200 ;Сравниваем 20Н байт
2. С <�началъный_адрес_1> <�конечный_адрес_1> <�начальный_адрес_2>
Пример команды, сравнивающей байты от DS:050H до DS:070H с байтами, начиная с DS:200:
С 050 070 200 ;Сравниваем диапазоны
Операция выводит на дисплей адреса и содержимое несовпадающих байтов.
D (Display или Dump)
Выводит на экран содержимое области памяти в шестнадцатеричной и ASCII-формах. Регистр по умолчанию – DS. Эту команду также можно использовать, указывая длину или диапазон:
1. d [<�начальный_адрес> [L<�длина>]]. Можно указывать начальный адрес с необязательной длиной. Длина по умолчанию – 80Н (128) байт. Вот несколько примеров:
D 200 ;Вывести 80Н байт, начиная с адреса DS:200H
D ;Вывести 80Н байт, начиная с адреса конца
;поcледней выведенной области
D CS:150 ;Вывести 80Н байт, начиная с адреса CS:150H
D DS:20 L5 ;Вывести 5 байт, начиная с адреса DS:20H
2. D [началъный_адрес конечный_адрес] .
Пример:
D 300 32С ;Вывести байты, начиная с 300Н, и заканчивая 32СН
Е (Enter)
Позволяет вводить в память данные или инструкции машинного кода. Регистр по умолчанию – DS, формат команды – е <�адрес> [<�список>]. Команда предоставляет две возможности:
1. Заменять байты на указанные в списке, как показано ниже:
Е 105 13 ЗА 21 ;Ввести три байта, начиная с адреса DS:105H
Е CS:211 21 2А ;Ввести два байта, начиная с адреса CS:211H
Е 110 `anything` ;Ввести строку символов, начиная с адреса DS:110H
Использовать для ограничения строк можно как одинарные, так и двойные кавычки.
2. Последовательно редактировать байты. Введите адрес, где расположен байт, который вы хотите просмотреть:
Е 12С ;Просмотреть содержимое байта DS:12CH
Операция будет ожидать ввода с клавиатуры. Введите один или несколько байтов в шестнадцатеричной форме, разделяя их пробелами, начиная с DS:12CH.
F(Fill)
Заполняет область памяти значениями из списка. Регистр по умолчанию -DS. Команду можно использовать как с длиной, так и с диапазоном:
1. F <�начальный_адрес> L<�длина> '<�данные>'.
Например:
F 210 L19 `Help!` ;Используем длину 19Н (25) байт
2. F <�начальный_адрес> <�конечный__адрес> '<�данные>'.
Например:
F 210 229 ‘Help!’ ;Используем диапазон от 210Н до 229Н
Обе команды заполняют ячейки памяти, начиная с адреса DS:210H байтами, содержащими повторения строки “Help!”.
G (Go)
Выполняет отлаженную программу на машинном языке, вплоть до указанной точки останова (breakpoint). Обязательно убедитесь, что IР содержит корректный адрес для исследуемого участка кода (некорректный адрес может привести к непредсказуемым результатам). Кроме того, устанавливайте точки останова только в своих программах, а не в модулях программ операционной системы или BIOS. Программа будет при необходимости вызывать требуемые обработчики прерываний и останавливаться в ожидании, например, ввода с клавиатуры. Регистр по умолчанию – CS. Формат команды:
G [=<�начальный_адрес>] <�адрес_останова> [<�адрес_останова> ...]
Начальный адрес указывать необязательно. Можно указывать до десяти точек останова. Команда G 11А требует выполнить программу, начиная с адреса, заданного в IР, и заканчивая адресом 11АН.
H (Hexadecimal)
Вычисляет сумму и разность двух шестнадцатеричных величин, указанных как н <�значение_1> <�значение_2>. Например, команда Н 14F 22 выведет в качестве результата 171 (сумму) и 12D (разность).
I (Input)
Считывает и выводит на дисплей один байт из порта. Формат команды
I <�адрес_порта>.
L(Load)
Загружает файл или данные из секторов диска в память. Файл можно указать одним из двух способов: указав имя файла в качестве аргумента при запуске DEBUG, или из запущенного DEBUG командой N (Name). Существует два формата команды L.
1. Загрузка уже указанного файла: l [<�адрес>]. Параметр адрес указывает, по какому адресу загрузить в память файл. Если адрес не указан, файл загружается, начиная с адреса CS:100H. Чтобы загрузить файл, не указанный при запуске DEBUG, его необходимо предварительно указать (смотрите команду N):
N <�имя_файла> ;Указать файл .
L ;Загрузить указанный файл, начиная с адреса CS:100H
Чтобы повторно загрузить файл, просто задайте команду L вновь, не указывая адреса. DEBUG вновь считает файл с диска и соответственно проинициализирует регистры.
2. Загрузка данных из секторов диска:
L [<�адрес> [<�диск> <�начало> <�количество>]].
Адрес указывает адрес в памяти, начиная с которого будут размещаться прочитанные данные (по умолчанию это адрес CS: 100).
Диск указывает номер диска (0 – А, 1 – В и т.д.).
Начало указывает шестнадцатеричный номер первого сектора, который нужно прочитать (относительному сектору 0 соответствует цилиндр 1, дорожка 0,сектор 1).
Количество - это шестнадцатеричное число, указывающее, сколько следующих друг за другом секторов нужно прочитать.
Приведенный ниже пример загружает в память, начиная с адреса CS:100, 15Н секторов, начиная с сектора 20Н, с диска А:
L 100 0 20 15
Команда L возвращает в пару регистров ВХ:СХ число прочитанных байтов. Для файла типа .EXE DEBUG игнорирует любой указанный адрес и использует адрес загрузки из ЕХЕ-заголовка. Он также стирает из памяти заголовок; чтобы сохранить его, перед вызовом DEBUG переименуйте файл, присвоив ему другое расширение.
М (Move)
Перемещает (точнее, копирует) содержимое ячеек памяти. По умолчанию используется регистр DS. Команду можно использовать, указывая длину или диапазон.
1. М <�началъный_адрес> L<�длина> <�адрес_назначения>.
Пример:
М DS:50 L100 DS:400 ;Перемещаем фрагмент длиной 100Н байтов
2. М <�начальный_адрес> <�конечный_адрес> <�адрес_назначения>.
Пример:
М DS:50 150 DS:400 ;Перемещаем байты с DS:50H no DS:150H
Обе команды выполняют одни и те же действия – перемещают байты с адресами от DS:050H до DS:150H по адресу DS:400H.
N (Name)
Задает имя программы или файла, которые нужно прочитать с диска или записать на диск. Команда используется как n <�имя_файла>, например
N С:\SAM.COM
Операция сохраняет введенное имя по адресу CS:80H в PSP. Первый байт (по адресу CS:80H) содержит длину (0АН), за ним следует пробел и имя файла. Для чтения файла используется команда L (Load), для записи – W (Write).
О (Output)
Посылает байт в порт, указанный в команде в виде о <�адрес_порта> <�байт>.
Р (Proceed)
Выполняет инструкцию CALL, LOOP, INT или повторяемую строковую инструкцию (с префиксами REPnn), переходя к следующей инструкции. Формат команды P [=<�адрес] [<�значение>], где = адрес –- необязательный адрес начала, а значение – необязательное количество инструкций, которые нужно выполнить. Если адрес не указывается, используется текущий адрес из пары CS:IP, а если не указано значение, выполняется одна инструкция. Например, если нужно выполнить обработчик прерывания INT 10H, введите Р, и он выполнится вплоть до следующей инструкции в вашей программе. Смотрите также команды G и Т.
Q(Quit)
Завершает сеанс работы DEBUG. Операция не сохраняет файлы; для этого необходимо применять команду W.
R (Register)
Выводит на дисплей содержимое регистров и следующую инструкцию. Формат команды r [<�имя_регистра>]. Вот примеры ее использования.
R Вывести значения из всех регистров.
R DX Вывести значение DX; DEBUG предоставит вам возможность нажать , чтобы оставить содержимое регистра неизменным, или ввести от одной до четырех шестнадцатеричных цифр, которые будут записаны в DX.
R IP Вывести значение IP; можно ввести другое значение с клавиатуры.
R F Вывести состояние флагов; в начале этого приложения приведена таблица, содержащая расшифровку сокращений.
S (Search)
Ищет в памяти символы из списка. Если символы найдены, будет выведен их адрес, если нет - операция не выдаст никакого результата. По умолчанию используется регистр DS. Команду можно использовать, указывая длину или диапазон:
1. S <�начальный адрес <�длина> '<�данные>'.
Например:
S 300 L2000 'VIRUS'
Эта команда будет искать строку "VIRUS" в 2000Н байтах, начиная с адреса DS:300H.
2. S <�начальный адрес> <�конечный адрес> '<�данные>'.
Например:
S CS:100 400 51
Эта команда ищет символ с ASCII-кодом 51Н в байтах от CS:100H до CS:400H.
Т (Trace)
Пошагово выполняет программу. Для выполнения обработчиков прерываний INT лучше пользоваться командой Р (Proceed). По умолчанию используется пара регистров CS:IP. Формат команды T [=<�адрес>] [<�значение>]. Необязательный операнд =adpec указывает DEBUG, откуда начинать пошаговое выполнение, а значение – количество команд, которые необходимо выполнить. Если операнды отсутствуют, DEBUG выполняет одну инструкцию и выводит на дисплей значения из регистров. Вот два примера использования этой команды:
Т ;Выполнить одну следующую инструкцию
Т 10 ;Выполнить следующие 10Н (16) инструкций
Команда Т будет пытаться выполнить что угодно, и если по указанному адресу будет находиться непригодный к исполнению код, процессор может войти в состояние останова, после чего придется перезагружать компьютер.
U (Unassemble)
Дизассемблирует машинный код, то есть преобразует его в соответствующие символьные инструкции ассемблера. По умолчанию используются регистры CS:IP, а формат команды следующий:
U [<�начальный_адрес>]
или
U [<начальный_адрес> <�конечный_адрес>]
Указанная область памяти должна содержать корректный машинный код, и команда отобразит его в виде символьных инструкций. Вот три примера:
U 100 ;Дизассемблировать 32 байта, начиная с адреса CS:100
U ;Дизассемблировать 32 байта, начиная с адреса, на
;котором закончилась последняя команда U, если она была
U 100 140 ;Дизассемблировать команды из адресов от СS:100 до CS:140
DEBUG некорректно дизассемблирует некоторые инструкции условных переходов и инструкции, специфичные для процессоров 80286 и последующих, но они все равно выполняются корректно, хотя DEBUG и представляет их как выражения DB.
W (Write)
Записывает файл из DEBUG. Необходимо заранее задать имя файла (командой N), если он не был загружен. По умолчанию используется регистр CS. Формат команды
W [<�адрес> [<�диск> <�начальный_сектор> <�число_секторов>]]
Программы можно записывать только в виде файлов .СОМ. Чтобы изменить программу типа .ЕХЕ, необходимо временно изменить ее расширение. Записывать файлы из DEBUG можно в двух случаях.
1. Прочитав с диска существующую программу, необходимо изменить ее, а затем сохранить. Для этого выполните следующие действия.
• Загрузите программу на машинном языке в память под ее именем: DEBUG <�имя файла>.
• С помощью команд D просмотрите программу, и с помощью команд Е внесите изменения.
• Командой W запишите на диск измененную программу.
2. С помощью DEBUG можно написать маленькую программу в машинных кодах и затем сохранить. Для этого необходимо следующее.
Используя команды A (Assemble) и Е, введите требуемые инструкции.
Введите имя программы командой N <�имя.сом>. Расширение файла обязательно должно быть .СОМ.
Поскольку только вам известна длина всей программы, введите длину в байтах в пару регистров ВХ:СХ.
Рассмотрим такой пример:
хххх:0100 MOV CL,42
хххх:0102 MOV DL,2A
хххх:0104 ADD CL,DL
хххх:0106 JMP 100
Хотя вводятся символьные инструкции, DEBUG преобразует их в машинный код, и именно машинный код будет записан в файл. Поскольку длина последней инструкции, JMP 100, составляет два байта, размер программы равен 8 байтам (от 100Н до 107Н включительно).
С помощью команды R ВХ просмотрите значение в ВХ и введите 0, чтобы очистить его.
Командой R СХ просмотрите содержимое СХ. DEBUG выведет значение СХ на дисплей и запросит новое. Введите размер программы, 8.
Введите команду W , чтобы записать программу на диск.
DEBUG выведет сообщение "Writing 8 bytes." Если указано число 0, возможно, вы некорректно ввели длину программы – попытайтесь еще раз. Внимательно определяйте размер программы, поскольку значение должно быть шестнадцатеричным, и последняя инструкция может быть длиннее одного байта. Размер программы можно определить, вычтя 100Н из смещения, показанного DEBUG после ввода последней команды программы и нажатия . Например, в рассматриваемом примере после инструкции JMP 100 DEBUG выведет адрес хххх:0108. Значит, размер программы равен 108Н - 100Н = 8 байт.
Приложение 2
|