基础知识 ;; 输入 MOV AH,01H ; 调用 DOS 功能 01H,从标准输入获取一个字符 INT 21H ; 中断 21H,调用 DOS 功能 ;; 输出 MOV AH,02H ; 输出一个字符 INT 21H ;; 终止程序 MOV AX,4C00H INT 21H ;; 终止程序 MOV AH,4CH INT 21H ;; 模板 DSEG SEGMENT DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG START: ; PROGRAM CSEG ENDS END START ;; 回车 MOV DL,0DH ; 为达到换行输出,突出效果的目的,换行输出 MOV AH,02H INT 21H ;; 换行 MOV DL,0AH MOV AH,02H INT 21H ;;1. **回车符 (CR - Carriage Return, ASCII 0x0D)**:在计算机中,回车符通常表示光标移动到当前行的开头。当输出字符时,光标会回到行首,但不会移动到下一行。在老式打字机中,回车的含义是将打印头移至纸张的开头位置。 ;;2. **换行符 (LF - Line Feed, ASCII 0x0A)**:换行符表示光标向下移动到下一行,但保持在当前列。它将光标从当前行移到下一行的相同列。在老式打字机中,换行的含义是将纸张向上移动一行。 LEA SI,NUM ; 将数组NUM的地址加载到SI寄存器 ;; JAE
下面是一些常见汇编指令的简要说明:
LOOP : 用于循环,根据CX寄存器的值判断是否继续循环。
JZ (Jump if Zero) : 如果标志寄存器的Zero标志位为1(表示上一次运算结果为零),则跳转。
JNZ (Jump if Not Zero) : 如果标志寄存器的Zero标志位为0(表示上一次运算结果不为零),则跳转。
ADD (Addition) : 将两个操作数相加,并将结果存储在目标操作数中。
SUB (Subtraction) : 将目标操作数减去源操作数,结果存储在目标操作数中。
SHL (Shift Left) : 将操作数左移,相当于乘以2的n次方。
INC (Increment) : 将目标操作数加1。
JMP (Jump) : 无条件跳转到指定的标签或地址。
XOR (Exclusive OR) : 将目标操作数与源操作数进行异或运算。
JLE (Jump if Less Than or Equal) : 如果标志寄存器的Zero标志位为1或者Sign标志位(表示结果为负数)为1,则跳转。
JS (Jump if Sign) : 如果标志寄存器的Sign标志位为1(表示结果为负数),则跳转。
JZ (Jump if Zero) : 如果标志寄存器的Zero标志位为1(表示上一次运算结果为零),则跳转。
SAL (Shift Arithmetic Left) : 算术左移,相当于将操作数左移,最高位(符号位)被移出并影响进位标志。
NEG (Negate) : 将目标操作数取负值。
JAE (Jump if Above or Equal) : 如果标志寄存器的Carry标志位为0(表示无进位)且Zero标志位为0(表示不等于),则跳转。
实验一 1、题目:编制程序利用功能调用键入及显示字符和字符串,将BUF中两个压缩BCD码数值相加并显示结果(十进制形式)。 DSEG SEGMENT ; 数据段定义 DSEG ENDS ; 数据段结束 CSEG SEGMENT ; 代码段定义 ASSUME CS:CSEG,DS:DSEG ; 假定 CS 寄存器指向代码段,DS 寄存器指向数据段 START: ; 程序入口标签 MOV AX,DSEG ; 将数据段地址加载到 AX 寄存器 MOV DS,AX ; 将 DS 寄存器设置为数据段地址 ; 先弹窗口,后输入 MOV AH,01H ; 调用 DOS 功能 01H,从标准输入获取一个字符 INT 21H ; 中断 21H,调用 DOS 功能 MOV BL,AL ; 将输入的字符存储到 BL 寄存器 ; 先输入,后弹窗口 MOV DL,BL ; 将 BL 寄存器的值复制到 DL 寄存器 MOV AH,02H ; 调用 DOS 功能 02H,输出一个字符 INT 21H ; 中断 21H,调用 DOS 功能 MOV AX,4C00H ; 调用 DOS 功能 4C00H,程序退出 INT 21H ; 中断 21H,调用 DOS 功能 CSEG ENDS ; 代码段结束 END START ; 程序结束
解析 2、设内存DATA单元中存放一个无符号字节数据,编写程序,将其拆分成两位十六进制数,并将存入在HEX,和,HEX+1 单元中,HEX存放高位十六进制数,HEX+1存放低位十六进制数。(拆字) DSEG SEGMENT ; 数据段定义 DATA DB 34H ; 定义DB(字节 8bit)类型的变量DATA,其值为34H HEX DB 0,0 ; 定义DB类型的变量HEX,即其后连续的一个变量HEX+1,初始值都为0 DSEG ENDS ; 数据段定义结束 CSEG SEGMENT ; 代码段定义 ASSUME CS:CSEG,DS:DSEG ; 将段与段寄存器关联 START: MOV AX,DSEG ; 将数据段首地址送入DS中 MOV DS,AX ; 将AX中的值加载到DS寄存器 MOV AL,DATA ; 将待拆字的变量DATA送入AL中(DATA仅一个字节) MOV BL,AL ; 将AL中值送入BL备份 AND AL,0F0H ; 将待拆字值高四位与F0H进行与(&)操作,获得第一个数字字符 MOV CL,4 ; 需要将高四位移位至第四位,由于位移运算符仅能配合操作数 1,而此次要位移四次,故将移动次数4送入CL中 ROR AL,CL ; ROR(循环右移)配合CL使用,达到高四位变低四位的目的,至此,拆出来的第一个“字”已获得 MOV HEX,AL ; 将第一个字符送入要求的HEX中 ADD AL,30H ; 为方便后期输出,将寄存器中数值加30H(数字零在十六进制ASCII中为30H) MOV DL,AL ; 将要输出字符送至DL中 MOV AH,02H ; 调用系统中断输出显示 INT 21H MOV DL,0DH ; 为达到换行输出,突出效果的目的,换行输出 MOV AH,02H INT 21H MOV DL,0AH MOV AH,02H INT 21H AND BL,0FH ; 将BL中的备份与0FH相与,达到仅提取出低四位的目的 MOV HEX+1,BL ; BL中已然是拆出来的第二个“字”,送入目标HEX+1中 ADD BL,30H ; 为方便后期输出,将寄存器中数值加30H MOV DL,BL ; 将带输出值送入DL MOV AH,02H ; 调用系统中断输出显示 INT 21H MOV AH,4CH ; 将返回码带回结束 INT 21H CSEG ENDS ; 代码段结束 END START ; 源程序结束
解析 实验二 1、 已知在数据区中DATA开始存放3个字符,编制分支程序完成,输出其中最大的字符 老师版 DSEG SEGMENT ; 数据段定义 ARG DW 1001H,2002H,3003H ; 定义一个包含三个字的数组 ARG,初始值分别为 1001H,2002H,3003H MAX DW ? ; 定义一个变量 MAX 用于存储最大值,初始化为空 DSEG ENDS ; 数据段结束 CSEG SEGMENT ; 代码段定义 ASSUME CS:CSEG,DS:DSEG ; 假定 CS 寄存器指向代码段,DS 寄存器指向数据段 START: ; 程序入口标签 MOV AX,DSEG ; 将数据段地址加载到 AX 寄存器 MOV DS,AX ; 将 DS 寄存器设置为数据段地址 LEA SI,ARG ; 将数组 ARG 的地址加载到 SI 寄存器 ; 比较第一个和第二个元素 MOV AX,[SI] ; 将数组的第一个元素加载到 AX 寄存器 MOV BX,[SI+2] ; 将数组的第二个元素加载到 BX 寄存器 CMP AX,BX ; 比较两个元素 JAE MAX1 ; 如果 AX >= BX,跳转到 MAX1 标签 XCHG AX,BX ; 交换 AX 和 BX 寄存器的值 MAX1: ; 比较当前最大值和第三个元素 MOV BX,[SI+4] ; 将数组的第三个元素加载到 BX 寄存器 CMP AX,BX ; 比较当前最大值和第三个元素 JAE MAX2 ; 如果 AX >= BX,跳转到 MAX2 标签 XCHG AX,BX ; 交换 AX 和 BX 寄存器的值 MAX2: MOV MAX,AX ; 将最大值存储到 MAX 变量中 MOV AX,4C00H ; 调用 DOS 功能 4C00H,程序退出 INT 21H ; 中断 21H,调用 DOS 功能 CSEG ENDS ; 代码段结束 END START ; 程序结束
学生版 DSEG SEGMENT NUM DW 1001H,2002H,3003H ; 定义一个包含三个WORD类型元素的数组NUM MAX DW 0 ; 定义一个用于存储最大值的变量MAX DSEG ENDS CSEG SEGMENT ASSUME DS:DSEG,CS:CSEG ; 指定数据段和代码段寄存器 START: MOV AX,DSEG ; 将数据段地址加载到AX寄存器 MOV DS,AX ; 将AX中的值加载到DS寄存器 LEA SI,NUM ; 将数组NUM的地址加载到SI寄存器 MOV AX,[SI] ; 将数组的第一个元素加载到AX寄存器 MOV BX,[SI+2] ; 将数组的第二个元素加载到BX寄存器 CMP AX,BX ; 比较数组的第一个和第二个元素 JAE MAX1 ; 如果第一个元素大于等于第二个元素,跳转到MAX1标签 XCHG AX,BX ; 交换AX和BX的值 MAX1: MOV BX,[SI+4] ; 将数组的第三个元素加载到BX寄存器 CMP AX,BX ; 比较AX和BX的值 JAE MAX2 ; 如果AX大于等于BX,跳转到MAX2标签 XCHG AX,BX ; 交换AX和BX的值 MAX2: MOV MAX,AX ; 将最大值存储到MAX变量中 MOV BL,AH ; 将AX的高字节(原数组的最后一个元素的高字节)存储到BL中 MOV AL,AH ; 复制AX的高字节到AL中 AND AL,0F0H ; 将AL中的高四位保留,低四位清零 MOV CL,4 ; 移动高四位到低四位的次数 ROR AL,CL ; 将高四位移到低四位 ADD AL,30H ; 转换为ASCII字符 MOV DL,AL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H AND BL,0FH ; 取出AX的高字节的低四位 ADD BL,30H ; 转换为ASCII字符 MOV DL,BL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H ; 后两位 MOV AX,MAX ; 将最大值重新加载到AX中 MOV BL,AL ; 复制AX的低字节到BL中 AND AL,0F0H ; 将低四位清零 MOV CL,4 ; 移动高四位到低四位的次数 ROR AL,CL ; 将高四位移到低四位 ADD AL,30H ; 转换为ASCII字符 MOV DL,AL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H AND BL,0FH ; 取出AX的低字节的低四位 ADD BL,30H ; 转换为ASCII字符 MOV DL,BL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H MOV AH,4CH ; 调用21H中断以结束程序 INT 21H CSEG ENDS END START ; 源程序结束
后面是拆字进行输出,由于数字是4字节,所以需要进行2次的拆字,输出4下
阿威版:
DSEG SEGMENT NUM DW 1001H,2002H,4124H MAX DW ? DSEG ENDS CSEG SEGMENT ASSUME DS:DSEG,CS:CSEG START: MOV AX,DSEG MOV DS,AX LEA SI,NUM MOV AX,[SI] MOV BX,[SI+2] CMP AX,BX JAE MAX1 XCHG AX,BX MAX1: MOV BX,[SI+4] CMP AX,BX JAE MAX2 XCHG AX,BX MAX2: MOV MAX,AX SHOW: MOV BL,AH AND BL,0F0H MOV CL,4 ROR BL,CL ADD BL,30H ; ASCII MOV DL,BL MOV AH,02H INT 21H MOV AX,MAX MOV BL,AH AND BL,00FH ADD BL,30H ; ASCII MOV DL,BL MOV AH,02H INT 21H MOV AX,MAX MOV BL,AL AND BL,0F0H MOV CL,4 ROR BL,CL ADD BL,30H ; ASCII MOV DL,BL MOV AH,02H INT 21H MOV AX,MAX MOV BL,AL AND BL,00FH ADD BL,30H ; ASCII MOV DL,BL MOV AH,02H INT 21H MOV AH,4CH INT 21H CSEG ENDS END START
分段函数 DSEG SEGMENT ARGX DB -1 ; 定义一个字节型变量 ARGX,并初始化为 -1 RLTY DB 00H ; 定义一个字节型变量 RLTY,并初始化为 00H DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 定义代码段和数据段寄存器 START: MOV AX,DSEG ; 将数据段地址加载到 AX 寄存器 MOV DS,AX ; 将 DS 寄存器设置为数据段地址 MOV AL,ARGX ; 将 ARGX 中的值加载到 AL 寄存器 AND AL,AL ; 按位与操作,检查 AL 是否为负数 JS A1 ; 如果为负数,跳转到标签 A1 JZ SAVE ; 如果为零,跳转到标签 SAVE CMP AL,8 ; 比较 AL 和 8 JLE ONE ; 如果 AL 小于等于 8,跳转到标签 ONE CMP AL,15 ; 比较 AL 和 15 JGE SAVE ; 如果 AL 大于等于 15,跳转到标签 SAVE SAL AL,1 ; 算术左移 AL 一位,相当于 AL = AL * 2 SAL AL,1 ; 再次左移,相当于 AL = AL * 2 ADD AL,ARGX ; 将 ARGX 加到 AL SUB AL,2 ; 减去 2 JMP SAVE ; 无条件跳转到标签 SAVE ONE: ADD AL,10 ; 如果 AL 小于等于 8,则加上 10 JMP SAVE ; 无条件跳转到标签 SAVE A1: NEG AL ; 如果 AL 为负数,取负值 SAVE: MOV RLTY,AL ; 将 AL 的值保存到 RLTY 变量 SHOWHFX: ADD AL,30H ; 将 AL 转换为 ASCII 码 MOV DL,AL ; 将 AL 的值加载到 DL 寄存器 MOV AH,02H ; 设置功能号为 02H(字符输出) INT 21H ; 调用 DOS 中断 21H,输出字符 MOV AX,4C00H ; 设置功能号为 4C00H(程序终止) INT 21H ; 调用 DOS 中断 21H CSEG ENDS END START
JS A1
:如果 AL
为负数,跳转到标签 A1
。
JZ SAVE
:如果 AL
为零,跳转到标签 SAVE
。
CMP AL,8
:比较 AL
和 8。
JLE ONE
:如果 AL
小于等于 8,跳转到标签 ONE
。
CMP AL,15
:比较 AL
和 15。
JGE SAVE
:如果 AL
大于等于 15,跳转到标签 SAVE
。
以下是一系列的算术和逻辑操作,最终结果保存在 RLTY
中。
在x86汇编语言中,JS
是条件跳转指令,其含义是“Jump if Sign (SF=1)”,即当符号标志 SF(Sign Flag)为1时跳转。在这里,JS A1
表示如果符号标志 SF 为1(也就是 AL 寄存器中的值为负数),则跳转到标签 A1
执行相关的代码。这是一种条件性的跳转,用于根据结果是否为负数来执行不同的代码分支。
在x86汇编语言中,JZ
是条件跳转指令,其含义是“Jump if Zero (ZF=1)”,即当零标志 ZF(Zero Flag)为1时跳转。在这里,JZ SAVE
表示如果零标志 ZF 为1(也就是 AL 寄存器中的值为零),则跳转到标签 SAVE
执行相关的代码。这是一种条件性的跳转,用于根据结果是否为零来执行不同的代码分支。
JMP
(Jump)指令是无条件跳转指令,执行时会直接跳转到指定的标签或地址,而不受其他条件的限制。因此,一旦JMP
执行,程序就会跳转到指定的目标,不再执行JMP
之后的代码。
实验三 统计由DATA单元开始的字节数据中的负数元素的个数。其中数据的总个数放在CNT单元中,最终结果放在RLT单元。 DSEG SEGMENT DATA DB -1, 2, -3, 4, -5 ; 定义一个数据段 DATA,包含 5 个字节的有符号整数 COUNT DB 5 ; 定义一个字节 COUNT,表示数组的长度 RLT DB 0 ; 定义一个字节 RLT,用于存储结果 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 定义代码段和数据段寄存器 START: MOV AX, DSEG ; 将数据段地址加载到 AX 寄存器 MOV DS, AX ; 将 DS 寄存器设置为数据段地址 MOV BX, OFFSET DATA ; 将数组 DATA 的偏移地址加载到 BX 寄存器 MOV CL, COUNT ; 将数组的长度加载到 CL 寄存器 MOV DX, 0 ; 将 DX 寄存器清零,用于存储负数的个数 AGAIN: MOV AL, [BX] ; 将 BX 地址指向的字节数据加载到 AL 寄存器 ADD AL, AL ; 将 AL 寄存器的值乘以 2 JNS PLUS ; 如果结果为正数或零,跳转到标签 PLUS INC DL ; 如果结果为负数,将 DX 寄存器加 1 PLUS: INC BX ; 将 BX 寄存器的值加 1,指向下一个数组元素 LOOP AGAIN ; 循环,CL 寄存器递减,直到为零 MOV RLT, DL ; 将负数的个数保存到 RLT 变量 SHOW: ADD DL, 30H ; 将结果转换为 ASCII 码 MOV AH, 02H ; 设置功能号为 02H(字符输出) INT 21H ; 调用 DOS 中断 21H,输出字符 MOV AX, 4C00H ; 设置功能号为 4C00H(程序终止) INT 21H ; 调用 DOS 中断 21H CSEG ENDS END START
2、题目2:从键盘输入0-9任何一个数字,然后让系统按指令响出铃声。 CSEG SEGMENT ; 代码段开始 ASSUME CS:CSEG ; 段寄存器关联 START: ; 程序入口标签 XOR AX, AX ; 清零 AX 寄存器 XOR CX, CX ; 清零 CX 寄存器 MOV AH, 01H ; 调用 DOS 中断服务功能 01H,等待从键盘输入一个字符,并在显示器上回显 INT 21H SUB AL,30H MOV CL,AL RING: ; 循环标签 MOV DL, 07H ; 声音字符 MOV AH, 02H ; 调用 DOS ,发出声音 INT 21H LOOP RING ; 循环指令,指定循环标签为 RING,CX 寄存器的值减 1,直到 CL 为零 MOV AX, 4CH ; 通过 DOS 中断服务功能 4C00H 结束程序 INT 21H CSEG ENDS ; 代码段结束 END START ; 程序结束
在内存中存放一个完全平方数,求平方根,并把平方根送入ROOT单元。 DSEG SEGMENT DATA DW 25 ; 定义一个数据 DATA,初始值为 25 ROOT DW 0 ; 定义一个变量 ROOT,用于保存计算得到的平方根 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG, DS:DSEG ; 段寄存器的默认段寄存器 CS 的别名是 CSEG,数据段 DS 的别名是 DSEG START: MOV AX, DSEG ; 将 DSEG 的地址加载到 AX 寄存器 MOV DS, AX ; 将 DS 寄存器设置为 DSEG,让 DS 指向数据段 XOR CX, CX ; 清零 CX 寄存器,用于保存计数器 XOR BX, BX ; 清零 BX 寄存器,用于保存中间结果 XOR AX, AX ; 清零 AX 寄存器,用于保存循环计数器 MOV DX, DATA ; 将 DATA 的地址加载到 DX 寄存器 AGAIN: AND DX, DX ; 判断 DX 是否为零 JZ SAVE ; 如果 DX 为零,则跳转到 SAVE MOV BX, AX ; 将 AX 寄存器的值复制到 BX,相当于 BX = AX SHL BX, 1 ; 将 BX 寄存器的值左移一位,相当于 BX = BX * 2 INC BX ; 将 BX 寄存器的值加一 SUB DX, BX ; 将 DX 寄存器的值减去 BX,相当于 DX = DX - BX INC CX ; 将 CX 寄存器的值加一,用于计数 INC AX ; 将 AX 寄存器的值加一,用于循环计数 JMP AGAIN ; 无条件跳转到 AGAIN SAVE: MOV ROOT, CX ; 将计算得到的平方根保存到 ROOT 变量 SHOW: MOV DX, CX ; 将 CX 寄存器的值复制到 DX ADD DX, 30H ; 将 DX 寄存器的值加上 ASCII '0',转换为字符 MOV AH, 02H ; 设置功能号为 02H(字符输出) INT 21H ; 调用 DOS 中断 21H MOV AX, 4C00H ; 设置功能号为 4C00H(程序终止) INT 21H ; 调用 DOS 中断 21H CSEG ENDS END START
实验四 现在有一组数据:1,3,5,2,9,8,4。请编写程序,按降序排序,并将排序结果输出到屏幕上。同时,将十进制结果输出到显示器上。 DSEG SEGMENT A DW 2,5,4,8,3,9 ; 定义一个包含整数2,5,4,8,3,9的数组A DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 假设代码段寄存器为CS,数据段寄存器为DS START: MOV AX,DSEG ; 将数据段DSEG的地址加载到寄存器AX MOV DS,AX ; 将数据段地址设置到数据段寄存器DS XOR AX,AX ; 寄存器AX清零 MOV CX,6 ; 初始化寄存器CX为数组元素个数6 DEC CX ; CX减一,用于循环计数 LOOP1: MOV DI,CX ; 将CX的值移动到DI寄存器,用于外层循环计数 MOV BX,0 ; 初始化BX为0,用于内层循环计数 LOOP2: MOV AX,A[BX] ; 从数组A中加载元素到寄存器AX CMP AX,A[BX+2] ; 比较当前元素和下一个元素 JGE LOOP3 ; 如果当前元素大于等于下一个元素,跳转到LOOP3 XCHG AX,A[BX+2] ; 这两个东西的值交换了 MOV A[BX],AX ; 将交换后的值放回数组 LOOP3: ADD BX,2 ; 移动到数组的下一个元素 LOOP LOOP2 ; 内层循环 MOV CX,DI ; 恢复CX的值 LOOP LOOP1 ; 外层循环 SHOW: XOR CX,CX ; 清零CX寄存器 MOV CX,6 ; 设置CX为数组元素个数6 XOR BX,BX ; 清零BX寄存器 MOV BX,OFFSET A ; 将数组A的偏移地址加载到BX寄存器 LOOP4: MOV DX,A[BX] ; 从数组A中加载元素到寄存器DX ADD DX,30H ; 将数字转换为ASCII码 MOV AH,02H ; DOS功能号,用于显示字符 INT 21H ; 调用DOS中断 ADD BX,2 LOOP LOOP4 ; 循环显示数组元素 MOV AX,4C00H ; 设置DOS功能号,用于程序退出 INT 21H ; 调用DOS中断 CSEG ENDS END START ; 结束程序
在 x86 汇编语言中,DI
是一个 16 位寄存器,通常用作源变址寄存器(Source Index Register)。DI
寄存器经常与字符串和数组操作相关的指令一起使用,用于指示数据的源地址。在上述程序中,MOV DI, CX
语句将 CX
寄存器的值移动到 DI
寄存器,用于循环计数。
外层循环(LOOP1):
MOV DI, CX
将 CX
寄存器的值移动到 DI
寄存器,用于保存外层循环计数值。
MOV BX, 0
初始化 BX
寄存器为 0,用于内层循环计数。
内层循环(LOOP2):
MOV AX, A[BX]
从数组 A
中加载元素到 AX
寄存器。
CMP AX, A[BX+2]
比较当前元素和下一个元素。
JGE LOOP3
如果当前元素大于等于下一个元素,跳转到 LOOP3
。
XCHG AX, A[BX+2]
交换当前元素和下一个元素的值。
MOV A[BX], AX
将交换后的值放回数组。
跳转和循环:
ADD BX, 2
移动到数组的下一个元素。
LOOP LOOP2
内层循环。如果 CX
寄存器不为零,就会跳回到 LOOP2
,继续内层循环。
外层循环结束后(LOOP1):
MOV CX, DI
恢复 CX
的值,以便回到外层循环的起始位置。
LOOP LOOP1
外层循环。如果 CX
寄存器不为零,就会跳回到 LOOP1
,继续外层循环。
LOOP
指令用于实现循环结构。它的工作方式是首先减小 CX
寄存器的值,然后检查 CX
是否为零。如果 CX
不为零,则根据指定的相对偏移量跳转到循环的起始位置。DI
寄存器并不直接参与 LOOP
指令的工作,而是在循环中的其他指令中使用。
求1到100的和,并将十六进制结果输出到屏幕上。 DSEG SEGMENT M DW 0 ; 定义数据段DSEG,包含一个字(2字节)的变量M,初始值为0 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 假设代码段寄存器为CS,数据段寄存器为DS START: MOV AX,DSEG ; 将数据段DSEG的地址加载到寄存器AX MOV DS,AX ; 将数据段地址设置到数据段寄存器DS MOV AX,0 ; 初始化寄存器AX为0 MOV BX,0 ; 初始化寄存器BX为0 L1: INC BX ; BX自增 ADD AX, BX ; 将BX的值加到AX寄存器 CMP BX,100 ; 比较BX和100 JL L1 ; 如果BX小于100,则跳转到标签L1 MOV M,AX ; 将AX的值存储到变量M中 MOV BX,AX ; 将AX的值存储到寄存器BX中 SHOW: MOV CH,4 ; 初始化寄存器CH为4,用于外循环 L2: MOV CL,4 ; 初始化寄存器CL为4,用于内循环 ROL BX,CL ; 将BX左循环移位CL位 MOV DX,BX ; 将移位后的值存储到寄存器DX中 AND DX,000FH ; 与操作,保留低4位的值 ADD DL,30H ; 转换为ASCII码 ; 数字9的后面一个字符是 : CMP DL,3AH ; 比较DL和ASCII码字符":"的值 JL PRINT ; 如果DL小于":",则跳转到PRINT标签 ADD DL,7H ; 如果DL大于等于":",则加7H,转化成16进制 PRINT: MOV AH,02H ; DOS功能号,用于显示字符 INT 21H ; 调用DOS中断 DEC CH ; 外循环计数减1 JNZ L2 ; 如果CH不为0,继续内循环 MOV AX,4C00H ; 设置DOS功能号,用于程序退出 INT 21H ; 调用DOS中断 CSEG ENDS END START ; 结束程序
在给 DL
寄存器的值加上 30H
后,DL
中存储的值就变成了相应的 ASCII 码字符。然后,通过比较 DL
和 ASCII 码字符 3AH
,程序判断 DL
中的字符是否小于 ':'
,如果是,则跳转到 PRINT
标签。
之后,如果 DL
中的字符大于等于 ':'
,则执行 ADD DL, 7H
,相当于将 DL
中的字符加上 7。这样的处理可能是为了将字符 ‘9’ 转换为字母 ‘A’。在 ASCII 码中,字符 ‘0’ 到 ‘9’ 的 ASCII 码是连续的,紧接着是字符 ‘:’,然后是字符 ‘A’ 到 ‘F’,它们也是连续的。为了符合16进制。
ascii码中,字符9与A,相差7H
实验五 十进制转十六进制 DECIHEX SEGMENT ; 段定义,DECIHEX 段开始 ASSUME CS:DECIHEX ; MAIN PROC FAR: 主程序开始 MAIN PROC FAR REPEAT1: CALL DECIBIN ; 调用 DECIBIN 过程,将用户输入的十进制数字转换为二进制 CALL CRLF ; 调用 CRLF 过程,输出换行符 CALL BINIHEX ; 调用 BINIHEX 过程,将二进制数字转换为十六进制并输出 CALL CRLF ; 调用 CRLF 过程,输出换行符 JMP REPEAT1 ; 无条件跳转到 REPEAT1 标签,实现循环 MAIN ENDP ; 主程序结束 ; DECIBIN PROC NEAR: 十进制转二进制过程开始 DECIBIN PROC NEAR MOV BX,0 ; BX 寄存器清零,用于存储二进制结果 NEW: MOV AH,01H ; 调用 DOS 功能 01H,从标准输入获取一个字符 INT 21H ; 中断 21H,调用 DOS 功能 SUB AL,30H ; 将 ASCII 字符转换为数字 JB EXIT ; 若小于 '0',跳转到 EXIT 标签,结束循环 CMP AL,9D ; 若大于 '9',跳转到 EXIT 标签,结束循环 JG EXIT CBW ; 将 AL 扩展为 AX,处理负数情况 XCHG AX,BX ; 交换 AX 和 BX 寄存器的值 MOV CX,10D ; CX 寄存器存储 10,用于乘法 MUL CX ; 乘以 10,将结果保存在 AX 寄存器 XCHG AX,BX ; 交换 AX 和 BX 寄存器的值 ADD BX,AX ; 将新的数字加到 BX 寄存器中 JMP NEW ; 无条件跳转到 NEW 标签,继续循环 EXIT: RET ; 返回调用点 DECIBIN ENDP ; 十进制转二进制过程结束 ; BINIHEX PROC NEAR: 二进制转十六进制过程开始 BINIHEX PROC NEAR MOV CH,4 ; CH 寄存器存储 4,用于循环处理每个四位二进制数 ROTATE: MOV CL,4 ; CL 寄存器存储 4,用于循环左移 BX 寄存器 ROL BX,CL ; 将 BX 寄存器左移 4 位,相当于将四位二进制数移到最高位 MOV AL,BL ; 将 BX 寄存器的低字节(四位二进制数)复制到 AL 寄存器 AND AL,0FH ; 将 AL 寄存器的高四位清零 ADD AL,30H ; 将 AL 寄存器的值转换为 ASCII 码 CMP AL,3AH ; 比较 AL 寄存器的值是否大于等于 'A' JL PRINTIT ; 若小于 'A',跳转到 PRINTIT 标签 ADD AL,7 ; 若大于等于 'A',加上偏移值,转换为正确的 ASCII 码 PRINTIT: MOV DL,AL ; 将 AL 寄存器的值复制到 DL 寄存器 MOV AH,02H ; 调用 DOS 功能 02H,输出一个字符 INT 21H ; 中断 21H,调用 DOS 功能 DEC CH ; CH 寄存器减一 JNZ ROTATE ; 若 CH 寄存器不为零,跳转到 ROTATE 标签,继续循环 RET ; 返回调用点 BINIHEX ENDP ; 二进制转十六进制过程结束 ; CRLF PROC NEAR: 输出换行符过程开始 CRLF PROC NEAR MOV DL,0DH ; DL 寄存器存储回车符 ASCII 码 MOV AH,02H ; 调用 DOS 功能 02H,输出一个字符 INT 21H ; 中断 21H,调用 DOS 功能 MOV DL,0AH ; DL 寄存器存储换行符 ASCII 码 MOV AH,02H ; 调用 DOS 功能 02H,输出一个字符 INT 21H ; 中断 21H,调用 DOS 功能 RET ; 返回调用点 CRLF ENDP ; 输出换行符过程结束 DECIHEX ENDS ; DECIHEX 段结束 END MAIN ; 主程序结束
太难了,放弃
其它
从键盘输入连续的字符。当输入小写字母时,显示出对应的大写字母;当输入大写字母时,显示出对应的小写字母。当输入0到9的任何一个数字时,退出程序。
小写转大写
CSEG SEGMENT ASSUME CS:CSEG START: MOV AH,01H ; 调用21H中断以获取一个字符 INT 21H CMP AL,'a' JB EXIT ; 如果小于 'a',跳到退出标签 CMP AL,'z' JA EXIT ; 如果大于 'z',跳到退出标签 SUB AL,20H ; 转换小写字母为大写字母,大小写的16进制相差20H MOV DL,AL ; 将转换后的字符放入DL寄存器 MOV AH,02H ; 调用21H中断以输出字符 INT 21H JMP START ; 继续循环 EXIT: MOV AX,4C00H ; 调用21H中断以程序结束 INT 21H CSEG ENDS END START
输入输出
DSEG SEGMENT NEXT DB 13,10,'$' ; 定义一个包含回车、换行和'$'的字符串 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 指定代码段和数据段寄存器 START: MOV AX,DSEG ; 将数据段地址加载到AX寄存器 MOV DS,AX ; 将AX中的值加载到DS寄存器 MOV AH,01H ; 调用21H中断以获取一个字符 INT 21H MOV BL,AL ; 将输入的字符保存到BL寄存器 LEA DX,NEXT ; 将NEXT的地址加载到DX寄存器 MOV AH,09H ; 调用21H中断以显示字符串 INT 21H MOV DL,BL ; 将之前保存在BL寄存器中的字符加载到DL寄存器 MOV AH,02H ; 调用21H中断以显示字符 INT 21H MOV AX,4C00H ; 调用21H中断以结束程序 INT 21H CSEG ENDS END START
LEA
是 x86 汇编语言中的一条指令,用于加载有效地址(Load Effective Address)。它的语法如下:
LEA
: 操作码,表示加载有效地址。
destination
: 目标操作数,通常是一个寄存器,用于存储源操作数的地址。
source
: 源操作数,通常是一个内存地址或者寄存器。
LEA
并不是用来加载实际的数据,而是用来加载源操作数的地址到目标寄存器中。这个指令在一些情况下用于进行地址计算,但并不执行内存访问。通常,LEA
的使用场景之一是计算数组元素的偏移地址。
在你提供的汇编代码中,有一条 LEA
指令:
这条指令将 NEXT
的地址加载到 DX
寄存器中。在这个上下文中,它为后续的显示字符串操作提供了字符串的起始地址。
MAx
这段代码通过比较数组中的元素,找到最大值,并将其存储在MAX变量中。
DSEG SEGMENT ARG DW 1001H,2002H,3003H ; 定义一个包含三个WORD类型元素的数组 MAX DW 0 ; 定义一个用于存储最大值的变量 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 指定代码段和数据段寄存器 START: MOV AX,DSEG ; 将数据段地址加载到AX寄存器 MOV DS,AX ; 将AX中的值加载到DS寄存器 LEA SI,ARG ; 将数组ARG的地址加载到SI寄存器 MOV AX,[SI] ; 将数组的第一个元素加载到AX寄存器 MOV BX,[SI+2] ; 将数组的第二个元素加载到BX寄存器 CMP AX,BX ; 比较AX和BX的值 JAE MAX1 ; 如果AX大于等于BX,跳转到MAX1标签 XCHG AX,BX ; 交换AX和BX的值 MAX1: MOV BX,[SI+4] ; 将数组的第三个元素加载到BX寄存器 CMP AX,BX ; 比较AX和BX的值 JAE MAX2 ; 如果AX大于等于BX,跳转到MAX2标签 XCHG AX,BX ; 交换AX和BX的值 MAX2: MOV MAX,AX ; 将最大值存储到MAX变量中 MOV AX, 4C00H ; 调用21H中断以结束程序 INT 21H CSEG ENDS END START
这段代码将一个字节的数据拆分为两个四位的十六进制数字,并输出到屏幕上。
分段函数
DSEG SEGMENT ARGX DB 20 ; 定义DB类型的变量ARGX,初始值为20 RLTY DB 0 ; 定义DB类型的变量RLTY,初始值为0 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG ; 指定代码段和数据段寄存器 START: MOV AX,DSEG ; 将数据段首地址送入DS中 MOV DS,AX ; 将AX中的值加载到DS寄存器 MOV AL,ARGX ; 将变量ARGX的值加载到AL寄存器 AND AL,AL ; 检查AL是否为负数 JS A1 ; 如果是负数,跳转到标签A1 JZ SAVE ; 如果是零,跳转到标签SAVE CMP AL,8 ; 比较AL是否小于等于8 JBE ONE ; 如果是,跳转到标签ONE CMP AL,15 ; 比较AL是否大于等于15 JGE SAVE ; 如果是,跳转到标签SAVE SAL AL,1 ; 算术左移一位(相当于乘以2) SAL AL,1 ; 算术左移一位(相当于乘以2) ADD AL,ARGX ; 加上ARGX的值 SUB AL,2 ; 减去2 JMP SAVE ; 无条件跳转到SAVE标签 ONE: ADD AL,10 ; 加上10 JMP SAVE ; 无条件跳转到SAVE标签 A1: NEG AL ; 取负值 SAVE: MOV RLTY,AL ; 将AL的值保存到RLTY变量中 MOV DL,10 ; 将10加载到DL寄存器 CBW ; 将AL的值符号扩展到AX寄存器 DIV DL ; AX除以DL,结果保存在AL中,余数保存在AH中 MOV BL,AH ; 将余数AH保存到BL中 CMP AL,0 ; 比较AL是否为0 JZ TT ; 如果是,跳转到标签TT CBW ; 将AL的值符号扩展到AX寄存器 DIV DL ; AX除以DL,结果保存在AL中,余数保存在AH中 MOV CL,AH ; 将余数AH保存到CL中 ADD CL,30H ; 加上ASCII值'0' MOV DL,CL ; 将CL的值保存到DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H TT: ADD BL,30H ; 加上ASCII值'0' MOV DL,BL ; 将BL的值保存到DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H MOV AH,4CH ; 调用21H中断以结束程序 INT 21H CSEG ENDS ; 代码段结束 END START ; 源程序结束
普通输出
STACKS SEGMENT STACK ; 定义堆栈段 DW 128 DUP(?) ; 分配128字节的堆栈空间 STACKS ENDS ; 堆栈段结束 DSGS SEGMENT ; 数据段定义 STRING DB 'WELCOME! Computer Science & Technology 2021-2 YangFengMei',13,10,'$' ; 定义字符串 DSGS ENDS ; 数据段结束 CSGS SEGMENT ; 代码段定义 ASSUME CS:CSGS,DS:DSGS ; 将段与段寄存器关联 START: MOV AX,DSGS ; 将数据段首地址送入AX MOV DS,AX ; 将AX中的值加载到DS寄存器 LEA DX,STRING ; 将字符串的地址加载到DX寄存器 MOV AH,9H ; 调用21H中断以显示字符串 INT 21H MOV AH,4CH ; 调用21H中断以结束程序 INT 21H CSGS ENDS ; 代码段结束 END START ; 源程序结束
三数排序
(看前面实验)DATA SEGMENT FIRST DB 0 ; 存储第一个输入的数 SECOND DB 0 ; 存储第二个输入的数 THIRD DB 0 ; 存储第三个输入的数 MAX DB 0 ; 存储最大值 MID DB 0 ; 存储中间值 MIN DB 0 ; 存储最小值 DATA ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DATA ; 指定代码段和数据段寄存器 START: MOV AX,DATA ; 将数据段首地址送入AX MOV DS,AX ; 将AX中的值加载到DS寄存器,设置数据段地址 MOV AH,01H ; 待排序数输入 INT 21H MOV FIRST,AL ; 将输入的第一个数存储到FIRST MOV AH,01H INT 21H MOV SECOND,AL ; 将输入的第二个数存储到SECOND MOV AH,01H INT 21H MOV THIRD,AL ; 将输入的第三个数存储到THIRD MOV DL,0DH ; 换行 MOV AH,02H INT 21H MOV DL,0AH MOV AH,02H INT 21H MOV AL,FIRST ; 比较前两个数并将大值放入AL,小值放BL MOV BL,SECOND CMP AL,BL JAE UP XCHG AL,BL UP: MOV CL,THIRD ; 取出第三个值准备比较 CMP AL,CL ; 将前一次比较中大值与第三个数比较 JAE GET XCHG AL,CL ; 此时AL中为最大值 GET: CMP BL,CL ; 将剩下两数相比较,最小放CL,大值放BL JAE FINAL XCHG BL,CL FINAL: MOV MAX,AL ; 将最大值存入MAX MOV MID,BL ; 将中间值存入MID MOV MIN,CL ; 将最小值存入MIN MOV DL,MIN ; 待排序数输出 MOV AH,02H INT 21H MOV DL,MID MOV AH,02H INT 21H MOV DL,MAX MOV AH,02H INT 21H MOV AH,4CH ; 调用21H中断以结束程序 INT 21H CSEG ENDS END START ; 源程序结束
最大值输出
(看前面实验)DSEG SEGMENT NUM DW 1001H,2002H,3003H ; 定义一个包含三个WORD类型元素的数组NUM MAX DW 0 ; 定义一个用于存储最大值的变量MAX DSEG ENDS CSEG SEGMENT ASSUME DS:DSEG,CS:CSEG ; 指定数据段和代码段寄存器 START: MOV AX,DSEG ; 将数据段地址加载到AX寄存器 MOV DS,AX ; 将AX中的值加载到DS寄存器 LEA SI,NUM ; 将数组NUM的地址加载到SI寄存器 MOV AX,[SI] ; 将数组的第一个元素加载到AX寄存器 MOV BX,[SI+2] ; 将数组的第二个元素加载到BX寄存器 CMP AX,BX ; 比较数组的第一个和第二个元素 JAE MAX1 ; 如果第一个元素大于等于第二个元素,跳转到MAX1标签 XCHG AX,BX ; 交换AX和BX的值 MAX1: MOV BX,[SI+4] ; 将数组的第三个元素加载到BX寄存器 CMP AX,BX ; 比较AX和BX的值 JAE MAX2 ; 如果AX大于等于BX,跳转到MAX2标签 XCHG AX,BX ; 交换AX和BX的值 MAX2: MOV MAX,AX ; 将最大值存储到MAX变量中 MOV BL,AH ; 将AX的高字节(原数组的最后一个元素的高字节)存储到BL中 MOV AL,AH ; 复制AX的高字节到AL中 AND AL,0F0H ; 将AL中的高四位保留,低四位清零 MOV CL,4 ; 移动高四位到低四位的次数 ROR AL,CL ; 将高四位移到低四位 ADD AL,30H ; 转换为ASCII字符 MOV DL,AL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H AND BL,0FH ; 取出AX的高字节的低四位 ADD BL,30H ; 转换为ASCII字符 MOV DL,BL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H MOV AX,MAX ; 将最大值重新加载到AX中 MOV BL,AL ; 复制AX的低字节到BL中 AND AL,0F0H ; 将低四位清零 MOV CL,4 ; 移动高四位到低四位的次数 ROR AL,CL ; 将高四位移到低四位 ADD AL,30H ; 转换为ASCII字符 MOV DL,AL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H AND BL,0FH ; 取出AX的低字节的低四位 ADD BL,30H ; 转换为ASCII字符 MOV DL,BL ; 将要输出的字符放入DL中 MOV AH,02H ; 调用21H中断以输出字符 INT 21H MOV AH,4CH ; 调用21H中断以结束程序 INT 21H CSEG ENDS END START ; 源程序结束
这段代码通过比较数组中的元素,找到最大值,并将其以ASCII字符的形式输出。