Просмотр полной версии : Ассемблер для новичков.
Ассембли. Урок 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. Вот и написали и разобрали вызов функций и написали полноценное приложение. Всё, до следующего туториала, всего хорошего...
ого. прям в строчку. жестко
Ассембли. Урок 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. Тут всё понятно и так.
Ассембли. Урок 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 лучше скачайте и посмотрите сами!
Ассембли. Урок 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 - это обьявить байт. Заметьте также,
что когда мы вызываем функцию - мы не обрамляем переменные скобками, то есть мы берём их адрес в памяти, а не их значения. Вот и всё. Пока...
-------------------------------------------------------------------
Вроде всё доходчиво описано... поймёт каждый. =)
Нафиг переделывать уроки iczelion-а, тем более у него они лучше получились.
neprovad
13.08.2008, 02:17
Повторение - мать учения. Кто-то может быть ни разу не видел эти пресловутые уроки от iczelion'а
wasm.ru и некаких вапросов!=)
реально, если б небыл знаком - хрен бы что понял. Первый урок - работа с Api, второй циклы - вобще улыбнуло.
Поюзайте уроки Калашникова, их очень хвалят.
vBulletin® v3.8.14, Copyright ©2000-2026, vBulletin Solutions, Inc. Перевод: zCarot