x86学习笔记

Posted by BUAADreamer on 2022-04-17
Words 6.1k and Reading Time 28 Minutes
Viewed Times

第1章 基础知识·

IBM-PC输入输出时采用ASCII码进行编码

第2章 IBM-PC计算机组织·

2.3 Intel 8086/8088 CPU的寄存器架构·

通用寄存器·

AX BX CX DX 常用于存放数据,称为数据寄存器,这四个寄存器可以拆分为AH,AL,BH,BL,CH,CL,DH,DL 8个8位寄存器,分别是相应寄存器的高8位和低8位

SP BP SI DI 常用于存放指针,称为指针或地址寄存器

数据寄存器·

AX是累加器(accumulator)常用来存放操作数和运算结果,乘除法强制使用,输入输出也需要使用

BX一般用来存放基地址(base address)

CX常在循环指令及串循环指令中用作计数器,移位指令则用CL作为计数器

DX用于32位乘除法时AX的扩展,输入输出指令中用来存放I/O端口的地址,实现间接寻址

指针与变址寄存器·

SP 堆栈寄存器,堆栈的操作(压入,弹出)会自动修改SP值

BP 基址指针,是一种基地址寄存器(类似于BX),不同的是相对于堆栈段而不是数据段

SI 源变址寄存器

DI 目的变址寄存器

段寄存器·

CS:代码段寄存器

DS:数据段寄存器

SS:堆栈段寄存器

ES:附加段寄存器

指令指针·

IP 指令指针寄存器

当前执行的指令在代码段的偏移地址

不能直接改动

标志寄存器·

9个一位的标志寄存器(或标志位)

组合在一起放入一个16位的程序状态字寄存器PSW

2.4 PC机内存组织·

20根地址线 总内存大小是 $2^{20}=1MB$

范围表示从 $00000H-FFFFFH$

同时x86是小端存储 即低地址存低位

采用16位寄存器记录分段信息,一共分为64K个段,每个段最多有64KB的段长

用逻辑地址,即段地址:偏移地址的格式映射某个物理地址

具体映射方式:物理地址=段地址*16D(或10H)+偏移地址

2.5 堆栈·

堆栈位置和大小由SS和SP寄存器确定

栈底由SP初始值确定,栈顶由SP值确定,一直压栈,SP值越来越小,栈顶距离栈底就越来越远

压栈·

1
PUSH AX

等价于

1
2
SP=SP-2 
[SP]=AX

弹出·

1
POP AX

等价于

1
2
AX=[SP]
SP=SP-2

第3章 寻址方式与指令系统·

3.1 指令格式·

指令汇编语言格式·

1
2
3
OP 	DST,SRC	;类似ADD AX,b
OP SRC ;类似POP
OP ;类似DIV

3.2 寻址方式·

与数据相关的寻址方式·

各个指令所需的操作数来自:

  • 寄存器。包括通用寄存器,段寄存器和标志寄存器(PSW)
  • 指令本身给出的立即数(常量)
  • 内存单元

立即寻址·

只能出现在源操作数不能出现目的操作数位置

目的操作数可以是寄存器或内存操作数

常用来给寄存器赋初值

常数可以直接写到指令,常量则需要线用EQU伪指令定义

1
2
3
MOV AX,512
VALUE EQU 51
MOV AX,VALUE

寄存器寻址·

操作数是CPU的某个寄存器

8位操作数,可以是AH,AL,BH,BL,CH,CL,DH,DL

16位操作数,可以是AX,BX,CX,DX,SP,BP,SI,DI,CS,DS,SS,ES

1
2
3
4
5
MOV AX,BX
ADD AX,DX
PUSH DS
STD ;设置DF=1
PUSHF ;PSW作为源操作数

直接寻址·

操作数的偏移地址直接在指令中指出的寻址方式

默认是相对于DS数据段的偏移量

1
MOV	AX,[2000H]

也可以先定义字/字节变量的方式

1
2
3
4
x	DW	?
c DB 'A'
MOV AX,x
MOV AL,c

汇编程序被汇编器汇编后,会计算出x,c的偏移值替换原来的x或c

寄存器间接寻址·

1
2
3
4
5
6
7
8
9
10
11
MOV	AX,[BX]
MOV BH,[BP]
MOV CX,[SI]
MOV DL,[DI]

#等价于 即缺省时是相应的段 也可以修改

MOV AX,DS:[BX]
MOV BH,SS:[BP]
MOV CX,DS:[SI]
MOV DL,DS:[DI]

注意不能用DX做间接寻址寄存器

寄存器相对寻址·

操作数有效地址EA是一个基址寄存器或变址寄存器的内容和指令中指定的8位或16位位移量之和

EA=间接寄存器的值+8位/16位常量

1
2
3
4
MOV	AX,[SI+10H]
MOV AX,10H[SI]
MOV AX,ARRAY[SI]
MOV TABLE[DI+1],AL

基址变址寻址方式·

操作数有效地址EA=基址寄存器+变址寄存器内容

1
2
MOV	AX,[BX][SI]
MOV AX,[BX+SI]

注意,基址变址寻址方式的基址寄存器只能是BX或BP变址寄存器只能是SI或DI

与转移地址有关的寻址方式·

主要运用于转移指令(JMP)和过程调用指令(CALL)

通过标号和过程名来确定同一代码段或另一代码段的偏移地址

段内直接寻址·

转向的指令实际有效地址是当前IP寄存器的内容和指令中指定的8位或16位位移量之和

条件转移指令必须是8位,所以省略了SHORT操作符

可以指定位移量

1
2
JMP	SHORT L1 ;8位 短跳转
JMP NEAR PTR L1 ;16位

段内间接寻址·

1
2
3
4
5
6
MOV	AX,OFFSET P1
MOV ADD1,AX
CALL ADD1
MOV BX,OFFSET ADD1
CALL [BX]
JMP BX

段间直接寻址·

1
CALL FAR PTR P2

要转移的标号或过程名必须具备FAR属性

段间间接寻址·

1
JMP	DWORD PTR [BX+INTERS] ;寄存器相对寻址方式

转移地址是一个双字,高位字在后,低位字在前

3.3 指令系统·

数据传送指令·

数据通路与类型匹配·

MOV和XCHG指令·

1
2
MOV DST,SRC
XCHG OPR1,OPR2

大部分指令需要遵守的规则:

  • 源和目的必须类型匹配(8位对8位,16位对16位)
  • 目的操作数不能为立即数
  • 源和目的操作数不能同时为内存操作数(串指令除外)
  • 源和目的操作数不能同时为段寄存器

PUSH,POP,PUSHF,POPF指令·

地址传送指令 LEA,LDS,LES·

将地址送到指定寄存器

1
2
3
LEA	REG,SRC	;源操作数src的偏移地址送入reg
LDS REG,SRC ;src中的双字内容依次送入reg和DS中
LES REG,SRC ;src中的双字内容依次送入reg和ES中

获得地址也可以使用OFFSET和SEG

比如

1
2
MOV	BX,OFFSET X
MOV AX,SEG X

算术运算指令·

查看45-49页

加减指令

CMP与NEG

乘法指令MUL IMUL和CBW

除法指令DIV IDIV和CWD

逻辑指令·

查看49-52页

逻辑运算指令

测试指令

移位指令

控制转移指令·

查看52-59页

无条件转移指令

条件转移指令

循环指令

过程调用和返回指令

处理器控制指令

第4章 汇编语言程序格式·

4.1 分段式程序结构·

SEGMENT ENDS DW EQU ASSUME ENDP END都是常见伪指令

标号命名必须以@/-/? 或者字母开头,指令与伪指令的常数以字母开头 A/B/C/D/E/F 开头需要在前面加0,避免混淆,不区分大小写!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
STACK1 	SEGMENT PARA STACK ;PARA STACK定义了堆栈
STACK_AREA DW 100H DUP(?)
STACK_BTM EQU $-STACK_AREA
STACK1 ENDS ;1-4行定义堆栈段 SEGMENTS和ENDS是一对
DATA SEGMENT
TABLE_LEN DW 16
TABLE DW 19,06,19,73,11,22,33,44
DW 20,06,20,74,55,66,77,88
DATA ENDS ;5-9行定义数据段
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1 ;为了阅读方便和整齐,需要字段对齐 指令语句和伪指令语句不能换行 这里其实没有真正的设置CS DS SS
MAIN PROC FAR ;PROC和ENDP是一对 如果只有一个过程则可以直接在代码段写指令
MOV AX,STACK1
MOV SS,AX
MOV SP,STACK_BTM ;栈底交给SP
MOV AX,DATA
MOV DS,AX
LP1: MOV BX,1
MOV CX,TABLE_LEN
DEC CX
MOV SI,OFFSET TABLE ;把TABLE的偏移地址送给SI
LP2: MOV AX,[SI] ;利用SI进行间接寻址
CMP AX,[SI+2] ;比较TABLE[i]与TABLE[i+1]的大小
JBE CONTINUE ;小于等于则跳转到CONTINUE 无符号数比较是JB/JA/JE 有符号数是 JG/JL/JE
XCHG AX,[SI+2] ;大于则交换,用AX当TEMP
MOV [SI],AX
MOV BX,0 ;清零标志变量
CONTINUE: ADD SI,2
LOOP LP2 ;<==> 先CX-- CX不为0就跳转到 LP2 CX为0则继续往下执行
CMP BX,1
JZ EXIT ;ZF为0则跳转到EXIT
JMP SHORT LP1 ;SHORT是相距较近的代码时用的
EXIT: MOV AX,4C00H ;AH-功能号 AL-返回码 相当于exit(0),返回MS-DOS命令提示符
INT 21H ;调用MS-DOS例程
MAIN ENDP
CODE1 ENDS ;10-36行定义代码段
END MAIN ;告诉编译器程序入口在MAIN

4.2 定义程序结构的伪指令·

4.3 数据定义与内存分配·

常数与常量·

二进制数:0-1序列,B结尾,比如:010B

八进制数:0-7组成序列,Q结尾,比如:127Q

十进制数:0-9组成序列,D结尾,D也可以省略。比如:129/129D

十六进制数:0-9,A-F组成序列,H结尾

字符或字符串:单引号或双引号括起来的字符:‘A’,“ABC”

实数:整数,小数,指数三部分,比如1.234E-5

EQU指令指定常量 比如:A EQU 12H

当前位置计数器 $,常用来计算长度,比如 SRACK_BTM EQU-TABLE

变量与变量定义·

x86中所有的地址+1,都是+1个BYTE对应的地址

String1 DB 'ABCD',0DH,0AH,'$' 这里其实定义了7个字,即A B C D 0DH 0AH $

ARRAY1 DB 10 DUP(?)

ARRAY2D DB 5 DUP(1,2,3,4,?) 二维数组定义

汇编,链接,运行·

1
2
3
masm code.asm
link code.asm
code.asm

调试与DEBUG·

1
debug code.exe

第5章 分支与循环程序设计·

5.1 顺序程序设计·

例题5.1 将一个25行,80列的数组的第y行,第x列元素的第i位置1·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
STACK1 	SEGMENT	PARA
STACK_AREA DW 100H DUP(?)
STACK_BOTTOM EQU $-STACK_AREA
STACK1 ENDS

DATA SEGMENT PARA
ARRAY DB 25*80 DUP(?)
X DB ? ;字节变量
Y DB ?
I DB ?
END SEGMENT

CODE SEGMENT PARA
ASSUME CS:CODE,SS:STACK1,DS:DATA
MAIN PROC FAR
MOV AX,STACK1
MOV SS,AX
MOV SP,STACK_BOTTOM
MOV AX,DATA
MOV DS,AX

MOV AL,80
MUL Y ;相当于AL*Y 结果送到AX
MOV DL,X
XOR DH,DH ;将DH清零 从而DX=X
ADD AX,DX ;AX=Y*80+X
MOV SI,OFFSET ARRAY ;SI=ARRAY首地址
ADD SI,AX;SI=需要的元素地址
MOV AL,80H;AL=10000000B
MOV CL,I;CL=I
SHR AL,CL ;AL=AL>>I 移位的数字不是1,必须使用CL寄存器!!
OR [SI],AL ;第I位置1 SI寄存器间接寻址
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE END
END MAIN

例题5.2 用查表方式将一位十六进制数转换成相应ascii码·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
STACK1 SEGMENT PARA STACK
STACK_AREA DB 100H DUP(?) ;定义PARA STACK就会自动初始化SP和SS
STACK1 ENDS

DATA SEGMENT PARA
ASCII_TABLE DB 30H,31H,32H,33H,34H,35H,36H,37H
DB 38H,39H,41H,42H,43H,44H,45H,46H
HEX DB ?
ASC DB ?
DATA ENDS

CODE SEGMENT PARA
ASSUME CS:CODE,SS:STACK,DS:DATA
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX
MOV SI,OFFSET ASCII_TABLE
MOV AL,HEX
XOR AH,AH;AX=HEX
ADD SI,AX;SI=HEX对应的ascii码元素的地址
MOV AL,[SI]
MOV ASC,AL

;打印ASCII码
MOV AH,2 ;二号中断
MOV DL,AL
INT 21H

EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

也可以用以下寄存器相对寻址方式

1
2
3
4
5
XOR		AH,AH
MOV AL,HEX
MOV SI,AX
MOV AL,ASCII_TABLE[SI]
MOV ASC,AL

也可以用基址加变址方式寻址

1
2
3
4
5
6
MOV		BX,OFFSET	ASCII_TABLE
MOV AL,HEX
XOR AH,AH
MOV SI,AX
MOV AL,[BX+SI]
MOV ASC,AL

5.2 分支程序设计·

例5.3 删除数组中目标元素·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
STACK1	SEGMENT		PARA STACK
STACK_AREA DB 100H DUP(?)
STACK1 ENDS

DATA SEGMENT
TABLE_LEN EQU 20
TABLE DW TABLE_LEN DUP(?)
TABLE_END LABEL WORD ;表最后的下一个元素
VALUE DW ?;要查找的目标值
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,SS:STACK1,DS:DATA
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX

SEARCH: MOV BX,OFFSET TABLE
MOV AX,VALUE
CMP AX,[BX]
JE FOUND
INC BX
INC BX ;BX+=2
CMP TABLE_END
JB SEARCH
MOV SI,0FFFFH ;没找到
JMP SHORT EXIT

FOUND: MOV SI,BX
DELETE: CMP BX,TABLE_END
JAE EXIT ;大于等于跳转
MOV AX,[BX+2]
MOV [BX],AX
ADD BX,2
JMP SHORT DELETE

EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

例5.4:跳转表·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
STACK0 SEGMENT PARA STACK
STACK_AREA DW 100H DUP(?)
STACK0 ENDS

DATA SEGMENT PARA
N EQU 5
JMP_TABLE DW ROAD1,ROAD2,ROAD3,ROAD4,ROAD5
I DW 3
DATA ENDS

CODE SEGMENT PARA
ASSUME CS:CODE,DS:DATA,SS:STACK0
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX
MOV BX,I
DEC BX
SHL BX,1
JMP JMP_TABLE[BX]
ROAD1: MOV AH,2
MOV DL,31H
INT 21H
JMP EXIT
ROAD2: MOV AH,2
MOV DL,32H
INT 21H
JMP EXIT
ROAD3: MOV AH,2
MOV DL,33H
INT 21H
JMP EXIT
ROAD4: MOV AH,2
MOV DL,34H
INT 21H
JMP EXIT
ROAD5: MOV AH,2
MOV DL,35H
INT 21H
JMP EXIT
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

5.3 循环程序设计·

与CX搭配使用的循环用法·

LOOP:先将CX设置为需要循环的次数,循环一次后,LOOP指令先将CX减1,并判断是否为0,不为0则继续循环,反之结束循环

LOOPE/LOOPZ:在LOOP基础上增加条件ZF==1 ,只有当ZF==1才继续循环

LOOPNE/LOOPNZ:在LOOP基础上增加条件ZF==0只有当ZF==0才继续循环

JCXZ:只判断,不递减CX。当CX==0时跳转

例5.5:内存中的一个字(二进制数)转换为十六进制数,并在屏幕上显示出来·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
STACK1	SEGMENT PARA STACK
STACK_AREA DB 100H DUP(?)
STACK1 ENDS

DATA SEGMENT PARA
VALUE DW 0011101000101111B ;3A2F
DATA ENDS

CODE SEGMENT PARA
ASSUME CS:CODE,SS:STACK1,DS:DATA
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX
MOV BX,VALUE
MOV CX,4 ;循环次数
SHIFT: PUSH CX
MOV CL,4
ROL BX,CL ;BX循环左移4位
MOV AL,BL ;取出低8位
AND AL,0FH;清除高四位,只留最低四位
ADD AL,30H
CMP AL,39H
JBE PRINT
ADD AL,'A'-'9'-1
PRINT: MOV DL,AL
MOV AH,2
INT 21H
POP CX
LOOP SHIFT
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

将内存中一个字(二进制或十六进制数)转换成十进制数的ASCII码,并显示出来·

方法1 例5.6 依次除以10000,1000,100,10,1 得到商·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
STACK1  SEGMENT PARA STACK
STACK_AREA DB 100H DUP(?)
STACK1 ENDS

DATA SEGMENT
VALUE DW 0FFFEH
DIVISOR DW 10000,1000,100,10,1
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,SS:STACK1,DS:DATA
;description
MAIN PROC
MOV AX,DATA
MOV DS,AX
MOV SI,OFFSET DIVISOR
MOV AX,VALUE
MOV CX,5
LP: XOR DX,DX ;清空被除数高16位
DIV WORD PTR [SI] ;AX=AX/DIVISOR
PUSH DX
OR AX,30H ;变成ASCII码
PRINT: MOV DL,AL
MOV AH,2
INT 21H
POP AX
ADD SI,2
LOOP LP
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

方法2 例5.7 不断除以10,按顺序所得的余数倒排即为所求·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
STACK1  SEGMENT PARA STACK
STACK_AREA DB 100H DUP(?)
STACK1 ENDS

DATA SEGMENT
VALUE DW 0FFFEH
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,SS:STACK1,DS:DATA
;description
MAIN PROC
MOV AX,DATA
MOV DS,AX
MOV CX,5
MOV AX,VALUE
MOV BX,10
LOOP1: XOR DX,DX
DIV BX
PUSH DX
LOOP LOOP1
MOV CX,5
LOOP2: POP AX
OR AX,30H
MOV DL,AL
MOV AH,2
INT 21H
LOOP LOOP2
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

堆栈的出入栈都必须以字为单位!

内存中组织好一个ASCII字符串,串的有效内容后加一个’$'结束字符,就可以利用DOS的9号功能打印字符串。

使用如下方式:

1
2
3
MOV	DX,串的首地址
MOV AH,9
INT 21H

方法3 例5.8 不断除以10得到商和余数,利用字符串进行输出·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
STACK1  SEGMENT PARA STACK
STACK_AREA DB 100H DUP(?)
STACK1 ENDS

DATA SEGMENT
VALUE DW 0FFFEH
RES DB 5 DUP(?),'$'
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,SS:STACK1,DS:DATA
;description
MAIN PROC
MOV AX,DATA
MOV DS,AX
MOV CX,5
MOV AX,VALUE
MOV BX,10
MOV DI,OFFSET RES + 4
LOOP1: XOR DX,DX
DIV BX
OR DX,30H
MOV [DI],DL
DEC DI
LOOP LOOP1
LOOP2: MOV DX,OFFSET RES
MOV AH,9
INT 21H
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

多重循环设计 冒泡排序为例·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
STACK1  SEGMENT PARA STACK
STACK_AREA DW 100H DUP(?)
STACK1 ENDS

DATA SEGMENT PARA
TABLEDATA_LEN DW 16
TABLEDATA DW 19,37,35,73,20,06,30,07
DW 20H,17H,0FFFFH,2001,2022,4,29,56
RES DB 5 DUP(?),20H,'$' ;十进制最多5位,20H表示空格
STR1 DB 'INIT_ARRAY:','$'
STR2 DB 'SORTED_ARRAY:','$'

NEWLINE DB 0DH,0AH,'$' ;回车换行
DATA ENDS

CODE SEGMENT PARA
ASSUME CS:CODE,SS:STACK1,DS:DATA
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX

PRINT_INIT_ARRAY: ;先打印初始的数组
MOV DX,OFFSET STR1
MOV AH,9
INT 21H
MOV DX,OFFSET NEWLINE
MOV AH,9
INT 21H
MOV CX,TABLEDATA_LEN
MOV SI,OFFSET TABLEDATA
WHILE1:
PUSH CX
MOV CX,5
MOV DI,OFFSET RES+4
MOV BX,10
MOV AX,[SI]
WHILE2:
XOR DX,DX
DIV BX
OR DL,30H
MOV [DI],DL
DEC DI
LOOP WHILE2
;打印字符串
MOV AH,9
MOV DX,OFFSET RES
INT 21H
INC SI
INC SI
POP CX
LOOP WHILE1
MOV AH,9
MOV DX,OFFSET NEWLINE
INT 21H

BUBBLE_SORT: ;冒泡排序
MOV CX,TABLEDATA_LEN
SORT_LOOP1: ;外层循环
PUSH CX
MOV SI,OFFSET TABLEDATA
MOV BX,0 ;BX作为一个标志变量,如果一次内层循环后仍然为0,说明已经是按照顺序排列了
SORT_LOOP2: ;内层循环
MOV AX,[SI]
CMP AX,[SI+2]
JNA CONTINUE
SWAP:
MOV BX,1
XCHG AX,[SI+2]
MOV [SI],AX
CONTINUE:
ADD SI,2
LOOP SORT_LOOP2
POP CX
CMP BX,0
JZ PRINT_SORTED_ARRAY
LOOP SORT_LOOP1

PRINT_SORTED_ARRAY: ;打印排序后的数组
MOV DX,OFFSET STR2
MOV AH,9
INT 21H
MOV DX,OFFSET NEWLINE
MOV AH,9
INT 21H
MOV CX,TABLEDATA_LEN
MOV SI,OFFSET TABLEDATA
WHILE3:
PUSH CX
MOV CX,5
MOV DI,OFFSET RES+4
MOV BX,10
MOV AX,[SI]
WHILE4:
XOR DX,DX
DIV BX
OR DL,30H
MOV [DI],DL
DEC DI
LOOP WHILE4
;打印字符串
MOV AH,9
MOV DX,OFFSET RES
INT 21H
INC SI
INC SI
POP CX
LOOP WHILE3
MOV AH,9
MOV DX,OFFSET NEWLINE
INT 21H

EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

5.4 串处理·

串处理指令·

典型的寻址过程是:DS:[SI]==>ES:[DI]

目的串——ES[DI] 即从这里取出

源串——DS[SI] 即写入这里

取串指令LODSB/LODSW·

LODSB将源串DS:[SI]的一个字节或一个字取到AL或AX中。

操作完后,按照DF的值自动修改SI的值。

DF=0则对SI+1或+2(根据字节或字)

DF=1则对SI-1或-2(根据字节或字)

存串指令STOSB/STOSW·

将AL或AX中的一个字节或字存入ES:[DI]中

操作完后,根据DF的值修改DI

DF=0则对DI +1或+2(根据字节或字)

DF=1则对DI -1或-2(根据字节或字)

串传送指令MOVSB/MOVSW·

将DS:[SI]中的字节或字传送到ES:[DI]中

操作完后,根据DF的值同时修改SI与DI

DF=0则SI与DI都+1或+2

DF=1则SI与DI都-1或-2

串比较指令CMPSB/CMPSW·

比较源串DS:[SI]与目的串ES:[DI]中的一个字节或一个字,与CMP类似

比较时,用源串中一个字节(字)减去目的串中一个字节(字)

不保留结果但影响标志寄存器,如CF,SF,ZF

执行完后根据DF值修改SI/DI

串扫描指令SCASB/SCASW·

在ES:[DI]中指定的目的串中扫描是否含有AL或AX中指定的字节或字,用AL或AX的内容减去ES:[DI]中的字节或字,比较结果影响标志寄存器。

执行完后根据DF值修改SI/DI

重复前缀指令REP·

格式:REP 串操作指令

比如:REP MOVSB

类似LOOP

每执行一次串操作指令就CX-1,直到CX为0时停止

条件重复前缀指令REPE/REPZ REPNE/REPNZ·

REPE/REPZ·

当CX==0或ZF==0时退出串操作指令,即运算结果不为0时退出

CX-=1

REPNE/REPNZ·

CX==0或ZF==1时退出串操作指令,即运算结果为0时退出

CX-=1

修改DF方向标志命令CLD,STD·

CLD清除DF标志寄存器,使得DF=0

STD设置DF标志寄存器,是的DF=1

串处理指令应用·

使用串处理的步骤

  • 根据需要设置DS,SI,ES,DI
  • 设置DF标志
  • 设置CX值
  • 选用REP,REPZ/REPE、REPNZ/REPNE

例5.10-5.14·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
STACK1  SEGMENT PARA    STACK
STACK_AREA DW 100H DUP(?)
STACK1 ENDS

DATA SEGMENT PARA
LEN DW 8
BUFF DB '19373573','$'
BUFF1 DB '20131839','$'
BUFF2 DB '33839230','$'
BUFF3 DB 'abcdEFZc','$'
BUFF4 DB 'AKSHBASB','$'
BUFF5 DB 'ASNSODOJ','$'
STR1 DB 'P_5_10:','$'
STR2 DB 'P_5_11:','$'
STR3 DB 'P_5_12:','$'
STR4 DB 'P_5_13:','$'
STR5 DB 'P_5_14:','$'
BIG_STR DB 'BUFF4>BUFF5','$'
SMALL_STR DB 'BUFF4<BUFF5','$'
NEW_LINE DB 0DH,0AH,'$'
FIND_STR DB 'BUFF5 CONTAINS A','$'
DATA ENDS

CODE SEGMENT PARA
ASSUME CS:CODE,DS:DATA,SS:STACK1
MAIN PROC FAR
;INIT
MOV AX,DATA
MOV DS,AX
P_5_10:
;PRINT
MOV AH,9
MOV DX,OFFSET STR1
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
;SAVE ES AND SET ES TO DS
PUSH ES
PUSH DS
POP ES
;STOSB
CLD
MOV CX,LEN
MOV DI,OFFSET BUFF
MOV AL,0
REP STOSB
POP ES
;PRINT
MOV AH,9
MOV DX,OFFSET BUFF
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
P_5_11:
;PRINT
MOV AH,9
MOV DX,OFFSET STR2
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF1
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF2
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
;SAVE ES AND SET ES TO DS
PUSH ES
PUSH DS
POP ES
;MOVSB
CLD
MOV CX,LEN
MOV DI,OFFSET BUFF2
MOV SI,OFFSET BUFF1
REP MOVSB
POP ES
;PRINT
MOV AH,9
MOV DX,OFFSET BUFF1
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF2
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
P_5_12:
;PRINT
MOV AH,9
MOV DX,OFFSET STR3
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF3
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
;SAVE ES AND SET ES TO DS
PUSH ES
PUSH DS
POP ES
;STOSB,LODSB
CLD
MOV CX,LEN
MOV DI,OFFSET BUFF3
MOV SI,OFFSET BUFF3
WHILE1:
LODSB
CMP AL,'a'
JB NEXT
CMP AL,'z'
JG NEXT
SUB AL,20H
STOSB
JMP NEXT1
NEXT: INC DI
NEXT1: LOOP WHILE1
POP ES
;PRINT
MOV AH,9
MOV DX,OFFSET BUFF3
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H

P_5_13:
;PRINT
MOV AH,9
MOV DX,OFFSET STR4
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF4
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AH,9
MOV DX,OFFSET BUFF5
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
;SAVE ES AND SET ES TO DS
PUSH ES
PUSH DS
POP ES
;CMPSB
CLD
MOV CX,LEN
MOV DI,OFFSET BUFF5
MOV SI,OFFSET BUFF4
JMP WHILE3
WHILE2: ;WAY1
CMPSB
JB SMALLER
JG BIGGER
LOOP WHILE2
WHILE3: ;WAY2
REPZ CMPSB
JB SMALLER
JA BIGGER
BIGGER: ;SRC>DST
MOV AH,9
MOV DX,OFFSET BIG_STR
INT 21H
JMP END_P_5_13
SMALLER: ;SRC<DST
MOV AH,9
MOV DX,OFFSET SMALL_STR
INT 21H
END_P_5_13:
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H

P_5_14: ;跑不通,原因不详
PUSH ES
PUSH DS
POP ES
MOV AH,9
MOV DX,OFFSET STR5
INT 21H
MOV AH,9
MOV DX,OFFSET NEW_LINE
INT 21H
MOV AL,'A'
CLD
MOV CX,LEN
MOV DI,OFFSET BUFF5
REPNZ SCASB
POP ES
JNZ EXIT
MOV AH,9
MOV AX,OFFSET BUFF5
INT 21H
EXIT: MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

第6章 子程序结构·

6.1 子程序设计方法·

过程定义·

1
2
3
PROC_NAME	PROC	FAR ;默认为NEAR
...
PROC_NAME ENDP

过程调用与返回·

使用CALL进行调用,RET返回调用者程序

CALL和RET都有FAR和NEAR属性

段内调用和返回使用NEAR,段间调用与返回使用FAR

段间返回的RET指令经汇编后会变成RETF

如果调用指令和所定义过程在同一代码段,则定义为NEAR属性,可省略NEAR

调用指令与所定义过程不在一个代码段,则定义为FAR属性。

6.2 编写子程序注意事项·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DISPLAY_STRING  PROC     FAR
PUSH AX
MOV AH,2
INT 21H
POP AX
RET
DISPLAY_STRING ENDP
DISPLAY_CHAR PROC FAR
PUSH AX
MOV AH,9
INT 21H
PUSH DX
MOV DX,OFFSET NEW_LINE ;打印换行符
MOV AH,9
INT 21H
POP DX
POP AX
RET
DISPLAY_CHAR ENDP

确定接口参数与传参·

  • 使用寄存器
  • 使用约定的内存变量
  • 使用堆栈

第7章 高级汇编语言技术·

7.1 宏·

宏定义·

1
2
3
宏名	MACRO	[形参表]
...
ENDM

例子·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PRINTCHAR 	MACRO	
OR DL,30H
MOV AH,2
INT 21H
ENDM
PRINTCHAR1 MACRO REG
MOV DL,REG
OR DL,30H
MOV AH,2
INT 21H
ENDM
PRINCHARS MACRO REG1,REG2
MOV DL,REG1
MOV AH,2
INT 21H
MOV DL,REG2
MOV AH,2
INT 21H
ENDM
PRINCHARS AL,BL

7.2 结构·

定义·

1
2
3
4
5
6
7
8
9
10
结构名	STRUC
...
结构名 ENDS

;如,描述学生
STUDENT STRUC
CLASS DB 8 DUP(?) ;班号
NUM DW ? ;学号
NAME1 DB 20 DUP(? ) ;名字
STEDENT ENDS

结构的预置与内存分配·

结构预置定义·

1
2
3
结构变量名	结构名 	<字段值表>
STUDENT1 STUDENT <'19373000',01,'SHARP'>
STUDENTS STUDENT 28 DUP(<'19373000',01,'SHARP'>)

访问结构变量及其字段·

1
2
3
4
5
6
7
8
9
10
MOV	CX,TYPE		STUDENT1	;CX=30 是结构体的长度
MOV BX,OFFSET STUDENT1 ;BX=STUDENT1的偏移值
MOV CX,LENGTH STUDENT1 ;CX=1
MOV CX,LENGTH STUDENTS ;CX=28
MOV CX,SIZE STUDENTS ;CX=28*30

MOV SI,OFFSET STUDENT1.NUM ;获得结构体中NUM变量的首地址
MOV AX,[SI].NUM[1]
MOV AX,STUDENT1.NUM[1]
MOV AX,STUDENT1.NUM+1

第8章 输入/输出程序设计·

8.1 输入/输出指令·

Intel 8086/8088内存寻址空间为1MB,而I/O空间为64KB

IN/OUT指令·

1
2
IN OP1,OP2 ;OP1为AL/AX OP2为输入端口地址或DX(用来存放端口地址)
OUT OP1,OP2 ;OP1为输出端口地址或DX,OP2为AL/AX

8.2 输入/输出控制方式·

程序控制的I/O方式·

立即传送方式·

程序查询方法·

中断控制方式·

直接内存访问方式 DMA·

8.3 中断控制方式·

中断·

中断源·

内中断·

外中断·

中断优先级·

中断向量表·

中断过程·

8.4 编写中断处理程序·