实验一
代码:
assume cs:code, ds:data data segment x db 1, 9, 3 len1 equ $ - x y dw 1, 9, 3 len2 equ $ - y data ends code segment start: mov ax, data mov ds, ax mov si, offset x mov cx, len1 mov ah, 2 s1:mov dl, [si] or dl, 30h int 21h mov dl, ' ' int 21h inc si loop s1 mov ah, 2 mov dl, 0ah int 21h mov si, offset y mov cx, len2/2 mov ah, 2 s2:mov dx, [si] or dl, 30h int 21h mov dl, ' ' int 21h add si, 2 loop s2 mov ah, 4ch int 21h code ends end start
反汇编截图:
1.跳转位移量为14,由于跳转的位置相对于当前位置在前面,所以位移量应当为负,表现在机器码中二进制应为补码形式,经过计算,补码的16进制表示确为在机器码中F2。
2.跳转位移量为16,由于跳转的位置相对于当前位置在前面,所以位移量应当为负,表现在机器码中二进制应为补码形式,经过计算,补码的16进制表示确为在机器码中F0。
对于这个跳转的机制,起初我存有疑问,为什么不是从此跳转指令处计算到标记处的位移量,但是后来经过思考,考虑到在CPU将当前指令送入执行时,程序计数器自动加一,指令寄存器会自动将下一条指令的地址存入,所以应当是当前loop指令下一条指令的地址与标记处指令的位移量。
实验二
代码:
assume cs:code, ds:data data segment dw 200h, 0h, 230h, 0h data ends stack segment db 16 dup(0) stack ends code segment start: mov ax, data mov ds, ax mov word ptr ds:[0], offset s1 mov word ptr ds:[2], offset s2 mov ds:[4], cs mov ax, stack mov ss, ax mov sp, 16 call word ptr ds:[0] s1: pop ax call dword ptr ds:[2] s2: pop bx pop cx mov ah, 4ch int 21h code ends end start
1.理论上分析,当程序顺序执行到第一个call指令时,由于指令中的转移为段内转移,所以将下一条指令的IP寄存器中的内容压入栈中,在访问内存单元中所存储的地址时刚好就是s1标号处的地址,所以ax就等于s1标号处的偏移地址。程序继续执行,遇到第二个call指令时,由于指令中的转移为段间转移,所以依次将CS和IP寄存器中的内容压入栈中,在访问内存单元所存储的地址时刚好就是s2标号处的地址,所以bx就等于s2标号处的偏移地址,cx等于程序cs寄存器值。
反汇编截图:
所以最终答案应该为ax=0021h,bx=0026h,cx=076Ch
2.最终执行截图:
结果无误
实验三
代码:
assume cs:code, ds:data data segment x db 99, 72, 85, 63, 89, 97, 55 len equ $- x data ends code segment start: mov ax,data mov ds,ax mov cx,len mov si,0 s: mov al,[si] mov ah,0 call printNumber call printSpace inc si loop s mov ah, 4ch int 21h printNumber: mov bl,10 div bl mov bh,ah mov ah,2h add al,48 mov dl,al int 21h mov ah,2h add bh,48 mov dl,bh int 21h ret printSpace: mov ah,2h mov dl,' ' int 21h ret code ends end start
结果:
实验四
代码:
assume cs:code, ds:data data segment str db 'try' len equ $ - str data ends code segment start: mov ax, data mov ds, ax mov ax,0b800h mov es,ax mov si,0 mov cx,len mov bl,02h mov bh,0 call printstr mov si,0 mov cx,len mov bl,04h mov bh,24 call printstr mov ah,4ch int 21h printStr: mov al,160 mul bh mov di,ax s: mov al,[si] mov es:[di],al mov es:[di+1],bl inc si add di,2 loop s ret code ends end start
结果:
实验五
代码:
assume cs:code, ds:data data segment stu_no db '201983290486' len equ $ - stu_no data ends code segment start: mov ax,data mov ds,ax mov ax,0b800h mov es,ax call printblue call printstu_no mov ah,4ch int 21h printblue: mov al,20h mov ah,10h mov di,0 mov cx,24 s2: mov bx,cx mov cx,80 s1: mov es:[di],al mov es:[di+1],ah add di,2 loop s1 mov cx,bx loop s2 ret printstu_no: mov al,2dh mov ah,17h mov cx,34 s3: mov es:[di],al mov es:[di+1],ah add di,2 loop s3 mov cx,12 mov si,0 s4: mov al,[si] mov es:[di],al mov es:[di+1],ah inc si add di,2 loop s4 mov al,2dh mov cx,34 s5: mov es:[di],al mov es:[di+1],ah add di,2 loop s5 ret code ends end start
结果:
实验总结
本次实验主要的实验内容为汇编语言中的几个常用跳转指令,验证性实验主要有两大收获,一个是按照位移进行跳转时,相对的偏移地址是由补码给出,另一个指令是侧式指令offset,值应该是该标记处到该段地址的偏移地址。后三个为编程实现屏幕显示指定内容,最主要的是模块化编程,由call指令和ret指令联合实现。