You are on page 1of 20

Посібник з програмування на Асемблері для Windows

Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Зміст
Введення.................................................................................................................... 2
Чому Асемблер?......................................................................................................................2
Чому Windows?.......................................................................................................................2
I. Початок 3
Асемблери...............................................................................................................................3
Редактори.................................................................................................................................3
II. Перша Програма.................................................................................................4
Версія console..........................................................................................................................4
Версія Windows.......................................................................................................................6
ADDR проти OFFSET............................................................................................................6
III. Основи Асемблера.............................................................................................7
Регістри CPU...........................................................................................................................7
Базова система Команд...........................................................................................................8
Push і Pop..................................................................................................................................8
Invoke (викликати)...................................................................................................................9
Приклад програми...................................................................................................................9
IV. Основи Windows..............................................................................................10
Попередні зауваження..........................................................................................................10
Макроозначення.....................................................................................................................10
Функції....................................................................................................................................10
Змінні......................................................................................................................................10
Просте Вікно.........................................................................................................................11
V. Додатково про Асемблер та Windows............................................................13
Операції над Рядками...........................................................................................................13
Управління файлами............................................................................................................13
Управління пам'яттю.............................................................................................................14
Приклад програми.................................................................................................................14
Контролі................................................................................................................................15
Додаткові Ресурси.................................................................................................16
www...................................................................................................................................................16
Книжки...................................................................................................................................16
MASM32.................................................................................................................................16
Бібліотека MSDN...................................................................................................................16
Конференції............................................................................................................................16
IRC..........................................................................................................................................16

2
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Введення
Мета посібника - прискорення засвоєння студентами основ мови та набуття навичок програмування
на Асемблері. Посібник зосереджується на Асемблері для Windows на платформі x86. Вивчення
матеріалу посібника передбачає знайомство з програмуванням на мовах високого рівня та з
основними поняттями архітектури обчислювальних систем. Для поглибленого вивчення мови
Асемблера та прийомів програмування існує багато інших джерел: інтерактивні посібники, книги,
конференції та IRC. Посилання на них наведені у розділі Додаткові ресурси.

Чому Асемблер?
Асемблер має декілька особливостей, які роблять його застосування ефективним у багатьох
ситуаціях.
1. Швидкість — програми на Асемблері загалом працюють швидше, ніж програми створені на
мовах програмування високого рівня. Часто функції, для яких істотно важлива швидкість
виконання, програмісти пишуть на Асемблері.
2. Потужність – Програміст отримує необмежену владу (майже!) над програмами в асемблері,
маючи на увазі те, що мови програмування високого рівня зазвичай мають такі обмеження, які
роблять здійснення певних речей важкими або неефективними.
3. Компактність - програми на Асемблер і набагато компактніші, ніж програми, написані на
мовах високого рівня. Ця властивість надзвичайно корисна, якщо існує проблема ресурсів.

Чому Windows?
Програми на мові асемблера можуть бути написані для будь-якої операційної системи і моделі CPU.
Однак більшість людей сьогодні використовують ОС Windows на x86 CPU, так що ми почнемо з
програм, які працюють саме в її середовищі. Як тільки основи мови асемблера будуть засвоєні,
створювати програми для середовищ інших ОС стане легшим.

Розділ 1
I. Початок
Для того, щоб створити програму на Асемблері, необхідно відповідне програмне забезпечення, а
саме, програма-компілятор (транслятор) з мови асемблера у машинний код - асемблер та текстовий
редактор. Існує широкий вибір Windows-програм, за допомогою яких цю роботу можна виконати.
Програма-компілятор мови асемблера, її зазвичай, називають Асемблер, приймає код, записаний
на мові Асемблера і перетворює його на машинний код. Часто компілятор поставляється разом із
редактором зв'язків (лінкером), який зв'язує від трансльовані файли, і створює виконувану
програму. Виконувані програми Windows мають тип .exe. Є декілька популярних асемблерів:
Примітка:

3
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Буде декілька директив і макроозначеннь, використаних в цьому посібнику, які доступні тільки в MASM, так що надзвичайно бажано
починати з нього

1. MASM — - асемблер на якому базується цей посібник, і використовувати при вивченні матеріалу
посібника потрібно саме його, оскільки в цьому посібнику буде використано декілька директив і
макроозначеннь, , які доступні тільки в MASM. Зараз він входить до пакету MASM32 v8 (версія 8),
який включає також і інші інструменти. Його можна одержати на http://www.masm32.com/.
Отриманий пакет MASM32 v8 (або більш нової версії) необхідно інсталювати у відповідності з
інструкцією, наприклад, у директорії D:\MASM32.
2. TASM - Інший популярний асемблер виробництва Borland. Це комерційна програма, так
що її не можна отримати безкоштовно.
3. NASM — загальнодоступний асемблер, з відкритим початковим кодом, який також
доступний і для інших платформ. Доступний на http://sourceforge.net/projects/nasm/ . Відзначимо,
що NASM не може транслювати більшість програм написаних для MASM і навпаки. Редактор – це
інструмент, за допомогою якого ви записуєте свій код перед тим, як його транслювати. Існує
багато Редакторів. Вибирати їх можна за власним уподобанням.
1. Notepad — Постачається разом з Windows; хоча відчувається недолік багатьох можливостей,
але його дуже просто використовувати.
2. Visual Studio —, хоч це і не вільно доступний редактор, він має чудові можливості
синтаксичного контролю та індикації, що робить код набагато більш читабельним.
3. Other - існує багато редакторів під Windows і буде недоречно всіх їх називати. Ось лише деякі
найпопулярніші:
a. Ultraedit http://www.ultraedit.com/
b. Textpad http://www.textpad.com/
c. VIM http://www.vim.org/
d. Emacs http://www.gnu.org/software/emacs/emacs.html
e. jEdit http://www.jedit.org/

Розділ 2

II. Ваша Перша Програма


Тепер, коли ми маємо інструменти, почнемо створювати програму. Відкрийте текстовий редактор
і, дійте за наступними інструкціями. Створюємо найпопулярнішу в світі перша програма - "Hello,
World!".

Версія console

4
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

console версія виконується на консолі Windows (також відомій як командний рядок). Щоб створити
цю програму, спочатку вставте наступний код у вашому текстовому редакторі і збережіть файл як
"hello.asm" у деякій папці (директорії), наприклад, D:\AsmProg, звичайно, попередньо створивши її.
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
.data
HelloWorld db "Hello, World!", 0
.code
start:
invoke StdOut, addr HelloWorld
invoke ExitProcess, 0
end start

Далі, відкрийте режим командного рядка: "Пуск-Меню->Выполнить" і, наберіть у вікні вводу "cmd"
(без лапок). У відкритому вікні Командного рядка перемістіться до директорії, де збережено
файл "hello.asm" (можна за допомогою команди cd /D d:\AsmProg: ), і наберіть рядок "d:\
masm32\bin\ml /c /coff hello.asm".
Маємо надію, що помилок немає і ваша програма відтрансльована правильно. Результатом роботи
програми "ml" – транслятора Асемблера – буде файл з назвою hello.obj у директорії d:\AsmProg.
Далі цей так званий об'єктний файл потрібно перетворити у виконуваний – "відлінкувати".
Для цього набираємо рядок:
"d:\masm32\bin\link /SUBSYSTEM:CONSOLE hello.obj".
В директорії d:\AsmProg програма link створить файл з назвою hello.exe - виконуваний. Наберіть
рядок " hello", щоб виконати вашу програму. У вікні командного рядка повинен з'явитись напис,
"Hello, World!".
Таким чином, потрібно досить багато коду, аби тільки відобразити, "Hello, World!" Що робить цей
код? Розглянемо текст програми рядок за рядком.
.386

Це директива асемблера, яка вказує асемблеру використовувати систему команд 386 процесора. У
наш час залишилась невелика кількість процесорів, старіших за 386. Альтернативно, можна
використовувати .486 або .586, але .386 буде найбільш сумісною системою команд.
.model flat, stdcall

.MODEL - директива асемблера, яка конкретизує модель пам'яті вашої програми. flat - зручна модель
для програм Windows, тому що не має відмінності між 'дальніми' і 'ближніми' покажчиками.
stdcall - метод передачі параметрів, використовуваний функціями Windows, який означає, що
потрібно передавати параметри справа-наліво.
option casemap :none

5
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Встановлює чутливість або нечутливість до регістру символів, що означає, Hello і hello


розглядаються асемблером по різному. Більшість мов програмування є чутливими до регістра, так
що до цього факту найкраще звикати якомога раніше.
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

Включає файли, потрібні для програм Windows.


windows.inc включається завжди, оскільки містить опис (декларації) для констант Win32 API та
визначення.
kernel32.inc містить функцію ExitProcess, яку ми використовуємо;
masm32.inc містить функцію StdOut, яка, хоча і не вбудована в функції Win32, але додана в
MASM32v8.
includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\masm32.lib

Функціям потрібні бібліотеки для того, щоб функціонувати (це не каламбур!), так що ці бібліотеки
включаються з цією метою.
.data

Всі дані у вашій програмі, які мають бути ініціалізованими, слідують за цією директивою. Є і інші
директиви як наприклад .data? яка передує неініціалізованим даним і .const - константам. В нашій
програмі їх використовувати немає потреби.
HelloWorld db "Hello World!", 0

db означає 'define byte' і визначає, що змінна HelloWorld, має значення рядка, "Здра вствуй Мир!",
який завершено символом НУЛЬ (байт, всі розряди якого дорівнюють 0), оскільки рядки ANSI мають
закінчуватися нулем.
.code

Це початковий пункт для програмного коду.


start:

Весь код повинен розміщуватися після цієї мітки, але до мітки end start.
invoke StdOut, addr HelloWorld

invoke викликає функцію за якою слідує параметр, addr HelloWorld. Цей рядок викликає функцію
StdOut, передаючи в параметрі addr HelloWorld, адресу рядка "Hello, World!". Майте на увазі, що
StdOut – це функція, яка доступна тільки в MASM32 і є макрокомандою, яка викликає іншу функцію
для виводу тексту. Для інших асемблерів, потрібно буде використовувати запис коду більшого
об'єму і використовувати функцію win32, WriteConsole.
invoke ExitProcess, 0

Цей виклик функції цілком очевидний. Він передає параметр 0 до функції ExitProcess, для
завершення програми.

Версія Windows
Тепер побудуємо Windows версію програми HelloWorld!. Вставте наступний текст у вашому
текстовому редакторі і збережіть файл як "hellow.asm".

6
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
HelloWorld db "Hello World!", 0
.code
start:
invoke MessageBox, NULL, addr HelloWorld, addr HelloWorld, MB_OK
invoke ExitProcess, 0
end start

Як і у попередньому прикладі, переміщуємося до директорії де збережено "hellow.asm".


Набираємо
"d:\masm32\bin\ml /c /coff hellow.asm",
потім
"d:\masm32\bin\Link /SUBSYSTEM:WINDOWS hellow.obj".
Відзначте, що тепер було використано SUBSYSTEM:W INDOWS замість
SUBSYSTEM:CONSOLE. Наша програма повинна створити вікно повідомлення, з текстом
"Hello, World!".
Є тільки 3 рядка коду, якими відрізняються версії програми для Windows і для console. Перші 2
мають відношення до заміна бібліотеки masm32 на user32 оскільки ми використовуємо функцію
MessageBox замість StdOut. Третя відмінність у замін і функції StdOut функцією MessageBox.

Addr проти offset


У нашому прикладі, ми використовували 'addr', щоб одержати адресу рядка, " Hello, World!". Є
також інша подібна директива, 'offset', хоча мета обох - одержати адресу змінних пам'яті у процесі
виконання. Основна різниця полягає в тому, що за допомогою. 'offset' можна одержати адресу
тільки глобальних змінних, тоді як 'addr' дає можливість одержати адресу як глобальних змінних,
так і локальних змінних. Локальні змінні ще не обговорювались. Але це треба мати на увазі.

7
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Розділ 3

III. Основи Асемблера


Отже ми можемо зробити просту програму і виконати її. Перейдемо тепер до основної частини
посібника — основам синтаксису Асемблера. Ці основи вам потрібно знати для того, щоб писати ваші
власні програми на Асемблері

Регістри CPU
Регістри - спеціальна пам'ять розміщена в CPU. Ми припускатимемо, що читач програмує для
комп'ютерів, використовуючи 386 або пізніші процесори. Старіші процесори в наш час
зустрічаються рідко, так що не варто втрачати час на їх вивчення. Найважливішою різницею між
старими і сучасними процесорами є те, що пре-386 процесори є 16-бітними а не 32-бітними.
Є 8 32-розрядних регістрів загального призначення. Перших 4 - eax, ebx, ecx, і edx можуть також бути
доступними з використанням 16 або 8-розрядних імен. ax адресує перші 16 біт eax, al адресує перш і
8 біт, і ах адресує біти 9-16. Інші регістри можуть бути доступні подібним чином. Взагалі, ці
регістри можуть використовуватися для будь-чого, хоча найбільше мають спеціальне використання:
Адреса Ім'я Опис
EAX* Регістр накопичувач обчислення результатів операцій над
(Accumulator даними
Register)
EBX Базовий Регістр (Base покажчик на дані в DS сегменті
Register)
ECX* Регістр рахівник рахівник для операцій над рядками і
(Count Register) організації циклу
EDX* Регістр Даних (Data покажчик вводу/виводу
Register)
ESI Індекс джерела початковий покажчик для строкових
(Source Index) операцій
EDI Індекс призначення покажчик призначення для строкових
(Destination Index) операцій
ESP Покажчик вершини покажчик вершини стека,
стека (Stack Pointer) використовувати не рекомендовано

8
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

EBP Базовий Покажчик покажчик на дані у стеку


(Base Pointer)

Примітка:
Хоча вони називаються регістрами загального призначення, тільки ті, які відмічений * потрібно використовуватися в програмуванні для
Windows

Є 6 16-розрядних сегментних регістрів. Вони визначають сегменти в пам'яті:


Адреса І м' я Опис
CS Кодовий де розміщуються виконувані команди
Сегмент
DS,ES,FS,GS Сегмент сегмент даних
Даних
SS Сегмент стека де розміщується стек для поточної програми

Нарешті, є 2 32-розрядні регістри, які не відповідають в будь-яку категорію:

Адреса Ім'я Опис


EFLAGS Кодовий Сегмент стан, елемент управління, і системні флаги
EIP Командний зміщення до наступної команди, яка має
Покажчик виконуватись

Базовий набір Команд


Система команд x86 надто велика, але нам зазвичай не потрібно використовувати її всю. Тут
наведені скорочений набір команд, який ви повинні знати, щоб для початку отримати необхідний
мінімальний досвід:

Команда Опис
ADD* reg/memory, reg/memory/constant Додає два операнди і запам'ятовує результат в першому операнді.
Якщо результат з переносом, то буде встановлено CF. (Carry Flag)

SUB* reg/memory, reg/memory/constant Віднімає другий операнд від першого і запам'ятовує результат в
першому операнді.
AND* reg/memory, reg/memory/constant Виконує порозрядну логічну операцію And (І) над операндами, і
запам'ятовує результат в першому операнді.

OR* reg/memory, reg/memory/constant Виконує порозрядний логічну операцію OR (Або) над операндами, і
запам'ятовує результат в першому операнді.

XOR* reg/memory, reg/memory/constant Виконує порозрядну логічну операцію XOR (виключне Або) на
операндах і запам'ятовує результат в першому операнді. Відзначте,

що не можна виконувати XOR двох операндах memory.

MUL reg/memory Перемножує операнд з Регістром Накопичувачем і запам'ятовує

9
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

результат в Регістрі Накопичувачі.

DIV reg/memory Ділить Регістр Накопичувач на операнд і запам'ятовує результат в


Регістрі Накопичувачі.

Inc reg/memory Збільшує значення операнда на 1 і запам'ятовує результат в


операнді.
DEC reg/memory Зменшує значення операнда на 1 і запам'ятовує результат в операнді.

NEG reg/memory Змінює знак операнда на протилежний операнд і запам'ятовує


результат в операнді.
NOT reg/memory Виконує порозрядну логічну операцію NOT на операнді і
запам'ятовує результат в операнді.

PUSH reg/memory/constant Поміщає значення операнда на до вершини стека.

POP reg/memory Виштовхує значення з вершини стека до операнда.

MOV* reg/memory, reg/memory/constant Запам'ятовує значення другого операнда в першому операнді.


CMP* reg/memory, reg/memory/constant Віднімає другий операнд від першого операнда і встановлює
відповідні флаги. Звичайно використано в поєднанні з JMP, REP, і
т.п.

JMP** Мітка Перехід до мітки.


LEA reg, memory Вибирає елемент зміщення адреси другого операнда і запам'ятовує
результат в першому операнді.

CALL Підпрограма Викликає іншу процедуру і передає управління цій процедурі до


виконання команди повернення
RET Повернення управління до програми, яка викликала.
INT Константа Викликає переривання, вказане операндом.

* Команди не можуть мати обох операндів типу пам'ять


** Ця команда може використовуватися в поєднанні з умовами. Наприклад, JNB ( не нижче) виконує
перехід тільки, коли CF = 0.
Push і Pop
Push і Pop є операціями, які маніпулюють стеком. Push бере значення і поміщає його на вершину
стека. Pop бере значення з вершини стека, видаляє його, і запам'ятовує в операнді. Тому, стек
використовує метод "перший прийшов – перший вийшов". Стеки – це загальні структури даних в
комп'ютерах, так що рекомендується, аби ви ближче з ними познайомились, якщо ви не
достатньо впевнені при роботі зі стеками.
Invoke
Функція Invoke визначена у MASM, і може використовуватися для виклику функції без
необхідності попереднього поміщення параметрів у стек. Це запобігає зайвого друку.
Наприклад:
invoke SendMessage, [hWnd], WM_CLOSE, 0, 0

Замість:
push 0
push 0
push WM_CLOSE

10
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

push [hWnd]
call [SendMessage]

Приклад програми
Нижче наведено приклад повністю функціональної програми, яка показує, як використовувати
деякі з команд і регістрів. Подивіться, чи зможете ви її зрозуміти.
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
.data
ProgramText db "Hello World!", 0
BadText db "Error: Sum is incorrect value",0
GoodText db "Excellent! Sum is 6", 0
Sum sdword 0
.code
start:
mov ecx, 6 ; set the counter to 6
xor eax, eax ;set eax to 0
_label: add eax, ecx ;add the numbers
dec ecx ;from 0 to 6
jnz label
mov edx, 7
mul edx ;multiply by 7
push eax ;pushes eax into the stack
pop Sum ;pops eax and places it in Sum
cmp Sum, 147 ;compares Sum to 147
jz good ;if they are equal, go to _good
_bad: invoke StdOut ;addr BadText
jmp quit
good: invoke StdOut ;addr GoodText
quit: invoke ExitProcess, 0
end start

Примітка:
Символ ';' означає початок коментарю. Наступне за цим символом, не транслюється. Це хороший засіб для розміщення підказок і приміток
в щоб зробити ваш код читабельнишім.

11
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Розділ 4

l V. Основи Windows
Програми Windows звичайно компонуються з одного або більше вікон. Тому, щоб стати реальним
Windows-програмістом, потрібно знати, як мінімум, як зробити просте вікно. Нажаль, це не так
легко, але спробуємо це зробити.

Попередні зауваження
Є декілька розділів в Асемблері, як і ми повинні обговорити перед зануренням у Windows-
програмування. Потрібен деякий час, щоб розглянути ці передумови.
Макроозначення
MASM включає багато макроозначень, які спрощують програмування в Асемблері. Ми вже бачили
'invoke', який спрощує виклики функцій. Є і інші; їх використання повинно бути очевидне для вас
якщо ви програмували на мовах високого рівня:
.if, .else, .endif .while, .break, .endw
Функції
Подібно до високорівневих мов, MASM дозволяє нам визначати функції, щоб зробити код
читабельнішим. Їх синтаксис подібний до:
<name> процедура <var1>:<var1 type> <var2>:<var2 type> ...
<function code>
ret
<name> endp

Значення, яке повертається функцією, запам'ятовується в регістрі eax, а функція викликається так:
invoke <name>, param1, param2 ...
Повернене значення може бути одержане, використанням команди:
mov RetVal, eax
Змінні
Змінні розміщуються в пам'яті і дозволяють зберігати дані. Вони можуть бути корисні також, якщо ви
не маєте достатньо регістрів. Є два види змінних - глобальні змінні і локальні змінні. Глобальні змінні

12
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

розміщені в .data секції, якщо вони ініціалізувались, і в .data? секції, якщо ні, або в .const секції, якщо
вони ініціалізувались і не будуть змінюватись. Синтаксис оголошення глобальних змінних такий:
<name> <type> <value, (або ? якщо неініціалізовані)
Локальні змінні розміщені усередині функції, і використовуються для тимчасового
запам'ятовування під час виконання функції. Вони не можуть ініціалізуватися під час створення. Їх
синтаксис такий:
local <name>:<type>
Є декілька типів змінних. Деякі з них добре знайомі 'byte', 'word' (4 байта), і 'dword' (8 байтів). Є і
інші, але вони зазвичай такі ж самі, як і один з цих трьох типів але з іншим іменем.

Просте Вікно
Програми Windows складаються з двох головних частин —WinMain створює вікно і містить дещо,
назване циклом повідомлення. Цикл повідомлення чекає повідомлень і розподіляє їх. Друга
частина - функція повторного виклику, WndProc, яка є тією функцією, до якої повідомлення
направлено. Це те місце, де обробляються події миші, перемалювання, і т.п.

.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
Це необхідні включення.
WinMain proto :DWORD, :DWORD, :DWORD, :DWORD

Це опис зовнішньої функції (прототип). Він дозволить нам викликати функцію WinMain в програмі
надалі. Схоже на оголошення функції в C/C++.

.data
ClassName db "WinClass", 0
AppName db "Simple Window", 0
Оголошення власних строкових змінних.
.data?
hInstance HINSTANCE ?
hInstance запам'ятовує дескриптор екземпляра модуля, який асоційовано з вікном. Нам потрібно
буде передати його до функції CreateWindow пізніше.
Примітка:
Тут ми припускатимемо, що ви можете знайти функції Windows в Бібліотеці MSDN. Вона включає інформацію щодо функціональних
параметрів, значень, які повертаються і окрім того ще дещо, що вам, можливо, буде потрібно знати. Подивіться на секцію Additional

Resources для більш повного ознайомлення з Бібліотекою MSDN.

.code start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke WinMain, hInstance, NULL, NULL, 0
invoke ExitProcess, eax
Отримати дескриптор модуля і запам'ятати його в hInstance. Потім викликати WinMain і вийти.
WinMain – центральна частина нашої програми, заглянемо в неї глибше.

13
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD


local wc:WNDCLASSEX
local msg:MSG
local hwnd:HWND
Це початок нашої функції WinMain. Ми оголошуємо три локальні змінні: wc, msg, і hwnd. wc
запам'ятовує віконний клас, який ми створюємо; віконний клас – це шаблон для створення вікон.
msg запам'ятовує повідомлення, які відшукує цикл повідомлення. hwnd запам'ятовує дескриптор
вікна.
mov wc.cbSize, SIZEOF_WNDCLASSEX
mov wc.style, CS_HREDRAW OR CS_VREDRAW
mov wc.lpfnWndProc, offset WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInstance
pop wc. hInstance
mov wc.hbrBackground, COLOR_WINDOW+1
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset ClassName
invoke LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
invoke LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
invoke RegisterClassEx, addr wc
Примітка:
У Windows, 'OR' оператор часто використовується для комбінування флагів в параметрах.

Все це зроблено для заповнення структури wc, яку ми оголосили раніше. Виклик RegisterClassEx
прийме wc як параметр. Для більш конкретної інформації про кожного члена wc, подивіться опис
структури WNDCLASSEX в бібліотеці MSDN.

invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE,


CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
mov hwnd, eax
Виклик функції CreateWindowEx фактично створює вікно. У параметрах передаються дані, щоб
конкретизувати, як створити вікно. Дескриптор вікна повертається і запам'ятовується в hwnd.

.while TRUE
invoke GetMessage, addr msg, NULL, 0, 0
.break .if (!eax)
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr
msg .endw
Це - цикл 'while', який є циклом повідомлення, згаданим раніше. Коли відбувається вхідна подія,
Windows транслює подію у повідомлення і передає повідомлення до черги повідомлень програми.
GetMessage відшукує ці повідомлення і запам'ятовує їх в msg. Потім TranslateMessage замінює
ключі повідомлення в символьні повідомлення. Нарешті, DispatchMessage відправляє повідомлення
WndProc, де вони обробляються.
mov eax, msg.wParam

ret
WinMain endp

14
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Повернене значення запам'ятовується в msg.wParam і WinMain закінчується.


WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg == WM_DESTROY
invoke PostQuitMessage, 0
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
xor eax, eax
ret
WndProc endp
WndProc функція, де повідомлення обробляються. Єдине повідомлення, яке повинне бути
оброблене, - WM_DESTROY, яке викликає PostQuitMessage для завершення. Якщо є інші події,
які ви хочете обробляти, треба їх додати тут. Загальні повідомлення, які обробляються -
WM_CREATE (коли вікно створюється), WM_PAINT (коли вікно потребує повторного виводу,
перемалювання), і WM_CLOSE (коли вікно закривається). Будь-що необроблюване, передається до
функції-обробника умовчанням, DefWindowProc.

end start

Це все! Тепер ви знаєте, як створити вікно!

Розділ 5

V. Додатково про Асемблер і Windows


Є ще декілька ресурсів, щоб розширити ваше знання Асемблеру і програмування для Windows:
операції над рядками, робота з файлами, і управління формами Windows.

Операція над Рядками


Рядки, масиви символів, - істотна частина до будь-якої програми. Вони звичайно використовуються,
якщо ви хочете відобразити текст або запросити ввід від користувача. Вони використовують
наступні регістри: esi, edi, ecx, eax, eflag's флаг напряму. Флаг напряму - задає напрямок руху уздовж
рядка. Деякі загальні строкові команди - movsb, cmpsb, stasb, і stosb. Щоб маніпулювати рядками,
ви використовуєте форму rep? при строковій команді. Ось таблиця використання rep? префікса, з і
строковими командами:
приста строкова Опис
вка команда
rep movsb Копіює рядок
repe cmpsb порівнює рядок
repne scasb проглядає рядок для
пошуку символу
rep stosb встановлює символ в рядку
Приклад копіювання рядка:

15
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Cld ; встановлення флага напряму вперед


mov esi, source ; помістити адресу джерела даних в esi

mov edi, dest ; помістити адресу призначення в edi


mov ecx, length ; помістити довжину копійованого рядка (у байтах) в ecx

rep movsb ; копіювання з адреси в esi до адреси в edi

Управління Файлами
У Dos, файлами маніпулювали б, використовуючи переривання. У Windows, ми використовуємо
функції Windows для того, щоб звернутися до файлів. Існують 4 функції, які ми можемо
використовувати:
CreateFile — Створює або відкриває файл, і повертає його дескриптор.
ReadFile — Читає дані з файлу.
WriteFile - Запис даних записів у файл.
CloseHandle - Закриває дескриптор, отриманий використанням CreateFile.

Пам'ять
Для того, щоб читати вміст файлу, потрібно буде зарезервувати деякий об'єм пам'яті, для
запам'ятовування даних. Пам'ять має бути зарезервована, блокованим, використана, розблокована, і
звільнена. Функції, які це роблять, - GlobalAlloc, GlobalLock, GlobalUnlock, і GlobalFree.
Приклад програми
Ця програма читає вміст "c:\test.txt" і виводить у MessageBox.

.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
Знайомі рядки!

.data
FileName db "c:\test.txt", 0
.data?
hFile HANDLE ?
hMemory HANDLE ?
pMemory DWORD ?
ReadSize DWORD ?
Ми визначаємо свій рядок і оголошуємо 4 змінних, які будуть використані пізніше.
.const
MEMORYSIZE equ 65535

Це об'єм пам'яті, яку ми резервуємо, так, щоб мати достатньо простору, щоб запам'ятати наш файл.

.code start:
invoke CreateFile, addr FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL
mov hFile, eax
Виклик CreateFile і запам'ятовування дескриптора файлу в hFile. Звичайно, пишуть 'h' на початку
дескриптора і 'p' - покажчика.

16
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMORYSIZE


mov hMemory, eax
invoke GlobalLock, hMemory
mov pMemory, eax
Резервування і блокування пам'яті.
invoke ReadFile, hFile, pMemory, MEMORYSIZE-1, addr ReadSize, NULL
invoke MessageBox, NULL, pMemory, addr FileName, MB_OK

Ці рядки читають файл в pMemory і виводять у вигляді MessageBox


invoke GlobalUnlock, pMemory
invoke GlobalFree, hMemory
invoke CloseHandle, hFile
invoke ExitProcess, NULL
end start
Не забувайте про прибирання!

Контролі
Як тільки ми зробимо вікно, ми захочемо розмістити на ньому деякі кнопки і текстбокси . На
щастя, це легко! Синтаксично це подібно до створення вікна, окрім того, що нам не доведеться
викликати RegisterClassEx, тому що наш клас буде вбудований.
Щоб зробити це, редагуйте свій WndProc з Розділу 4 для реакції на повідомлення WM_CREATE:
.elseif uMsg == WM_CREATE
invoke CreateWindowEx, NULL, addr ButtonClassName, addr ButtonText, WS_CHILD or WS_VISIBLE or
BS_DEFPUSHBUTTON, 10, 50, 80, 30, hWnd, ButtonID, hInstance, NULL
mov hButton, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr EditClassName, NULL, WS_CHILD or WS_VISIBLE, 10, 10, 100,
20, hWnd, EditID, hInstance, NULL
mov hEdit, eax
У розділі .data, вам потрібно буде додати деякі змінні. Визначте EditClassName як "edit" і
ButtonClassName як "button". Також, вам потрібно мати EditID і ButtonID, визначені як
константи. Не має ніякого значення, що вони є, поки вони не мають того ж ID, як будь-який інший
елемент управління. Також, вам будуть потрібні неініціалізовані змінні, hEdit і hButton, які мають тип
HWND. І нарешті, ButtonText має бути рядком, який відображатиметься на кнопці.
Тепер ми також маємо знати, коли наша кнопка була натиснута. Це може бути зроблено,
спостеріганням повідомлення WM_COMMAND, яке є повідомленням посланим від кнопки, коли її
натискають.
.elseif uMsg == WM_COMMAND
mov eax, wParam
.if ax == ButtonID
shr eax, 16

wParam містить інформацію про повідомлення. Ми повинні перевірити, чи це кнопка, яка послала
повідомлення, з тих пір, як нам не треба обробляти повідомлення інших контролів. shr – оператор
зсуву, який переміщає значення wParam на 16 біт управо. Це засіб одержати старші 16 біт 32-
розрядного регістра таким чином, що вони можуть бути легко доступні в ax.
.if ax == BN_CLICKED
<code для виконання дії повязаної з натисканням кнопки>
.endif
.endif

Отже тепер, коли ми знаємо, що кнопка була натиснута, ми можемо виконати необхідну нам дію.

17
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

В секції Додаткові ресурси, розміщено посилання на книжки та веб-вузли по програмуванню


для Windows.

Додаткові Ресурси
www
http: / /www.xs4all.nl/~smit/ - посібники по програмуванню на Асемблері.
http: / /win32asm.cjb.net/ - посібники по програмуванню на Асемблері для Windows.
http: / /board.win32asmcommunity.net/ - діалоговий форум по питаннях, пов'язаних з програмуванням
на Асемблері для Windows.
Книги
Програмування для Windows, П'яте Видання Чарльз Petzold - чудова книга по програмуванню для
Windows. Містить зразки коду для багатьох програм Windows і покриває великий діапазон розділів
програмування для Windows.
Intel Pentium 4 Керівництво по Процесорах, доступно на
http://www.intel.com/design/pentium4/manuals/ - повне довідкове керівництво для x86
програмування на Асемблері.
Мистецтво Програмування на Асемблері, Randall Hyde, доступно на
http: / /webster.cs.ucr.edu/AoA.html мова асемблера x86
MASM32
У папці \masm32\HELP\, є файл masm32.hlp, який містить керівництво MASM32. Він включає опис
всіх макроозначень, регістрів, флагів, інформацію по оптимізації Pentium, і т.п. Це дуже хороше
джерело, щоб знайти специфічні речі MASM32.
Бібліотека MSDN
Бібліотека MSDN звичайно поставляється з Visual Studio, також доступна інтерактивно в
http://msdn.microsoft.com/ Містить описи всіх функцій Windows, констант, і багато іншої інформації
щодо Windows.
Конференції
Є дві конференції, які мають справу з x86 Асемблером. Це - comp.lang.asm.x86 і alt.lang.asm.
IRC
В каналі IRC, можна отримати інформацію з програмування на Асемблері для Windows, #win32asm на
EFNet http://www.efnet.org/

18
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Додаток 1. Ключі програми асемблера.


C:\masm32\bin>ml /?
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
ML [ /options ] filelist [ /link linkoptions ]
/AT Enable tiny model (.COM file)
/Bl<linker> Use alternate linker
/c Assemble without linking
/Cp Preserve case of user identifiers
/Cu Map all identifiers to upper case
/Cx Preserve case in publics, externs
/coff generate COFF format object file
/D<name>[=text] Define text macro
/EP Output preprocessed listing to stdout
/F <hex> Set stack size (bytes)
/Fe<file> Name executable
/Fl[file] Generate listing
/Fm[file] Generate map
/Fo<file> Name object file
/FPi Generate 80x87 emulator encoding
/Fr[file] Generate limited browser info
/FR[file] Generate full browser info
/G<c|d|z> Use Pascal, C, or Stdcall calls
/H<number> Set max external name length
/I<name> Add include path
/link <linker options and libraries>
/nologo Suppress copyright message
/Sa Maximize source listing
/Sc Generate timings in listingC:\masm32\bin>
/Sf Generate first pass listing
/Sl<width> Set line width
/Sn Suppress symbol-table listing
/Sp<length> Set page length
/Ss<string> Set subtitle
/St<string> Set title
/Sx List false conditionals
/Ta<file> Assemble non-.ASM file
/w Same as /W0 /WX
/WX Treat warnings as errors
/W<number> Set warning level
/X Ignore INCLUDE environment path
/Zd Add line number debug info
/Zf Make all symbols public
/Zi Add symbolic debug info
/Zm Enable MASM 5.10 compatibility
/Zp[n] Set structure alignment
/Zs Perform syntax check only

19
Посібник по програмуванню на Асемблері для Windows від ДЖЕФ ХУАНГ та ТВС (Укр)

Додаток 2. Ключі програми Link


C:\masm32\bin>link /?
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
usage: LINK [options] [files] [@commandfile]
options:
/ALIGN:#
/BASE:{address|@filename,key}
/COMMENT:comment
/DEBUG
/DEBUGTYPE:{CV|COFF}
/DEF:filename
/DEFAULTLIB:library
/DLL
/DRIVER[:{UPONLY|WDM}]
/ENTRY:symbol
/EXETYPE:DYNAMIC
/EXPORT:symbol
/FIXED[:NO]
/FORCE[:{MULTIPLE|UNRESOLVED}]
/GPSIZE:#
/HEAP:reserve[,commit]
/IMPLIB:filename
/INCLUDE:symbol
/INCREMENTAL:{YES|NO}
/LARGEADDRESSAWARE[:NO]
/LIBPATH:dir
/MACHINE:{ALPHA|ARM|IX86|MIPS|MIPS16|MIPSR41XX|PPC|SH3|SH4}
/MAP[:filename]
/MAPINFO:{EXPORTS|FIXUPS|LINES}
/MERGE:from=to
/NODEFAULTLIB[:library]
/NOENTRY
/NOLOGO
/OPT:{ICF[,iterations]|NOICF|NOREF|NOWIN98|REF|WIN98}
/ORDER:@filename
/OUT:filename
/PDB:{filename|NONE}
/PDBTYPE:{CON[SOLIDATE]|SEPT[YPES]}
/PROFILE
/RELEASE
/SECTION:name,[E][R][W][S][D][K][L][P][X]
/STACK:reserve[,commit]
/STUB:filename
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/SWAPRUN:{CD|NET}
/VERBOSE[:LIB]
/VERSION:#[.#]
/VXD
/WARN[:warninglevel]
/WINDOWSCE:{CONVERT|EMULATION}
/WS:AGGRESSIVE

20

You might also like