0%

第四部分_实战代码

通用启动模版

1
2
3
4
5
6
7
8
9
10
11
12
13
DATA SEGMENT
STR DB 'Hello world', '$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX

MOV AH, 4CH
INT 21H
CODE ENDS
END START

输出hello world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DATA SEGMENT
STR DB 'Hello world', '$' ; '$'表示结尾
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET STR ; 将要打印的东西的首地址的偏移地址移入寄存器DX
MOV AH, 9H
INT 21H
MOV AH, 4CH
INT 21H
CODE ENDS
END START

字符串大小写转换

难点1:大小写转换

小写转大写

小写字母 - 20H = 大写字母

大写转小写

大写字母 + 20H = 小写字母

难点2:写for循环

1
MOV [0] 1	; 错误,不可以把立即数写到内存里面

难点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
42
43
44
45
46
47
48
49
50
51
DATA SEGMENT
STR DB 'HEllo World',32,'$'
CHARA DB 'a'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
; 全部转为大写
; for(int i = 0; i < str.lentth; i++)
; if(str[i]是小写) str 转大写
;
MOV CX, 11 ;11表示字符串长度
MOV SI, OFFSET STR
LABEL1:
MOV AL, [SI] ;将指针BI当前指向的字母放到AL
CMP AL, 32 ;如果AL里面是空格
JE LABEL2 ;直接跳到LABEL2
CMP AL, CHARA ;将AL和CHARA比较
JB LABEL2 ;如果AL比CHARA小,说明AL是大写
; 如果AX比CHARA大,说明是小写,需要转大写
SUB AX, 20H
LABEL2: ;如果是大写,直接写回并递增
MOV [SI],AL
INC SI
LOOP LABEL1
MOV AH, 9H
INT 21H

; 全部转为小写
MOV CX, 11
MOV SI, OFFSET STR
LABEL3:
MOV AL, [SI]
CMP AL, 32
JE LABEL4
CMP AL, CHARA
JNB LABEL4
ADD AL, 20H
LABEL4:
MOV [SI], AL
INC SI
LOOP LABEL3
MOV AH, 9
INT 21H

MOV AH, 4CH
INT 21H
CODE ENDS
END START

求数组最值

遍历数组

1
2
3
4
5
6
7
DATA SEGMENT
BUF DB 08AH,093H,02EH,037H,019H,040H,074H,055H,0H,0A2H
PLUS DB 100H DUP(0)
TMP DB 100H DUP(0)
POS_NUM DB 0
DATA ENDS
MOV SI, OFFSET BUF ;将数组偏移地址移入SI,SI作为遍历数组的指针

判断正负

注意有符号数和无符号数使用不同跳转

  1. 无符号数比较
    • JB (Jump if Below):如果前一个操作数小于后一个操作数,则跳转。
    • JAE (Jump if Above or Equal):如果前一个操作数大于等于后一个操作数,则跳转。
    • 这些指令适用于无符号整数比较,因为它们直接比较数值的大小。
  2. 有符号数比较
    • JL (Jump if Less):如果前一个操作数小于后一个操作数,则跳转。
    • JGE (Jump if Greater or Equal):如果前一个操作数大于等于后一个操作数,则跳转。
    • 这些指令适用于有符号整数比较,因为它们考虑了数的符号

十进制转十六进制并打印输出

字符串表示的十进制“12345” --> 十六进制并在寄存器中3039H --> 字符串表示的十六进制“3039”

第一个箭头

上面这个图就是得到10进制,但是只要存放在寄存器中会自动转为十六进制

实现string类型转int类型,用宏实现

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
; 宏定义
STRDIGIT2INTDIGIT MACRO STRING_NAME, LENGTH
LOCAL FOR
PUSHF
LEA SI, STRING_NAME ; 获取字符串的首地址
XOR DX, DX
XOR AX, AX
XOR CX, CX
MOV CL, LENGTH
FOR:
; AX = 10 * AX --> AX = 8 * AX + AX --> AX << 3 + AX << 1
; 实现乘10
MOV DX, AX
PUSH CX
MOV CX, 3
SHL AX, CL
POP CX
SHL DX, 1
ADD AX, DX
; 加上当前的字符值
ADD AL, [SI]
ADC AH, 0
; - ‘0’
SUB AX, '0'
INC SI
LOOP FOR
POPF
ENDM

注:宏需要放在start里面

将int类型转str类型(大写字母)并在屏幕上打印

十六进制0~9加30H得到对应ASCII码

十六进制A~z加37H得到对应ASCII码

十六进制a~z加57H得到对应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
; 将十六进制转ASCII码打印输出,当前结果保存在AX中
FOR1:
; 将AX中数保存到DX中
MOV DX, AX
; 将DX与0FH相与,那么前面都清0,就保留最后1位
AND DX, 0FH
; 将当前DX中的数先加上30H看得到的数与40H关系
ADD DX, 30H
CMP DX, 39H
; 如果比40H小,说明目前得到的就是0~9的ASCII码,否则还要加7H才能得到A~F的ASCII码
JB DIGIT
ADD DX, 7H
DIGIT:
; 将DX中保存的ASCII码保存到内存中
MOV RES[BX], DL
DEC BX
; 通过将AX右移1位,去掉AX中最后一个数
SHR AX, 4
LOOP FOR1

MOV AH, 9H
; 通过将RES字符串首地址赋给DX从而打印字符串
MOV DX, OFFSET RES
INT 21H

含字母的ASCII码转int类型

0 ~ 9对应的ASCII码:31H到39H

A ~ Z对应的ASCII码:41H到5AH

a ~ z 对应的ASCII码:61H到7AH

用了宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ASCII2INT MACRO TMPBUF
LOCAL LABEL1, LABEL2, END0
PUSHF
XOR AX, AX
MOV AL, TMPBUF
; 先看是不是数字
CMP AL, 39H
JG LABEL1
SUB AL, 30H
JMP END0
LABEL1:
; 再看是不是大写字母
CMP AL, 5AH
JG LABEL2
SUB AL, 37H
JMP END0
; 最后判断是不是小写字母
LABEL2:
SUB AL, 57H
END0:
POPF
PUSH AX
ENDM

字符串

STOS

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
DATA SEGMENT
BUFFER DB 10H DUP(0) ; 假设有一个10字节的缓冲区
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA ; 将数据段地址加载到 AX 中
MOV DS, AX ; 将 AX 中的数据段地址复制到 DS 中
MOV ES, AX ; 将 AX 中的数据段地址复制到 ES 中
XOR DI, DI ; 清零 DI 寄存器

CLD
MOV CX, 10 ; 循环10次
MOV AL, 'A' ; 将 'A' 存储到 AL 中

STORE_LOOP:
STOSB ; 将 AL 寄存器中的数据存储到 ES:DI 指定的内存地址中,并递增 DI 寄存器
LOOP STORE_LOOP ; 循环

; 这里可以继续添加其他代码

MOV AH, 4Ch ; 退出程序
INT 21h

CODE ENDS
END START

MOVS

CX中设置为多少就会遍历字符串中多少位

SI

SI是16位寄存器,也就是与AX,BX这类大小相同,所以移动SI要与AX等一个字相加

SI可以指向一个字MOV AX, SI也可以指向一个字节MOV AL, SI

寻址

内存寻址的时候必须是与AX这种16位寄存器搭配使用,不能与AL这类8位寄存器搭配使用

ADD AL, RES_INT[BX]

字变量的原,反,补码转换

理论

正数的原码 = 反码 = 补码

负数的反码 = 原码符号位不变,其他取反

负数的补码 = 原码符号位不变,其他位取反,末尾加1

设计

  1. TEST指令是用来将target和source想与,结果存放在CF里,这里是将AH与80H想与
  2. 这里符号位不变是在用NOT取反后加1
  3. 补码的取反加1是对低位用ADD,高位考虑进位用ADC
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
DATA SEGMENT
BUF1 DW 0FF23H
BUF2 DW 0
BUF3 DW 0
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX

MOV AX, BUF1
TEST AH, 80H
MOV BX, AX
JZ POSTIVE
NOT AX
ADD AH, 80H
ADD AL, 1
ADC AH, 0
NOT BX
ADD BH, 80H
POSTIVE:
MOV BUF2, AX
MOV BUF3, BX
MOV AH, 4CH
INT 21H
CODE ENDS
END START

用宏定义写的询问输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ASK_INPUT MACRO STR_ADDRESS
LEA DX, STR_ADDRESS
MOV AH, 09H
INT 21H
LEA DX, NEW_LINE
INT 21H
XOR AX, AX
MOV AH, 01H
INT 21H
MOV TMPBUF, AL
LEA DX, NEW_LINE
MOV AH, 09H
INT 21H
ENDM
; 其中NEW_LINE是NEW_LINE DB 0AH, 0DH, '$'
; STR_ADDRESS是询问输入的语句

冒泡排序

  1. 用JCXZ防止一开始CX里面就是0陷入死循环
  2. 如果MOV DX SI,那么从SI中取出的就是1个字,如果是MOV DL, SI,那么从SI中取出的就是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
BUBBLE_SORT MACRO WAIT_SORT_ARRAY, ARRAY_LENGTH
LOCAL FOR, FOR2, END0, END1
PUSHF
PUSH CX
XOR CX, CX
MOV CL, ARRAY_LENGTH
FOR:
PUSH CX
DEC CX
CMP CX, 0
JCXZ END0
LEA DI, WAIT_SORT_ARRAY
MOV AX, 0
FOR2:
MOV DL, [DI]
CMP DL, [DI + 1]
JL END1
XCHG DL, [DI + 1]
XCHG [DI], DL
MOV AX, 1
END1:
INC DI
LOOP FOR2
CMP AX, 0
JE END0
POP CX
LOOP FOR
END0:
POP CX
POPF
ENDM

将十进制数转换成指定进制

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
jinzhizhuanhuan MACRO TMP_INT_HIGH, TMP_INT_LOW, TMP_RADIX, STR_TAR, BITS
LOCAL WHILE, BREAK, FOR, DIGIT1
;将待转换的数保存回AX
XOR AX, AX
MOV AH, TMP_INT_HIGH
MOV AL, TMP_INT_LOW
; 将目标进制保存到BX
MOV BL, TMP_RADIX

WHILE:
CMP AX, 0
JE BREAK
XOR DX, DX
DIV BX
PUSH DX
INC BITS
JMP WHILE
BREAK:
XOR CX, CX
MOV CL, BITS

; 转ASCII码
LEA SI, STR_TAR
ADD SI, 2
FOR:
POP AX
CMP AX, 9
JBE DIGIT1
ADD AX, 7H
DIGIT1:
ADD AX, 30H
MOV [SI], AL
INC SI
LOOP FOR
ENDM