实验3 转移指令跳转原理及其简单应用编程
任务1
源码:
1 assume cs:code, ds:data 2 3 data segment 4 x db 1, 9, 3 5 len1 equ $ - x 6 7 y dw 1, 9, 3 8 len2 equ $ - y 9 data ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov si, offset x 17 mov cx, len1 18 mov ah, 2 19 s1:mov dl, [si] 20 or dl, 30h 21 int 21h 22 23 mov dl, ' ' 24 int 21h 25 26 inc si 27 loop s1 28 29 mov ah, 2 30 mov dl, 0ah 31 int 21h 32 33 mov si, offset y 34 mov cx, len2/2 35 mov ah, 2 36 s2:mov dx, [si] 37 or dl, 30h 38 int 21h 39 40 mov dl, ' ' 41 int 21h 42 43 add si, 2 44 loop s2 45 46 mov ah, 4ch 47 int 21h 48 code ends 49 end start
所有循环指令都是短转移,对应机器码中为位移而不是地址
loop指令,先令cx的值减1,再判断cx不等于0,则跳转到标号处
对于这条loop指令的分析:
s1标号处的地址是 000D ,即十进制的13;loop后面一条指令的地址是001B,即十进制27,相减得到-14,换成二进制原码是1000 1110,补码是1111 0010,十六进制补码就是F2,和机器码内容一致。
同样的,再来分析下面这个loop。
s2标号地址是0029,loop后面一条地址的指令是0039,减一减,刚好差了十进制的16,换算成十六进制补码,-16(dec)=F0(hex补码)
任务2
1 assume cs:code, ds:data 2 3 data segment 4 dw 200h, 0h, 230h, 0h 5 data ends 6 7 stack segment 8 db 16 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov word ptr ds:[0], offset s1 17 mov word ptr ds:[2], offset s2 18 mov ds:[4], cs 19 20 mov ax, stack 21 mov ss, ax 22 mov sp, 16 23 24 call word ptr ds:[0] 25 s1: pop ax 26 27 call dword ptr ds:[2] 28 s2: pop bx 29 pop cx 30 31 mov ah, 4ch 32 int 21h 33 code ends 34 end start
执行到程序退出前,ax=0021h, bx=0026h, cx=076eh
下面进行分析:
第一个call,push ip,然后跳到s1;pop ax,把ip出栈,ax=ip 注意,这里的ip是call命令后面一条指令的ip
同样的,第二个call,因为是call dword 所以执行的操作是先push cs,再push ip;然后pop的时候bx=ip,cx=cs
任务3
1 assume cs:code, ds:data 2 data segment 3 x db 99,72,85,63,89,97,55 ;x=0 4 len equ $- x ;len=7 5 data ends 6 7 code segment 8 start: 9 mov ax,data 10 mov ds,ax 11 12 mov si,offset x 13 mov cx,len 14 15 do: 16 mov ax,[si] 17 mov ah,0 18 inc si 19 push ax ;保存寄存器状态 20 push bx ;保存寄存器状态 21 push cx ;保存寄存器状态 22 push dx ;保存寄存器状态 23 24 mov bx,10 25 mov cx,0 26 27 yazhan: 28 mov dx,0 29 div bx 30 31 push dx 32 inc cx 33 34 cmp ax,0 35 jz chuzhan 36 37 jmp yazhan 38 39 chuzhan: 40 pop dx 41 printNumber: 42 add dl,30h 43 mov ah,2 44 int 21h 45 46 loop chuzhan 47 48 pop dx 49 pop cx 50 pop bx 51 pop ax 52 53 printSpace: 54 mov ah,2 55 mov dl,' ' 56 int 21h 57 58 loop do 59 60 61 mov ah, 4ch 62 int 21h 63 code ends 64 end start
结果截图
简要的说一下这题的思路:根据提示,要么输出字符,要么输出ASCII码。数字0-9有对应的ASCII码,所以需要先对每一个数字进行拆分,然后分别输出每一位的数字对应的ASCII码。拆分数字很简单,只要模10除10循环就好。在这题,利用栈,保存每一次得到的数,出栈的过程中转换成对应的ASCII码即可。
实验4
1 assume cs:code,ds:data 2 data segment 3 str db 'try' 4 len equ $- str 5 data ends 6 7 code segment 8 start: 9 mov ax,data 10 mov ds,ax 11 mov si,offset str 12 mov cx,3 13 mov ax,0b800h 14 mov es,ax 15 mov bx,0 16 printStr: 17 mov ax,[si] 18 mov ah,02h ;绿色 19 mov es:[bx],ax 20 inc si 21 add bx,2 22 loop printStr 23 24 mov si,offset str 25 mov cx,3 26 mov bx,0f00h 27 printStr2: 28 mov ax,[si] 29 mov ah,00000100b ;红色 30 mov es:[bx],ax 31 inc si 32 add bx,2 33 loop printStr2 34 35 36 37 mov ah, 4ch 38 int 21h 39 code ends 40 end start
在这个任务点中,遇到了一些问题,暂时还没有想明白,先把问题放这里:
任务5
1 assume cs:code,ds:data 2 data segment 3 stu_no db '201983290386' 4 len = $ - stu_no 5 sign db '-' 6 space db ' ' 7 data ends 8 9 code segment 10 start: 11 mov ax,data 12 mov ds,ax 13 mov ax,0b800h 14 mov es,ax 15 16 mov cx,24*80 17 blue: 18 mov si,offset space 19 mov ax,[si] 20 mov ah,00010111b 21 mov es:[bx],ax 22 inc si 23 add bx,2 24 loop blue 25 26 mov cx,80 27 mov bx,0f00h 28 fill: 29 mov si,offset sign 30 mov ax,[si] 31 mov ah,00010111b 32 mov es:[bx],ax 33 inc si 34 add bx,2 35 loop fill 36 37 38 mov si,offset stu_no 39 mov cx,len 40 mov bx,0f00h 41 add bx,68 ;80-12 42 printStr: 43 mov ax,[si] 44 mov ah,00010111b ;蓝底白字 45 mov es:[bx],ax 46 inc si 47 add bx,2 48 loop printStr 49 50 51 mov ah, 4ch 52 int 21h 53 code ends 54 end start
可能受到前两题的锤炼,第五题感觉没那么难。思路很简单,第一步:把背景都弄蓝,最后一行不管。第二步:最后一行全部用-填充,记得背景色改成蓝色。第三步:用学号覆盖中间那一块。这里在覆盖的时候需要简单的计算一下,学号是12位的,一行最多80个字符,也就是说首字符2处于的位置是0f00h+80-12(后面两个是10进制数)
通过这题 我还学会了在data区里设置变量,要用的时候就offset导一下就好了,很方便