Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование на ассемблере под Windows с нуля Выпуск №5


Информационный Канал Subscribe.Ru


В поисках истины

или программирование на ассемблере под Windows с нуля.


Выпуск №5

Сегодня в выпуске:


Обращение к подписчикам

   

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



Глава №3

Моя первая... программа =)

   Когда я решил написать этот выпуск, я думал продолжить писать в том же стиле, который я избрал - максимум информации при минимуме расходуемой площади бумаги (экрана). Но, порывшись в своем недалеком прошлом, я начал вспоминать, насколько мне было сложно понять сухие выкладки разных учебников, и как было трудно читать статьи "делай как я". Поясню, "делай как я" - это статьи, в которых написано, что нужно делать, без объяснений почему так, а не иначе. Метод обучения, применяемый в таких публикациях, сводится к банальному "copy-past", и обучающиеся максимум что могут самостоятельно сделать, так это вместо окошка с сообщением "Hello, world", вывести тоже окошко с таким же тривиальным "Bill - gay, tcc…". Поэтому, выпуски станут менее информативными, но более понятными. А тот, кто посчитает, что я "лью воду", пусть выругается на форуме, либо оставит свое мнение при себе ;-), так как я вряд ли его послушаю =).

   Итак, первое что мы сделаем - это настроим наши основные инструменты. Наш главный инструмент - MASM32, который уже должен быть скачен вами. Весь пакет будет установлен в корневой каталог, там ему и место, потом будет меньше проблем. Открыв папку "MASM32" вы обнаружите в ней много вложенных папок и файлов. Для нас сейчас важна только одна из таких папок - "bin", в ней находятся множество разных файлов, от "батника" (*.bat) до "экзешника" (*.exe). И опять, на тут интересуют только два файла ml.exe и link.exe. Что это за файлы? Первый (ml) - это и есть ассемблер. Эту программу называют по разному - ассемблер, транслятор или даже компилятор. Я буду называть эту программу "ассемблер", хотя чтобы примерить все споры, лучше называть её "транслятор". А называть её "компилятор", по-моему, не очень правильно. Ну, да ладно, это не самое главное. Вторая программа (link) так же имеет свое название - компоновщик. Хотя вы достаточно часто встретите в литературе слово "линкер", знайте, это одно и тоже, просто на разных языках =). Программы эти особенные, работать с ними надо через командную строку, в связи с этим, рекомендуя вам запастись каким-нибудь файл менеджером. На мой взгляд лучший - Windows (Total) Commander. Если вы запустите компоновщик "как обычно", двойным кликом мыши, то он выведет в консоли справочку по опциям его запуска.

   Следующий шаг. Теперь надо выбрать программу, в которой мы напишем свои первые программы. Для этого нам подойдет обычный Блокнот (но лучше скачайте текстовой редактор Bred2), ну или другой текстовой редактор не вставляющий в текст символы форматирования. Единственная хитрость при его использовании - вам нужно будет сохранять файл с расширением *.asm.

   Третий шаг. Подготавливаем рабочую территорию. Создаем папку для своих проектов с таким, например, названием -ASM_Progi. В этой папке будем создавать для каждого программы свои папки. Пусть папка для первой программы будет называться "Prog_01", в неё мы поместим готовую программа и исходники к ней ;-). Так же создадим рабочую папку с названием "Work", по-моему, логично =). В эту папку нужно забросить следующие файлы из папки "bin" - ml.exe, link.exe и mspdb70.dll. В папку work мы будем хранить рабочие варианты программ. На этом же шаге необходимо создать тестовой файл следующего содержания

@echo off ml /c /coff /Cp Prog_01.asm
link /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib Prog_01.obj
echo Компановка завершена. Закройте командный файл.
pause>nul

И сохранить его с расширением *.bat в папке work. Я подробно объясню текст это файлы чуть позже, после подготовительных моментов. Чтобы был выведен русский текст необходимо сохранить файл в ДОСовской кодировке.Для этого нам и нужен BRED2. Блокнот с ДОСовской кодировкой плохо работает.

   И ещё один шаг. Настраиваем отладчик. Установка его у вас проблем не вызовет. Можете установить отладчик в любое свободное место =). А вот немного настроить его надо. Запустив программу вы увидите привычное windows приложение. Главное окно отладчика разделено на несколько окошек с непонятными названиями - CPU, Registers, что то знакомое ;-), ну и еще несколько =). Все эти окошки пустые. В этом нет ничего удивительного, мы, ведь, еще ничего в отладчик не загрузили, чтобы он нам что-то показывал ;-). Первое что необходимо настроить - это шрифт. Это нужно для того, чтобы этот отладчик "понимал по-русски". Это можно сделать двумя путями. Первый такой - меню Options/ Appearance. Появится диалоговое окно с закладками. Выбираем закладку '"Fonts", жмем кнопку "Change", в появившемся диалоге выбора шрифта выбираем шрифт "Courier New" и набор символов "Кирилица", размер шрифта можете подобрать под себя. Второй путь настройки мы рассмотрим в процессе отладки нашей программы. Можно также изменить цвет шрифта и фона, это дело вкуса.

   Начинаем!!! Запускаем Блокнот и набиваем в нем такой текст:

.386
.model flat, stdcall
option casemap:none
.data
.code
start:
ret
end start

   И сохраняем его в папке work под таким именем prog_01.asm. Запускаем батник make.bat. И видим, что в нашей папке появились два новых файла, откуда они =)? Итак, начинаем разбирать все по порядку. Что мы собственно написали в нашей программе. И программа ли это, ведь, она ничего не делает. Можете не сомневаться, это полноценная программа. Но единственное что она умеет, так это корректно завершаться. Исходник программы, написанной на ассемблере, состоит из ассемблерных команд и директив транслятора. Ассемблерная команда "говорит" что нужно делать процессору, а директивы влияют на работу транслятора. Скажу сразу, в этой программе только одна ассемблерная команда - ret. Вам уже знакомы две команды - mov и add. В данном случае эта команда применяется для корректного завершения программы, в последствии мы её для этого никогда не будем использовать. Теперь директивы. .386 - Это ассемблерная директива, указывающая ассемблеру использовать набор операций для процессора 80386. Можно использовать и .486, .586 или даже .686, но самый безопасный выбор - это указывать .386. Вас это наверно удивляет ;-), но в большинстве случаев мы будем писать именно ".386". Именно с этого процессора началась эра 32-разрядных процессоров. .model flat, - плоская модель памяти, хотя мне больше нравится название "непрерывная". Эта модель памяти используется в операционной системе Windows. Об организации памяти будет разговор отдельный. Stdcall - используемое соглашение о вызовах процедур. Вызовы процедур - это отдельный большой вопрос. Поэтому наберитесь терпения и дождитесь соответствующего выпуска ;-). option casemap:none - говорит MASM сделать метки чувствительными к регистрам, то есть ExitProcess и exitprocess - это различные имена.

.data
.code

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

.DATA - Эта секция содержит инициализированные данные вашей программы. Поясняю, допустим вы решили присвоить переменной A значение 50 или 20, или даже "Hello world", вот именно в этой секции и нужно располагать такие данные

.DATA? - Эта секция содержит неинициализированные данные вашей программы. Иногда вам нужно только предварительно выделить некоторое количество памяти, но вы не хотите инициализировать ее. Эта секция для этого и предназначается. преимущество неинициализированных данных следующее: они не занимают места в исполняемом файле. Hапpимеp, если вы хотите выделить 10.000 байт в вашей .DATA? секции, ваш exe-файл не увеличиться на 10kb. Его размер останется таким же. Вы всего лишь говорите компилятору, сколько места вам нужно, когда программа загрузится в память.

.CONST - Эта секция содержит объявления констант, используемых программой. Константы не могут быть изменены ей. Это всего лишь константы. Вы не обязаны задействовать все три секции. Объявляйте только те, которые хотите использовать. Для кода существует одна секция - .code.

start:
...
end start

   Это простые метки, указывающие на начало и конец секции кода, их название может быть произвольным.

   Для начала про директивы достаточно, теперь немного про опции командной строки. Начнем с опций ассемблера.

ml /c /coff /Cp Prog_01.asm

    /c говоpит MASM'у создать .obj файл в фоpмате COFF. MASM использует вариант COFF (Common Object File Format), использующийся под Unix, как его собственный объектный и исполняемый формат файлов. В этом месте необходимо пояснить одну вещь. Сборка программы состоит из двух этапов, для этого нам и нужны две программы (ассемблер и компоновщик ), ассемблирования и компоновки. На первом этапе из исходника мы получаем объектный модуль (*.obj), он включает в себя представление исходной программы в машинных кодах и некоторую другую информацию, необходимую для отладки и компоновки его с другими модулями. /Cp говоpит MASM'у сохранять регистр имен, заданных пользователем. Если вы используете hutch'евский MASM32 пакет, вы можете вставить "option casemap:none" в начале вашего исходника, сразу после директивы .model, чтобы добиться того же эффекта.

link /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib msgbox.obj

   /SUBSYSTEM:WINDOWS информирует компоновщик о том, что исполняемый файл должен быть обычным windows приложением, возможные варианты - консоль, драйвер. /LIBPATH:<путь к библиотекам импоpта> говоpит компоновщику, где находятся библиотеки импоpта. Этот пункт я подробно, пока объяснять не буду, это не важно сейчас для вас.

   Ну вот, немного разобрались теперь можно написать программу, которая кроме того что корректно завершается, ещё и что-то делает. Сегодня мы продолжим изучение простейших арифметических операций. Мы поговорим о умножении и вычитании. Вычитание. Команда SUB вычитает второй операнд (источник) из первого (приемника) и п омещает результат на место первого операнда. Исходное значение первого операнда (уменьшаемое) теряется. Таким образом, если команду вычитания записать в общем виде

sub операнд_1, операнд_2


то есть ее действие можно условно изобразить следующим образом:

операнд_1 - операнд_2 -> операнд_1


Теперь запишем в виде ассемблерной программы.

  mov eax, 100d ; помещаем в eax 100d
mov ebx, 50d ; помещаем в ebx 50d
sub eax, bx ; вычитаем ebx из eax



   По моему все просто =).
Умножение. Команда mul выполняет умножение целого числа без знака, находящегося в регистре AL (в случае умножения на байт), АХ (в случае умножения на слово) или EAX (в случае умножения на двойное слово), на операнд-источник (целое число без знака). Для однобайтовых операций один из сомножителей помещается в регистр AL; после выполнения операции произведение записывается в регистр АХ.
Для двухбайтовых операций один из сомножителей помещается в регистр АХ; после выполнения операции произведение записывается в регистры DX:AX (в DX - старшая часть, в АХ - младшая). Предыдущее содержимое регистра DX затирается. Помните, я говорил про специализацию регистров, mul - яркий пример этого.
Для четырехбайтовых (dword) операций произведение записывается в регистры edx:eax (в EDX - старшая часть, в EАХ - младшая).

Mul сомножитель_1



   Повторяю, второй сомножитель задан неявно через AL, АХ или EAX.
Пример ассемблерной программы

mov AL,5 ;Первый сомножитель
mov BL,3 ;Второй сомножитель
  mul BL ;AX=OOOFh, произведение


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

.386
.model flat, stdcall
option casemap:none
.data
.code
start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
mov eax, 2
mov ebx, 2
add eax, ebx
mov ecx, 10d
sub ecx, eax
mul ebx
ret
end start

   В этой программе была использована одна, еще вам не известная ассемблерная команда - xor. Эту команду мы подробно обсудим в выпуске, посвященном логическим операциям. Запомните одно, если в качестве двух операндов использован один и тот же регистр, эта команда просто-напросто очищает его. Для чего мы очищаем регистры в данном случае? Просто во время запуска нашей программы регистры инициализированы каким-то значением. Каким конкретно значением, нас сейчас не волнует. Да и вам будет более удобно под отладчиком разобраться с работой этой программы.

   В нашем батнике достаточно изменить "Prog_01" на "Prog_02", и запустить его. И опять мы получим в нашей рабочей папке ещё два файла Prog_02.obj, Prog_02.exe. Теперь мы сделаем то, о чем так долго я говорил - запустим эту программу под отладчиком. Для этого запускаем OllyDbg, нажимаем F3, выбираем нашу программу (Prog_02) и ждем, совсем недолго, и видим, что во внутренних окнах OllyDbg, появилось какое-то содержимое. Давайте разберемся с тем что мы увидели. Основное окно с заголовком CPU main thread, module Prog_02. То есть отладчик нам указывает на то, что запущенна программа Prog_02. В верхней левой части основного окна расположено окно дизассемблера, в котором мы видим следующее:

XOR EAX,EAX
XOR EBX,EBX
XOR ECX,ECX
MOV EAX,2  
MOV EBX,2  
ADD EAX,EBX
MOV ECX,0A 
SUB ECX,EAX
MUL EBX    
RETN       


    Что-то до боли нам знакомое ;-) Да, ведь это наша программа :-). В правом верхнем углу с заловком Registers мы видим знакомые "буковки" - eax, ebx, и т.д.

EAX 00401000
ECX 81749BDC
EDX 81749C1C
EBX 00530000
...


   Напротив имени регистра шестнадцатеричными цифрами указано значение этих регистров на данный момент. Остальные окошки мы трогать пока не будем, разберемся для начала с этими двумя. Основным приемом при отладке программ является трассировка. Что это? Если по простому, то трассировка - это пошаговое исполнение программы. Как шаги бывают разные, так и трассировка бывает разной. Различают трассировку с заходом в процедуры и без захода. Поясняю, в первом случае буду выполнятся последовательно команды как главного модуля так и команд находящихся в других модулях, вызываемых из главного модуля, во втором случае все команды вызываемого модуля выполняются за один шаг, как одна команда. Нам же трассировка поможет увидеть работу нашей программу. Для каждого вида трассировки существует своя клавиша, с заходом (step into) - F7, без захода (step over) - F8.

   В данном случае мы можем применять оба вида трассировки, т.к. в нашей программе нет вызова процедур.
   1)   Нажав первый раз F8 (или F7), мы замечаем, что в верхнем правом окошке произошли некоторые изменения, об этом свидетельствует подсветка (если вы не меняли настройки цвета шрифта, то подсветка будет красного цвета). Посмотрев на значение регистра eax, мы замечаем, что теперь оно равно 00000000, значит, первый xor сработал.
   2)   Нажимаем еще раз - ebx F8 - 00000000
   3)   Нажимаем еще раз - ecx F8 - 00000000
   4)   Теперь, нажав на F8 значение регистра eax должно стать - 00000002. Жмем. Смотрим. Работает!!!
   5)   Жмем F8. И видим, что ebx - 00000002.
   6)   Теперь, по идее, в регистре eax, после нажатия F8, должна быть сумма eax и ebx, т.е. 4. Жмем. Смотрим содержимое eax, и к своему восторгу обнаруживаем там такое значение 00000004.
   7)   Следующая команда должна поместить в регистр ecx 10d. Жмем. Гляим в регистр и немного удивляемся 8-). Где наша десятка? Почему там буковка "A"? Отладчик показывает содержимое регистров в hex. А 10d - 0Ah, если вы еще не запомнили =).
   8)   Вычитание. После этой операции в регистре ecx должно остаться 0000000Ah - 00000004h= 00000006h. Опять получилось ;-).
   9)   Последний шаг. Умножение. Жмем F8 и видим что и умножение работает. Eax = 00000008
 10)   Конец.
Несмотря на то, что эта программа себя явно не проявляет, он делает достаточно многое - сложение, вычитание, умножение. Теперь вы можете экспериментировать с этими регистрами - складывать, вычитать, умножать.

Дерзайте! До новым встреч!


Обратная связь

   Если вы хотите что-то спросить по ассемблеру, крэку, или просто поболтать прошу на форум нашей команды, там вы сможете получить ответы от меня, и моих товарищей Mafia32, formatC Вы можете отправить письмо на мой почтовый ящик , только в том случае если вопрос имеет отношение к рассылке. Обязательно заполняйте поле "Тема", письма без темы, я не буду читать. Для вашего удобства я разместил в рассылке e-mail форму, вы можете прямо из нее отправлять свое письмо, но для этого должна быть настроена ваша почтовая программа.

Имя:
Тема:
Сообщение:



Копирайты

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

Copyright © 2004 SeDoYHg

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу


В избранное