通用启动模版
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作为遍历数组的指针
判断正负
注意有符号数和无符号数使用不同跳转
无符号数比较 :
JB
(Jump if
Below):如果前一个操作数小于后一个操作数,则跳转。
JAE
(Jump if Above or
Equal):如果前一个操作数大于等于后一个操作数,则跳转。
这些指令适用于无符号整数比较,因为它们直接比较数值的大小。
有符号数比较 :
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
设计
TEST指令是用来将target和source想与,结果存放在CF里,这里是将AH与80H想与
这里符号位不变是在用NOT取反后加1
补码的取反加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是询问输入的语句
冒泡排序
用JCXZ防止一开始CX里面就是0陷入死循环
如果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