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平 ...
随机推荐
- Django学习之九: auth 认证组件
目录 Django auth 认证组件 配置使用auth组件及其中间件 request.user 可以直接在template模版中使用 auth组件常用api 获取认证model类 认证检测装饰器@l ...
- Android自定义控件实例,圆形头像(图库 + 裁剪+设置),上传头像显示为圆形,附源码
Android项目开发中经常会遇见需要实现圆角或者圆形的图片功能,如果仅仅使用系统自带的ImageView控件显然无法实现此功能,所以通过系列文章的形式由简到繁全方位的介绍一下此功能的实现,巩固一下自 ...
- vue.js 学习笔记3——TypeScript
目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...
- 【English】十、"谓语的地方"看到有两个动词:I go say hello.、非谓语形式
一.I go say hello. 这是一种偏口语的说法.一个句子中不能同时有两个谓语. 标准的用法有: I go and say hello. and 连接这两个动词,表示并列等关系.go and ...
- Vue2.0 --- vue-cli脚手架中全局引入JQ
第一步:安装jQuery npm/cmpn方式安装(默认安装1.7.X版本的JQ) npm/cnpm install jQuery 如果想安装更高版本的JQ那么可以选择在package.json文件下 ...
- redis -hash(哈希.对象)
hash 用于储存对象,对象的结构为属性.值 值的类型string 增加.修改: 设置单个属性: hset 键 field 值 例如: 设置键 user 的属性name 为 python hset u ...
- Java 基本文件操作
Java 文件操作 , 这也是基于Java API 操作来实现的. 文件是操作系统管理外存数据管理的基本单位, 几乎所有的操作系统都有文件管理机制. 所谓文件, 是具有符号名而且在逻辑上具有完整意义的 ...
- js坚持不懈之15:修改html内容和属性的方法
1. 修改 HTML 内容 <!DOCTYPE html> <html> <body> <p id = "change">原始内容& ...
- 光盘安装win7系统教程
光盘安装系统是最传统的安装系统的方法,虽然现在U盘安装和硬盘安装已经很方便,但仍有很多用户习惯光盘安装的方式,下面小编教大家如何利用光盘安装系统. 来源:https://www.haoxitongx. ...
- vue 动态样式
<p :style="{width:'4px',height: '24px',background: '#f7ce51'}"></p> <p:styl ...