masm32汇编环境配置

下载并安装masm32

打开http://www.masm32.com/download/masm32v11r.zip

下载masm32,并将压缩包解压,解压完成后,运行安装文件install.exe,具体安装步骤除了指定路径,就一路YES|OK就可以。

然后在这两处添加masm32中lib和include文件夹的地址

image-20240829215518802

image-20240829215618722

容易出现的问题

可能在编译的时候出现错误:A2026 constant expected

解决方案:https://blog.csdn.net/weixin_50836014/article/details/124880063

代码示例

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
.386    ;指令集
.model flat,stdcall
OPTION CASEMAP:none

;__UNICODE__ EQU

include windows.inc
include kernel32.inc
include user32.inc
include Gdi32.inc

includelib user32.lib
includelib kernel32.lib
includelib Gdi32.lib

.const
CLASS_NAME db "MainWClass",0
WINDOW_NAME db "51ASM",0

.code
MainWndProc proc hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.if uMsg==WM_CLOSE
invoke PostQuitMessage,0
mov eax,TRUE
ret
.endif
invoke DefWindowProc,hwnd,uMsg,wParam,lParam
ret
MainWndProc endp

START proc
local @wcx:WNDCLASSEX
local @hInstance:HINSTANCE

mov @wcx.cbSize,sizeof @wcx
mov @wcx.style,CS_HREDRAW or CS_VREDRAW
mov @wcx.lpfnWndProc,offset MainWndProc
mov @wcx.cbClsExtra,0
mov @wcx.cbWndExtra,0
invoke GetModuleHandle,NULL
mov @hInstance,eax
mov @wcx.hInstance,eax
invoke LoadIcon,NULL,IDI_APPLICATION
mov @wcx.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov @wcx.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov @wcx.hbrBackground,eax
mov @wcx.lpszMenuName,NULL
mov @wcx.lpszClassName,offset CLASS_NAME
mov @wcx.hIconSm,0

invoke RegisterClassEx,addr @wcx
.if eax==0
ret
.endif

invoke CreateWindowEx,
NULL,\
offset CLASS_NAME,\
offset WINDOW_NAME,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
@hInstance\
NULL

mov @hWnd,eax
.if eax==0
ret
.endif

INVOKE ShowWindow,@hWnd,SW_NORMAL

;消息循环
.while TRUE
INVOKE GetMessage,ADDR msg,NULL,0,0
.if eax==0
.break
.elseif eax==-1
.break
.endif
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr @msg
.endw
invoke ExitProcess,0
ret
START endp

end START

这是一个简单的 Windows 应用程序框架,用于创建一个窗口并处理基本的消息循环。代码是用 x86 汇编语言编写的,下面是对每一行代码的分析:

指令集和模型设置

1
2
3
.386    ; 指令集,表示使用 80386 及以上的指令集
.model flat,stdcall
OPTION CASEMAP:none ; 关闭大小写不敏感的选项
  • .386:指明代码使用 80386 或更高版本的指令集。
  • .model flat,stdcall:选择平面内存模型和 stdcall 调用约定。
  • OPTION CASEMAP:none:关闭大小写不敏感处理,区分大小写。

引入必要的库和头文件

1
2
3
4
5
6
7
8
include windows.inc
include kernel32.inc
include user32.inc
include Gdi32.inc

includelib user32.lib
includelib kernel32.lib
includelib Gdi32.lib
  • include windows.inc 等:包含 Windows API 函数的声明。
  • includelib:链接所需的 Windows 库,这些库包含了 Windows API 的实现。

常量定义

1
2
3
.const
CLASS_NAME db "MainWClass",0
WINDOW_NAME db "51ASM",0
  • CLASS_NAMEWINDOW_NAME 定义了窗口类名和窗口名的字符串。

主窗口过程 (Window Procedure)

1
2
3
4
5
6
7
8
9
10
.code
MainWndProc proc hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.if uMsg == WM_CLOSE
invoke PostQuitMessage,0
mov eax,TRUE
ret
.endif
invoke DefWindowProc,hwnd,uMsg,wParam,lParam
ret
MainWndProc endp
  • MainWndProc proc:这是窗口过程的入口,处理发送到窗口的消息。
  • uMsg == WM_CLOSE:如果收到 WM_CLOSE 消息(窗口关闭),调用 PostQuitMessage 结束消息循环。
  • invoke DefWindowProc:对于未处理的消息,调用默认的窗口过程。
  • ret:返回结果。

程序入口点 (Entry Point)

1
2
3
4
5
START proc
local @wcx:WNDCLASSEX
local @hInstance:HINSTANCE
local @hWnd:HWND
local @msg:MSG
  • START proc:程序的入口点,定义局部变量。
  • @wcx:WNDCLASSEX:定义一个 WNDCLASSEX 结构,用于注册窗口类。
  • @hInstance:HINSTANCE:存储应用程序的实例句柄。
  • @hWnd:HWND:存储创建的窗口句柄。
  • @msg:MSG:存储消息结构,用于消息循环。

注册窗口类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mov @wcx.cbSize,sizeof @wcx
mov @wcx.style,CS_HREDRAW or CS_VREDRAW
mov @wcx.lpfnWndProc,offset MainWndProc
mov @wcx.cbClsExtra,0
mov @wcx.cbWndExtra,0
invoke GetModuleHandle,NULL
mov @hInstance,eax
mov @wcx.hInstance,eax
invoke LoadIcon,NULL,IDI_APPLICATION
mov @wcx.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov @wcx.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov @wcx.hbrBackground,eax
mov @wcx.lpszMenuName,NULL
mov @wcx.lpszClassName,offset CLASS_NAME
mov @wcx.hIconSm,0
  • 设置 @wcx 的各个字段,用于窗口类的注册:
    • cbSize:结构体的大小。
    • style:窗口类的风格,这里是横向和纵向重新绘制。
    • lpfnWndProc:窗口过程的指针。
    • hInstance:应用程序的实例句柄。
    • hIcon:窗口的图标。
    • hCursor:窗口的光标。
    • hbrBackground:窗口背景的画刷。
    • lpszClassName:窗口类名。

注册窗口类并创建窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
invoke RegisterClassEx,addr @wcx
.if eax==0
ret
.endif

invoke CreateWindowEx,
NULL,
offset CLASS_NAME,
offset WINDOW_NAME,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
@hInstance,
NULL
  • invoke RegisterClassEx:注册窗口类。
  • invoke CreateWindowEx:创建窗口。
  • 如果注册或创建失败,程序会返回(退出)。

显示窗口

1
2
3
4
5
6
mov @hWnd,eax
.if eax == 0
ret
.endif

invoke ShowWindow,@hWnd,SW_NORMAL
  • ShowWindow:显示创建的窗口。

消息循环

1
2
3
4
5
6
7
8
9
10
11
12
13
    .while TRUE
invoke GetMessage,ADDR @msg,NULL,0,0
.if eax == 0
.break
.elseif eax == -1
.break
.endif
invoke TranslateMessage,addr @msg
invoke DispatchMessage,addr @msg
.endw
invoke ExitProcess,0
ret
START endp
  • while TRUE:开始消息循环。
  • GetMessage:从消息队列中获取消息。
  • TranslateMessage:将虚拟按键消息翻译为字符消息。
  • DispatchMessage:将消息分发到窗口过程。
  • ExitProcess:当消息循环结束时,退出程序。

运行结果

image-20240829220057439