实验任务1
验证 add 指令对对标志寄存器中的零标志位 ZF(Zero Flag)、进位标志位 CF(Carry Flag) 的影响的实验截图如下:
可见,add 指令既能影响零标志位 ZF,也能影响进位标志位 CF。
验证 inc 指令对对标志寄存器中的零标志位 ZF(Zero Flag)、进位标志位 CF(Carry Flag) 的影响的实验截图如下:
可见,add 指令能影响零标志位 ZF,但不能影响进位标志位 CF。
1 assume cs:code, ds:data 2 data segment 3 x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h 4 y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h 5 data ends 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, offset x 11 mov di, offset y 12 call add128 13 14 mov ah, 4ch 15 int 21h 16 add128: 17 push ax 18 push cx 19 push si 20 push di 21 22 sub ax, ax 23 24 mov cx, 8 25 s: mov ax, [si] 26 adc ax, [di] 27 mov [si], ax 28 29 inc si 30 inc si 31 inc di 32 inc di 33 loop s 34 35 pop di 36 pop si 37 pop cx 38 pop ax 39 ret 40 code ends 41 end start
1 add si, 2 2 add di, 2
答:不能替换。因为 inc 指令不影响 CF 标志位,而 add 指令影响会影响 CF 标志位,当加法计算过程中出现进位,CF = 1,如果中途对 si, di 使用 add 指令,CF就会被重新置0,导致最终的计算结果不正确,因此 inc 指令是不能用 add 指令替换的。
答:做128位加法之前,数据段值如下图所示:
做128位加法之后,数据段值如下图所示:
实验任务2
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 s1: 12 mov ah, 1 13 int 21h 14 mov [si], al 15 cmp al, '#' 16 je next 17 inc si 18 jmp s1 19 next: 20 mov ah, 2 21 mov dl, 0ah 22 int 21h 23 24 mov cx, si 25 mov si, 0 26 s2: mov ah, 2 27 mov dl, [si] 28 int 21h 29 inc si 30 loop s2 31 32 mov ah, 4ch 33 int 21h 34 code ends 35 end start
可以看到,程序实现了对输入字符串的打印输出。
① 汇编指令代码line11-18,实现的功能是?
答:代码 line11-18 的功能是逐个读取键盘输入的字符,依次存入data 数据段中,直到遇到字符 ‘#’ 时,才停止读取。
② 汇编指令代码line20-22,实现的功能是?
答:代码 line20-22 的功能是进行换行,方便后续在新的一行显示输入的字符串。
③ 汇编指令代码line24-30,实现的功能是?
答:代码 line24-30 的功能是在屏幕上输出之前输入的字符串,但输出的字符串中不包含最后的 ‘#’。
实验任务3
1 assume cs:code, ds:data, ss:stack 2 data segment 3 x dw 91, 792, 8536, 65521, 2021 4 len equ $ - x 5 data ends 6 7 stack segment 8 dw 0,0,0,0,0,0,0,0 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 mov ax, stack 16 mov ss, ax 17 mov sp, 16 18 19 mov cx, len/2 20 mov si, 0 21 mov di, 0 22 s: mov ax, ds:[si] 23 call printNumber 24 call printSpace 25 add si, 2 26 loop s 27 28 mov ah, 4ch 29 int 21h 30 printNumber: 31 push cx 32 mov cx, 0 33 mov bx, 10 34 s1: 35 mov dx, 0 36 div bx 37 push dx 38 inc cx ;cx存储栈中数字个数 39 cmp ax, 0 40 je s2 41 jmp s1 42 s2: 43 mov ah, 2 44 pop dx 45 or dl, 30h 46 int 21h 47 loop s2 48 49 pop cx 50 ret 51 52 printSpace: 53 mov ah, 2 54 mov dl, ' ' 55 int 21h 56 ret 57 code ends 58 end start
从运行结果中可以看出,程序成功实现了对 data 段连续数据的输出。
实验任务4
1 assume cs:code, ds:data 2 data segment 3 str db "assembly language, it's not difficult but tedious" 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 12 mov cx, len 13 mov si, 0 14 call strupr 15 16 mov ah, 4ch 17 int 21h 18 strupr: 19 s: 20 cmp byte ptr ds:[si], 'a' 21 jl s1 22 cmp byte ptr ds:[si], 'z' 23 jg s1 24 and byte ptr ds:[si], 11011111b 25 s1: 26 inc si 27 loop s 28 ret 29 code ends 30 end start
call strupr 指令调用之前,数据段的值:
call strupr 指令调用之后,数据段的值:
从 call strupr 指令调用前后数据段的值可以看出,程序成功将小写字母转化成了大写字母。
实验任务5
1 assume cs:code, ds:data 2 3 data segment 4 str1 db "yes", '$' 5 str2 db "no", '$' 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 13 mov ah, 1 14 int 21h ; 从键盘输入字符 15 16 mov ah, 2 17 mov bh, 0 18 mov dh, 24 ; 设置光标位置在第24行 19 mov dl, 70 ; 设置光标位置在第70列 20 int 10h ; 设置光标位置 21 22 cmp al, '7' 23 je s1 24 mov ah, 9 25 mov dx, offset str2 26 int 21h ; 显示标号str2处的字符串 27 28 jmp over 29 30 s1: mov ah, 9 31 mov dx, offset str1 32 int 21h ; 显示标号str2处的字符串 33 over: 34 mov ah, 4ch 35 int 21h 36 code ends 37 end start
实验任务6
中断有硬中断和软中断之分,软中断是利用软件方式进行模拟,以达到异步执行的效果,int属于软中断指令,软中断的中断过程一般是固定的,都是由 CPU 通过中断类型码在中断向量表中找到中断处理程序的入口地址,设置CS和IP。由于有一部分中断向量表项是空的,所以用户可以选取一个未被使用的中断码,实现一个软中断,本次实验中出现的 int 42 软中断,就是这样的例子。我以为这是对系统已有的int软中断的补充与拓展,给了用户一定的自由,增加了程序的灵活性,与C++中的运算符重载有异曲同工之妙。与运算符重载类似,由用户自定义的软中断在实际应用中也应当有所节制,不能滥用,否则会导致程序可读性较差。