x86汇编语言实践(2)
0 写在前面
为了更深入的了解程序的实现原理,近期我学习了IBM-PC相关原理,并手工编写了一些x86汇编程序。
在2017年的计算机组成原理中,曾对MIPS体系结构及其汇编语言有过一定的了解,考虑到x86体系结构在目前的广泛应用,我通过两个月左右的时间对x86的相关内容进行了学习。
在《x86汇编语言实践》系列中(包括本篇、x86汇编语言实践(1)、x86汇编语言实践(3)、x86汇编语言实践(4)以及x86汇编语言复习笔记),我通过几个具体案例对x86汇编语言进行实践操作,并记录了自己再编写汇编代码中遇到的困难和心得体会,与各位学习x86汇编的朋友共同分享。
我将我编写的一些汇编代码放到了github上,感兴趣的朋友可以点击屏幕左上角的小猫咪进入我的github,或请点击这里下载源代码。
1 十进制输入输出的乘法练习
1-1 练习要点
- 输入输出中断调用练习
- 宏练习
- 子程序编写与调用
1-2 实现思路
- 数据区使用byte类型存放两个十进制乘数NUM1和NUM2
- 输入采用宏GETNUM实现,从百位读到个位,调用乘法宏MULTI计算出NUM1和NUM2的值
- 调用乘法宏MULTI计算出结果,并保存到RESULT,以便debug调试
- 调用OUTPUT子程序进行输出,输出从RESULT中保存的结果
- 其他对于输入输出的控制对输出结果进行改进
1-3 代码实现
- STACK SEGMENT PARA STACK
- DW 100H DUP(?)
- STACK ENDS
- DATA SEGMENT PARA
- NUM1 DB ?
- NUM2 DB ?
- RESULT DW ?
- DATA ENDS
- CODE SEGMENT PARA
- ASSUME CS:CODE,DS:DATA,SS:STACK
- GETNUM MACRO
- MOV AH,
- INT 21H
- SUB AL,30H
- ENDM
- MULTI MACRO N1,N2
- MOV AL,N1
- MOV BL,N2
- MUL BL
- ENDM
- DIVIDE MACRO N1,N2
- MOV AX,N1
- MOV BX,N2
- XOR DX,DX
- DIV BX
- ENDM
- DISPNUM MACRO
- PUSH DX
- MOV AH,
- MOV DL,AL
- ADD DL,30H
- INT 21H
- POP DX
- ENDM
- INPUT MACRO NUM
- GETNUM
- MULTI AL,
- MOV NUM,AL
- GETNUM
- MULTI AL,
- ADD NUM,AL
- GETNUM
- ADD NUM,AL
- ENDM
- NEWLINE MACRO
- MOV AH,
- MOV DL,0DH
- INT 21H
- MOV AH,
- MOV DL,0AH
- INT 21H
- ENDM
- OUTPUT PROC
- DIVIDE AX,
- DISPNUM
- DIVIDE DX,
- DISPNUM
- DIVIDE DX,
- DISPNUM
- DIVIDE DX,
- DISPNUM
- MOV AL,DL
- DISPNUM
- RET
- OUTPUT ENDP
- MAIN PROC FAR
- MOV AX,DATA
- MOV DS,AX
- ;get num1
- INPUT NUM1
- ;getchar
- GETNUM
- XOR AX,AX
- ;get num2
- INPUT NUM2
- ;num1 * num2
- MULTI NUM1,NUM2
- MOV RESULT,AX
- ;newline
- NEWLINE
- ;output result
- MOV AX,RESULT
- CALL OUTPUT
- EXIT: MOV AX,4C00H
- INT 21H
- MAIN ENDP
- CODE ENDS
- END MAIN
1-4 实现效果截图
经验证,发现输出结果符合预期。
2 字符串操作与跳转表练习
2-1 练习要点
- 字符串的操作,包括:字符串的拼接、比较、查找
- 子程序调用与宏
- 跳转表的使用
2-2 重点难点
- 子程序调用需要对子程序中使用到的变量进行压栈处理,以免变量污染
- 字符串操作通常都需要对ES:DI和DS:SI进行初始化
- 宏的内容不能有标签
2-3 实现思路
- 首先为输入和输出单独编写子程序,程序主体采用跳转表实现
- 为每一个条件单独编写一个子程序,有4个条件,因此共需编写4个子程序
2-4 代码实现
- STACK SEGMENT PARA STACK
- DW 100H DUP(?)
- STACK ENDS
- DATA SEGMENT PARA
- LEN EQU
- MSG1 DB 'INPUT OPRAND:',,,'$' ;THE MSG TO OUTPUT
- MSG2 DB 'INPUT STRING 1:',,,'$'
- MSG3 DB 'INPUT STRING 2:',,,'$'
- MSG4 DB '<','$'
- MSG5 DB '=','$'
- MSG6 DB '>','$'
- MSG7 DB 'S3=','$'
- MSG8 DB 'INPUT A CHAR:',,,'$'
- MSG9 DB 'CHAR FOUND IN STR1!',,,'$'
- MSG10 DB 'CHAR NOT FOUND IN STR1!',,,'$'
- STR1 DB LEN-
- DB ?
- DB LEN DUP(?)
- STR2 DB LEN-
- DB ?
- DB LEN DUP(?)
- STR3 DB LEN-
- DB ?
- DB LEN DUP(?)
- CHAR DB ?
- OP DB ? ;THE OPRAND USER INPUT
- DATA ENDS
- CODE SEGMENT PARA
- ASSUME CS:CODE,DS:DATA,SS:STACK
- HINT MACRO MSG
- LEA DX,MSG ;OUTPUT MSG1
- MOV AH,09H
- INT 21H
- ENDM
- GETOP MACRO
- MOV AH,
- INT 21H
- SUB AL,30H
- MOV OP,AL
- ENDM
- NEWLINE MACRO
- PUSH AX
- PUSH DX
- MOV AH,
- MOV DL,0DH
- INT 21H
- MOV AH,
- MOV DL,0AH
- INT 21H
- POP DX
- POP AX
- ENDM
- GETCHAR MACRO
- MOV AH,
- INT 21H
- MOV CHAR,AL
- ENDM
- GETSTR1 PROC
- MOV DX,OFFSET STR1
- MOV AH,0AH
- INT 21H
- MOV CL,STR1+
- XOR CH,CH
- MOV SI,OFFSET STR1+
- LP1: INC SI
- LOOP LP1
- MOV BYTE PTR [SI],'$'
- RET
- GETSTR1 ENDP
- GETSTR2 PROC
- MOV DX,OFFSET STR2
- MOV AH,0AH
- INT 21H
- MOV CL,STR2+
- XOR CH,CH
- MOV SI,OFFSET STR2+
- LP2:INC SI
- LOOP LP2
- MOV BYTE PTR [SI],'$'
- RET
- GETSTR2 ENDP
- STRCAT PROC
- PUSH AX
- CLD
- CAT_LP1:LODSB
- STOSB
- CMP AL,
- JNZ CAT_LP1
- POP AX
- RET
- STRCAT ENDP
- P2_PUTEND PROC
- MOV CL,STR1+ ;SET CX TO LEN FOR LOOP
- ADD CL,STR2+
- XOR CH,CH
- MOV SI,OFFSET STR3+ ;GET ACTUAL STRING
- PLP2: INC SI
- LOOP PLP2
- MOV BYTE PTR [SI],'$' ;PUT END TO STRING
- RET
- P2_PUTEND ENDP
- ;STRCMP
- P1 PROC
- PUSH CX
- CLD
- PUSH SI
- MOV CX,
- SLP1: LODSB
- CMP AL,00H
- JZ SLP1_1
- INC CX
- JMP SHORT SLP1
- SLP1_1: POP SI
- REPE CMPSB
- HINT STR1+
- JA SL1
- JB SL2
- HINT MSG5
- MOV AL,
- JMP SHORT RETURN
- SL1: HINT MSG6
- MOV AL,
- JMP SHORT RETURN
- SL2: HINT MSG4
- MOV AL,
- RETURN: HINT STR2+
- POP CX
- RET
- P1 ENDP
- ;STRCAT(S1,S2)+STRCPY(S3,S1)
- P2 PROC
- ;STRCAT(S1,S2)
- PUSH AX
- MOV SI,OFFSET STR2+
- MOV CL,STR1+
- XOR CH,CH
- MOV DI,OFFSET STR1+
- CATLP1: INC DI
- LOOP CATLP1
- CALL STRCAT
- ;STRCPY(S3,S1)
- MOV SI,OFFSET STR1+
- MOV DI,OFFSET STR3+
- CALL STRCAT
- CALL P2_PUTEND
- HINT MSG7
- HINT STR3+
- POP AX
- RET
- P2 ENDP
- ;STRCAT(S2,S1)+STRCPY(S3,S2)
- P2_2 PROC
- ;STRCAT(S2,S1)
- PUSH AX
- MOV SI,OFFSET STR1+
- MOV CL,STR2+
- XOR CH,CH
- MOV DI,OFFSET STR2+
- CATLP2: INC DI
- LOOP CATLP2
- CALL STRCAT
- ;STRCPY(S3,S1)
- MOV SI,OFFSET STR2+
- MOV DI,OFFSET STR3+
- CALL STRCAT
- CALL P2_PUTEND
- HINT MSG7
- HINT STR3+
- POP AX
- RET
- P2_2 ENDP
- ;STRFIND
- P3 PROC
- HINT MSG8
- GETCHAR
- NEWLINE
- MOV DI,OFFSET STR1+
- MOV CL,STR1+
- XOR CH,CH
- MOV AL,CHAR
- CLD
- REPNZ SCASB
- JZ FOUND
- HINT MSG10
- JMP P3_RETURN
- FOUND: HINT MSG9
- P3_RETURN:RET
- P3 ENDP
- ;SRTCMP+STRCAT+STRCPY
- P4 PROC
- MOV SI,OFFSET STR1+
- MOV DI,OFFSET STR2+
- CALL P1
- NEWLINE
- CMP AL,
- JNE LA41
- CALL P2
- JMP CONTINUE4
- LA41: CMP AL,
- JNE LA42
- CALL P2
- JMP CONTINUE4
- LA42: CMP AL,
- JNE CONTINUE4
- CALL P2_2
- CONTINUE4:
- RET
- P4 ENDP
- SWITCH PROC
- CMP OP,
- JNE LA1
- MOV SI,OFFSET STR1+
- MOV DI,OFFSET STR2+
- CALL P1
- JMP CONTINUE
- LA1: CMP OP,
- JNE LA2
- CALL P2
- JMP CONTINUE
- LA2: CMP OP,
- JNE LA3
- CALL P3
- JMP CONTINUE
- LA3: CMP OP,
- JNE LAN
- CALL P4
- JMP CONTINUE
- LAN: HINT MSG3
- CONTINUE:RET
- SWITCH ENDP
- MAIN PROC FAR
- MOV AX,DATA
- MOV DS,AX
- MOV ES,AX
- ;input str1
- HINT MSG2
- CALL GETSTR1
- NEWLINE
- ;input str2
- HINT MSG3
- CALL GETSTR2
- NEWLINE
- ;input op
- HINT MSG1
- GETOP
- NEWLINE
- ;SWITCH OP
- CALL SWITCH
- EXIT: MOV AX,4C00H
- INT 21H
- MAIN ENDP
- CODE ENDS
- END MAIN
2-5 运行结果
2-5-1 操作类型为1,即比较str1和str2的字典序
2-5-2 操作类型为2,即将str2拼接到str1后,并将整个串拷贝至str3
2-5-3 操作类型为3,即再输入一个字符char,判断char是否属于str1
2-5-4 操作类型为4,即比较str1和str2的字典序按降序进行拼接,并拷贝到str3
显然,运行结果符合预期。
3 字符串按字典序排序
3-1 练习要点
- 字符串的操作,LODSB,STOSB,CMPSB,REPE等等
- 各个字符串操作指令对PSW和SI,DI的影响
- 子程序调用与宏
- 冒泡排序算法
- 复杂程序的调试
3-2 重点难点
- 冒泡排序
- 宏和子程序的编写时必须注意堆栈的维护,用到的变量必须压栈处理
- 字符串交换的逻辑
- 操作字符串的子程序必须对SI,DI压栈保存,因为会隐式修改SI,DI
3-3 实现思路
- 调用输出子程序输出原单词表
- 调用排序子程序
- 调用输出子程序输出排序后的单词表
3-4 代码实现
- 输出子程序中每输出一个单词,就将SI增加STR_LEN,循环输出TABLE_LEN次
- 排序子程序采用冒泡,在相邻两单词比较时,将当前单词置于DS:SI,相邻下一单词置于ES:DI,并比较其字典序,若当前单词字典序较大,则调用交换子程序,并将标志位BX置0,表示这一趟外层循环排序有调整。当一趟外层循环排序无调整,则表示当前单词表有序,即可退出排序子程序。
- 比较子程序要注意对SI的维护,以及REPE CMPSB的含义:当CX≠0且ZF=1时执行CMPSB,CMPSB返回SI和DI的比较结果,并将二者分别+1,CX为提前计算好的两字符串的长度。含义是,当两字符串的前若干位字符相同时,就继续向后比较,直到比较到长度的结尾,或出现不同时结束。后接JA,JB指令,根据比较结果进行跳转与执行相关逻辑。
- 交换S1,S2的逻辑:S1->TMP , S2->S1 , TMP->S2。
- STACK SEGMENT PARA STACK
- DW 100H DUP(?)
- STACK ENDS
- DATA SEGMENT PARA
- TABLE_LEN EQU
- STR_LEN EQU
- TABLE DB 'QIQI',20H,,'$'
- DB 'CHEN',20H,,'$'
- DB 'XIAN',20H,,'$'
- DB 'QIQJ',20H,,'$'
- DB 'XHAN',20H,,'$'
- DB 'XIBN',20H,,'$'
- DB 'XHQI',20H,,'$'
- DB 'LOVE',20H,,'$'
- DB 'SURE',20H,,'$'
- TEMP DB STR_LEN DUP(?)
- NEW_LINE DB 0DH,0AH,'$'
- DATA ENDS
- CODE SEGMENT PARA
- ASSUME CS:CODE,DS:DATA,SS:STACK
- NEWLINE MACRO
- PUSH DX
- PUSH AX
- MOV DX,OFFSET NEW_LINE
- MOV AH,
- INT 21H
- POP AX
- POP DX
- ENDM
- OUTPUT PROC
- PART1:
- MOV CX,TABLE_LEN
- MOV SI,OFFSET TABLE
- LP1:
- MOV DX,SI
- MOV AH,
- INT 21H
- ADD SI,STR_LEN
- LOOP LP1
- NEWLINE
- RET
- OUTPUT ENDP
- COMP PROC
- COMPARE:
- PUSH SI
- PUSH CX
- CLD
- PUSH SI
- MOV CX,
- SLP1:
- LODSB
- CMP AL,00H
- JZ SLP1_1
- INC CX
- JMP SHORT SLP1
- SLP1_1:
- POP SI
- REPE CMPSB
- JA SL1
- JB SL2
- MOV AL, ;SI=DI
- JMP SHORT RETURN
- SL1:
- MOV AL, ;SI>DI
- JMP SHORT RETURN
- SL2:
- MOV AL, ;SI<DI
- RETURN:
- POP CX
- POP SI
- RET
- COMP ENDP
- STRCPY PROC
- STRING_COPY:
- PUSH SI
- PUSH DI
- PUSH AX
- CLD
- CPY_LP1:
- LODSB
- STOSB
- CMP AL,
- JNZ CPY_LP1
- POP AX
- POP DI
- POP SI
- RET
- STRCPY ENDP
- EXCHG PROC
- EXCHANGE:
- PUSH SI
- PUSH DI
- MOV DI,OFFSET TEMP
- CALL STRCPY
- MOV DI,SI
- ADD SI,STR_LEN
- CALL STRCPY
- MOV DI,SI
- MOV SI,OFFSET TEMP
- CALL STRCPY
- POP DI
- POP SI
- RET
- EXCHG ENDP
- SORT PROC
- PART2:
- MOV CX,TABLE_LEN
- DEC CX
- LP2:
- MOV BX,
- MOV SI,OFFSET TABLE
- PUSH CX
- LP2_1:
- MOV AX,SI
- ADD AX,STR_LEN
- MOV DI,AX
- CALL COMP
- CMP AL,
- JBE CONTINUE
- CALL EXCHG
- MOV BX,
- CONTINUE:
- ADD SI,STR_LEN
- LOOP LP2_1
- POP CX
- DEC CX
- CMP BX,
- JZ SORT_RETURN
- JMP SHORT LP2
- SORT_RETURN:
- RET
- SORT ENDP
- MAIN PROC FAR
- MAIN_PART:
- MOV AX,DATA
- MOV DS,AX
- MOV ES,AX
- ;DISPLAY ORIGIN TABLE
- CALL OUTPUT
- ;SORT
- CALL SORT
- ;DISPLAY ORDERED TABLE
- CALL OUTPUT
- EXIT:
- MOV AX,4C00H
- INT 21H
- MAIN ENDP
- CODE ENDS
- END MAIN
3-5 运行结果
在DATA段预置字典如下图所示
编译、链接并执行程序,得到结果如下,第一行为元单词表,第二行为排序后的单词表(按字典序升序)
显然,运行结果符合预期。
x86汇编语言实践(2)的更多相关文章
- x86汇编语言实践(3)
0 写在前面 为了更深入的了解程序的实现原理,近期我学习了IBM-PC相关原理,并手工编写了一些x86汇编程序. 在2017年的计算机组成原理中,曾对MIPS体系结构及其汇编语言有过一定的了解,考虑到 ...
- x86汇编语言实践(1)
0 写在前面 为了更深入的了解程序的实现原理,近期我学习了IBM-PC相关原理,并手工编写了一些x86汇编程序. 在2017年的计算机组成原理中,曾对MIPS体系结构及其汇编语言有过一定的了解,考虑到 ...
- 进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17
(十)保护模式下的栈 ;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 mov cx,00000000000_11_000B ;加载堆栈段选择子 mov ss,cx mov esp,0x7c00 ...
- VS2013的x86汇编语言开发环境配置
转载:https://blog.csdn.net/infoworld/article/details/45085415 转载:https://blog.csdn.net/u014792304/arti ...
- 存储器的保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记20
存储器的保护(三) 修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响).要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量 ...
- 存储器的保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记18
本文是原书第12章的学习笔记. 说句题外话,这篇博文是补写的,因为让我误删了,可恶的是CSDN的回收站里找不到! 好吧,那就再写一遍,我有坚强的意志.司马迁曰:“文王拘而演<周易>:仲尼厄 ...
- 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16
一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...
- 进入保护模式(二)——《x86汇编语言:从实模式到保护模式》读书笔记14
首先来段题外话:之前我发现我贴出的代码都没有行号,给讲解带来不便.所以从现在起,我要给代码加上行号.我写博客用的这个插入代码的插件,确实不支持自动插入行号.我真的没有找到什么好方法,无奈之下,只能按照 ...
- linux平台学x86汇编语言学习集合帖
linux平台学x86汇编语言学习集合帖 linux平台学x86汇编(一):https://blog.csdn.net/shallnet/article/details/45543237 linux平 ...
随机推荐
- MySQL InnoDB 存储引擎探秘
在MySQL中InnoDB属于存储引擎层,并以插件的形式集成在数据库中.从MySQL5.5.8开始,InnoDB成为其默认的存储引擎.InnoDB存储引擎支持事务.其设计目标主要是面向OLTP的应用, ...
- spring cloud feign 文件上传和文件下载
文件上传参考文档:http://blog.didispace.com/spring-cloud-starter-dalston-2-4/ 文件下载参考文档:https://blog.csdn.net/ ...
- Openlayer 3加载本地ArcGIS切片
第一篇博客,简单的开个头吧.希望自己能坚持记录.一般什么情况什么人需要这样的需求呢,伐木的光头强大哥说我们在深山老林里,没网的啊,地图就手机本地duang的加载一下吧.那么Server啊就要丢掉丢掉. ...
- 如何快速清理 docker 资源
如果经常使用 docker,你会发现 docker 占用的资源膨胀很快,其中最明显也最容易被察觉的应该是对磁盘空间的占用.本文将介绍如何快速的清理 docker 占用的系统资源,具体点说就是删除那些无 ...
- JMeter 接口测试-if控制器
JMeter 接口测试-if控制器 使用场景: 当业务场景是用户登录才能支付操作, 不登录点击支付, 页面会跳转到登录页面. 对于接口也是这样, 一个接口需要执行前, 需要有前提条件, 比如0状态 ...
- 测者的测试技术手册:智能化测试框架EvoSuite的一个坑以及填坑方法
问题 最近在不断地学习和探索EvoSuite框架的时候,在生产JUnit单元测试框架后,出现如下问题: Exception: Caused by: org.evosuite.runtime.TooMa ...
- hbase snapshot 表备份/恢复
snapshot其实就是一组metadata信息的集合,它可以让管理员将表恢复到以前的一个状态.snapshot并不是一份拷贝,它只是一个文件名的列表,并不拷贝数据.一个全的snapshot恢复以为着 ...
- oracle相关函数
(大写的PS:oracle存储过程测试进不去解决方案:重新编译:) TRUNC(sysdate, 'd') + 1 ////表示今天所在周的周一的年月日,如今天是2016.04.21周四,则TRU ...
- Web前端教程-HTML及标签的使用
目录 1. HTML简介 1.1. HTML文档基本结构 2. 标签 2.1. 标签语法 1.2. 标签的属性和值 1.3. 常见的标签 1. 基础标签 2. 格式标签 3. 表单标签 4. 框架标签 ...
- 浏览器中 F12 功能的简单介绍
chrome浏览器中 F12 功能的简单介绍 由于F12是前端开发人员的利器,所以我自己也在不断摸索中,查看一些博客和资料后,自己总结了一下来帮助自己理解和记忆,也希望能帮到有需要的小伙伴,嘿嘿! 首 ...