PDA

Просмотр полной версии : Ассемблер для новичков.


luz3r
13.08.2008, 00:53
Ассембли. Урок I - Вызовы API

Привет. Итак приступим к делу, для этого нам нужно скачать какой-нибудь компилятор ассемблера, качайте или FASM или MASM, так как отличия в синтаксисе минимальны. Скачать их можно тут (http://www.robo9.xaker.name/) в соответствующем разделе. Лучше конечно скачать FASM, так как этот компилятор нравиться мне больше остальных и обьяснять я буду именно на нём.

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

Создадим простой текстовый файлик и назовём его "first.asm" и начинаем программировать:


include 'win32ax.inc'
.code
start:
invoke ExitProcess,0 ; вызываем функцию ExitProcess c параметром 0 (нуль)
.end start


Что делает этот код? Да ничего... Если мы его скомпилируем то получим полноценную программу которая просто завершает сама себя. Компилируем:

fasm.exe first.asm

Итак, вы попытались скомпилировать... Но не получилось, а всё потому что компилятор не знает где находиться файл-инклудник - "win32ax.inc". Необходимо ему явно указать этот файл для этого меняем код программы, например вот так:

include 'D:\FASM\includу\win32ax.inc'
.code
start:
invoke ExitProcess,0 ; вызываем функцию ExitProcess c параметром 0 (нуль)
.end start


Теперь всё скомпилируеться отлично, но чтобы это не писать каждый раз, можно задействовать переменные среды, присвоив например переменной %inc% путь "D:\FASM\include". Но этим мы займемся в следующем туториале, так как в этом я собираюсь показать как вызываеться функция Windows API (какой и являеться ExitProcess).

Кстати invoke - это макрос, который обьявлен в инклуднике win32ax.inc. Он позволяет нам вызывать функции привычным образом как например в С++ или Delphi. Без него мы будем писать в следующих туториалах. Короче усвойте что invoke это вызов функций (но только на первый туториал, ну или на все если в будущем вы собираетесь программировать именно с его помощью).

Теперь давайте добавим в нашу программу ещё одну функцию - MessageBox:


include 'D:\FASM\include\win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hallo antichat.ru","Caption",MB_ICONASTERISK

invoke ExitProcess,0 ; вызываем функцию ExitProcess c параметром 0 (нуль) .end start

Первый параметр функции MessageBox являеться дескриптор окна-родителя нашего окошка, в качестве него мы передаём константу HWND_DESKTOP - дескриптор Рабочего Стола.
Второй параметр - адрес на текст самого окошка. Возникает вопрос - почему же мы не пишем: invoke MessageBox,HWND_DESKTOP,offset Message....? Да потому что, макрос invoke достаточно универсален, чтобы принимать в параметре просто текст... Подробнее обьясню в следующих уроках.
Третий параметр - заголовок окна, то есть его адрес.
Ну а четвёртый параметр - стиль окна, у нас это MB_ICONASTERISK то есть окошко с восклицанием.

Кстати дополнительную информацию об API - можно получить либо на MSDN либо из любой справки Windows SDK, которая поставляеться с любым продуктом Borland. Вот и написали и разобрали вызов функций и написали полноценное приложение. Всё, до следующего туториала, всего хорошего...

Piflit
13.08.2008, 00:58
ого. прям в строчку. жестко

luz3r
13.08.2008, 01:02
Ассембли. Урок II - Циклы и условные переходы

Привет. Сегодня поговорим о циклах и условных переходах. Для этого давайте возьмём код из первого урока и немного его усложним, добавив сначала цикл, затем условный переход. Давайте сделаем так чтобы окошко вызывалось 5 раз. Для этого приведём следующий код:


include 'D:\FASM\include\win32ax.inc'

.code

start:

mov esi,5d ; кладём в регистр esi число 5

@@loop: ; обьявили метку

invoke MessageBox,0,0,0,0 ; вызываем окно

dec esi ; уменьшаем счётчик

cmp esi,0 ; сравниваем esi c нулём (проверяем не кончился ли счётчик)

ja @@loop ; и если число в esi превышает 0 (нуль) то прыгаем на метку @@loop

invoke ExitProcess,0 ; ну а если равно то выходим из программы

.end start




Тут наверное стоит пояснить что метка @@loop - так написанна для удобства и только для этого. Есть ещё понятие анонимных меток - о них мы поговорим в следующих уроках. Итак из комментариев в коде я думаю всё ясно. Мы просто обьявили регистр esi как счётчик, затем мы вызываем окошко и уменьшаем счётчик на 1 (dec - уменьшить на 1). Сравниваем счётчик с нулём, так мы проверяем, не кончился ли счётчик, и если не кончился - переходим на метку @@loop. Поясню, что JA - Jump if Above то есть переход если больше. Так и получаеться что пока в esi больше нуля то мы "бегаем по коду" и выполняем вызов окна. Как только счётчик установлен в 0 (нуль) - выполнение программы прекращаеться, то есть выполняеться ExitProcess.

Кстати в этой программе мы использовали и цикл и условный переход. Но давайте превратим этот код в более привычный вид для программистов на C++ и Delphi:



include 'D:\FASM\include\win32ax.inc'

.code

start:

mov esi,5d

@@loop:

invoke MessageBox,0,0,0,0

dec esi

.if esi = 0

invoke ExitProcess,0

.endif

jmp @@loop
.end start



Тут уже попонятнее да? Появился привычный нам всем if. Как вы уже знаете после if выполняеться код если условие верно. То есть если у нас esi = 0, то выполняеться ExitProcess. Тут всё понятно и так.

luz3r
13.08.2008, 01:04
Ассембли. Урок III - Сравнения и переходы (более подробно)

Привет. На этом уроке поговорим про операторы cmp & условные переходы более подробно. Для начала обратите внимание на таблицу условных переходов. Вы уже видели нечто подобное на прошлом уроке:

http://www.geekgames.ru/jn.GIF

Теперь давайте посмотрим на практике. Есть код:



1) mov eax,32 ; в EAX 32h

2) mov ebx,33 ; в EBX 33h

3) cmp eax,ebx ; сравниваем EAX c EBX

4) jne metka ; Если не равны то прыгаем на metka

5) sub eax,eax ; иначе обнуляем EAX

metka:

6) invoke ExitProcess,0 ; завершаем процесс



Разберём каждую инструкцию:

1) mov - инструкция, которая присваивает значения. В данном случаи мы присваиваем регистру EAX число 32h (hex)

2) Аногогично, только теперь регистру EBX присваиваеться 33h

3) cmp - оператор сравнения (Compare - сравнивать). Сравнивает EAX c EBX и взависимости от результата выставляет соответствующие арифметические флаги (у нас ZF, SF, CF - но не подумайте что это все флаги!)

4) Наш условный переход, чтобы его понять обратимся к таблице. Смотрим тип операндов - любые, значит не имеет значения, со знаком числа или без. Далее смотрим критерий условного перехода - 1операнд НЕ РАВЕН 2операнду. И третие - смотрим значение флага, в данном случаи это флаг "нуля" (ZF - Zerro Flag). Итак из таблицы видно что, чтобы мы прыгнули на метку - регистры EAX & EBX не должны быть равны и флаг нуля устанавливаеться в 0(нуль). То есть если они не равны - мы прыгаем на метку "metka"

5) Так как переходу быть - процессор не выполняет эту инструцкию. Она предназначена для вычитания. То есть если бы перехода не было она бы вычла из EAX, EAX (значения) - тем самым обнулив его.

6) Уже до боли знакомый вам вызов функции API ExitProcess, который просто завершит программу.

Если бы мы в 4) пункте написали бы не JNE a JZ то мы бы не прыгнули на метку, так как регистры EAX & EBX не равны между собой.

Для полноты всей картины давайте воспроизведём всё выше описаное в полноценную программу:



include 'D:\FASM\include\win32ax.inc'

.code

start:

mov eax,32 ; в EAX 32h

mov ebx,33 ; в EBX 33h

cmp eax,ebx ; сравниваем EAX c EBX

jne metka ; Если не равны то прыгаем на metka

sub eax,eax ; иначе обнуляем EAX

metka:

invoke ExitProcess,0 ; завершаем процесс

.end start



Вот и весь урок. Можно эксперементировать задавая разные значения регистрам и изменяя прыжок - так вы быстрее поймёте. Есстественно нужно это делать в отладчике. Возьмите Olly. Кстати вот этот наш кусок кода в отладчике выглядит следующим образом:

http://www.geekgames.ru/oll.GIF

Красная стрелочко означает что сейчас произойдёт переход, и я ещё там написал что флаг нуля = 0 (нуль), чтобы не постить весь экран от Olly. А вот Olly лучше скачайте и посмотрите сами!

luz3r
13.08.2008, 01:09
Ассембли. Урок IV - Переменные и возвращаемые значения функций

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

воспользуемся всё той-же функцией MessageBox. Вы можете спросить: что может возвращать простое окно сообщения? А возвращает она одно из следующих

значений:

IDABORT ; нажата кнопка ABORT
IDCANCEL ; нажата кнопка CANCEL
IDIGNORE ; нажата кнопка IGNORE
IDNO ; нажата кнопка NO
IDOK ; нажата OK
IDRETRY ; нажата RETRY
IDYES ; нажата кнопка YES

Более подробную информацию по функциям API можно найти на MSDN (http://msdn2.microsoft.com/ru-ru/default.aspx), или в любом справочнике который

поставляеться с продуктами от Borland. Посмотрим на следующий код:



include 'D:\FASM\include\win32ax.inc'

.code

start:

invoke MessageBox,0,'привет!','заголовок', MB_OK ; вызываем окошко
invoke ExitProcess,0 ; завершаем процесс

.end start



Посмотрите стиль окошка - MB_OK, соответственно окошко выскочит с одной кнопкой OK. И если мы нажмём OK то функция возвратит IDOK. Но что если нам

нужно например использовать две кнопки, например OK & CANCEL. Для этого есть специальный стиль окна - MB_OKCANCEL. Вообще они конечно описаны в MSDN,

так что я не буду их приводить в этом тексте. Пример:



include 'D:\FASM\include\win32ax.inc'

.code

start:

invoke MessageBox,0,'привет!','заголовок', MB_OKCANCEL ; вызываем окошко
invoke ExitProcess,0 ; завершаем процесс

.end start



Тогда, соответственно при выполнении этого кода, если мы нажали на OK, функция возвратит IDOK, если CANCEL - то получим IDCANCEL. Чтобы узнать что

возвращает та или иная функция - обратитесь к MSDN (для этого знание технического английского вам поможет). Кстати функции возвращают значения через

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

если мы нажимаем например на OK выскакивает окошко и говорит нам что мы нажали именно эту кнопку, если CANCEL - то соответственно сообщение будет

другим:



include 'D:\FASM\include\win32ax.inc'

.code

start:

invoke MessageBox,0,'привет!','заголовок', MB_OKCANCEL ; вызываем окошко
cmp eax,IDOK ; проверяем что нажали ok
jz OK_PRESSED ; если да - прыгаем на соответствующее сообщение
invoke MessageBox,0,'вы нажали CANCEL','заголовок',MB_OK ; если нет - то не прыгаем и выводим что нажали CANCEL
jmp EXIT ; прыгаем на выход чтобы избежать появления второго окна

OK_PRESSED:

invoke MessageBox,0,'вы нажали OK','заголовок',MB_OK ; выводим сообщение про OK
EXIT:

invoke ExitProcess,0 ; завершаем процесс

.end start



Надеюсь из комментариев всё ясно, но на всякий случай поясню, что после того как мы вивели окно с приветствием, мы проверяем с помощью оператора CMP,

значение регистра EAX и если там IDOK то прыгаем на сообщение и говорим что нажали OK, иначе выводим сообщение что нажали CANCEL и прыгаем на метку

EXIT дабы избежать появления второго окна, ведь код продолжит выполняться и наткнёться на строку invoke MessageBox,0,'вы нажали OK','заголовок',MB_OK

. То есть инструкцией jmp (безусловный переход) мы перепрыгиваем эту запись и выходим из программы.

Теперь займёмся переменными:

Переменные должны быть обьявлены в секции данных - .data . Сначала мы пишем имя переменной потом через пробел - её размер, и только потом через пробел

её значение. Пример:



include 'D:\FASM\include\win32ax.inc'

.data

perem1 dd 0

.code

start:

invoke ExitProcess,0

.end start



В этом примере мы обьявили переменную perem1 размером в 4 байта (dd - define dword (двойное слово - 4 байта)) и присвоили ей значение 0 (нуль). Теперь

в неё можно писать данные, но не более 4 байт, так как мы задали размер именно в 4 байта. Можно считывать значение переменной итд. Кстати, для того

чтобы считать значение переменной, её нужно обрамить скобками вот так:



include 'D:\FASM\include\win32ax.inc'

.data

perem1 dd 0

.code

start:

mov eax,[perem1]
invoke ExitProcess,0

.end start



Но чтобы считать её адрес в памяти - обрамление скобками не требуеться. Пример:



include 'D:\FASM\include\win32ax.inc'

.data

perem1 dd 0

.code

start:

mov eax,perem1
invoke ExitProcess,0

.end start



Давайте теперь примерим всё это на практике. Напимеш программу для вывода текста в окно при помощи переменных. Для этого рассмотрим параметры самой

функции, которые кстати вы можете и сами посмотреть в MSDN, но у меня мало трафика и я приведу кусок из справки от Borland:

int MessageBox(

HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);

Из этого ясно что: Для текста в заголовке и для текста в окне, мы должны передавать не значения, а адреса переменных, которые этот текст содержат.

Сделаем это:



include 'D:\FASM\include\win32ax.inc'

.data

text db "наш текст",00h
zagolovok db "заголовок",00h

.code

start:

invoke MessageBox,0,text,zagolovok,0
invoke ExitProcess,0

.end start



Обратите внимание как мы обьявляем строки - как массив байтов, которые заканчиваються нулевым байтом. Кстати db - это обьявить байт. Заметьте также,

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



-------------------------------------------------------------------
Вроде всё доходчиво описано... поймёт каждый. =)

GALIAFF
13.08.2008, 02:03
уебись =\

furang
13.08.2008, 02:14
Нафиг переделывать уроки iczelion-а, тем более у него они лучше получились.

neprovad
13.08.2008, 02:17
Повторение - мать учения. Кто-то может быть ни разу не видел эти пресловутые уроки от iczelion'а

NorB
13.08.2008, 02:25
wasm.ru и некаких вапросов!=)

Midas
13.08.2008, 04:04
реально, если б небыл знаком - хрен бы что понял. Первый урок - работа с Api, второй циклы - вобще улыбнуло.

Поюзайте уроки Калашникова, их очень хвалят.

z01b
14.08.2008, 13:42
Удалите этот треш ...