抱歉,还是只能用米国的软件以及技术以及等等等等。。。。。。,所以各位勿怪。
如果配置完成,在vs2022调试环境下正确编译运行后,可以看到如下画面:
在VS022中开发学习汇编必然很方便。
这里可以下载vs2022项目源码: vs2022中Win32汇编(MASM32)环境配置和测试源码-桌面系统文档类资源-CSDN下载
注意, AsmDude(GitHub - vilyLei/asm-dude: Visual Studio extension for assembly syntax highlighting and code completion in assembly files and the disassembly window)只支持到vs2019。
主要配置过程如下:
step1: 按照vs2022(直接官网下载Community版本)
step2:Download The MASM32 SDK这里下载masm32v11r.zip这个压缩包
step3: 将MASM32的install.exe运行安装到C盘(也可以是别的盘),安装过程注意同意其解压,这里会耽搁一小段时间。
step4: 在vs2022中建立一个控制台应用。删除原来默认生成的cpp文件。
step5: 在项目图标上上右键, 生成依赖项->生成自定义->选中masm, 如下图:
step6: 在源文件图标上右键,添加 -> 新建项, 新建 test.asm文件。
step7: 在test.asm写入代码如下:
.386
.model flat, stdcall
.stack 4096
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.const
szCaption db '恭喜',0
szText db 'Win32汇编程序成功编译!',0
.data
ExitProcess proto, dwExitcode: dword
; 代码段
.code
mainT PROC
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,NULL
mainT ENDP
END mainT
// 部分代码源自 <<[琢石成器—Windows环境下32位汇编语言程序设计].罗云彬.第三版>>
上面代码中的 mainT是我这里为了解释如何配置而故意起的名字。
step8: 设置test.asm属性。在test.asm文件图标上点击右键->属性, 在弹出的界面设置如下图示:
step9: 设置解决方案平台配置为x86,如下图。
step10: 在项目图标上右键,属性,设置程序入口为mainT,如下图:
step11: 配置MASM32库目录。我的masm32安装目录是 C:\masm32, 所以才有如下图示的相关路径配置:
step12: 平台工具集的相关设置。右键项目图标,打开属性界面,设置如下:
首先看到的是如下界面:
设置完成应用之后是就会变成如下图所示的界面:
注意,默认vs2022所带的平台工具集版本版本较高,无法正常支持masm32, 需要按照低版本的工具集。(vs2022顶部主菜单)工具 -> 获取工具和功能 -> 修改,如下图:
至此,设置完成,可以运行了。
再写一个 message box中的hello world显示代码:
.386
.model flat, stdcall
.stack 4096
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szCaption db 'A MessageBox !',0
szText db 'Hello, World !',0
; 代码段
.code
mainT PROC
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,NULL
mainT ENDP
END mainT
调用成功如下图:
注意:
1. 防止 LNK2026 模块对于 SAFESEH 映像是不安全的 这个错误(release环境下)导致编译运行问题在属性窗口->连接器->命令行 里做如下图的设置(/SAFESEH:NO):
2. 非法(错误的)访问不应该访问的内存区域会报 处有未经处理的异常: 0xC0000005: 执行位置 0x00585022 时发生访问冲突 这种错误。例如 asm代码中将函数定义在数据区就会报这个错误。下面是示例代码:
.386
.model flat, stdcall
.stack 4096
option casemap:none
; include some libs
include windows.inc
include kernel32.inc
includelib kernel32.lib
; data section
.data
szText db 'Hello, MASM PROC !',0
; 因为这个函数定义在数据区(段),数据区是不具备可执行属性的,所以调用此函数会报 处有未经处理的异常: 0xC0000005: 执行位置 0x00585022 时发生访问冲突
ErrorDefineFunc proc c uses eax ecx param0, param1
mov eax, param0
mov ecx, param1
add eax, ecx
ret
ErrorDefineFunc endp
.code
; define some proc
; 定义在代码区域(段)内,能正确访问
CorrectDefineFunc proc stdcall uses eax ecx param0, param1
mov eax, param0
mov ecx, param1
add eax, ecx
ret
CorrectDefineFunc endp
mainT proc
; 调用此函数会出现崩溃错误:执行位置 0x00585022 时发生访问冲突
;invoke ErrorDefineFunc, 1, 2
; 能正确调用此函数
invoke CorrectDefineFunc, 1, 2
xor eax, eax
invoke ExitProcess,NULL
mainT endp
end
; 注意 0x00585022 这个内存位置是的的值和运行时具体使用的内存有关
上面的汇编代码编译为Debug程序再反汇编如下图:
上图中的一些指令:
INT3指令: Debugger breakpoint trap.
RETN指令:The ret instruction pops and jumps to the return address on the stack. A nonzero #n in the RET instruction indicates that after popping the return address, the value #n should be added to the stack pointer. RETN 8也就是 stack(栈) pop 8个字节。在这个程序里面也就是 ESP += 8。之所以8个字节,因为函数调用的时候,为了传参数,push了一个dword(4字节) 的2和一个dword(4字节) 的1,push一次执行一次ESP -= 4操作。注意,这里的操作全部是内存地址上的操作。
LEAVE指令:Tear down stack frame, 相当于如下汇编代码:
mov esp, ebp
pop ebp
因为进入函数的时候,执行了如下代码:
PUSH EBP
MOV EBP, ESP
因此函数返回之前要执行 LEAVE 指令。
汇编指令细节详见: https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x86-instructions
一些x86伪指令(例如 .data, .code, invoke, proc 等等):
伪指令由汇编编译器翻译为对应的汇编代码(指令),用了伪指令能方便开发者写程序,但是也因为隐藏了细节而造成一些麻烦。因此,需要通过汇编程序编译出来之后再反汇编才能看到真正的汇编代码或指令。注意Release版本反汇编看到的汇编代码和Debug版本反汇编看到的汇编代码是有区别的。
上面的汇编代码编译为Release程序再反汇编如下图:
3.查看寄存器相关信息(寄存器中的值)
第一步, 在汇编源程序中设置断点,运行并进入调试状态。
第二步,vs顶部主菜单中选择: 调试 -> 窗口 -> 寄存器。就可以看到各个寄存器的值了。
第三步,在显示寄存器值得区域内点金右键,弹出菜单,就可以选择显示 标志寄存器、MMX、SSE等状态信息了。如下图:
可以和ARM(Advanced RISC Machines)处理器的寄存器做个比较,ARM 寄存器如下图:
一些汇编相关的资料:
https://www.cs.virginia.edu/~evans/cs216/guides/x86.pdf
https://docs.oracle.com/cd/E19641-01/802-1948/802-1948.pdf
windows api: