Include masm32 include windows inc

Решил начать цикл статей по ассемблеру, и, в частности, по MASM32. Пригодятся эти мануалы с примерами тем, кто хочет поднять свои навыки программирования и развить умение программировать на ассемблере. Пакет MASM32 — это не просто голый ассемблер. В нём есть огромное множество облегчающих разработку софта вещей — пользовательские макросы, встроенные функции и макросы, дебаггер и прочее, и обо всём этом я буду рассказывать. Конечно, читать такие статьи будет гораздо легче тем, кто уже умеет программировать на каком-нибудь языке. Если вы программируете на каком-нибудь говне вроде Visual Basic, или фанатеете от перетаскивания компонентов и кнопочек на формы в дельфи или Borland C++ — не расстраивайтесь, я расскажу, как можно перетаскивать кнопочки и в ассемблере. Разумеется, никаких стандартных облегчающих жизнь компонентов здесь не будет, но это побудит разобраться с WinAPI — огромной кладезью полезных функций, которые способны делать всё, начиная от чтения данных из сокета и заканчивая отображением окон.

Собственно, эту статью я начну с примера простого GUI-приложения на MASM. Конечно, проектировать дизайн окна мы будем визуально (я же обещал). Для этого сначала следует скачать визуальный редактор ресурсов ResEd. Запускаем его и видим интерфейс:

Создаем новый файл ресурсов (File — New Project и вводим имя). В правой верхней панели появляется значок папки и имя файла. Кликаем по ней правой кнопкой и нажимаем «Add Dialog». Теперь мы можем визуально спроектировать интерфейс окна и изменить его настройки. Я создал простое окно TEST_DIALOG с двумя кнопками TEST_BTN и EXIT_BTN:

Если вы успели обрадоваться — не спешите: здесь нельзя программировать, можно только делать дизайн интерфейса. Теперь необходимо добавить в наш файл ресурсов еще пару вещей. Первое — это include-файл с определениями всех констант, который будет необходим компилятору ресурсов MASM32. Как и раньше, нажимаем правой кнопкой мыши по значку папки, выбираем «Include file», «Add» и вводим путь. У меня это C:\masm32\include\RESOURCE.H. У вас может быть и другой, зависит от папки установки masm32 (как? вы еще не установили его?).

Теперь еще одна вещь. Пусть наше окно и кнопки выглядят в современном XP-стиле. Для этого необходимо добавить к файлу ресурсов XP Manifest. Добавляется он аналогично предыдущим пунктам (Add XP Manifest).

Теперь сохраняем файл ресурсов. Он должен выглядеть примерно таким образом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#define MANIFEST 24

#define TEST_DIALOG 1000

#define TEST_BTN 1001

#define EXIT_BTN 1002

#define IDR_XPMANIFEST1 1

#include «C:/masm32/include/RESOURCE.H»

TEST_DIALOG DIALOGEX 6,6,134,51

CAPTION «Test Dialog»

FONT 8,«MS Sans Serif»,0,0,0

STYLE WS_VISIBLE|WS_CAPTION|WS_SYSMENU

BEGIN

  CONTROL «Тест»,TEST_BTN,«Button»,WS_CHILD|WS_VISIBLE|WS_TABSTOP,6,18,54,13

  CONTROL «Выход»,EXIT_BTN,«Button»,WS_CHILD|WS_VISIBLE|WS_TABSTOP,72,18,54,13

END

IDR_XPMANIFEST1 MANIFEST «xpmanifest.xml»

Осталось написать программу. Я в качестве редактора предпочитаю обычный Блокнот Windows. Сначала я приведу полный листинг, а потом прокомментирую его построчно:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

.386

.model flat, stdcall

option casemap :none

include \masm32\include\windows.inc

include \masm32\macros\macros.asm

uselib kernel32, user32, masm32, comctl32

WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

TEST_DIALOG = 1000

TEST_BTN = 1001

EXIT_BTN = 1002

.data?

  hInstance dd ?

  hWnd dd ?

  icce INITCOMMONCONTROLSEX <>

.code

  start:

    mov icce.dwSize, SIZEOF INITCOMMONCONTROLSEX

    mov icce.dwICC, ICC_DATE_CLASSES or \

                    ICC_INTERNET_CLASSES or \

                    ICC_PAGESCROLLER_CLASS or \

                    ICC_COOL_CLASSES

    invoke InitCommonControlsEx, offset icce

    invoke GetModuleHandle, NULL

    mov hInstance, eax

    invoke DialogBoxParam, hInstance, TEST_DIALOG, 0, offset WndProc, 0

    invoke ExitProcess,eax

WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD

  switch uMsg

    case WM_INITDIALOG

      invoke SendMessage, hWin, WM_SETICON, 1, FUNC(LoadIcon, NULL, IDI_ASTERISK)

    case WM_COMMAND

      switch wParam

        case TEST_BTN

          invoke MessageBox, hWin, chr$(«Hello, world!»), chr$(«Test»), 0

        case EXIT_BTN

          jmp exit_program

      endsw

    case WM_CLOSE

      exit_program:

      invoke EndDialog, hWin, 0

    endsw

  xor eax,eax

ret

WndProc ENDP

end start

Итак, начнем:

.386

.model flat, stdcall

option casemap :none

Эти директивы говорят о том, что мы пишем код под 386 архитектуру процессора (это так и будет всегда), вторая говорит о том, что модель памяти мы используем плоскую и вызовы функций по стандарту stdcall. Этот стандарт подразумевает, что аргументы функциям передаются через стек в обратном порядке, и функция сама должна удалять их оттуда. Кроме того, функции сохраняют регистры ebx, edi и esi и возвращают значение в регистре eax. Если вы сейчас ничерта не поняли — не расстраивайтесь, это всё прекрасно разъяснено в гугле — и про регистры, и про стек. Если вы занимаетесь программированием, то понять это не составит труда.

include \masm32\include\windows.inc

include \masm32\macros\macros.asm

uselib kernel32, user32, masm32, comctl32

Здесь мы подключаем необходимые библиотеки. kernel32 содержит функцию ExitProcess, user32 — всякие GUI-функции, comctl32 — функции работы с common controls, masm32 — библиотека встроенных функций masm32, я не знаю, зачем я ее здесь подключил, потому что она все равно в этом простом проекте не используется. Ну, лишнего объема, как в дельфи, это не добавит, если функции из библиотеки не используются. Я расскажу о ней в будущем. uselib — это макрос masm32, который всё необходимое позволяет одной строкой подключить. Только представьте, эти три строки эквивалентны следующему коду:

include \masm32\include\windows.inc

include \masm32\macros\macros.asm

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

include \masm32\include\masm32.inc

include \masm32\include\comctl32.inc

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\masm32.lib

includelib \masm32\lib\comctl32.lib

Как узнать, из какой библиотеки функция? Смотреть msdn.

Идем дальше…

WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

Эта строка представляет собой прототип процедуры. Если вы программируете на C или C++, то знаете, что это такое, если нет — я поясню. Функцию нельзя вызывать до того, как она будет объявлена, поэтому в начало файла часто пишутся прототипы функций, расположенных в других файлах или ниже места первого вызова функции.

TEST_DIALOG = 1000

TEST_BTN = 1001

EXIT_BTN = 1002

Этими строками мы просто объявили некоторые значения из нашего файла ресурсов new.rc. Можно было бы этого и не делать, но с ними программа будет более читаемой.

.data?

  hInstance dd ?

  icce INITCOMMONCONTROLSEX <>

В этом куске кода у нас объявляются глобальные переменные в секции неинициализированных данных. Что это такое? Это просто переменные, не имеющие начального значения. Они не занимают места в получающемся после компиляции exe-файле. В hInstance мы будем хранить указатель на модуль нашей программы (зачем — позже поясню), а в icce — структуру INITCOMMONCONTROLSEX (также объясню позже). dd — он же DWORD — тип данных «двойное слово». В C++ такой тип имеют int, long и все указатели, но C и C++ являются более типизированными языками, а в ассемблере всё сводится к двойным словам (4 байта).

Чтобы объявить секцию инициализированных данных и глобальные переменные в ней, пишут так:

.data

  vasya dd 0

  some_string db «hello, world», 0 ;строковая переменная, состоящая из db — байтов (он же BYTE)

В нашей программе тоже будет секция инициализированных данных, просто она неявно объявляется, далее я расскажу об этом.

.code

  start:

    mov icce.dwSize, SIZEOF INITCOMMONCONTROLSEX

    mov icce.dwICC, ICC_DATE_CLASSES or \

                    ICC_INTERNET_CLASSES or \

                    ICC_PAGESCROLLER_CLASS or \

                    ICC_COOL_CLASSES

    invoke InitCommonControlsEx, offset icce

    invoke GetModuleHandle, NULL

    mov hInstance, eax

    invoke DialogBoxParam, hInstance, TEST_DIALOG, 0, offset WndProc, 0

    invoke ExitProcess, eax

Что же происходит здесь? Здесь мы уже объявляем секцию исполняемого кода и метку start, которую потом объявим точкой входа.
Мы инициализируем объявленную ранее структуру icce и вызываем функцию InitCommonControlsEx. Инструкция mov загружает данные в регистр или ячейку памяти. Представьте, что мы пишем

    icce.dwSize = SIZEOF(INITCOMMONCONTROLSEX);

    icce.dwICC = ICC_DATE_CLASSES |

                    ICC_INTERNET_CLASSES |

                    ICC_PAGESCROLLER_CLASS |

                    ICC_COOL_CLASSES;

    InitCommonControlsEx(&icce);

… и всё станет понятнее. Встроенный макрос invoke используется для вызовы любых функций, у которых есть прототип (а прототипы всех WinAPI прописаны в заголовочных файлах MASM32, которые мы подключили в самом начале программы). Sizeof возвращает размер структуры в байтах, offset позволяет получить смещение в памяти какого-либо байта. Есть еще addr, позволяющая получить смещение какого-то байта, размещенного в памяти по заранее неизвестному адресу (например, для локальных переменных в процедурах).

Теперь дальше — мы получаем указатель на начало нашего исполняемого модуля. Опять-таки, представьте, что мы пишем

    hInstance = GetModuleHandle(NULL);

Все stdcall-функции возвращают значение в регистре eax, как я уже говорил, а GetModuleHandle как раз stdcall WinAPI. Ах да, у вас, вероятно, есть вопросы по этим функциям, если вы впервые слышите про WinAPI? Ну так вбейте название непонятной функции в гугл, и получите ссылку на msdn с подробнейшим описанием.

И, как вы уже могли догадаться, мы создаем диалоговое окно функцией DialogBoxParam с указанием идентификатора диалога из файла ресурса (TEST_DIALOG = 1000). Эта функция начинает цикл сообщений windows с использованием функции WndProc, на которую мы передали указатель. Это типизированная функция, далее я опишу ее, но пока что — пара слов о цикле сообщений. Каждое окно в Windows получает множество сообщений от системы или других приложений, от других окон или от своего же в непрерывном цикле. Процедура WndProc будет эти сообщения получать, а мы будем в ней обрабатывать часть сообщений. которые нужны нам.

Далее я распишу код с комментариями:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

;WndProc — это процедура, которая принимает 4 параметра

;hWin — хендл окна, которому передается сообщение

;uMsg — тип сообщения

;wParam и lParam — по сути, дополнительные данные,

;различные для каждого сообщения

WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD

  ;switch — такой же, как во всех языках. Это макрос MASM32, удобно, не так ли?

  switch uMsg

    ;WM_INITDIALOG отсылается диалогу 1 раз — когда форма загружается

    case WM_INITDIALOG

      ;Давайте установим диалогу иконку «Инфо»

      ;Для этого мы пошлем ему самому сообщение

      ;WM_SETICON с указателем на иконку

      ;которую загрузим функцией LoadIcon

      invoke SendMessage, hWin, WM_SETICON, 1, FUNC(LoadIcon, NULL, IDI_ASTERISK)

      ;FUNC — еще один удобный макрос MASM32

      ;он вызывает функцию и возвращает ее возвращаемое значение :)

      ;теперь — к обработке нажатий на кнопки

      ;за это ответственно сообщение WM_COMMAND

    case WM_COMMAND

      ;идентификатор кнопки будет в wParam

      ;не верите — вбейте в гугл «WM_COMMAND»

      switch wParam

        ;если нажали на TEST_BTN

        case TEST_BTN

          ;выведем сообщение Hello, World

          invoke MessageBox, hWin, chr$(«Hello, world!»), chr$(«Test»), 0

          ;здесь chr$(«строка») — еще один удобный макрос MASM32

          ;он создает строку в инициализированной секции данных

          ;и возвращает указатель на нее

          ;это эквивалентно записи:

          ;.data

          ;some_name db «Hello, world!»,0

          ;…

          ;invoke MessageBox, hWin, offset some_name, …

          ;Если нажали Выход

        case EXIT_BTN

          jmp exit_program ;переходим на выход

          ;ДА! Ассемблер — это язык, где никто не будет

          ;ругаться за использование в программе GOTO!

      endsw

    ;WM_CLOSE посылается окну при нажатии на крестик или при Alt+F4

    case WM_CLOSE

      exit_program:

      invoke EndDialog, hWin, 0 ;закрываем диалог

    endsw

  xor eax,eax ;всегда возвращаем 0

ret

WndProc ENDP

Ну и последнее:

Здесь мы устанавливаем точку входа на метку start, т.е. с нее начнется выполнение программы.

Ну что же, сохраним код как new.asm, закинем в одну папку new.rc, new.asm и xpmanifest.xml и скомпилируем всё следующим bat-файлом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@echo off

cls

REM ну сюда впишите свои пути

SET PATH=C:\Masm32\bin

SET INCLUDE=C:\Masm32\INCLUDE

SET LIB=C:\Masm32\LIB

REM компилируем ресурсы

Rc.exe /v %1.rc

REM компилируем исходник

ML /nologo c coff %1.asm

if errorlevel 1 goto terminate

REM линкуем всё в exe

REM !!!!!! файл 64stub.exe можно взять отсюда:

REM http://kaimi.io/2009/08/пакет-для-компиляции-masm32

REM и положить его в папку с батником и проектом

LINK /nologo %1.obj %1.res /SUBSYSTEM:WINDOWS /STUB:64stub.exe /FILEALIGN:512 /VERSION:4.0 /MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR /ignore:4078 /RELEASE /BASE:0x400000

REM ключей тут много, я описывать их не буду, вот самый примитивный вариант линкования:

rem LINK32 /nologo %1.obj  /SUBSYSTEM:WINDOWS

if errorLevel 1 goto terminate

echo OK

:terminate

После компиляции и линкования получаем программу размером 2.5 кб, которая еще и работает. Ну не прелесть ли?

Надеюсь, эта статья была вам полезна. Хотя о чем это я… Если вы дочитали до этого момента, то явно почерпнули для себя что-то полезное. Надеюсь, вам уже хочется писать свои GUI-программы на ассемблере с использованием MASM32, наполняя их функционалом, ну или хотя бы немного заинтересовала эта тема. В следующей статье я напишу что-нибудь более полезное, чем простой «Hello, world!», и представлю Вашему вниманию.

И последнее. Если после прочтения вы будете находиться в состоянии, подобном этому — не расстраивайтесь, у вас ещё все впереди! :)

Многие считают, что Assembler – уже устаревший и нигде не используемый язык, однако в основном это молодые люди, которые не занимаются профессионально системным программированием. Разработка ПО, конечно, хорошо, но в отличие от высокоуровневых языков программирования, Ассемблер научит глубоко понимать работу компьютера, оптимизировать работку с аппаратными ресурсами, а также программировать любую технику, тем самым развиваясь в направлении машинного обучения. Для понимания этого древнего ЯП, для начала стоит попрактиковаться с простыми программами, которые лучше всего объясняют функционал Ассемблера.

IDE для Assembler

Первый вопрос: в какой среде разработки программировать на Ассемблере? Ответ однозначный – MASM32. Это стандартная программа, которую используют для данного ЯП. Скачать её можно на официальном сайте masm32.com в виде архива, который нужно будет распаковать и после запустить инсталлятор install.exe. Как альтернативу можно использовать FASM, однако для него код будет значительно отличаться.

Перед работой главное не забыть дописать в системную переменную PATH строчку:

С:\masm32\bin

Программа «Hello world» на ассемблере

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

.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
msg_title db "Title", 0
msg_message db "Hello world", 0
 
.code
start:
invoke MessageBox, 0, addr msg_message, addr msg_title, MB_OK
invoke ExitProcess, 0
end start

Для начала запускаем редактор qeditor.exe в папке с установленной MASM32, и в нём пишем код программы. После сохраняем его в виде файла с расширением «.asm», и билдим программу с помощью пункта меню «Project» → «Build all». Если в коде нет ошибок, программа успешно скомпилируется, и на выходе мы получим готовый exe-файл, который покажет окно Windows с надписью «Hello world».

Сложение двух чисел на assembler

В этом случае мы смотрим, равна ли сумма чисел нулю, или же нет. Если да, то на экране появляется соответствующее сообщение об этом, и, если же нет – появляется иное уведомление.

.486
.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

include /masm32/macros/macros.asm 
uselib masm32, comctl32, ws2_32

.data

.code
start:

mov eax, 123
mov ebx, -90 
add eax, ebx

test eax, eax

jz zero 
invoke MessageBox, 0, chr$("В eax не 0!"), chr$("Info"), 0
jmp lexit

zero:
invoke MessageBox, 0, chr$("В eax 0!"), chr$("Info"), 0

lexit:
invoke ExitProcess, 0

end start

Здесь мы используем так называемые метки и специальные команды с их использованием (jz, jmp, test). Разберём подробнее:

  • test – используется для логического сравнения переменных (операндов) в виде байтов, слов, или двойных слов. Для сравнения команда использует логическое умножение, и смотрит на биты: если они равны 1, то и бит результата будет равен 1, в противном случае – 0. Если мы получили 0, ставятся флаги совместно с ZF (zero flag), которые будут равны 1. Далее результаты анализируются на основе ZF.
  • jnz – в случае, если флаг ZF нигде не был поставлен, производится переход по данной метке. Зачастую эта команда применяется, если в программе есть операции сравнения, которые как-либо влияют на результат ZF. К таким как раз и относятся test и cmp.
  • jz – если флаг ZF всё же был установлен, выполняется переход по метке.
  • jmp – независимо от того, есть ZF, или же нет, производится переход по метке.

Программа суммы чисел на ассемблере

Примитивная программа, которая показывает процесс суммирования двух переменных:

.486
.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

include /masm32/macros/macros.asm 
uselib masm32, comctl32, ws2_32

.data
msg_title db "Title", 0
A DB 1h
B DB 2h
buffer db 128 dup(?)
format db "%d",0

.code
start:

MOV AL, A
ADD AL, B

invoke wsprintf, addr buffer, addr format, eax
invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK

invoke ExitProcess, 0

end start

В Ассемблере для того, чтобы вычислить сумму, потребуется провести немало действий, потому как язык программирования работает напрямую с системной памятью. Здесь мы по большей частью манипулируем ресурсами, и самостоятельно указываем, сколько выделить под переменную, в каком виде воспринимать числа, и куда их девать.

Получение значения из командной строки на ассемблере

Одно из важных основных действий в программировании – это получить данные из консоли для их дальнейшей обработки. В данном случае мы их получаем из командной строки и выводим в окне Windows:

.486
.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

include /masm32/macros/macros.asm 
uselib masm32, comctl32, ws2_32

.data

.code
start:

call GetCommandLine ; результат будет помещен в eax
 
push 0
push chr$("Command Line")
push eax ; текст для вывода берем из eax
push 0
call MessageBox

push 0
call ExitProcess

end start

Также можно воспользоваться альтернативным методом:

.486
.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

include /masm32/macros/macros.asm 
uselib masm32, comctl32, ws2_32

.data

.code
start:

call GetCommandLine ; результат будет помещен в eax
 
invoke GetCommandLine
invoke MessageBox, 0, eax, chr$("Command Line"), 0
invoke ExitProcess, 0

push 0
call ExitProcess

end start

Здесь используется invoke – специальный макрос, с помощью которого упрощается код программы. Во время компиляции макрос-команды преобразовываются в команды Ассемблера. Так или иначе, мы пользуемся стеком – примитивным способом хранения данных, но в тоже время очень удобным. По соглашению stdcall, во всех WinAPI-функциях переменные передаются через стек, только в обратном порядке, и помещаются в соответствующий регистр eax.

Циклы в ассемблере

Вариант использования:

.data

msg_title db "Title", 0
A DB 1h
buffer db 128 dup(?)
format db "%d",0

.code
start:

mov AL, A
.REPEAT
inc AL

.UNTIL AL==7

invoke wsprintf, addr buffer, addr format, AL
invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK
 
invoke ExitProcess, 0

end start
.data

msg_title db "Title", 0
buffer db 128 dup(?)
format db "%d",0

.code
start:

mov eax, 1
mov edx, 1

.WHILE edx==1
inc eax
.IF eax==7
.BREAK
.ENDIF
.ENDW

invoke wsprintf, addr buffer, addr format, eax
invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK
 
invoke ExitProcess, 0

Для создания цикла используется команда repeat. Далее с помощью inc увеличивается значение переменной на 1, независимо от того, находится она в оперативной памяти, или же в самом процессоре. Для того, чтобы прервать работу цикла, используется директива «.BREAK». Она может как останавливать цикл, так и продолжать его действие после «паузы». Также можно прервать выполнение кода программы и проверить условие repeat и while с помощью директивы «.CONTINUE».

Сумма элементов массива на assembler

Здесь мы суммируем значения переменных в массиве, используя цикл «for»:

.486
.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

include /masm32/macros/macros.asm 
uselib masm32, comctl32, ws2_32

.data

msg_title db "Title", 0
A DB 1h
x dd 0,1,2,3,4,5,6,7,8,9,10,11
n dd 12

buffer db 128 dup(?)
format db "%d",0

.code
start:
mov eax, 0
mov ecx, n
mov ebx, 0
L: add eax, x[ebx]
add ebx, type x
dec ecx
cmp ecx, 0
jne L

invoke wsprintf, addr buffer, addr format, eax
invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK
 
invoke ExitProcess, 0

end start

Команда dec, как и inc, меняет значение операнда на единицу, только в противоположную сторону, на -1. А вот cmp сравнивает переменные методом вычитания: отнимает одно значение из второго, и, в зависимости от результата ставит соответствующие флаги.

С помощью команды jne выполняется переход по метке, основываясь на результате сравнения переменных. Если он отрицательный – происходит переход, а если операнды не равняются друг другу, переход не осуществляется.

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


Post Views:
60 290

alex-rudenkiy

5 / 5 / 0

Регистрация: 02.01.2013

Сообщений: 438

1

02.04.2015, 18:47. Показов 8548. Ответов 7

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Люди помогите разобраться с WINDOWS.INC. Я когда добавлял этот inc, вылазила такая ошибка

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Assembling: ex.asm
WINDOWS.INC(7938) : error A2179: structure improperly initialized
WINDOWS.INC(7938) : error A2008: syntax error : in structure
WINDOWS.INC(7950) : error A2179: structure improperly initialized
WINDOWS.INC(7950) : error A2008: syntax error : in structure
WINDOWS.INC(7968) : error A2005: symbol redefinition : hinst
WINDOWS.INC(8747) : error A2179: structure improperly initialized
WINDOWS.INC(8747) : error A2008: syntax error : in structure
WINDOWS.INC(8754) : error A2179: structure improperly initialized
WINDOWS.INC(8754) : error A2008: syntax error : in structure
WINDOWS.INC(8759) : error A2179: structure improperly initialized
WINDOWS.INC(8759) : error A2008: syntax error : in structure
.....
WINDOWS.INC(10188) : fatal error A1012: error count exceeds 100; stopping assemb
ly

Потом я добавил такую строчку «option casemap:none» в надежде исправить ошибку, но и потом тоже вылезла ошибка.

Assembler
1
2
3
4
5
1.obj : error LNK2001: unresolved external symbol _MessageBoxA@16
1.obj : error LNK2001: unresolved external symbol _CreateThread@24
1.obj : error LNK2001: unresolved external symbol _ExitProcess@4
1.obj : error LNK2001: unresolved external symbol _ExitThread@4
1.exe : fatal error LNK1120: 4 unresolved externals

Что делать ?



0



NoNaMe

Модератор

Эксперт по компьютерным сетям

1541 / 626 / 127

Регистрация: 10.06.2009

Сообщений: 2,436

02.04.2015, 22:42

2

Вызовы каким образом осуществляются?

Assembler
1
.model flat, stdcall

Как вариант cdecl
Как вариант fastcall
Как вариант pascal
Я не знаю как вы осуществляете свои вызовы покажите исходник с которым работаете, я не «Ванга»….



0



Shvonder

46 / 35 / 24

Регистрация: 16.03.2015

Сообщений: 179

03.04.2015, 04:01

3

Assembler
1
2
3
4
5
6
7
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
 
.data
; [B]...[/B]

( если путь каталога отличный от «\masm32\», изменить )



0



alex-rudenkiy

5 / 5 / 0

Регистрация: 02.01.2013

Сообщений: 438

03.04.2015, 14:26

 [ТС]

4

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.386
 
.model flat, stdcall
 
 
 
include user32.inc
 
include kernel32.inc
 
include WINDOWS.INC
 
.data
MsgBoxCaption  db "Win32 Программа",0
MsgBoxText     db "Привет пользователь пк!",0
 
.code
start:
     invoke MessageBox, NULL, ADDR MsgBoxText,\
ADDR MsgBoxCaption, MB_OK
     invoke ExitProcess, NULL
end start



0



Модератор

Эксперт по компьютерным сетям

1541 / 626 / 127

Регистрация: 10.06.2009

Сообщений: 2,436

04.04.2015, 02:34

5

D:\masm\masm32\bin\Link.exe /LIBPATH:»D:\masm\masm32\lib» /SUBSYSTEM:WINDOWS /MERGE:.data=.text /ALIGN:16 /OPT:NOREF «%1.obj»
А так-же вы не добавили библиотеки, но всёравно хотите использовать их функции.
Либо вам нужно их самому описать.
Либо добавить их.
includelib kernel32.lib
includelib user32.lib



0



5 / 5 / 0

Регистрация: 02.01.2013

Сообщений: 438

04.04.2015, 13:25

 [ТС]

6

WINDOWS.INC(7938) : error A2179: structure improperly initialized
WINDOWS.INC(7938) : error A2008: syntax error : in structure
WINDOWS.INC(7950) : error A2179: structure improperly initialized
WINDOWS.INC(7950) : error A2008: syntax error : in structure
WINDOWS.INC(7968) : error A2005: symbol redefinition : hinst
WINDOWS.INC(8747) : error A2179: structure improperly initialized
WINDOWS.INC(8747) : error A2008: syntax error : in structure
WINDOWS.INC(8754) : error A2179: structure improperly initialized
WINDOWS.INC(8754) : error A2008: syntax error : in structure
WINDOWS.INC(8759) : error A2179: structure improperly initialized
WINDOWS.INC(8759) : error A2008: syntax error : in structure
WINDOWS.INC(8765) : error A2179: structure improperly initialized
WINDOWS.INC(8765) : error A2008: syntax error : in structure
WINDOWS.INC(8772) : error A2179: structure improperly initialized
WINDOWS.INC(8772) : error A2008: syntax error : in structure
WINDOWS.INC(8782) : error A2179: structure improperly initialized
WINDOWS.INC(8782) : error A2008: syntax error : in structure
WINDOWS.INC(8788) : error A2179: structure improperly initialized
WINDOWS.INC(8788) : error A2008: syntax error : in structure
WINDOWS.INC(8795) : error A2179: structure improperly initialized
WINDOWS.INC(8795) : error A2008: syntax error : in structure
WINDOWS.INC(9041) : error A2179: structure improperly initialized
WINDOWS.INC(9041) : error A2008: syntax error : in structure
WINDOWS.INC(9927) : error A2179: structure improperly initialized
WINDOWS.INC(9927) : error A2008: syntax error : in structure
WINDOWS.INC(9940) : error A2179: structure improperly initialized
WINDOWS.INC(9940) : error A2008: syntax error : in structure
WINDOWS.INC(9952) : error A2179: structure improperly initialized
WINDOWS.INC(9952) : error A2008: syntax error : in structure
WINDOWS.INC(9957) : error A2179: structure improperly initialized
WINDOWS.INC(9957) : error A2008: syntax error : in structure
WINDOWS.INC(9962) : error A2179: structure improperly initialized
WINDOWS.INC(9962) : error A2008: syntax error : in structure
WINDOWS.INC(9967) : error A2179: structure improperly initialized
WINDOWS.INC(9967) : error A2008: syntax error : in structure
WINDOWS.INC(9972) : error A2179: structure improperly initialized
WINDOWS.INC(9972) : error A2008: syntax error : in structure
WINDOWS.INC(9979) : error A2179: structure improperly initialized
WINDOWS.INC(9979) : error A2008: syntax error : in structure
WINDOWS.INC(9986) : error A2179: structure improperly initialized
WINDOWS.INC(9986) : error A2008: syntax error : in structure
WINDOWS.INC(9993) : error A2179: structure improperly initialized
WINDOWS.INC(9993) : error A2008: syntax error : in structure
WINDOWS.INC(9998) : error A2179: structure improperly initialized
WINDOWS.INC(9998) : error A2008: syntax error : in structure
WINDOWS.INC(10004) : error A2179: structure improperly initialized
WINDOWS.INC(10004) : error A2008: syntax error : in structure
WINDOWS.INC(10012) : error A2179: structure improperly initialized
WINDOWS.INC(10012) : error A2008: syntax error : in structure
WINDOWS.INC(10013) : error A2179: structure improperly initialized
WINDOWS.INC(10013) : error A2008: syntax error : in structure
WINDOWS.INC(10017) : error A2179: structure improperly initialized
WINDOWS.INC(10017) : error A2008: syntax error : in structure
WINDOWS.INC(10023) : error A2179: structure improperly initialized
WINDOWS.INC(10023) : error A2008: syntax error : in structure
WINDOWS.INC(10030) : error A2179: structure improperly initialized
WINDOWS.INC(10030) : error A2008: syntax error : in structure
WINDOWS.INC(10037) : error A2179: structure improperly initialized
WINDOWS.INC(10037) : error A2008: syntax error : in structure
WINDOWS.INC(10042) : error A2179: structure improperly initialized
WINDOWS.INC(10042) : error A2008: syntax error : in structure
WINDOWS.INC(10050) : error A2179: structure improperly initialized
WINDOWS.INC(10050) : error A2008: syntax error : in structure
WINDOWS.INC(10057) : error A2179: structure improperly initialized
WINDOWS.INC(10057) : error A2008: syntax error : in structure
WINDOWS.INC(10065) : error A2179: structure improperly initialized
WINDOWS.INC(10065) : error A2008: syntax error : in structure
WINDOWS.INC(10072) : error A2179: structure improperly initialized
WINDOWS.INC(10072) : error A2008: syntax error : in structure
WINDOWS.INC(10082) : error A2179: structure improperly initialized
WINDOWS.INC(10082) : error A2008: syntax error : in structure
WINDOWS.INC(10083) : error A2179: structure improperly initialized
WINDOWS.INC(10083) : error A2008: syntax error : in structure
WINDOWS.INC(10087) : error A2179: structure improperly initialized
WINDOWS.INC(10087) : error A2008: syntax error : in structure
WINDOWS.INC(10088) : error A2179: structure improperly initialized
WINDOWS.INC(10088) : error A2008: syntax error : in structure
WINDOWS.INC(10093) : error A2179: structure improperly initialized
WINDOWS.INC(10093) : error A2008: syntax error : in structure
WINDOWS.INC(10099) : error A2179: structure improperly initialized
WINDOWS.INC(10099) : error A2008: syntax error : in structure
WINDOWS.INC(10106) : error A2179: structure improperly initialized
WINDOWS.INC(10106) : error A2008: syntax error : in structure
WINDOWS.INC(10113) : error A2179: structure improperly initialized
WINDOWS.INC(10113) : error A2008: syntax error : in structure
WINDOWS.INC(10119) : error A2179: structure improperly initialized
WINDOWS.INC(10119) : error A2008: syntax error : in structure
WINDOWS.INC(10130) : error A2179: structure improperly initialized
WINDOWS.INC(10130) : error A2008: syntax error : in structure
WINDOWS.INC(10138) : error A2179: structure improperly initialized
WINDOWS.INC(10138) : error A2008: syntax error : in structure
WINDOWS.INC(10149) : error A2179: structure improperly initialized
WINDOWS.INC(10149) : error A2008: syntax error : in structure
WINDOWS.INC(10161) : error A2179: structure improperly initialized
WINDOWS.INC(10161) : error A2008: syntax error : in structure
WINDOWS.INC(10169) : error A2179: structure improperly initialized
WINDOWS.INC(10169) : error A2008: syntax error : in structure
WINDOWS.INC(10177) : error A2179: structure improperly initialized
WINDOWS.INC(10177) : error A2008: syntax error : in structure
WINDOWS.INC(10188) : error A2179: structure improperly initialized
WINDOWS.INC(10188) : fatal error A1012: error count exceeds 100; stopping assemb
ly



0



NoNaMe

Модератор

Эксперт по компьютерным сетям

1541 / 626 / 127

Регистрация: 10.06.2009

Сообщений: 2,436

04.04.2015, 18:49

7

Лучший ответ Сообщение было отмечено alex-rudenkiy как решение

Решение

Спойлеры….
D:\masm\masm32\bin\ml /I «D:\masm\masm32\include» /I «D:\masm\masm32\macros» /c /Cp /coff /Gz «%1.asm»

Assembler
1
2
.386
.model flat
Assembler
1
/CP == option casemap :none
Assembler
1
/Gz == stdcall

Кликните здесь для просмотра всего текста

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    .386
    .model flat
;    option casemap :none 
 
    include windows.inc       ; Всегда в самом начале
;    include macros.asm       ; MASM потдерживает дополнительные макросы.
    include user32.inc
    include kernel32.inc
 
    includelib user32.lib
    includelib kernel32.lib
 
.data
MsgBoxCaption  db "Win32 Программа",0
MsgBoxText     db "Привет пользователь пк!",0
.code
start: invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK
invoke ExitProcess, NULL
end start



1



5 / 5 / 0

Регистрация: 02.01.2013

Сообщений: 438

05.04.2015, 11:33

 [ТС]

8

Спасибо огромное, заработало



0




     Оглавление

    Исходники

    Программы

    Справочник

Есть вопросы - пишите...

Разминка. Первая программа

    
Итак, приступим. Нам понадобится сам MASM32, который легко найти в Интернете.
Для своих проектов создадим папку, но, желательно не внутри MASM32. Назовем ее, но так,
чтобы в названии были только английские буквы — компилятор, гад, по-русски не понимает и
при компилляции будут трудности. Если имя не придумывается, то назовем просто ASM. Получилось? Тогда начнем. Немножко теории. В ассемблере
любая программа содержит сегмент данных — он отмечается символом .data, сегмент констант
— .const и сегмент кода — .code. В сегмент данных заносятся переменные, которые будут
доступны из любой точки программы (глобальные переменные). То же самое относится и к
сегменту констант. Тогда в общем виде структура программы имеет вид:



    .data — глобальные переменные

    .const — константы (по ходу дела не меняются)

    .code — исполняемый код прогаммы

    start: — его начало и наконец,

    end start — его окончание.

MASM32 использует плоскую модель памяти — никаких сегментов памяти нет,
она, в принципе, доступна вся. Об этом — в самом начале программы мы должны
сообщить компиллятору (который сделает их нашего текста исполняемый .ехе файл):

     .386 ; процессор

     .model flat, stdcall ; 32 разрядная модель памяти

     option casemap :none ; различает строчные
и заглавные буквы

Накопленный человечеством опыт собран в библиотеках. Опыт программистов
также собран в библиотеках — динамических и статических. Нам не нужно изобретать
велосипед заново — воспользуемся
тем, что уже есть (по крайней мере, на первых порах).
Windows содержит огромное количество функций в библиотеках динамической компоновки (DLL — dynamic link library),
эти функции часто называют API(Application Programming Interface).
Подключим к нашему проекту библиотеки. Это делается помощью include и includelib так:

    include \masm32\include\user32.inc

    includelib \masm32\lib\user32.lib

Если мы впишем в текст программы эти строки, то к нашему проекту будет подключена
библиотека user32. Одной библиотекой, как правило, не обойтись, чаще всего стандартный набор
выглядит так:



; Подключаемые файлы.

include \masm32\include\windows.inc

include \masm32\include\masm32.inc

include \masm32\include\gdi32.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

include \masm32\include\Comctl32.inc

include \masm32\include\comdlg32.inc

include \masm32\include\shell32.inc

include \MASM32\include\oleaut32.inc

; Подключаемые библиотеки.

includelib \masm32\lib\masm32.lib

includelib \masm32\lib\gdi32.lib

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\Comctl32.lib

includelib \masm32\lib\comdlg32.lib

includelib \masm32\lib\shell32.lib

includelib \masm32\lib\oleaut32.lib


Все понятно? Если не все (или все не) — ничего страшного, потом разберемся.
Едем дальше. Наша первая программа:

———————————————Линия отреза———————————————



.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

TitleMsg db «Первая программа»,0

TextMsg db «Пишем здесь чаво-нибудь, типа — это я сам сделал(а)!» ,0

.code

start:

invoke MessageBox, NULL,ADDR TextMsg,ADDR TitleMsg, MB_OK

invoke ExitProcess, NULL

end start

uild

————————————-Линия отреза——————————————————

Аккуратно копируем то, что между линиями отреза (они не должны попасть в копируемую область!),
откравыем MASM32 editor, в меню File выбираем пункт New и вставляем туда скопированное. Теперь сохраним созданный файл
в нашей папке под каким-нибудь название, и, что очень важно, с расширением .asm, ну, например, first.asm. Получилось?
Если нет — то повторим все еще раз (или не раз, пока не получится). Теперь — компиляция, т.е. создание .ехе-файла. В меню
редактора выбираем пункт Project и в нем — пункт Build All. Выдохнули и нажали. Если все сделано правильно, через
какое-то время на экране появится что-то вроде:

Если картинка похожа, то .ехе-файл создан. Открываем нашу папку и находим его. Если папка была сначала
пустой, то после компиляции там три файла — один first.asm — это наш исходник, другой, похожий на использованную
туалетную бумагу — first.obj, и наконец, наш файл first.exe. Щелкаем по нему мышкой. Работает? Если не работает —
ищем, что сделано неправильно, а если работает — то еще похожий пример:

———————————————Линия отреза———————————————



.386

.model flat, stdcall

option casemap :none

include \masm32\include\windows.inc

include \masm32\include\masm32.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\masm32.lib

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

.data

TextMsg1 db «Здесь — текст, типа — это я сам сделал(а)!» ,0

TextMsg2 db» (чтобы показывать друзьям и знакомым )»,0

TextMsg3 db «Copyright © А здесь — свою ФИО., «,13,10,»(полностью, чтобы они поверили)»,13,10,»ну и, конечно, -All Right Reserved»,0

.code

start:

invoke AboutBox,NULL,NULL,NULL,ADDR TextMsg1,ADDR TextMsg2,ADDR TextMsg3

invoke ExitProcess, NULL

end start

end start

————————————-Линия отреза——————————————————

Повторим все то, что мы сделали раньше. Запускается? Для тех, у кого рука дрожит и текст
не копируется, исходники — пример 1 и пример 2

Ну вот, разминка закончена. Тот, кто понял, что MASM32 он уже полностью освоил, может
расслабиться, а для остальных — продолжение на следующей странице…

   В начало
   Дальше

MASM32 и OpenGL

Запуск
.EXE-программы
может быть осуществлён с помощью двойного
щелчка мышью.

Если
вы создали программу, которая ничего
не выводит на экран, то за её работой
можно наблюдать при помощи
программы-отладчика, например, OllyDbg.
Отладчики позволяют наблюдать за
изменением содержимого регистров и
флагов. Подробнее работа в отладчике
OllyDbg будет описана ниже.

2.4. Инструментальный пакет masm32

В
п.2.3 отмечено, что для создания программ
на ассемблере в Windows,
необходим текстовый редактор и компилятор.
Реальные программы Win32 используют также
внешние функции, стандартные константы
и переменные, ресурсы и много другое.
Всё это требует дополнительных файлов,
которые есть в инструментальном пакете
MASM32. Важно понять, что MASM32 не компилятор,
а сборник для программирования под
Win32, в который входит 32-битный компилятор
MASM.

Инструментальный
пакет MASM32
предназначен для создания приложений
Windows
на языке ассемблера и содержит все
необходимые инструменты, к тому же он
распространяется бесплатно.

Основные сведения и порядок работы в пакете masm32:

1.
Для создания исходных текстов программ
рекомендуется использовать текстовый
процессор пакета MASM32
под названием QEDITOR
(от Quick
Editor,
быстрый редактор):

После
набора сохранить текст программы
командой File
Save,
указать папку BIN
и расширение .ASM,
например MYPROG.ASM.

2.
Командой Project
Build
All
создать объектный и исполнимый файлы:

Если
исходный текст программы набран без
ошибок, то в папке, где он хранился,
увидим два новых файла: MYPROG.OBJ
и MYPROG.EXE.

3.
Когда объектный и исполнимый файлы
созданы, запустите программу на
выполнение. Для этого можно дважды
щелкнуть мышью по названию исполнимого
файла (в папке BIN)
или запустить программу через редактор
QEDITOR
командой Project
Run
Program.

2.5. Примеры

Пример
0
.
«Скелет»
стандартной программы

.386

.model flat, stdcall

option casemap :none

;подключение
необходимых
библиотек

include
\MASM32\INCLUDE\windows.inc

include
\MASM32\INCLUDE\masm32.inc

include
\MASM32\INCLUDE\gdi32.inc

include
\MASM32\INCLUDE\user32.inc

include
\MASM32\INCLUDE\kernel32.inc

includelib
\MASM32\LIB\masm32.lib

includelib
\MASM32\LIB\gdi32.lib

includelib
\MASM32\LIB\user32.lib

includelib
\MASM32\LIB\kernel32.lib

;раздел, где
объявляются все константы

.const

;раздел, где
объявляются переменные, уже имеющие
какое-то значение

.data

;раздел, где
объявляются переменные, еще не имеющие
значения

.data?

.code

start: ;с этого слова
начинается код программы

invoke ExitProcess,0

end start ;с этого
слова заканчивается код программы

Сохраните
этот «скелет» в отдельном файле для
удобства и используйте как заготовку.

Пример
1
.
Структура
программы и основные директивы

Построчно
разберём простейшую программу.

Текст
программы на ассемблере содержит кроме
инструкций процессору еще и служебную
информацию

(в виде директив),
предназначенную для программы-ассемблера.

Начнем
с простого. В первой программе не будет
вызовов API-функций,
ее цель – понять саму структуру программы
на языке ассемблера для Windows.
Поэтому программа, прибавляющая к 2
число 3, будет выглядеть следующим
образом:

.386

.model
flat, stdcall

.code

start:

mov
eax,
8

add
eax,
8

ret

end
start

В
ней инструкции процессора mov,
add,
ret
окружены
директивами. Первые три директивы
начинаются с точки.

Директива
.386
показывает,
для какого процессора предназначена
программа. В нашем случае это процессор
Intel
80386 и более поздние модели, ведь семейство
процессоров Intel
совместимо снизу вверх.

Вторая
директива .model
flat,
stdcall
показывает,
в какой среде будет работать программа.
Все программы работают под управлением
операционной системы, которая их
запускает и обеспечивает взаимодействие
с внешней средой. Директива .model задаёт
модель памяти flat (плоская или сплошная)
для нашей программы. Эта модель памяти
используется для программирования под
Windows,
т.е. директива говорит о том, что именно
для операционных систем семейства
Windows
952
предназначена программа.

Stdcall
— это «уговор» о том, кто будет
чистить параметры (функция, которую
вызвали, или сам вызывающий). Мы всегда
будем использовать вариант «функция
чистит свои параметры». Он и называется
stdcall. Однако такое объяснение не полное,
и мы вернемся к параметру stdcall при
объяснении вызова функций. К этому
моменту вы уже будете знать, что такое
стек.

Третья
директива .code
показывает,
где начинаются сами команды процессора.
Когда операционная система пытается
запустить программу, она ищет в ней
инструкцию, с которой нужно начать, и
отправляет ее процессору. Когда же
инструкции кончаются, операционная
система «подхватывает» программу и
помогает ей правильно завершиться,
чтобы освободить место другим, ведь
Windows
– многозадачная операционная система,
способная выполнять одновременно
несколько программ. Уйти из-под «опеки»
операционной системы помогает инструкция
ret.

Инструкция,
с которой начинается программа, обычно
помечается последовательностью символов
с двоеточием на конце (меткой). В нашем
случае это start:.
Там, где оканчивается последовательность
команд процессора, в программе должна
стоять директива end
<метка первой инструкции программы>
,
в нашем случае это
end
start.
Эта директива, а также сама метка не
переводятся в инструкции ассемблера,
а лишь помогают получить программу,
которую способен выполнить процессор.
Без них программа-ассемблер не поймет,
с какой инструкции процессор начнет
работу.

Отладка

Программа
ничего не выводит на экран, поэтому за
для изучения её работы воспользуемся
программой-отладчиком OllyDbg.
Чтобы открыть программу в отладчике,
достаточно загрузить OllyDbg и открыть
программу как обычный документ –
File-Open.

В
верхней левой части отладчика можно
увидеть свою программу. Вверху справа
– регистры процессора.

Внизу
слева — байты памяти (OllyDbg сразу же
показывает секцию данных программы).
Внизу справа отображается содержимое
стека (работа со стеком будет описана
ниже).

Необходимо
помнить, что Ollydbg это отладчик и у него
есть свои ограничения. Рекомендуется
закрывать его каждый раз перед загрузкой
новой программы.

С
помощью клавиши F8
можно выполнить программу по шагам и
просмотреть, как меняется содержимое
регистров. Ответьте на вопрос, почему
в результате сложения 8+8 регистр EAX
стал равен 10? Состояние флагов также
меняется. Мы видим, что после выполнения
первой команды флаг Z
опустился (обратился в ноль), потому что
результат выполнения операции не равен
нулю.

Пример
2
.
Использование
функций
API

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

API
– это стандартные функции, на основе
которых и пишут все программы для
Windows.
Например MessageBox выдаёт сообщение на
экран, PostQuitMessage сообщит Windows, что программа
хочет закончить работу и т.д. Все они
уже готовы – остается только вызывать
их. Получается, что используя API-функции,
мы применяем элементы программирования
высокого уровня.

Находятся
API-функции
обычно в динамически загружаемых
библиотеках – файлах с расширением
.DLL.

При
вызове каждой API-функции
надо передавать параметры, т.е. аргументы,
с которыми ей предстоит работать. Раньше
это делалось так: параметры заталкивались
в стек (команда push) задом наперед –
сначала последний, потом предпоследний
и т.д., а затем вызывалась сама программа
(команда call). Например:

push addr Text2

push addr Text1

push hWnd

call MessageBox

Такая
запись допускается и сейчас, но существует
и более компактная: invoke
MessageBox, hWnd, Text1, Text2

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

Рассмотрим
программу с использованием функций
API.
Прежде чем приступить к выводу на экран,
изучим более простую процедуру
ExitProcess.
Её
вызывает каждая Windows-программа,
чтобы завершить свою работу. В ассемблере
под DOS
мы пользовались инструкцией возврата
ret.
Но ExitProcess
действует
правильнее, не только возвращая управление
операционной системе, но и освобождая
занятые программой ресурсы.

В
следующем листинге показана программа
для Windows,
которая только и делает, что правильно
завершается.

.386

.model flat, stdcall

option casemap:none

includelib
C:\MASM32\LIB\kernel32.lib

ExitProcess proto :DWORD

.code

start:

push 0

call
ExitProcess

end
start

Вызываемая
в ней процедура ExitProcess
требует
одного параметра – это код завершения,
возвращаемый операционной системе. Он
передается процедуре командой push
0
.
Число 0 считается признаком удачного
завершения.

Поскольку
ExitProcess

«чужая» процедура, не определенная в
нашей программе, ассемблер должен знать,
где она находится, а также (для проверки
– она ли это) число и размер ее параметров.

Сведения
об адресе и параметрах процедуры хранятся
в файле библиотеки kernel32.lib,
который подключается к ассемблерному
тексту директивой includelib
C:\MASM32\LIB\kernel32.lib.

Перед
тем как создать инструкцию вызова этой
процедуры компоновщик сравнивает
сведения из библиотеки с прототипом
ExitProcess
proto
:
DWORD,
и если все совпадает, создает пригодный
к исполнению файл с расширением .EXE.
Прототип процедуры очень прост и состоит
из имени, слова proto
и
параметров. В нашем случае параметр
один – это двойное слово (то есть 4 байта)
DWORD.
Если параметров несколько, они разделяются
запятой.

Пример
3
.
Вывод
строки на экран

Создадим
программу, выводящую на экран фразу
“Hello,
world!”:

.386

.model
flat, stdcall

option casemap:none

ExitProcess proto :dword

GetStdHandle
proto :dword

WriteConsoleA proto :dword,
:dword, :dword, :dword, :dword

includelib
C:\MASM32\LIB\kernel32.lib

.data

stdout dd ?

msg db “Hello, world!”,
0dh, 0ah

cWritten dd ?

.code

start:

invoke GetStdHandle, -11

mov stdout, eax

invoke WriteConsoleA,
stdout, ADDR msg, sizeof msg, ADDR cWritten, 0

invoke
ExitProcess,
0

end
start

В
программе вызываются три процедуры:
GetStdHandle,
WriteConsoleA
и
ExitProcess.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

  • Install java 64 bit windows 10
  • Inshot скачать на компьютер для windows скачать бесплатно
  • Install iis on windows 10
  • Insert your windows installation or recovery media
  • Inassimilable boot device windows 10 как исправить