学习之前建议如果你是临近考试了千万千万要先学习每一条常用的指令然后熟记框架最后我觉得多练习不要左边千问右边代码然后的话就是注意细节目录一、前言二、核心原理讲解三、怎么配置汇编语言编写环境四、注意事项五、最简单的测试代码模块一顺序程序设计基础运算、符号扩展1.无符号扩展2.有符号数混合运算符号扩展3. 综合四则运算例题模块二分支程序设计条件判断、逻辑短路1. 逻辑或 || 短路规则前真后不执行2. 逻辑与 规则前假后不执行模块三分段函数多区间判断必考大题分段题型1双变量区间判断分段题型2正负区间逻辑判断模块四循环与排序Loop、冒泡、选择排序2. 选择排序完整代码模块五子程序设计栈传参、stdcall栈平衡模块六地址表查表跳转多分支最优解法模块七Windows系统API调用ExitProcess / CopyFile1. 标准进程退出正规结束程序2. CopyFile 文件复制API实战总结指令搞清db dw dd本文一次性补齐32位x86汇编必学7大核心知识点每一章都是一篇独立可直接发布的完整博客包含原理讲解、32/64位区别、完整可编译代码、逐行解析、运行结果、常见坑点。7大知识点清单顺序程序设计加减乘除、符号扩展、多类型混合运算分支程序设计条件跳转、逻辑与/或短路运算分段函数判断多区间多条件复合判断模板循环排序算法冒泡排序、选择排序、Loop循环机制子程序栈调用手动栈传参、ret 8 栈平衡、局部变量地址表跳转查表法、多分支超级精简写法Windows系统调用API调用原理、文件操作、进程退出一、前言寄存器是汇编的核心所有计算、传参、系统调用都依赖寄存器。很多新手学汇编混淆 16位、32位、64位寄存器导致代码跑崩、概念混乱。本文专注纯32位 x86 架构详解 EAX/EBX/ECX/EDX/ESP/EBP 六大核心寄存器带你彻底区分32位与64位架构差异。我使用的是微软的Visual Studio 2022二、核心原理讲解EAX累加器运算、系统调用功能号专用EBX基址寄存器存放内存基地址ECX计数寄存器循环次数专用EDX数据寄存器乘除运算高位、系统调用传参ESP栈指针永远指向栈顶32位程序核心EBP栈基址指针用于函数栈帧定位三、怎么配置汇编语言编写环境打开Visual Studio 2022创建新项目--空项目---点击创建如果用这个学习过C语言的那么前面的步骤跟C语言一样创建好项目开始配置汇编语言编写环境右键项目也就是project9然后找到生成依赖项来到这里勾选倒数第三个然后找到源文件右键添加---新建项后缀为.asm然后把上面的x64改为x86有的还要确认一下项目属性中平台是否为Win32四、注意事项如果你没有生成依赖项就点击添加源文件也会报错五、最简单的测试代码.386 ;指定当前程序为 32位 x86 80386架构指令集 .model flat,stdcall ;flat平坦内存模式,是32位程序标志性特性 option casemap:none ;关闭大小写敏感,也就是在代码中EAX和eax是一样的 .data ;数据块 .code ;代码块 main proc _start:: ;主函数定义与程序入口 push ebp mov ebp,esp ; 标准32位栈帧搭建 xor eax,eax ;寄存器清零指令 pop ebp ret ; 栈帧恢复与函数返回 main endp end _start ;函数结束与程序入口绑定我最常用的是上面的还有一种是ExitProcessWindows汇编中想要正常终止程序必须调用系统APIExitProcess。这个也很重要呀.386 .model flat,stdcall option casemap:none includelib kernel32.lib ExitProcess proto,dwExitCode:dword .data .code main proc _start:: ; 标准32位栈帧搭建 push ebp mov ebp,esp ; 寄存器清零 xor eax,eax ; Windows 32位系统调用退出进程 push 0 call ExitProcess ; 此处代码永远不会执行 pop ebp ret main endp end _start返回0成功编译配置没有问题模块一顺序程序设计基础运算、符号扩展1.无符号扩展核心考点8位/16位/32位混合运算、有符号/无符号扩展、movzx/movsx、加减乘除、进位处理.386 .model flat,stdcall option casemap:none .data x db 12H y dw 3456H z dd 0aabb1234H ;起始为字母前面需要加0编译器才知道这是16进制数 sum dd 0 .code main proc _start:: push ebp mov ebp,esp ; 无符号零扩展8位→32位、16位→32位 movzx eax,x movzx ebx,y mov ecx,z add eax,ebx ;xy adc ecx,0 ;adc计算算加法进位 add eax,ecx mov sum,eax xor eax,eax pop ebp ret main endp end _start解析无符号扩展必须使用movzxadc 处理加法进位保证多字节数据运算精度。movzx 无符号扩展8位---32位16位---32位movsx 有符号扩展8位---32位16位---32位2.有符号数混合运算符号扩展.386 .model flat,stdcall option casemap:none .data x db -19H y dw -3453H z dd -0aabb1122H sum dd 0 .code main proc _start:: push ebp mov ebp,esp ; 8位→16位→32位符号扩展 mov al,x cbw cwde ; 16位带符号扩展32位 mov bx,y movsx ebx,bx add eax,ebx add eax,z mov sum,eax xor eax,eax pop ebp ret main endp end _start考点有符号数必须movsx/cbw/cwde防止负数高位补0导致数据错误3. 综合四则运算例题计算sum4a3b-b/2.386 .model flat,stdcall option casemap:none .data a db 12 b dw 250 cc dd 1000 result dd 0 .code main proc _start:: push ebp mov ebp,esp ; 4*a movzx eax,a add eax,eax add eax,eax mov ecx,eax ; 3*b movzx eax,b mov ebx,3 mul ebx add ecx,eax ; c / 2 mov eax,cc mov ebx,2 xor edx,edx div ebx sub ecx,eax mov result,ecx pop ebp ret main endp end _start模块二分支程序设计条件判断、逻辑短路核心考点CMP 比较、标志位跳转、|| 逻辑或短路、 逻辑与短路、printf 输出1. 逻辑或 || 短路规则前真后不执行.386 .model flat,stdcall option casemap:none includelib ucrt.lib includelib legacy_stdio_definitions.lib printf proto C :ptr byte, :VARARG ;这些看不懂不用管是printf实现的必要函数 .data a dd 5 b dd 6 cc dd 7 d dd 8 m dd 2 n dd 2 fm1 db m%d n%d,0ah,0 ;0ah换行符 .code main proc _start:: push ebp mov ebp,esp ; (mab) || (ncd) ;或运算前面为真后面的不用验真 mov eax,a cmp eax,b jl setm1 ;为真直接跳到setm1那里给m赋值1后直接结束程序 ; 前式为假才执行后式 mov m,0 mov eax,cc ;为什么这里用cc,因为变量名 c 在 MASM32 里是系统保留关键字 cmp eax,d jg setn1 mov n,0 jmp print setm1: mov m,1 jmp print setn1: mov n,1 print: invoke printf, offset fm1, m, n xor eax,eax pop ebp ret main endp end _start2. 逻辑与 规则前假后不执行.386 .model flat,stdcall option casemap:none includelib ucrt.lib includelib legacy_stdio_definitions.lib printf proto C :ptr byte, :VARARG .data a dd 5 b dd 6 cc dd 7 d dd 8 m dd 2 n dd 2 fm1 db m%d n%d,0ah,0 .code main proc _start:: push ebp mov ebp,esp mov eax,a cmp eax,b jl m_true mov m,0 jmp end_s m_true: mov m,1 mov eax,cc cmp eax,d jg n_true mov n,0 jmp end_s n_true: mov n,1 end_s: invoke printf,offset fm1,m,n xor eax,eax pop ebp ret main endp end _start模块三分段函数多区间判断必考大题核心考点多区间嵌套判断、多条件同时成立、区间互斥跳转分段题型1双变量区间判断.386 .model flat,stdcall option casemap:none .data x dd 5 y dd 4 fxy dd 0 .code main proc _start:: push ebp mov ebp,esp ;x1 y1 → -1 mov eax,x cmp eax,1 jge L1 mov eax,y cmp eax,1 jge L1 mov fxy,-1 jmp end_s ;1~5 1~5 → 0 L1: mov eax,x cmp eax,5 jg L2 cmp eax,1 jl L2 mov eax,y cmp eax,5 jg L2 cmp eax,1 jl L2 mov fxy,0 jmp end_s ;5 5 →1 L2: mov eax,x cmp eax,5 jle end_s mov eax,y cmp eax,5 jle end_s mov fxy,1 end_s: xor eax,eax pop ebp ret main endp end _start分段题型2正负区间逻辑判断.386 .model flat,stdcall option casemap:none .data x dd 6 y dd 6 fxy dd 0 .code main proc _start:: push ebp mov ebp,esp ;x0 y0 10 mov eax,x cmp eax,0 jle L1 mov eax,y cmp eax,0 jle L1 mov fxy , 10 jmp end_s ;x0 y0 -10 L1: mov eax,x cmp eax,0 jge other mov eax,y cmp eax,0 jge other mov fxy,-10 jmp end_s other: mov fxy,0 end_s: xor eax,eax pop ebp ret main endp end _start模块四循环与排序Loop、冒泡、选择排序核心考点ECX循环计数、栈保存外层循环、ESI指针遍历、XCHG交换.386 .model flat,stdcall .data addr_lab dd 7,8,3,1,2,4,6,9,13,12,18,20 dat_count dd ($-addr_lab)/4 ;这里可以这样理解 $ 为尾指针addr_lab为初始指针/4计算排序数组的个数 .code main5 proc _start5:: push ebp mov ebp,esp mov ecx,dat_count outerLoop: push ecx ;压栈保护外层循环的ecx lea esi,addr_lab innerLoop: mov ebx,[esi] cmp ebx,[esi4] jle no_swap xchg ebx,[esi4] xchg ebx,[esi] ;这里直接写两个xchg好记和上面mov ebx,[esi] ;cmp ebx,[esi4]对应 no_swap: add esi,4 ;因为我定义的是dd所以是加4如是db,加1就OK loop innerLoop pop ecx ;上面压栈了这里出栈 loop outerLoop xor eax,eax pop ebp ret main5 endp end _start52. 选择排序完整代码.386 .model flat,stdcall option casemap:none .data array dd 12,3,4,2,7,8,20,9,5,30 count dd ($ - array)/4 .code main proc _start:: push ebp mov ebp,esp mov ecx,count dec ecx outer: push ecx lea esi,array mov edi,esi inner: mov eax,[esi] cmp eax,[edi] jge not_min mov edi,esi not_min: add esi,4 loop inner ;交换首尾与最小值 mov eax,[ebp-4] mov ebx,4 mul ebx lea esi,array[eax] mov edx,[esi] xchg edx,[edi] mov [esi],edx pop ecx loop outer xor eax,eax pop ebp ret main endp end _start模块五子程序设计栈传参、stdcall栈平衡核心考点ebp栈偏移传参、ret 8 自动平栈、call调用子程序.386 .model flat,stdcall option casemap:none .code ; 子程序x y*2 addxy proc push ebp mov ebp,esp _x$ 8 _y$ 12 mov eax,_x$[ebp] mov ebx,_y$[ebp] add ebx,ebx add eax,ebx pop ebp ret 8 ; stdcall自动清理8字节参数栈 addxy endp ; 主程序 main proc _x$ -4 _y$ -8 _z$ -12 _start:: push ebp mov ebp,esp mov eax,23 mov _x$[ebp],eax mov eax,2 mov _y$[ebp],eax ; 从右往左压栈 push _y$[ebp] push _x$[ebp] call addxy mov _z$[ebp],eax xor eax,eax mov esp,ebp pop ebp ret main endp end _start模块六地址表查表跳转多分支最优解法核心考点地址表数组、寄存器偏移跳转、替代大量if-else工业级写法.386 .model flat,stdcall option casemap:none includelib ucrt.lib includelib legacy_stdio_definitions.lib printf PROTO C :ptr byte, :vararg .data x dd 8 msg0 db Invalid,0 msg1 db Jan,0 msg2 db Feb,0 msg3 db Mar,0 msg4 db Apr,0 msg5 db May,0 msg6 db Jun,0 msg7 db Jul,0 msg8 db Aug,0 msg9 db Sep,0 msg10 db Oct,0 msg11 db Nov,0 msg12 db Dec,0 .code main proc _start:: push ebp mov ebp,esp mov eax,x cmp eax,1 jb case_0 cmp eax,12 ja case_0 ; 查表跳转 jmp [addr_tableeax*4] addr_table dd offset case_0,offset case_1,offset case_2,offset case_3 dd offset case_4,offset case_5,offset case_6,offset case_7 dd offset case_8,offset case_9,offset case_10,offset case_11,offset case_12 case_0: invoke printf,offset msg0 jmp end_s case_1: invoke printf,offset msg1 jmp end_s case_2: invoke printf,offset msg2 jmp end_s case_3: invoke printf,offset msg3 jmp end_s case_4: invoke printf,offset msg4 jmp end_s case_5: invoke printf,offset msg5 jmp end_s case_6: invoke printf,offset msg6 jmp end_s case_7: invoke printf,offset msg7 jmp end_s case_8: invoke printf,offset msg8 jmp end_s case_9: invoke printf,offset msg9 jmp end_s case_10: invoke printf,offset msg10 jmp end_s case_11: invoke printf,offset msg11 jmp end_s case_12: invoke printf,offset msg12 end_s: xor eax,eax pop ebp ret main endp end _start模块七Windows系统API调用ExitProcess / CopyFile核心考点库链接、函数原型声明、stdcall压栈传参、进程正常退出1. 标准进程退出正规结束程序.386 .model flat,stdcall option casemap:none includelib kernel32.lib ExitProcess proto,dwExitCode:dword .code main proc _start:: push ebp mov ebp,esp push 0 call ExitProcess pop ebp ret main endp end _start2. CopyFile 文件复制API实战.386 .model flat,stdcall option casemap:none includelib kernel32.lib CopyFile proto stdcall,:dword,:dword,:dword MY_NULL EQU 0 .const sf db a.txt,0 df db b.txt,0 .code main proc _start:: push ebp mov ebp,esp invoke CopyFile,offset sf,offset df,MY_NULL pop ebp ret main endp end _start总结指令## 二、数据定义 1. db定义字节数据 2. dw定义字数据 3. dd定义双字数据 4. $取当前地址 ## 三、数据传送 1. mov数据直接传送 2. lea取有效地址 3. push数据压入栈 4. pop数据弹出栈 5. xchg交换两数据 ## 四、位数扩展 1. movzx无符号扩展 2. movsx有符号扩展 3. cbw字节转字 4. cwde字转双字 5. cdq双字扩64位 ## 五、算术运算 1. add加法运算 2. adc带进位加法 3. sub减法运算 4. mul无符号乘法 5. div无符号除法 ## 六、逻辑运算 1. xor异或清零 ## 七、比较与跳转 1. cmp数值比较 2. jmp无条件跳转 3. je/jz相等则跳转 4. jne/jnz不等则跳转 5. jl小于则跳转 6. jg大于则跳转 7. jb无符小于跳 8. ja无符大于跳 9. loop循环跳转 ## 八、函数与栈操作 1. call调用子程序 2. ret函数返回 3. ret n返回并平栈 4. invoke调用API搞清db dw dd1字两字节 1字节8bitdb 1字节 8bit 定义数字时 x db 12H 两个数字dw 2字节 16bit 定义数字时 x dw 1234H 4个数字dd 4字节 32bit 定义数字时 x dd 0aabbccddH 8个数字