среда, 6 мая 2009 г.

Первый шаг

Путь длиной в тысячу ли начинается с первого шага
Конфуций

Вот чем мне понравилась книжка Абеля, так это тем, что начинать практиковаться можно даже без наличия на компьютере ассемблера. Потом, конечно, он будет необходим, но все же, для быстрого начала и «въезда» в тему очень даже не дурственно.

Итак, поехали! Жмем «Пуск» -> «Выполнить…» и в появившемся окошке вбиваем debug, давим Enter. Получаем вот такое окошко:

Это запустился древний как… , но все же пригодный для изучения ассемблера, отладчик debug.exe, который позволяет просматривать память, вводить программы и осуществлять трассировку их выполнения.

Приглашением отладчика к работе является вывод символа дефиса «», отладчик ждет команд. Первой командой, с которой будем работать, будет команда D - просмотр дампа памяти.

Посмотрим дату ROM BIOS. Дата ROM BIOS в формате mm/dd/yy находится по адресу FFFF5h. Введим D FFFF:05 (и нажмите Enter). Получаем:

Дата ROM BIOS моего компа 02/03/05. Я выделил на скриншоте ее красным прямоугольником. После выполнения данной команды debug снова переходит в режим ожидания следующих команд. Для выхода из отладчика используется команда Q.

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

Команда    Назначение

B82301 Переслать 0123h в AX.
052500 Прибавить 0025h к AX.
8BD8 Переслать содержимое AX в BX.
03D8 Прибавить содержимое AX к BX.
8BCB Переслать содержимое BX в CX.
2BC8 Вычесть содержимое AX из AX (очистка AX).
90 Нет операции.
CB Возврат в DOS.

Можно заметить, что машинные команды имеют различную длину: один, два или три байта. Машинные команды находятся в памяти непосредственно друг за другом. Выполнение программы начинается с первой команды и далее последовательно выполняются остальные. Не следует, однако, в данный момент искать
большой смысл в приведенном машинном коде. Например, в одном случае MOV - B8, а в другом - 8B.
Можно ввести эту программу непосредственно в память и выполнить ее покомандно. В тоже время можно просматривать содержимое регистров после выполнения каждой команды.

Запускаем debug (если он не был уже запущен). Для непосредственного ввода программы на машинном языке введите следующую команду, включая пробелы:

E CS:100 B8 23 01 05 25 00 (нажмите Enter)

Команда E обозначает Enter(ввод). CS:100 определяет адрес памяти, куда будут вводиться команды, - 100h (256) байт от начала сегмента кодов (обычный стартовый адрес для машинных кодов в отладчике DEBUG). Команда E записывает каждую пару шестнадцатиpичных цифр в память в виде байта, начиная с адреса CS:100 до адреса CS:105.

Следующая команда:

E CS:106 8B D8 03 D8 8B CB (Enter)

Вводит шесть байтов в ячейки, начиная с адреса CS:106 и далее в 107, 108, 109, 10A и 10B.

Последняя команда:

E CS:10C 2B C8 2B C0 90 CB (Return)

вводит шесть байтов, начиная с CS:10C в 10D, 10E, 10F, 110 и 111. Проверьте правильность ввода значений. Если есть ошибки, то следует повторить команды, которые были введены неправильно.

Теперь осталось только выполнить программу. Но перед этим посмотрим содержимое регистров при помощи команды R, а так же посмотрим дамп памяти сегмента кодов (CS) начиная с адреса 100h, с которого начинается наша программа. Сперва вводим команду R (чтобы увидеть содержимое регистров) и жмем Enter, затем команду d cs:100 (чтобы увидеть нашу программу в памяти). Смотрим на скриншот.

Вводимые команды раскрашены желтым цветом, вывод компьютера - серый, программа в памяти обведена красной рамкой. Как уже говорилось, машинные команды находятся в памяти одна за другой, что и видно из скриншота. Адрес сегмента кода, в данному случае 13E5, у вас может быть другим. Это зависит от того, как ОС расположит программу в памяти.
Отладчик выводит всю информацию в шестнадцатеричном виде. Это касается как содержимого регистров, так и памяти.

Отладчик выдает на каждую строку экрана по 16 байт данных в шестнадцатеричном представлении (32 шестнадцатеричные цифры) и в символьном представлении в коде ASCII (один символ на каждую пару шестнадцатеричных цифр). Представление машинного кода в символах ASCII не имеет смысла и может быть игнорировано. Первая строка дампа представляет содержимое ячеек от CS:100 до CS:10F. Вторая строка представляет содержимое ячеек от CS:110 до CS:11F. Несмотря на то, что программа заканчивается по адресу CS:111, команда Dump автоматически выдаст на восьми строках экрана дамп с адреса CS:100 до адреса CS:170.

CS=13E5 указывает, что начало сегмента когда находится по смещению 13E5 или, точнее, 13E50.
Содержимое регистра IP (указатель команд) выводится в виде IP=0100, показывая что выполняемая команда находится на смещении 100h байт от начала сегмента кодов (начало сегмента кодов находится в регистре CS). Вот почему использовалась команда E CS:100 для установки начала программы.
Команда R показывает также по смешению 0100 первую выполняемую машинную команду. Регистр CS содержит значение CS=13E5 (у вас оно может быть другим), а машинная команда выглядит следующим образом:
13E5:0100 B82301 MOV AX,0123

Но в данный момент команда MOV AX,0123 еще не выполнена. Для ее выполнения надо ввести команду - T(трасировка) и жмакнуть по Enter. Смотрим скриншот.

В результате команда MOV будет выполнена и отладчик выдаст на экран содержимое регистров, флаги, а также следующую на очереди команду. Заметим, что регистр AX теперь содержит 0123. Машинная команда пересылки в регистр AX
имеет код B8 и за этим кодом следует непосредственные данные 2301. В ходе выполнения команда B8 пересылает значение 23 в младшую часть регистра AX, т.е. однобайтовый регистр AL, а значение 01 - в старшую часть регистра AX, т.е. в регистр AH. В результате регистр AX содержит 0123h.
Содержимое регистра IP:0103 показывает адрес следующей выполняемой команды в сегменте кодов:
13C6:0103 052500 ADD AX,0025

Для ее выполнения снова жмем T. Команда прибавит 25 к младшей (AL) части регистра AX и 00 к старшей (AH) части регистра AX, т.е. прибавит 0025 к регистру AX. Теперь регистр AX содержит 0148, а регистр IP 0106 – адрес следующей команды для выполнения.
Введите снова команду T. Следующая машинная команда пересылает содержимое регистра AX в регистр BX, и после ее выполнения в регистре BX будет содержаться значение 0148. Регистр AX сохраняет прежнее значение 0148, поскольку команда MOV только копирует данные из одного места в другое.
Теперь вводите команду T для пошагового выполнения каждой оставшейся в программе команды. Следующая команда прибавит содержимое регистра AX к содержимому регистра BX, в последнем получим 0290.
Затем программа скопирует содержимое регистра BX в CX, вычтет AX из CX, и вычтет AX из него самого. После этой последней команды, флаг нуля изменит
свое состояние с NZ(не нуль) на ZR(нуль), так как результатом этой команды является нуль (вычитание AX из самого себя очищает этот регистр в 0).
Можно ввести T для выполнения последних команд NOP и RET, но это мы сделаем позже.
Последовательность ввода команд и результаты выполнения приведены ниже:

-e cs:100 b8 23 01 05 25 00
-e cs:106 8b d8 03 d8 8b cb
-e cs:10c 2b c8 2b c0 90 cb
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=0100 NV UP EI PL NZ NA PO NC
13E5:0100 B82301 MOV AX,0123
-d cs:100
13E5:0100 B8 23 01 05 25 00 8B D8-03 D8 8B CB 2B C8 2B C0 .#..%.......+.+.
13E5:0110 90 CB 00 00 00 00 00 00-00 00 00 00 34 00 D4 13 ............4...
13E5:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E5:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E5:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E5:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E5:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E5:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-t

AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=0103 NV UP EI PL NZ NA PO NC
13E5:0103 052500 ADD AX,0025
-t

AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=0106 NV UP EI PL NZ NA PE NC
13E5:0106 8BD8 MOV BX,AX
-t

AX=0148 BX=0148 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=0108 NV UP EI PL NZ NA PE NC
13E5:0108 03D8 ADD BX,AX
-t

AX=0148 BX=0290 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=010A NV UP EI PL NZ AC PE NC
13E5:010A 8BCB MOV CX,BX
-t

AX=0148 BX=0290 CX=0290 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=010C NV UP EI PL NZ AC PE NC
13E5:010C 2BC8 SUB CX,AX
-t

AX=0148 BX=0290 CX=0148 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=010E NV UP EI PL NZ AC PE NC
13E5:010E 2BC0 SUB AX,AX
-t

AX=0000 BX=0290 CX=0148 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13E5 ES=13E5 SS=13E5 CS=13E5 IP=0110 NV UP EI PL ZR NA PE NC
13E5:0110 90 NOP
-


При необходимости повторить выполнение этих команд можно изменить содержимое регистра IP и повторите трассировку снова. Для изменения значения введите R IP (Enter) и затем введите 100 (Enter). Далее введите необходимое число команд T.

Стоит обратить внимание, что сегментные регистры DS, ES, SS и CS указывают на один и тот же адрес – 13E5. Так сказать информация к размышлению :).

2 комментария:

Unknown комментирует...

прекрасная работа! меня спасли ваши материалы:) СПАСИБО АВТОР.

-=*=- комментирует...

на здоровье :)