《汇编语言基础教程》 学习实录

tech2023-07-16  102

《汇编语言基础教程》 学习实录

第3章 算术运算指令第4章 选择结构第5章 迭代结构第6章 逻辑运算指令、移位指令、循环移位指令和堆栈 书目:《Guide to assembly language. A concise introduction》 by James T.Streib

时间紧迫,这里仅记录我学习过程中写的一些示例代码,每个示例代码都有对应C语言版本。长时间不用难免忘记,希望能通过一些简单示例快速拾起intel汇编语法。

IDE:VS2017 Intel x86汇编环境搭建与配置

第3章 算术运算指令

COMMENT @ #include<stdio.h> int main(){ int volts, ohms, amperes; printf("\n%s","Enter the number of volts: "); scanf("%d", &volts); printf("%s","Enter the number of ohms: "); scanf("%d", &ohms); amperes = volts / ohms; printf("\n%s%d\n\n", "The number of amperes is:", amperes); } @ .386 .model flat, C .stack 100h includelib msvcrt.lib printf proto arg1:Ptr Byte, printlist:VARARG scanf proto arg1:Ptr Byte, printlist:VARARG .data volts SDWORD ? ohms SDWORD ? amperes SDWORD ? in1fmt Byte "%d",0 msg1fmt Byte 0Ah,"%s",0 msg2fmt Byte "%s",0 msg3fmt Byte 0Ah,"%s%d",0Ah,0Ah,0 msg1 Byte "Enter the number of volts: ",0 msg2 Byte "Enter the number of ohms: ",0 msg3 Byte "The number of amperes is:",0 .code start1: INVOKE printf, ADDR msg1fmt, ADDR msg1 INVOKE scanf, ADDR in1fmt, ADDR volts INVOKE printf, ADDR msg2fmt, ADDR msg2 INVOKE scanf, ADDR in1fmt, ADDR ohms mov eax, volts cdq idiv ohms mov amperes, eax INVOKE printf, ADDR msg3fmt,ADDR msg3, amperes ret end start1

第4章 选择结构

COMMENT @ C语言表述 #include<stdio.h> int main(){ int voltage; printf("%s", "Enter an AC Voltage: "); scanf("%d", &voltage); if (voltage >= 110 && voltage <= 120) printf("\n%s\n", "Voltage is Acceptable"); else { printf("\n%s\n", "Warning!"); if(voltage < 110) printf("%s\n", "Voltage too Low"); else printf("%s\n", "Voltage too High"); } if(voltage >=380) printf("%s", "Generator power off..."); printf("\n"); return 0; } @ ; 以下是上述C代码的汇编语言表述 ; MASM32 intelx86 Debugger ; ============================================= .listall .386 .model flat, c .stack 100h includelib msvcrt.lib scanf PROTO :PTR Byte, :VARARG printf PROTO :PTR Byte, :VARARG .data in1fmt Byte "%d",0 msg1fmt Byte "%s",0 msg1 Byte "Enter an AC Voltage: ",0 msg2fmt Byte 0Ah,"%s",0Ah,0 msg2 Byte "Voltage is Acceptable",0 msg3 Byte "Warning!",0 msg3fmt Byte "%s",0Ah,0 msg4 Byte "Voltage too Low",0 msg5 Byte "Voltage too High",0 msg4fmt Byte 0Ah,0 msg6 Byte "Generator power off...",0 voltage SDWORD ? .code main PROC INVOKE printf, ADDR msg1fmt, ADDR msg1 INVOKE scanf, ADDR in1fmt, ADDR voltage if01: cmp voltage, 110 jl else01 cmp voltage, 120 jg else01 then01: INVOKE printf, ADDR msg2fmt, ADDR msg2 jmp endif01 else01: nop INVOKE printf, ADDR msg2fmt, ADDR msg3 if02: cmp voltage, 110 jge else02 then02: INVOKE printf, ADDR msg3fmt, ADDR msg4 jmp endif02 else02: INVOKE printf, ADDR msg3fmt, ADDR msg5 endif02: nop endif01: nop .if voltage >= 380 INVOKE printf, ADDR msg1fmt, ADDR msg6 nop ;这里要有一个补位的,否则会抛出未知异常 .endif INVOKE printf, ADDR msg4fmt ret main ENDP END main

第5章 迭代结构

INVOKE指令破坏寄存器eax、ecx和edx的值,故用ecx计数时需要用到一个内存变量存储计数值

loop指令使用时ecx的值不能为0或负值

完整代码示例:实现幂函数

COMMENT @ #include<stdio.h> int main() { int x, n, i, ans; printf("%s", "Enter x: "); scanf_s("%d", &x); printf("%s", "Enter n: "); scanf_s("%d", &n); if (x < 0 || n < 0) printf("\n%s\n\n", "Error: Negative x and/or y"); else if (x == 0 && n == 0) printf("\n%s\n\n", "Error: Undefined answer"); else { i = 1; ans = 1; while (i <= n) { ans = ans * x; ++i; } printf("\n%s%d\n\n", "The answer is: ", ans); } return 0; } @ .listall .386 .model flat, c .stack 100h includelib msvcrt.lib printf PROTO :Ptr Byte, :VARARG scanf PROTO :Ptr Byte, :VARARG .data x SDWORD ? n SDWORD ? i SDWORD ? ans SDWORD ? msg1fmt Byte "%s",0 msg2fmt Byte 0Ah,"%s",0Ah,0Ah,0 msg3fmt Byte 0Ah,"%s%d",0Ah,0Ah,0 in1fmt Byte "%d",0 msg1 Byte "Enter x: ",0 msg2 Byte "Enter n: ",0 msg3 Byte "Error: Negative x and/or y",0 msg4 Byte "Error: Undefined answer",0 msg5 Byte "The answer is: ",0 .code main PROC INVOKE printf, ADDR msg1fmt, ADDR msg1 INVOKE scanf, ADDR in1fmt, ADDR x INVOKE printf, ADDR msg1fmt, ADDR msg2 INVOKE scanf, ADDR in1fmt, ADDR n if01: cmp x, 0 jge else01 OR01: cmp n, 0 jge else01 then01: nop INVOKE printf, ADDR msg2fmt, ADDR msg3 else01: nop if02: cmp x, 0 jne else02 cmp n, 0 jne else02 then02: nop INVOKE printf, ADDR msg2fmt, ADDR msg4 else02: nop mov i, 1 mov ans, 1 mov ecx, i w01: cmp ecx, n jg endw01 mov eax, ans imul x mov ans, eax inc ecx jmp w01 endw01: nop mov i, ecx INVOKE printf, ADDR msg3fmt, ADDR msg5, ans endif02: nop endif01:nop ret main ENDP END main

第6章 逻辑运算指令、移位指令、循环移位指令和堆栈

逻辑运算:and \ or \ xor A, B

逻辑移位:左shl \ shr A, B右

测试比特位:test A, B A值不变 || and A, B,A值会变

算术移位:左sal A, B\ sar A, B 右,sal与shl完全一样,但sar与shr不一样,考虑负数的情况即可

循环移位:左rol A, B \ ror A, B右,一般移动一整轮使得值复原

堆栈:push reg\mem\imm; pop reg\mem; 注意:①只能16位或32位寄存器/内存空间可使用;②pop不能取立即数

堆栈应用:排序算法中的交换值 方法一 (较慢)          方法二: 中等             方法三:较快

push num1 mov eax, num1 mov eax, num1 push num2 xchg eax, num2 mov edx, num2 pop num1 mov num1, eax mov num1, edx pop num2 mov num2, eax

原因:指令执行速度 mov > xchg > push/pop,但从方法一到方法三,使用的寄存器数分别为0、1、2,所以折中考虑方法二

章节实例:模拟OCR设备,检测文档状态字节(每一位都代表一个状态)

COMMENT @ bit ERROR STATE 0 SHORT DOCUMENT 1 LONG DOCUMENT 2 CLOSE FEED 3 MULTIPLE FEED 4 EXCESSIVE SKEW 5 DOCUMENT MISFEED 6 DOCUMENT JAM 7 UNSPECIFIED ERROR @ .listall .386 .model flat,stdcall .stack 100h includelib msvcrt.lib printf PROTO C :PTR Byte, :VARARG scanf PROTO C :PTR Byte, :VARARG .data msg1fmt Byte "%s",0 in1fmt Byte "%x",0 msg2fmt Byte "%s%x",0Ah,0Ah,0 msg1 Byte 0Ah,"Enter a hexadecimal number: ",0 msg2 Byte "The hexadecimal number is: ",0 msgshort Byte "SHORT DOCUMENT",0Ah,0 msglong Byte "LONG DOCUMENT",0Ah,0 msgclose Byte "CLOSE FEED",0Ah,0 msgmult Byte "MULTIPLE FEED",0Ah,0 msgskew Byte "EXCESSIVE SKEW",0Ah,0 msgfeed Byte "DOCUMENT MISFEED",0Ah,0 msgjam Byte "DOCUMENT JAM",0Ah,0 msgerror Byte "UNSPECIFIED ERROR",0Ah,0 dsb DWORD ? .code main PROC INVOKE printf, ADDR msg1fmt, ADDR msg1 INVOKE scanf, ADDR in1fmt, ADDR dsb INVOKE printf, ADDR msg2fmt, ADDR msg2, dsb while01: cmp dsb, 0ffh ; .while dsb<=0ffh jg endwhile01 test dsb, 00000001b if01: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgshort endif01: .endif test dsb, 00000010b if02: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msglong endif02: .endif test dsb, 00000100b if03: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgclose endif03: .endif test dsb, 00001000b if04: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgmult endif04: .endif test dsb, 00010000b if05: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgskew endif05: .endif test dsb, 00100000b if06: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgfeed endif06: .endif test dsb, 01000000b if07: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgjam endif07: .endif test dsb, 10000000b if08: .if !ZERO? INVOKE printf, ADDR msg1fmt, ADDR msgerror endif08: .endif INVOKE printf, ADDR msg1fmt, ADDR msg1 INVOKE scanf, ADDR in1fmt, ADDR dsb INVOKE printf, ADDR msg2fmt, ADDR msg2, dsb endwhile01: nop ;.endw ret main ENDP END main 附:Intel x86汇编环境搭建与配置

打开VS2017, 选择VC++的“桌面安装向导”,创建项目

勾选“空项目”(有的VS版本还有安全周期检查,若有的话则把它也去掉),确定

右键项目 → \rightarrow 生成依赖项 → \rightarrow 生成自定义

勾选masm,确定

然后在源文件夹下创建如图所示的源文件,后缀名为.asm

右键项目 → \rightarrow 属性 → \rightarrow 弹出属性页,进行如下设置:

设置完成,写个示例代码编译调试

.386 .model flat, c .stack 100h includelib msvcrt.lib ;输入输出函数所在的库 printf PROTO arg1:Ptr Byte, printlist:VARARG .data msg1fmt Byte "%s%d", 0 msg1 Byte "Hello World! ",0Ah, 0 num1 SDWORD ? .code main PROC mov num1, 7777 INVOKE printf, ADDR msg1fmt, ADDR msg1, num1 ret main ENDP END main

运行结果如下: 设置完成!!!

最新回复(0)