汇编语言(王爽第三版)检测点:9
检测点:9.1
(1)
assume cs:code
data segment
???????
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
jmp word ptr [bx+1]
mov ax,4c00H
int 21H
code ends
end start
若要使程序中jmp指令执行后,cs:ip指向程序的第一条指令,在data段中应定义哪些数据?
程序分析:
1) 这个指令jmp word ptr [bx+1]是一个段内近转移,它只是修改了ip的值。它的转移地址在内存中。明确:[bx+1]在此例子中是只的data段的第二个字节。
2)我们发现ds:bx指向了data段,word ptr [bx+1]指向的是data段中的第二个字节开始的字单元,也就是说它所指向的该字单元的内容。这个内容就是jmp跳转的偏移地址。
3)word ptr [bx+1]指的是一个字单元,也就是说是2个字节,也就是说在data段中是第2和第3个字节,如果jmp转移到程序第一条指令,也就是说ip的值应为:00 00即可;我们要保证这二个字节的值是00 00就行。
4)要想jmp跳转到start标号处,它的ip值是offset start即可(在汇编语言层面我们也不必关心它们代表的具体ip值是多少);也就是说:(ds:[bx+1])==offset start,那么在data段中定义的第二个字必须是offset start。至于offset start具体代表的二进制码是什么,那是编译器的事情。
5)第一个字节,你随意定义成什么都行。
这个结果是多个:
dw 00xxH, offset start ;xx代表任意数值(一个字节的)
讲解:此时借用的是00xxH的高位字节值,00
db x,0,0 ;x代表任意数值(一个字节的)
dd 0 ;2个字的内存单元,00 00 00 00
db 3 dup (0)
dw 2 dup (0)
dd 0
简单来说就是,只要ds:[bx+1]起始地址的两个字节为0就可以了
(2)程序如下:
assume cs:code
data segment
dd 12345678H
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov [bx], offset start
mov [bx+2], code
jmp dword ptr ds:[0]
mov ax,4c00H
int 21H
code ends
end start
补全程序,使cs:ip指向程序的第一条指令。
程序分析:
1)在data段中定义了一个双字的值,占用4个字节,内存中是12 34 56 78
2)jmp dword ptr ds:[0]代表的含义是,此指令是段间转移的指令,cs和ip是存储在一个双字的单元中,其中高16位存储的是cs值,低16位存储的是ip值。
3) [bx]代表了低16位的值==ip。[bx+2]代表了高16位的值==cs。
4)也就是说保证data段中前2个字节是ip的值,第3,4字节是cs的值就可以。
5)答案也就多了。
[bx]==ip
offset start
ptr word 0
0000H
bx
[bx+2] ==cs
cs
code
(3)用Debug查看内存,结果如下:
2000:1000 BE 00 06 00 00 00 ......
则此时,CPU执行指令:
mov ax,2000h
mov es,ax
jmp dword ptr es:[1000h]
程序分析:
1)通过上面二条指令,es指向了段地址是2000H的内存段。
2)jmp dword ptr es:[1000h]指令的含义:是一个段间转移指令,指令的转移地址在内存中,该内存单元是一个双字单元(32位的单元),也就是说在1000H地址开始,低16位存储的是ip的值,高16位存储的是cs的值。
3)我们在debug内存存储显示中,不难发现,低16位是BE 00,也就是它的值是00BE。高16位是0600,也就是它的值是0006H,得出结论:(cs)= 0006H ,(ip)= 00BEH
检测点9.2
补全编程,利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s:
jmp short s
ok: mov dx,bx
mov ax ,4c00h
int 21h
code ends
end start
程序分析:
标号s前面是将ds:bx指向了段地址为2000H的内存段。s标号到jmp short s是一个循环(死循环,除非有跳出语句)。
这里我们需要jcxz有条件转移语句来实现循环的跳出,jcxz的逻辑表达式只有一个就是(cx)=0,想法将cx的内容赋值为ds:bx,也就是说从ds:[0]开始,逐个字节的将单元内容赋值给cx,然后执行jcxz语句。
由于是逐个字节的比较,bx的偏移量应该是以字节为单元。我们使用的cx寄存器是16位的,我们只需要低8位的cl寄存器就可以了。为了保证ch为0,首先必须置零。它们组合在一起就是cx的整体值(dh+dl)
需填充的第一行:mov cl,[bx] ;将2000段内存逐个字节赋值给cl
第二行:mov ch, 0 ;保证高8位为0
第三行:jcxz ok ;判断cx值,如果cx=0,跳转到ok标号
第四行:inc bx ;cx!=0,继续执行jcxz后面的语句。递增bx,
完整的程序是:
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch, 0
jcxz ok
inc bx
jmp short s
ok: mov dx,bx
mov ax ,4c00h
int 21h
code ends
end start
检测点9.3
补全编程,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s:mov cl,[bx]
mov ch,0
inc cx
inc bx
loop s
ok:dec bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
程序分析:
1)保证这个loop循环的动力是:cx!=0,首先搞清这点。
2) 如果ds:[0]=0情况下。如果我们使用jcxz指令,只有这种情况满足条件,第一个字节为0.故不能使用jcxz指令。
3)理解loop指令的动作,首先是(cx)=(cx)-1.然后才是跳转到标号执行。
4)添加inc cx指令
如果第一个字节是0情况,inc cx导致(cx)=1,执行到loop指令时,首先(cx)=(cx)-1,导致(cx)=0,loop顺序执行下面的指令(也就是标号ok的指令)。
如果第一个字节非0情况,inc cx导致(cx)>1,执行到loop指令是,首先(cx)=(cx)-1,导致(cx)> 0(不为0),loop跳转到s标号处执行代码。
5)答案:inc cx