20 уроков Ассемблера - Страница 2
Перевод числа из двоичной системы в десятичную. Возьмём любое двоичное число, например 10,112. Запишем его в развёрнутой форме и произведём вычисления:
10,112 = 1 × 21 + 0 × 20 + 1 × 2-1 + 1 × 2-2 = 1 × 2 + 0 × 1 + 1 × 1/2 + 1 × 1/4 = 2,7510.
Перевод чисел из шестнадцатеричной системы в десятичную. Возьмём любое шестнадцатеричное число, например 19F16. Запишем его в развёрнутой форме (при этом необходимо помнить, что шестнадцатеричная цифра F соответствует десятичному числу 15) и произведём вычисления:
19F16 = 1 × 162 + 9 × 161 + F × 160 = 1 × 256 + 9 × 16 + 15 × 1 = 41510.
Алгоритм перевода целых десятичных чисел в двоичную систему счисления. Пусть Ацд – целое десятичное число. Запишем его в виде суммы степеней основания 2 с двоичными коэффициентами. В его записи в развёрнутой форме будут отсутствовать отрицательные степени основания (числа 2):
Ацд = аn-1 × 2n-1 + аn-2 × 2n-2 + … + а1 × 21 + а0 × 20.
На первом шаге разделим число Ацд на основание двоичной системы, то есть на 2. Частное от деления будет равно
аn-1 × 2n-2 + аn-2 × 2n-3 + … + а1 ,
а остаток – равен a0.
На втором шаге целое частное опять разделим на 2, остаток от деления будет теперь равен a1.
Если продолжать этот процесс деления, то после n-го шага получим последовательность остатков:
а0 , а1 , … , аn-1.
Легко заметить, что их последовательность совпадает с обратной последовательностью цифр целого двоичного числа, записанного в свёрнутой форме:
A2 = an-1 … a1 a0
Таким образом, достаточно записать остатки в обратной последовательности, чтобы получить искомое двоичное число.
Алгоритм перевода целого десятичного числа в двоичное будет следующим:
1. Последовательно выполнять деление исходного целого десятичного числа и получаемых целых частных на основание системы (на 2) до тех пор, пока не получится частное, меньшее делителя, то есть меньшее 2.
2. Записать полученные остатки в обратной последовательности.
Перевод чисел из десятичной системы в двоичную, восьмеричную и шестнадцатеричную более сложен и может осуществляться различными способами. Рассмотрим один из алгоритмов перевода на примере перевода чисел из десятичной системы в двоичную. При этом необходимо учитывать, что алгоритмы перевода целых чисел и правильных дробей будут различаться.
Регистры
Существуют регистры общего назначения, сегментные регистры, счётчик команд и регистры флагов. Здесь мы встречаемся впервые с регистрами общего назначения ax и dx. Причём каждый из них состоит из двух частей – старшей (ah) и младшей (al) (для ax):
Каждое имя регистра несёт какой-либо смысл.
В нашей программе мы использовали старшую часть регистра ax (аккумулятор) и регистр dx (разместили данные). Каждый регистр состоит из двух байт – старшего (идёт первым) и младшего. Например, число 3DEFh можно занести в регистр ax двумя путями. Первый – прямым:
и отдельно к старшему и младшему байту:
Надеюсь, с этим всё ясно. Скомпилируем нашу программу, создав с помощью Far новый файл test.asm (Shift+F4) и поместив в каталог с ним программы MASM.EXE, ML.EXE, LINK.EXE (либо прописав соответствующие системные пути для них. Для LINK.EXE у меня это сделать не получилось, он остаётся в папке с программой). Не забудьте выбрать кодировку файла 866 (клавишей F8), иначе увидите на экране кракозябры.
Выполняем: ML test.asm /AT
В папке с программой должно появиться ещё два файла – test.obj и test.com. Последний нам и нужен. Запускаем его и видим на экране фразу "Hello, world!".
Глава 4. Отладчик
Итак, понемногу мы подвигаемся вперёд. Сегодня мы узнаем о такой важной вещи, как отладчик. В нашем комплекте программ он есть и называется AFD Pro. Для чего нужен отладчик? Как ясно из его названия, для отладки программы. Например, у вас что-то не работает, и нужно найти причину. У нас пока всё работает, но мы хотим посмотреть на работу программы "изнутри". Откроем нашу программу test.com в отладчике:
Файл afdpro.exe должен быть прописан в системных путях или находиться в папке с программой.
Что же мы видим? В верхней части – значения регистров, о которых мы писали в предыдущей статье. Правее – состояние Stack – стека, о чём мы будем говорить позже. Ниже – командная строка, а ещё ниже, как мы, наверное, догадались, наша программа (первые четыре строчки соответствуют нашему коду). Теперь немного об управлении:
F1 – пошаговая трассировка с заходом в прерывания и процедуры.
F2 – то же самое, но без захода в процедуры и прерывания.
Чтобы перемещаться и изменять, например, регистры, дамп памяти – используйте клавиши F7 (вверх), F8 (вниз), F9 (влево), F10 (вправо).
Нажмём F2: программа переместится на следующую строчку, при этом регистры будут отображать нам числовые значения, в них хранящиеся. Первой командой мы занесли в ah число 9. Всё правильно: в левом верхнем углу значение регистра ax показывает 0900 (ah=9, al=0 – он не менялся).
Следующее нажатие F2 – значение регистра dx стало равным 109h. Почему 109? Сейчас узнаем. Ещё раз нажимаем F2 и ещё раз – и мы видим надпись "Program terminated OK" – программа успешно завершила свою работу. Если хотите, можете проверить работу программы ещё раз – для этого нужно нажать клавишу F3 и Enter. Но где же хранят нашу фразу "Hello, world!"?
Рассмотрим подробнее команду mov dx,offset helloworld. В отладчике мы видим иное: MOV DX,0109. Почему так?
Дело в том, что как мы узнали из предыдущей главы, регистры общего назначения, в том числе и dx, хранят всего лишь 2 байта. Вся фраза никак не поместится в регистр dx. Поэтому запись MOV DX,0109 указывает на смещение, где хранится наша фраза. Проверим это.